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  * 2022-07-1      Rbb666            first version
9  * 2025-04-24     Passionate0424    fix ifx_pin_irq_enable
10  */
11 
12 #include "drv_gpio.h"
13 
14 #ifdef RT_USING_PIN
15 
16 #define PIN_GET(pin)        ((uint8_t)(((uint8_t)pin) & 0x07U))
17 #define PORT_GET(pin)       ((uint8_t)(((uint8_t)pin) >> 3U))
18 
19 #if defined(SOC_XMC7200D_E272K8384AA)
20 #define __IFX_PORT_MAX      35u
21 #else
22 #define __IFX_PORT_MAX      14u
23 #endif
24 
25 #define PIN_IFXPORT_MAX     __IFX_PORT_MAX
26 
27 static cyhal_gpio_callback_data_t irq_cb_data[PIN_IFXPORT_MAX];
28 
29 static struct pin_irq_map pin_irq_map[] =
30 {
31     {CYHAL_PORT_0,  ioss_interrupts_gpio_0_IRQn},
32 #if !defined(SOC_CY8C6245LQI_S3D72) && !defined(SOC_CY8C6244LQI_S4D92)
33     {CYHAL_PORT_1,  ioss_interrupts_gpio_1_IRQn},
34 #endif
35     {CYHAL_PORT_2,  ioss_interrupts_gpio_2_IRQn},
36     {CYHAL_PORT_3,  ioss_interrupts_gpio_3_IRQn},
37 #if !defined(SOC_CY8C6245LQI_S3D72) && !defined(SOC_CY8C6244LQI_S4D92)
38     {CYHAL_PORT_4,  ioss_interrupts_gpio_4_IRQn},
39 #endif
40     {CYHAL_PORT_5,  ioss_interrupts_gpio_5_IRQn},
41     {CYHAL_PORT_6,  ioss_interrupts_gpio_6_IRQn},
42     {CYHAL_PORT_7,  ioss_interrupts_gpio_7_IRQn},
43     {CYHAL_PORT_8,  ioss_interrupts_gpio_8_IRQn},
44     {CYHAL_PORT_9,  ioss_interrupts_gpio_9_IRQn},
45     {CYHAL_PORT_10,  ioss_interrupts_gpio_10_IRQn},
46     {CYHAL_PORT_11,  ioss_interrupts_gpio_11_IRQn},
47     {CYHAL_PORT_12,  ioss_interrupts_gpio_12_IRQn},
48 #if !defined(SOC_CY8C6245LQI_S3D72) && !defined(SOC_CY8C6244LQI_S4D92)
49     {CYHAL_PORT_13,  ioss_interrupts_gpio_13_IRQn},
50 #endif
51     {CYHAL_PORT_14,  ioss_interrupts_gpio_14_IRQn},
52 #if defined(SOC_XMC7200D_E272K8384AA)
53     {CYHAL_PORT_15,  ioss_interrupts_gpio_15_IRQn},
54     {CYHAL_PORT_16,  ioss_interrupts_gpio_16_IRQn},
55     {CYHAL_PORT_17,  ioss_interrupts_gpio_17_IRQn},
56     {CYHAL_PORT_18,  ioss_interrupts_gpio_18_IRQn},
57     {CYHAL_PORT_19,  ioss_interrupts_gpio_19_IRQn},
58     {CYHAL_PORT_20,  ioss_interrupts_gpio_20_IRQn},
59     {CYHAL_PORT_21,  ioss_interrupts_gpio_21_IRQn},
60     {CYHAL_PORT_22,  ioss_interrupts_gpio_23_IRQn},
61     {CYHAL_PORT_24,  ioss_interrupts_gpio_24_IRQn},
62     {CYHAL_PORT_25,  ioss_interrupts_gpio_25_IRQn},
63     {CYHAL_PORT_26,  ioss_interrupts_gpio_26_IRQn},
64     {CYHAL_PORT_27,  ioss_interrupts_gpio_27_IRQn},
65     {CYHAL_PORT_28,  ioss_interrupts_gpio_28_IRQn},
66     {CYHAL_PORT_29,  ioss_interrupts_gpio_29_IRQn},
67     {CYHAL_PORT_30,  ioss_interrupts_gpio_30_IRQn},
68     {CYHAL_PORT_31,  ioss_interrupts_gpio_31_IRQn},
69     {CYHAL_PORT_32,  ioss_interrupts_gpio_32_IRQn},
70     {CYHAL_PORT_33,  ioss_interrupts_gpio_33_IRQn},
71     {CYHAL_PORT_34,  ioss_interrupts_gpio_34_IRQn},
72 #endif
73 };
74 
75 static struct rt_pin_irq_hdr pin_irq_handler_tab[] =
76 {
77     {-1, 0, RT_NULL, RT_NULL},
78     {-1, 0, RT_NULL, RT_NULL},
79     {-1, 0, RT_NULL, RT_NULL},
80     {-1, 0, RT_NULL, RT_NULL},
81     {-1, 0, RT_NULL, RT_NULL},
82     {-1, 0, RT_NULL, RT_NULL},
83     {-1, 0, RT_NULL, RT_NULL},
84     {-1, 0, RT_NULL, RT_NULL},
85     {-1, 0, RT_NULL, RT_NULL},
86     {-1, 0, RT_NULL, RT_NULL},
87     {-1, 0, RT_NULL, RT_NULL},
88     {-1, 0, RT_NULL, RT_NULL},
89     {-1, 0, RT_NULL, RT_NULL},
90     {-1, 0, RT_NULL, RT_NULL},
91     {-1, 0, RT_NULL, RT_NULL},
92     {-1, 0, RT_NULL, RT_NULL},
93 #if defined(SOC_XMC7200D_E272K8384AA)
94     {-1, 0, RT_NULL, RT_NULL},
95     {-1, 0, RT_NULL, RT_NULL},
96     {-1, 0, RT_NULL, RT_NULL},
97     {-1, 0, RT_NULL, RT_NULL},
98     {-1, 0, RT_NULL, RT_NULL},
99     {-1, 0, RT_NULL, RT_NULL},
100     {-1, 0, RT_NULL, RT_NULL},
101     {-1, 0, RT_NULL, RT_NULL},
102     {-1, 0, RT_NULL, RT_NULL},
103     {-1, 0, RT_NULL, RT_NULL},
104     {-1, 0, RT_NULL, RT_NULL},
105     {-1, 0, RT_NULL, RT_NULL},
106     {-1, 0, RT_NULL, RT_NULL},
107     {-1, 0, RT_NULL, RT_NULL},
108     {-1, 0, RT_NULL, RT_NULL},
109     {-1, 0, RT_NULL, RT_NULL},
110     {-1, 0, RT_NULL, RT_NULL},
111     {-1, 0, RT_NULL, RT_NULL},
112     {-1, 0, RT_NULL, RT_NULL},
113 #endif
114 };
115 
pin_irq_handler(int irqno)116 rt_inline void pin_irq_handler(int irqno)
117 {
118     Cy_GPIO_ClearInterrupt(CYHAL_GET_PORTADDR(irqno), CYHAL_GET_PIN(irqno));
119 
120     if (pin_irq_handler_tab[irqno].hdr)
121     {
122         pin_irq_handler_tab[irqno].hdr(pin_irq_handler_tab[irqno].args);
123     }
124 }
125 
gpio_exint_handler(uint16_t GPIO_Port)126 void gpio_exint_handler(uint16_t GPIO_Port)
127 {
128     pin_irq_handler(GPIO_Port);
129 }
130 
131 /* interrupt callback definition*/
irq_callback(void * callback_arg,cyhal_gpio_event_t event)132 static void irq_callback(void *callback_arg, cyhal_gpio_event_t event)
133 {
134     /* To avoid compiler warnings */
135     (void) callback_arg;
136     (void) event;
137 
138     /* enter interrupt */
139     rt_interrupt_enter();
140 
141     gpio_exint_handler(*(rt_uint16_t *)callback_arg);
142 
143     /* leave interrupt */
144     rt_interrupt_leave();
145 }
146 
ifx_pin_mode(rt_device_t dev,rt_base_t pin,rt_uint8_t mode)147 static void ifx_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
148 {
149     rt_uint16_t gpio_pin;
150 
151     if (PORT_GET(pin) < PIN_IFXPORT_MAX)
152     {
153         gpio_pin = pin;
154     }
155     else
156     {
157         return;
158     }
159 
160     switch (mode)
161     {
162     case PIN_MODE_OUTPUT:
163         cyhal_gpio_init(gpio_pin, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, true);
164         break;
165 
166     case PIN_MODE_INPUT:
167         cyhal_gpio_init(gpio_pin, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE, false);
168         break;
169 
170     case PIN_MODE_INPUT_PULLUP:
171         cyhal_gpio_init(gpio_pin, CYHAL_GPIO_DIR_BIDIRECTIONAL, CYHAL_GPIO_DRIVE_PULLUP, true);
172         break;
173 
174     case PIN_MODE_INPUT_PULLDOWN:
175         cyhal_gpio_init(gpio_pin, CYHAL_GPIO_DIR_BIDIRECTIONAL, CYHAL_GPIO_DRIVE_PULLDOWN, false);
176         break;
177 
178     case PIN_MODE_OUTPUT_OD:
179         cyhal_gpio_init(gpio_pin, CYHAL_GPIO_DIR_BIDIRECTIONAL, CYHAL_GPIO_DRIVE_PULLUP, true);
180         break;
181     }
182 }
183 
ifx_pin_write(rt_device_t dev,rt_base_t pin,rt_uint8_t value)184 static void ifx_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
185 {
186     rt_uint16_t gpio_pin;
187 
188     if (PORT_GET(pin) < PIN_IFXPORT_MAX)
189     {
190         gpio_pin = pin;
191     }
192     else
193     {
194         return;
195     }
196 
197     cyhal_gpio_write(gpio_pin, value);
198 }
199 
ifx_pin_read(struct rt_device * device,rt_base_t pin)200 static rt_ssize_t ifx_pin_read(struct rt_device *device, rt_base_t pin)
201 {
202     rt_uint16_t gpio_pin;
203 
204     if (PORT_GET(pin) < PIN_IFXPORT_MAX)
205     {
206         gpio_pin = pin;
207     }
208     else
209     {
210         return -RT_EINVAL;
211     }
212 
213     return cyhal_gpio_read(gpio_pin);
214 }
215 
ifx_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)216 static rt_err_t ifx_pin_attach_irq(struct rt_device *device, rt_base_t pin,
217                                    rt_uint8_t mode, void (*hdr)(void *args), void *args)
218 {
219     rt_uint16_t gpio_port;
220     rt_uint16_t gpio_pin;
221     rt_base_t level;
222 
223     if (PORT_GET(pin) < PIN_IFXPORT_MAX)
224     {
225         gpio_port = PORT_GET(pin);
226         gpio_pin = pin;
227     }
228     else
229     {
230         return -RT_ERROR;
231     }
232 
233     level = rt_hw_interrupt_disable();
234 
235     if (pin_irq_handler_tab[gpio_port].pin == pin &&
236             pin_irq_handler_tab[gpio_port].hdr == hdr &&
237             pin_irq_handler_tab[gpio_port].mode == mode &&
238             pin_irq_handler_tab[gpio_port].args == args)
239     {
240         rt_hw_interrupt_enable(level);
241         return RT_EOK;
242     }
243 
244     if (pin_irq_handler_tab[gpio_port].pin != -1)
245     {
246         rt_hw_interrupt_enable(level);
247         return -RT_EBUSY;
248     }
249 
250     pin_irq_handler_tab[gpio_port].pin = pin;
251     pin_irq_handler_tab[gpio_port].hdr = hdr;
252     pin_irq_handler_tab[gpio_port].mode = mode;
253     pin_irq_handler_tab[gpio_port].args = args;
254     rt_hw_interrupt_enable(level);
255 
256     return RT_EOK;
257 }
258 
ifx_pin_dettach_irq(struct rt_device * device,rt_base_t pin)259 static rt_err_t ifx_pin_dettach_irq(struct rt_device *device, rt_base_t pin)
260 {
261     rt_uint16_t gpio_port;
262     rt_uint16_t gpio_pin;
263     rt_base_t level;
264 
265     if (PORT_GET(pin) < PIN_IFXPORT_MAX)
266     {
267         gpio_port = PORT_GET(pin);
268         gpio_pin = pin;
269     }
270     else
271     {
272         return -RT_ERROR;
273     }
274 
275     level = rt_hw_interrupt_disable();
276 
277     if (pin_irq_handler_tab[gpio_port].pin == -1)
278     {
279         rt_hw_interrupt_enable(level);
280         return RT_EOK;
281     }
282 
283     pin_irq_handler_tab[gpio_port].pin = -1;
284     pin_irq_handler_tab[gpio_port].hdr = RT_NULL;
285     pin_irq_handler_tab[gpio_port].mode = 0;
286     pin_irq_handler_tab[gpio_port].args = RT_NULL;
287     rt_hw_interrupt_enable(level);
288 
289     return RT_EOK;
290 }
291 
ifx_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)292 static rt_err_t ifx_pin_irq_enable(struct rt_device *device, rt_base_t pin,
293                                    rt_uint8_t enabled)
294 {
295     rt_uint16_t gpio_port;
296     rt_uint16_t gpio_pin;
297     rt_base_t level;
298     rt_uint8_t pin_irq_mode;
299     const struct pin_irq_map *irqmap;
300 
301     if (PORT_GET(pin) < PIN_IFXPORT_MAX)
302     {
303         gpio_port = PORT_GET(pin);
304         gpio_pin = pin;
305     }
306     else
307     {
308         return -RT_ERROR;
309     }
310 
311     if (enabled == PIN_IRQ_ENABLE)
312     {
313         level = rt_hw_interrupt_disable();
314 
315         if (pin_irq_handler_tab[gpio_port].pin == -1)
316         {
317             rt_hw_interrupt_enable(level);
318             return -RT_EINVAL;
319         }
320 
321         irqmap = &pin_irq_map[gpio_port];
322 
323 #if !defined(COMPONENT_CAT1C)
324         IRQn_Type irqn = irqmap->irqno;
325         irq_cb_data[irqn].callback = irq_callback;
326         irq_cb_data[irqn].callback_arg = (rt_uint16_t *)&pin_irq_map[gpio_port].port;
327         cyhal_gpio_register_callback(gpio_pin, &irq_cb_data[irqn]);
328 #endif
329         Cy_GPIO_ClearInterrupt(CYHAL_GET_PORTADDR(gpio_pin), CYHAL_GET_PIN(gpio_pin));
330 
331         switch (pin_irq_handler_tab[gpio_port].mode)
332         {
333         case PIN_IRQ_MODE_RISING:
334             pin_irq_mode = CYHAL_GPIO_IRQ_RISE;
335             break;
336 
337         case PIN_IRQ_MODE_FALLING:
338             pin_irq_mode = CYHAL_GPIO_IRQ_FALL;
339             break;
340 
341         case PIN_IRQ_MODE_RISING_FALLING:
342             pin_irq_mode = CYHAL_GPIO_IRQ_BOTH;
343             break;
344 
345         default:
346             break;
347         }
348 
349         cyhal_gpio_enable_event(gpio_pin, pin_irq_mode, GPIO_INTERRUPT_PRIORITY, RT_TRUE);
350 
351         rt_hw_interrupt_enable(level);
352     }
353     else if (enabled == PIN_IRQ_DISABLE)
354     {
355         level = rt_hw_interrupt_disable();
356 
357         irqmap = &pin_irq_map[gpio_port];
358 
359 #if !defined(COMPONENT_CAT1C)
360         IRQn_Type irqn = irqmap->irqno;
361         if (irqn < 0 || irqn >= PIN_IFXPORT_MAX)
362         {
363             rt_hw_interrupt_enable(level);
364             return -RT_EINVAL;
365         }
366         _cyhal_irq_disable(irqn);
367 #endif
368         rt_hw_interrupt_enable(level);
369     }
370     else
371     {
372         return -RT_EINVAL;
373     }
374 
375     return RT_EOK;
376 }
377 
378 const static struct rt_pin_ops _ifx_pin_ops =
379 {
380     ifx_pin_mode,
381     ifx_pin_write,
382     ifx_pin_read,
383     ifx_pin_attach_irq,
384     ifx_pin_dettach_irq,
385     ifx_pin_irq_enable,
386     RT_NULL,
387 };
388 
rt_hw_pin_init(void)389 int rt_hw_pin_init(void)
390 {
391     return rt_device_pin_register("pin", &_ifx_pin_ops, RT_NULL);
392 }
393 
394 #endif /* RT_USING_PIN */
395