1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-08-25 RT-Thread the first version for MCXC444.
9 */
10
11 #include "drv_pin.h"
12
13 #include "fsl_common.h"
14 #include "fsl_gpio.h"
15 #include "fsl_port.h"
16
17 #ifdef RT_USING_PIN
18
19 #define GET_GPIO_PORT(x) ((x) / 32)
20 #define GET_GPIO_PIN(x) ((x) % 32)
21
22 static struct rt_pin_ops mcx_pin_ops;
23
24 static GPIO_Type *GPIO_TYPE_TBL[] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE};
25 static PORT_Type *PORT_TYPE_TBL[] = {PORTA, PORTB, PORTC, PORTD, PORTE};
26 static void (*pin_irq_hdr_tab[32 * 5])(void *args) = {0};
27 static void *pin_irq_arg_tab[32 * 5] = {0};
28
29 #define PIN2GPIO(x) GPIO_TYPE_TBL[GET_GPIO_PORT(x)]
30 #define PIN2PORT(x) PORT_TYPE_TBL[GET_GPIO_PORT(x)]
31
mcx_pin_mode(rt_device_t dev,rt_base_t pin,rt_uint8_t mode)32 static void mcx_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
33 {
34 gpio_pin_config_t gpio_config = {0};
35 PORT_SetPinMux(PIN2PORT(pin), GET_GPIO_PIN(pin), kPORT_MuxAsGpio);
36
37 switch (mode)
38 {
39 case PIN_MODE_OUTPUT:
40 gpio_config.pinDirection = kGPIO_DigitalOutput;
41 gpio_config.outputLogic = 0;
42 break;
43 case PIN_MODE_INPUT:
44 gpio_config.pinDirection = kGPIO_DigitalInput;
45 //PORT_SetPinPullSelect(PIN2PORT(pin), GET_GPIO_PIN(pin), kPORT_PullDisable);
46 break;
47 case PIN_MODE_INPUT_PULLUP:
48 gpio_config.pinDirection = kGPIO_DigitalInput;
49 //PORT_SetPinPullSelect(PIN2PORT(pin), GET_GPIO_PIN(pin), kPORT_PullUp);
50 break;
51 case PIN_MODE_INPUT_PULLDOWN:
52 gpio_config.pinDirection = kGPIO_DigitalInput;
53 //PORT_SetPinPullSelect(PIN2PORT(pin), GET_GPIO_PIN(pin), kPORT_PullDown);
54 break;
55 case PIN_MODE_OUTPUT_OD:
56 gpio_config.pinDirection = kGPIO_DigitalOutput;
57 gpio_config.outputLogic = 1;
58 //PORT_SetPinOpenDrainEnable(PIN2PORT(pin), GET_GPIO_PIN(pin), true);
59 break;
60 }
61
62 GPIO_PinInit(PIN2GPIO(pin), GET_GPIO_PIN(pin), &gpio_config);
63 }
64
mcx_pin_write(rt_device_t dev,rt_base_t pin,rt_uint8_t value)65 static void mcx_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
66 {
67 GPIO_PinWrite(PIN2GPIO(pin), GET_GPIO_PIN(pin), value);
68 }
69
mcx_pin_read(rt_device_t dev,rt_base_t pin)70 static rt_ssize_t mcx_pin_read(rt_device_t dev, rt_base_t pin)
71 {
72 return GPIO_PinRead(PIN2GPIO(pin), GET_GPIO_PIN(pin));
73 }
74
mcx_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)75 static rt_err_t mcx_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args)
76 {
77 PORT_Type *port = PIN2PORT(pin);
78 uint32_t pin_index = GET_GPIO_PIN(pin);
79 uint32_t port_index = GET_GPIO_PORT(pin);
80 port_interrupt_t port_int = kPORT_InterruptOrDMADisabled;
81
82 switch (mode)
83 {
84 case PIN_IRQ_MODE_RISING:
85 port_int = kPORT_InterruptRisingEdge;
86 break;
87 case PIN_IRQ_MODE_FALLING:
88 port_int = kPORT_InterruptFallingEdge;
89 break;
90 case PIN_IRQ_MODE_RISING_FALLING:
91 port_int = kPORT_InterruptEitherEdge;
92 break;
93 case PIN_IRQ_MODE_HIGH_LEVEL:
94 port_int = kPORT_InterruptLogicOne;
95 break;
96 case PIN_IRQ_MODE_LOW_LEVEL:
97 port_int = kPORT_InterruptLogicZero;
98 break;
99 default:
100 return RT_EINVAL;
101 }
102
103 PORT_SetPinInterruptConfig(port, pin_index, kPORT_InterruptOrDMADisabled);
104
105 pin_irq_hdr_tab[port_index * 32 + pin_index] = hdr;
106 pin_irq_arg_tab[port_index * 32 + pin_index] = args;
107
108 PORT_SetPinInterruptConfig(port, pin_index, port_int);
109
110 return RT_EOK;
111 }
112
113
mcx_pin_detach_irq(struct rt_device * device,rt_base_t pin)114 static rt_err_t mcx_pin_detach_irq(struct rt_device *device, rt_base_t pin)
115 {
116 PORT_Type *port = PIN2PORT(pin);
117 uint32_t pin_index = GET_GPIO_PIN(pin);
118
119 PORT_SetPinInterruptConfig(port, pin_index, kPORT_InterruptOrDMADisabled);
120
121 return RT_EOK;
122 }
123
mcx_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)124 static rt_err_t mcx_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
125 {
126 PORT_Type *port = PIN2PORT(pin);
127 uint32_t pin_index = GET_GPIO_PIN(pin);
128 IRQn_Type irqn;
129
130 switch ((uint32_t)port)
131 {
132 case PORTA_BASE:
133 irqn = PORTA_IRQn;
134 break;
135 case PORTB_BASE:
136 irqn = NotAvail_IRQn;
137 break;
138 case PORTC_BASE:
139 irqn = PORTC_PORTD_IRQn;
140 break;
141 case PORTD_BASE:
142 irqn = PORTC_PORTD_IRQn;
143 break;
144 case PORTE_BASE:
145 irqn = NotAvail_IRQn;
146 break;
147 default:
148 return RT_ERROR;
149 }
150
151 if (enabled)
152 {
153 PORT_SetPinInterruptConfig(port, pin_index, kPORT_InterruptRisingEdge);
154
155 PORT_ClearPinsInterruptFlags(port, (1U << pin_index));
156
157 NVIC_EnableIRQ(irqn);
158 }
159 else
160 {
161 PORT_SetPinInterruptConfig(port, pin_index, kPORT_InterruptOrDMADisabled);
162
163 NVIC_DisableIRQ(irqn);
164 }
165
166 return RT_EOK;
167 }
168
169
mcx_gpio_irq_handler(PORT_Type * port)170 static void mcx_gpio_irq_handler(PORT_Type *port)
171 {
172 uint32_t pin_index;
173 uint32_t port_index = ((uint32_t)port - PORTA_BASE) / (PORTB_BASE - PORTA_BASE);
174
175
176 for (pin_index = 0; pin_index < 32; pin_index++)
177 {
178 if (PORT_GetPinsInterruptFlags(port) & (1U << pin_index))
179 {
180 PORT_ClearPinsInterruptFlags(port, 1U << pin_index);
181 if (pin_irq_hdr_tab[port_index * 32 + pin_index])
182 {
183 pin_irq_hdr_tab[port_index * 32 + pin_index](pin_irq_arg_tab[port_index * 32 + pin_index]);
184 }
185 }
186 }
187 }
188
PORTA_IRQHandler(void)189 void PORTA_IRQHandler(void)
190 {
191 rt_interrupt_enter();
192 mcx_gpio_irq_handler(PORTA);
193 rt_interrupt_leave();
194 }
195
196
PORTC_PORTD_IRQHandler(void)197 void PORTC_PORTD_IRQHandler(void)
198 {
199 rt_interrupt_enter();
200 mcx_gpio_irq_handler(PORTC);
201 rt_interrupt_leave();
202 }
203
rt_hw_pin_init(void)204 int rt_hw_pin_init(void)
205 {
206 int ret = RT_EOK;
207
208 mcx_pin_ops.pin_mode = mcx_pin_mode;
209 mcx_pin_ops.pin_read = mcx_pin_read;
210 mcx_pin_ops.pin_write = mcx_pin_write;
211 mcx_pin_ops.pin_attach_irq = mcx_pin_attach_irq;
212 mcx_pin_ops.pin_detach_irq = mcx_pin_detach_irq;
213 mcx_pin_ops.pin_irq_enable = mcx_pin_irq_enable;
214 mcx_pin_ops.pin_get = RT_NULL;
215
216 ret = rt_device_pin_register("pin", &mcx_pin_ops, RT_NULL);
217
218 return ret;
219 }
220 INIT_BOARD_EXPORT(rt_hw_pin_init);
221
222 #endif /* RT_USING_PIN */
223