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