1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date             Author              Notes
8  * 2021-07-29       KyleChan            first version
9  * 2022-01-19       Sherman             add PIN2IRQX_TABLE
10  * 2025-01-13       newflydd            pin_get for RZ
11  */
12 
13 #include <drv_gpio.h>
14 
15 #ifdef RT_USING_PIN
16 
17 #define DBG_TAG              "drv.gpio"
18 #ifdef DRV_DEBUG
19     #define DBG_LVL               DBG_LOG
20 #else
21     #define DBG_LVL               DBG_INFO
22 #endif /* DRV_DEBUG */
23 
24 #ifdef R_ICU_H
25 #include "gpio_cfg.h"
26 
ra_pin_get_irqx(rt_uint32_t pin)27 static rt_base_t ra_pin_get_irqx(rt_uint32_t pin)
28 {
29     PIN2IRQX_TABLE(pin)
30 }
31 
32 static struct rt_pin_irq_hdr pin_irq_hdr_tab[RA_IRQ_MAX] = {0};
33 struct ra_pin_irq_map pin_irq_map[RA_IRQ_MAX] = {0};
34 
ra_irq_tab_init(void)35 static void ra_irq_tab_init(void)
36 {
37     for (int i = 0; i < RA_IRQ_MAX; ++i)
38     {
39         pin_irq_hdr_tab[i].pin  = -1;
40         pin_irq_hdr_tab[i].mode = 0;
41         pin_irq_hdr_tab[i].args = RT_NULL;
42         pin_irq_hdr_tab[i].hdr  = RT_NULL;
43     }
44 }
45 
ra_pin_map_init(void)46 static void ra_pin_map_init(void)
47 {
48 #if defined(VECTOR_NUMBER_ICU_IRQ0) || (VECTOR_NUMBER_IRQ0)
49     pin_irq_map[0].irq_ctrl = &g_external_irq0_ctrl;
50     pin_irq_map[0].irq_cfg = &g_external_irq0_cfg;
51 #endif
52 #if defined(VECTOR_NUMBER_ICU_IRQ1) || (VECTOR_NUMBER_IRQ1)
53     pin_irq_map[1].irq_ctrl = &g_external_irq1_ctrl;
54     pin_irq_map[1].irq_cfg = &g_external_irq1_cfg;
55 #endif
56 #if defined(VECTOR_NUMBER_ICU_IRQ2) || (VECTOR_NUMBER_IRQ2)
57     pin_irq_map[2].irq_ctrl = &g_external_irq2_ctrl;
58     pin_irq_map[2].irq_cfg = &g_external_irq2_cfg;
59 #endif
60 #if defined(VECTOR_NUMBER_ICU_IRQ3) || (VECTOR_NUMBER_IRQ3)
61     pin_irq_map[3].irq_ctrl = &g_external_irq3_ctrl;
62     pin_irq_map[3].irq_cfg = &g_external_irq3_cfg;
63 #endif
64 #if defined(VECTOR_NUMBER_ICU_IRQ4) || (VECTOR_NUMBER_IRQ4)
65     pin_irq_map[4].irq_ctrl = &g_external_irq4_ctrl;
66     pin_irq_map[4].irq_cfg = &g_external_irq4_cfg;
67 #endif
68 #if defined(VECTOR_NUMBER_ICU_IRQ5) || (VECTOR_NUMBER_IRQ5)
69     pin_irq_map[5].irq_ctrl = &g_external_irq5_ctrl;
70     pin_irq_map[5].irq_cfg = &g_external_irq5_cfg;
71 #endif
72 #if defined(VECTOR_NUMBER_ICU_IRQ6) || (VECTOR_NUMBER_IRQ6)
73     pin_irq_map[6].irq_ctrl = &g_external_irq6_ctrl;
74     pin_irq_map[6].irq_cfg = &g_external_irq6_cfg;
75 #endif
76 #if defined(VECTOR_NUMBER_ICU_IRQ7) || (VECTOR_NUMBER_IRQ7)
77     pin_irq_map[7].irq_ctrl = &g_external_irq7_ctrl;
78     pin_irq_map[7].irq_cfg = &g_external_irq7_cfg;
79 #endif
80 #if defined(VECTOR_NUMBER_ICU_IRQ8) || (VECTOR_NUMBER_IRQ8)
81     pin_irq_map[8].irq_ctrl = &g_external_irq8_ctrl;
82     pin_irq_map[8].irq_cfg = &g_external_irq8_cfg;
83 #endif
84 #if defined(VECTOR_NUMBER_ICU_IRQ9) || (VECTOR_NUMBER_IRQ9)
85     pin_irq_map[9].irq_ctrl = &g_external_irq9_ctrl;
86     pin_irq_map[9].irq_cfg = &g_external_irq9_cfg;
87 #endif
88 #if defined(VECTOR_NUMBER_ICU_IRQ10) || (VECTOR_NUMBER_IRQ10)
89     pin_irq_map[10].irq_ctrl = &g_external_irq10_ctrl;
90     pin_irq_map[10].irq_cfg = &g_external_irq10_cfg;
91 #endif
92 #if defined(VECTOR_NUMBER_ICU_IRQ11) || (VECTOR_NUMBER_IRQ11)
93     pin_irq_map[11].irq_ctrl = &g_external_irq11_ctrl;
94     pin_irq_map[11].irq_cfg = &g_external_irq11_cfg;
95 #endif
96 #if defined(VECTOR_NUMBER_ICU_IRQ12) || (VECTOR_NUMBER_IRQ12)
97     pin_irq_map[12].irq_ctrl = &g_external_irq12_ctrl;
98     pin_irq_map[12].irq_cfg = &g_external_irq12_cfg;
99 #endif
100 #if defined(VECTOR_NUMBER_ICU_IRQ13) || (VECTOR_NUMBER_IRQ13)
101     pin_irq_map[13].irq_ctrl = &g_external_irq13_ctrl;
102     pin_irq_map[13].irq_cfg = &g_external_irq13_cfg;
103 #endif
104 #if defined(VECTOR_NUMBER_ICU_IRQ14) || (VECTOR_NUMBER_IRQ014)
105     pin_irq_map[14].irq_ctrl = &g_external_irq14_ctrl;
106     pin_irq_map[14].irq_cfg = &g_external_irq14_cfg;
107 #endif
108 #if defined(VECTOR_NUMBER_ICU_IRQ15) || (VECTOR_NUMBER_IRQ015)
109     pin_irq_map[15].irq_ctrl = &g_external_irq15_ctrl;
110     pin_irq_map[15].irq_cfg = &g_external_irq15_cfg;
111 #endif
112 }
113 #endif  /* R_ICU_H */
114 
ra_pin_mode(rt_device_t dev,rt_base_t pin,rt_uint8_t mode)115 static void ra_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
116 {
117     fsp_err_t err;
118 
119     /* Initialize the IOPORT module and configure the pins */
120     err = R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg);
121 
122     if (err != FSP_SUCCESS)
123     {
124         LOG_E("GPIO open failed");
125         return;
126     }
127 
128     switch (mode)
129     {
130     case PIN_MODE_OUTPUT:
131         err = R_IOPORT_PinCfg(&g_ioport_ctrl, (bsp_io_port_pin_t)pin, BSP_IO_DIRECTION_OUTPUT);
132         if (err != FSP_SUCCESS)
133         {
134             LOG_E("PIN_MODE_OUTPUT configuration failed");
135             return;
136         }
137         break;
138 
139     case PIN_MODE_INPUT:
140         err = R_IOPORT_PinCfg(&g_ioport_ctrl, (bsp_io_port_pin_t)pin, BSP_IO_DIRECTION_INPUT);
141         if (err != FSP_SUCCESS)
142         {
143             LOG_E("PIN_MODE_INPUT configuration failed");
144             return;
145         }
146         break;
147 
148     case PIN_MODE_OUTPUT_OD:
149         err = R_IOPORT_PinCfg(&g_ioport_ctrl, (bsp_io_port_pin_t)pin, IOPORT_CFG_NMOS_ENABLE);
150         if (err != FSP_SUCCESS)
151         {
152             LOG_E("PIN_MODE_OUTPUT_OD configuration failed");
153             return;
154         }
155         break;
156     }
157 }
158 
ra_pin_write(rt_device_t dev,rt_base_t pin,rt_uint8_t value)159 static void ra_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
160 {
161     bsp_io_level_t level = BSP_IO_LEVEL_HIGH;
162 
163     if (value != level)
164     {
165         level = BSP_IO_LEVEL_LOW;
166     }
167 
168     R_BSP_PinAccessEnable();
169 #ifdef SOC_SERIES_R9A07G0
170     R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)pin, (bsp_io_level_t)level);
171 #else
172     R_BSP_PinWrite(pin, level);
173 #endif
174     R_BSP_PinAccessDisable();
175 }
176 
ra_pin_read(rt_device_t dev,rt_base_t pin)177 static rt_ssize_t ra_pin_read(rt_device_t dev, rt_base_t pin)
178 {
179     if ((pin > RA_MAX_PIN_VALUE) || (pin < RA_MIN_PIN_VALUE))
180     {
181         return -RT_EINVAL;
182     }
183 #ifdef SOC_SERIES_R9A07G0
184     bsp_io_level_t io_level;
185     R_IOPORT_PinRead(&g_ioport_ctrl, (bsp_io_port_pin_t)pin, &io_level);
186     return io_level;
187 #else
188     return R_BSP_PinRead(pin);
189 #endif
190 }
191 
ra_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)192 static rt_err_t ra_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
193 {
194 #ifdef R_ICU_H
195     rt_err_t err;
196     rt_int32_t irqx = ra_pin_get_irqx(pin);
197     if (PIN_IRQ_ENABLE == enabled)
198     {
199         if (0 <= irqx && irqx < sizeof(pin_irq_map) / sizeof(pin_irq_map[0]))
200         {
201             err = R_ICU_ExternalIrqOpen((external_irq_ctrl_t *const)pin_irq_map[irqx].irq_ctrl,
202                                         (external_irq_cfg_t const * const)pin_irq_map[irqx].irq_cfg);
203             /* Handle error */
204             if (FSP_SUCCESS != err)
205             {
206                 /* ICU Open failure message */
207                 LOG_E("\r\n**R_ICU_ExternalIrqOpen API FAILED**\r\n");
208                 return -RT_ERROR;
209             }
210 
211             err = R_ICU_ExternalIrqEnable((external_irq_ctrl_t *const)pin_irq_map[irqx].irq_ctrl);
212             /* Handle error */
213             if (FSP_SUCCESS != err)
214             {
215                 /* ICU Enable failure message */
216                 LOG_E("\r\n**R_ICU_ExternalIrqEnable API FAILED**\r\n");
217                 return -RT_ERROR;
218             }
219         }
220     }
221     else if (PIN_IRQ_DISABLE == enabled)
222     {
223         err = R_ICU_ExternalIrqDisable((external_irq_ctrl_t *const)pin_irq_map[irqx].irq_ctrl);
224         if (FSP_SUCCESS != err)
225         {
226             /* ICU Disable failure message */
227             LOG_E("\r\n**R_ICU_ExternalIrqDisable API FAILED**\r\n");
228             return -RT_ERROR;
229         }
230         err = R_ICU_ExternalIrqClose((external_irq_ctrl_t *const)pin_irq_map[irqx].irq_ctrl);
231         if (FSP_SUCCESS != err)
232         {
233             /* ICU Close failure message */
234             LOG_E("\r\n**R_ICU_ExternalIrqClose API FAILED**\r\n");
235             return -RT_ERROR;
236         }
237     }
238     return RT_EOK;
239 #else
240     return -RT_ERROR;
241 #endif
242 }
243 
ra_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)244 static rt_err_t ra_pin_attach_irq(struct rt_device *device, rt_base_t pin,
245                                   rt_uint8_t   mode, void (*hdr)(void *args), void *args)
246 {
247 #ifdef R_ICU_H
248     rt_int32_t irqx = ra_pin_get_irqx(pin);
249     if (0 <= irqx && irqx < (sizeof(pin_irq_map) / sizeof(pin_irq_map[0])))
250     {
251         int level = rt_hw_interrupt_disable();
252         if (pin_irq_hdr_tab[irqx].pin == irqx &&
253                 pin_irq_hdr_tab[irqx].hdr == hdr &&
254                 pin_irq_hdr_tab[irqx].mode == mode &&
255                 pin_irq_hdr_tab[irqx].args == args)
256         {
257             rt_hw_interrupt_enable(level);
258             return RT_EOK;
259         }
260         if (pin_irq_hdr_tab[irqx].pin != -1)
261         {
262             rt_hw_interrupt_enable(level);
263             return -RT_EBUSY;
264         }
265         pin_irq_hdr_tab[irqx].pin = irqx;
266         pin_irq_hdr_tab[irqx].hdr = hdr;
267         pin_irq_hdr_tab[irqx].mode = mode;
268         pin_irq_hdr_tab[irqx].args = args;
269         rt_hw_interrupt_enable(level);
270     }
271     else return -RT_ERROR;
272     return RT_EOK;
273 #else
274     return -RT_ERROR;
275 #endif
276 }
277 
ra_pin_dettach_irq(struct rt_device * device,rt_base_t pin)278 static rt_err_t ra_pin_dettach_irq(struct rt_device *device, rt_base_t pin)
279 {
280 #ifdef R_ICU_H
281     rt_int32_t irqx = ra_pin_get_irqx(pin);
282     if (0 <= irqx && irqx < sizeof(pin_irq_map) / sizeof(pin_irq_map[0]))
283     {
284         int level = rt_hw_interrupt_disable();
285         if (pin_irq_hdr_tab[irqx].pin == -1)
286         {
287             rt_hw_interrupt_enable(level);
288             return RT_EOK;
289         }
290         pin_irq_hdr_tab[irqx].pin = -1;
291         pin_irq_hdr_tab[irqx].hdr = RT_NULL;
292         pin_irq_hdr_tab[irqx].mode = 0;
293         pin_irq_hdr_tab[irqx].args = RT_NULL;
294         rt_hw_interrupt_enable(level);
295     }
296     else
297     {
298         return -RT_ERROR;
299     }
300     return RT_EOK;
301 #else
302     return -RT_ERROR;
303 #endif
304 }
305 
ra_pin_get(const char * name)306 static rt_base_t ra_pin_get(const char *name)
307 {
308 #ifdef SOC_FAMILY_RENESAS_RZ
309     /* RZ series: use "PXX_X" format, like "P01_1" */
310     if ((rt_strlen(name) == 5) &&
311         ((name[0] == 'P') || (name[0] == 'p')) &&
312         (name[3] == '_') &&
313         ('0' <= (int) name[1] && (int) name[1] <= '1') &&
314         ('0' <= (int) name[2] && (int) name[2] <= '9') &&
315         ('0' <= (int) name[4] && (int) name[4] <= '7'))
316     {
317         return (((int) name[1] - '0') * 10 + ((int) name[2] - '0')) * 0x100 + ((int) name[4] - '0');
318     }
319     LOG_W("Invalid pin expression, use `PXX_X` format like `P01_1`");
320 #else
321     /* RA series: use "PXXX" format, like "P101"*/
322     if ((rt_strlen(name) == 4) &&
323         (name[0] == 'P' || name[0] == 'p') &&
324         (name[1] >= '0' && name[1] <= '9') &&
325         (name[2] >= '0' && name[1] <= '9') &&
326         (name[3] >= '0' && name[1] <= '9'))
327     {
328         return (name[1] - '0') * 0x100 + (name[2] - '0') * 10 + (name[3] - '0');
329     }
330     LOG_W("Invalid pin expression, use `PXXX` format like `P101`");
331 #endif
332     return -RT_ERROR;
333 }
334 
335 const static struct rt_pin_ops _ra_pin_ops =
336 {
337     .pin_mode       = ra_pin_mode,
338     .pin_write      = ra_pin_write,
339     .pin_read       = ra_pin_read,
340     .pin_attach_irq = ra_pin_attach_irq,
341     .pin_detach_irq = ra_pin_dettach_irq,
342     .pin_irq_enable = ra_pin_irq_enable,
343     .pin_get        = ra_pin_get,
344 };
345 
rt_hw_pin_init(void)346 int rt_hw_pin_init(void)
347 {
348 #ifdef R_ICU_H
349     ra_irq_tab_init();
350     ra_pin_map_init();
351 #endif
352 
353     return rt_device_pin_register("pin", &_ra_pin_ops, RT_NULL);
354 }
355 
356 #ifdef R_ICU_H
irq_callback(external_irq_callback_args_t * p_args)357 void irq_callback(external_irq_callback_args_t *p_args)
358 {
359     rt_interrupt_enter();
360     if (p_args->channel == pin_irq_hdr_tab[p_args->channel].pin)
361     {
362         pin_irq_hdr_tab[p_args->channel].hdr(pin_irq_hdr_tab[p_args->channel].args);
363     }
364     rt_interrupt_leave();
365 };
366 #endif /* R_ICU_H */
367 
368 #endif /* RT_USING_PIN */
369