1 /*
2  * Copyright (c) 2021-2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Change Logs:
7  * Date         Author      Notes
8  * 2022-01-11   HPMicro     First version
9  * 2022-07-28   HPMicro     Fixed compiling warnings
10  * 2023-05-08   HPMicro     Adapt RT-Thread V5.0.0
11  * 2023-08-15   HPMicro     Enable pad loopback feature
12  * 2024-01-08   HPMicro     Implemented pin_get
13  * 2024-04-17   HPMicro     Refined pin irq implementation
14  * 2024-05-31   HPMicro     Adapt later PIN driver framework
15  * 2024-07-03   HPMicro     Determined the existence of GPIO via GPIO_DO_GPIOx macro
16  */
17 
18 #include <rtthread.h>
19 
20 #ifdef BSP_USING_GPIO
21 #include <rthw.h>
22 #include <rtdevice.h>
23 #include "board.h"
24 #include "drv_gpio.h"
25 #include "hpm_gpio_drv.h"
26 #include "hpm_gpiom_drv.h"
27 #include "hpm_clock_drv.h"
28 #include "hpm_soc_feature.h"
29 
30 
31 typedef struct
32 {
33     uint32_t gpio_idx;
34     uint32_t irq_num;
35     struct rt_pin_irq_hdr *pin_irq_tbl;
36 } gpio_irq_map_t;
37 
38 #ifdef GPIO_DO_GPIOA
39 static struct rt_pin_irq_hdr hpm_gpio0_a_pin_hdr[32];
40 #endif
41 #ifdef GPIO_DO_GPIOB
42 static struct rt_pin_irq_hdr hpm_gpio0_b_pin_hdr[32];
43 #endif
44 #ifdef GPIO_DO_GPIOC
45 static struct rt_pin_irq_hdr hpm_gpio0_c_pin_hdr[32];
46 #endif
47 #ifdef GPIO_DO_GPIOD
48 static struct rt_pin_irq_hdr hpm_gpio0_d_pin_hdr[32];
49 #endif
50 #ifdef GPIO_DO_GPIOE
51 static struct rt_pin_irq_hdr hpm_gpio0_e_pin_hdr[32];
52 #endif
53 #ifdef GPIO_DO_GPIOF
54 static struct rt_pin_irq_hdr hpm_gpio0_f_pin_hdr[32];
55 #endif
56 #ifdef GPIO_DO_GPIOV
57 static struct rt_pin_irq_hdr hpm_gpio0_v_pin_hdr[32];
58 #endif
59 #ifdef GPIO_DO_GPIOW
60 static struct rt_pin_irq_hdr hpm_gpio0_w_pin_hdr[32];
61 #endif
62 #ifdef GPIO_DO_GPIOX
63 static struct rt_pin_irq_hdr hpm_gpio0_x_pin_hdr[32];
64 #endif
65 #ifdef GPIO_DO_GPIOY
66 static struct rt_pin_irq_hdr hpm_gpio0_y_pin_hdr[32];
67 #endif
68 #ifdef GPIO_DO_GPIOZ
69 static struct rt_pin_irq_hdr hpm_gpio0_z_pin_hdr[32];
70 #endif
71 
72 static const gpio_irq_map_t hpm_gpio_irq_map[] = {
73 #ifdef GPIO_DO_GPIOA
74         { GPIO_IE_GPIOA, IRQn_GPIO0_A, hpm_gpio0_a_pin_hdr },
75 #endif
76 #ifdef GPIO_DO_GPIOB
77         { GPIO_IE_GPIOB, IRQn_GPIO0_B, hpm_gpio0_b_pin_hdr },
78 #endif
79 #ifdef GPIO_DO_GPIOC
80         { GPIO_IE_GPIOC, IRQn_GPIO0_C, hpm_gpio0_c_pin_hdr },
81 #endif
82 #ifdef GPIO_DO_GPIOD
83         { GPIO_IE_GPIOD, IRQn_GPIO0_D, hpm_gpio0_d_pin_hdr },
84 #endif
85 #ifdef GPIO_DO_GPIOE
86         { GPIO_IE_GPIOE, IRQn_GPIO0_E, hpm_gpio0_e_pin_hdr },
87 #endif
88 #ifdef GPIO_DO_GPIOF
89         { GPIO_IE_GPIOF, IRQn_GPIO0_F, hpm_gpio0_f_pin_hdr },
90 #endif
91 #ifdef GPIO_DO_GPIOV
92         { GPIO_IE_GPIOV, IRQn_GPIO0_V, hpm_gpio0_v_pin_hdr },
93 #endif
94 #ifdef GPIO_DO_GPIOW
95         { GPIO_IE_GPIOW, IRQn_GPIO0_W, hpm_gpio0_w_pin_hdr },
96 #endif
97 #ifdef GPIO_DO_GPIOX
98         { GPIO_IE_GPIOX, IRQn_GPIO0_X, hpm_gpio0_x_pin_hdr },
99 #endif
100 #ifdef GPIO_DO_GPIOY
101         { GPIO_IE_GPIOY, IRQn_GPIO0_Y, hpm_gpio0_y_pin_hdr },
102 #endif
103 #ifdef GPIO_DO_GPIOZ
104         { GPIO_IE_GPIOZ, IRQn_GPIO0_Z, hpm_gpio0_z_pin_hdr },
105 #endif
106 };
107 
lookup_pin_irq_hdr_tbl(rt_base_t pin)108 static struct rt_pin_irq_hdr *lookup_pin_irq_hdr_tbl(rt_base_t pin)
109 {
110     struct rt_pin_irq_hdr *pin_irq_hdr_tbl = RT_NULL;
111     uint32_t gpio_idx = pin >> 5;
112 
113     for (uint32_t i = 0; i < ARRAY_SIZE(hpm_gpio_irq_map); i++)
114     {
115         if (hpm_gpio_irq_map[i].gpio_idx == gpio_idx)
116         {
117             pin_irq_hdr_tbl = hpm_gpio_irq_map[i].pin_irq_tbl;
118             break;
119         }
120     }
121     return pin_irq_hdr_tbl;
122 }
123 
hpm_get_gpio_irq_num(uint32_t gpio_idx)124 static int hpm_get_gpio_irq_num(uint32_t gpio_idx)
125 {
126     int irq_num = -1;
127 
128     for (uint32_t i = 0; i < ARRAY_SIZE(hpm_gpio_irq_map); i++)
129     {
130         if (hpm_gpio_irq_map[i].gpio_idx == gpio_idx)
131         {
132             irq_num = hpm_gpio_irq_map[i].irq_num;
133             break;
134         }
135     }
136     return irq_num;
137 }
138 
hpm_gpio_isr(uint32_t gpio_idx,GPIO_Type * base)139 static void hpm_gpio_isr(uint32_t gpio_idx, GPIO_Type *base)
140 {
141     /* Lookup the Pin IRQ Header Table */
142     struct rt_pin_irq_hdr *pin_irq_hdr = RT_NULL;
143     for (uint32_t i = 0; i < ARRAY_SIZE(hpm_gpio_irq_map); i++)
144     {
145         if (hpm_gpio_irq_map[i].gpio_idx == gpio_idx)
146         {
147             pin_irq_hdr = hpm_gpio_irq_map[i].pin_irq_tbl;
148             break;
149         }
150     }
151 
152     for(uint32_t pin_idx = 0; pin_idx < 32; pin_idx++)
153     {
154         if (gpio_check_pin_interrupt_flag(base, gpio_idx, pin_idx))
155         {
156             gpio_clear_pin_interrupt_flag(base, gpio_idx, pin_idx);
157 
158             if (pin_irq_hdr[pin_idx].hdr != RT_NULL)
159             {
160                 pin_irq_hdr[pin_idx].hdr(pin_irq_hdr[pin_idx].args);
161             }
162         }
163     }
164 }
165 
166 #ifdef GPIO_DO_GPIOA
gpioa_isr(void)167 void gpioa_isr(void)
168 {
169     hpm_gpio_isr(GPIO_IF_GPIOA, HPM_GPIO0);
170 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_A,gpioa_isr)171 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_A, gpioa_isr)
172 #endif
173 
174 #ifdef GPIO_DO_GPIOB
175 void gpiob_isr(void)
176 {
177     hpm_gpio_isr(GPIO_IF_GPIOB, HPM_GPIO0);
178 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_B,gpiob_isr)179 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_B, gpiob_isr)
180 #endif
181 
182 #ifdef GPIO_DO_GPIOC
183 void gpioc_isr(void)
184 {
185     hpm_gpio_isr(GPIO_IF_GPIOC, HPM_GPIO0);
186 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_C,gpioc_isr)187 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_C, gpioc_isr)
188 #endif
189 
190 #ifdef GPIO_DO_GPIOD
191 void gpiod_isr(void)
192 {
193     hpm_gpio_isr(GPIO_IF_GPIOD, HPM_GPIO0);
194 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_D,gpiod_isr)195 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_D, gpiod_isr)
196 #endif
197 
198 #ifdef GPIO_DO_GPIOE
199 void gpioe_isr(void)
200 {
201     hpm_gpio_isr(GPIO_IF_GPIOE, HPM_GPIO0);
202 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_E,gpioe_isr)203 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_E, gpioe_isr)
204 #endif
205 
206 #ifdef GPIO_DO_GPIOF
207 void gpiof_isr(void)
208 {
209     hpm_gpio_isr(GPIO_IF_GPIOF, HPM_GPIO0);
210 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_F,gpiof_isr)211 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_F, gpiof_isr)
212 #endif
213 
214 #ifdef GPIO_DO_GPIOV
215 void gpiov_isr(void)
216 {
217     hpm_gpio_isr(GPIO_IF_GPIOV, HPM_GPIO0);
218 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_V,gpiox_isr)219 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_V, gpiox_isr)
220 #endif
221 
222 #ifdef GPIO_DO_GPIOW
223 void gpiow_isr(void)
224 {
225     hpm_gpio_isr(GPIO_IF_GPIOW, HPM_GPIO0);
226 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_W,gpiox_isr)227 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_W, gpiox_isr)
228 #endif
229 
230 #ifdef GPIO_DO_GPIOX
231 void gpiox_isr(void)
232 {
233     hpm_gpio_isr(GPIO_IF_GPIOX, HPM_GPIO0);
234 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_X,gpiox_isr)235 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_X, gpiox_isr)
236 #endif
237 
238 #ifdef GPIO_DO_GPIOY
239 void gpioy_isr(void)
240 {
241     hpm_gpio_isr(GPIO_IF_GPIOY, HPM_GPIO0);
242 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_Y,gpioy_isr)243 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_Y, gpioy_isr)
244 #endif
245 
246 #ifdef GPIO_DO_GPIOZ
247 void gpioz_isr(void)
248 {
249     hpm_gpio_isr(GPIO_IF_GPIOZ, HPM_GPIO0);
250 }
SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_Z,gpioz_isr)251 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_Z, gpioz_isr)
252 #endif
253 
254 /**
255  * @brief Get Pin index from name
256  *
257  * Name rule is : <GPIO NAME><Index>
258  *  for example: PA00, PZ03
259  *
260  **/
261 static rt_base_t hpm_pin_get(const char *name)
262 {
263     if (!(  (rt_strlen(name) == 4) &&
264             (name[0] == 'P') &&
265             ((('A' <= name[1]) && (name[1] <= 'F')) || (('V' <= name[1]) && (name[1] <= 'Z'))) &&
266             (('0' <= name[2]) && (name[2] <= '9')) &&
267             (('0' <= name[3]) && (name[3] <= '9'))
268         ))
269     {
270         return -RT_EINVAL;
271     }
272 
273     uint32_t gpio_idx = (name[1] <= 'F') ? (name[1] - 'A') : (11 + name[1] - 'V');
274     uint32_t pin_idx = (uint32_t)(name[2] - '0') * 10 + (name[3] - '0');
275     return (gpio_idx * 32 + pin_idx);
276 }
277 
hpm_pin_mode(rt_device_t dev,rt_base_t pin,rt_uint8_t mode)278 static void hpm_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
279 {
280     /* TODO: Check the validity of the pin value */
281     uint32_t gpio_idx = pin >> 5;
282     uint32_t pin_idx = pin & 0x1FU;
283 
284     gpiom_set_pin_controller(HPM_GPIOM, gpio_idx, pin_idx, gpiom_soc_gpio0);
285 
286     HPM_IOC->PAD[pin].FUNC_CTL = 0;
287 
288     switch (gpio_idx)
289     {
290     case GPIO_DI_GPIOY :
291         HPM_PIOC->PAD[pin].FUNC_CTL = 3;
292         break;
293 #ifdef GPIO_DI_GPIOZ
294     case GPIO_DI_GPIOZ :
295 #ifdef HPM_BIOC
296         HPM_BIOC->PAD[pin].FUNC_CTL = 3;
297 #endif
298         break;
299 #endif
300     default :
301         break;
302     }
303 
304     switch (mode)
305     {
306     case PIN_MODE_OUTPUT:
307         gpio_set_pin_output(HPM_GPIO0, gpio_idx, pin_idx);
308         HPM_IOC->PAD[pin].PAD_CTL &=  ~(IOC_PAD_PAD_CTL_PS_MASK | IOC_PAD_PAD_CTL_PE_MASK | IOC_PAD_PAD_CTL_OD_MASK);
309         break;
310     case PIN_MODE_INPUT:
311         gpio_set_pin_input(HPM_GPIO0, gpio_idx, pin_idx);
312         HPM_IOC->PAD[pin].PAD_CTL &= ~(IOC_PAD_PAD_CTL_PS_MASK | IOC_PAD_PAD_CTL_PE_MASK);
313         break;
314     case PIN_MODE_INPUT_PULLDOWN:
315         gpio_set_pin_input(HPM_GPIO0, gpio_idx, pin_idx);
316         HPM_IOC->PAD[pin].PAD_CTL = (HPM_IOC->PAD[pin].PAD_CTL & ~IOC_PAD_PAD_CTL_PS_MASK) | IOC_PAD_PAD_CTL_PE_SET(1);
317         break;
318     case PIN_MODE_INPUT_PULLUP:
319         gpio_set_pin_input(HPM_GPIO0, gpio_idx, pin_idx);
320         HPM_IOC->PAD[pin].PAD_CTL |= IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1);
321         break;
322     case PIN_MODE_OUTPUT_OD:
323         gpio_set_pin_output(HPM_GPIO0, gpio_idx, pin_idx);
324         HPM_IOC->PAD[pin].PAD_CTL = (HPM_IOC->PAD[pin].PAD_CTL & ~(IOC_PAD_PAD_CTL_PS_MASK | IOC_PAD_PAD_CTL_PE_MASK)) | IOC_PAD_PAD_CTL_OD_SET(1);
325         break;
326     default:
327         /* Invalid mode */
328         break;
329     }
330     HPM_IOC->PAD[pin].FUNC_CTL = IOC_PAD_FUNC_CTL_LOOP_BACK_MASK;
331 }
332 
hpm_pin_read(rt_device_t dev,rt_base_t pin)333 static rt_ssize_t hpm_pin_read(rt_device_t dev, rt_base_t pin)
334 {
335     /* TODO: Check the validity of the pin value */
336     uint32_t gpio_idx = pin >> 5;
337     uint32_t pin_idx = pin & 0x1FU;
338 
339     return (rt_ssize_t) gpio_read_pin(HPM_GPIO0, gpio_idx, pin_idx);
340 }
341 
hpm_pin_write(rt_device_t dev,rt_base_t pin,rt_uint8_t value)342 static void hpm_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
343 {
344     /* TODO: Check the validity of the pin value */
345     uint32_t gpio_idx = pin >> 5;
346     uint32_t pin_idx = pin & 0x1FU;
347 
348     gpio_write_pin(HPM_GPIO0, gpio_idx, pin_idx, value);
349 }
350 
hpm_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)351 static rt_err_t hpm_pin_attach_irq(struct rt_device *device,
352                                    rt_base_t pin,
353                                    rt_uint8_t mode,
354                                    void (*hdr)(void *args),
355                                    void *args)
356 {
357     struct rt_pin_irq_hdr *pin_irq_hdr_tbl = lookup_pin_irq_hdr_tbl(pin);
358     if (pin_irq_hdr_tbl == RT_NULL)
359     {
360         return -RT_EINVAL;
361     }
362 
363     rt_base_t level = rt_hw_interrupt_disable();
364     uint32_t pin_idx = pin & 0x1FUL;
365     pin_irq_hdr_tbl[pin_idx].pin = pin;
366     pin_irq_hdr_tbl[pin_idx].hdr = hdr;
367     pin_irq_hdr_tbl[pin_idx].mode = mode;
368     pin_irq_hdr_tbl[pin_idx].args = args;
369     rt_hw_interrupt_enable(level);
370 
371     return RT_EOK;
372 }
373 
hpm_pin_detach_irq(struct rt_device * device,rt_base_t pin)374 static rt_err_t hpm_pin_detach_irq(struct rt_device *device, rt_base_t pin)
375 {
376     struct rt_pin_irq_hdr *pin_irq_hdr_tbl = lookup_pin_irq_hdr_tbl(pin);
377     if (pin_irq_hdr_tbl == RT_NULL)
378     {
379         return -RT_EINVAL;
380     }
381     rt_base_t level = rt_hw_interrupt_disable();
382     uint32_t pin_idx = pin & 0x1FUL;
383     pin_irq_hdr_tbl[pin_idx].pin = -1;
384     pin_irq_hdr_tbl[pin_idx].hdr = RT_NULL;
385     pin_irq_hdr_tbl[pin_idx].mode = 0;
386     pin_irq_hdr_tbl[pin_idx].args = RT_NULL;
387     rt_hw_interrupt_enable(level);
388 
389     return RT_EOK;
390 }
391 
hpm_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)392 static rt_err_t hpm_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
393 {
394     /* TODO: Check the validity of the pin value */
395     uint32_t gpio_idx = pin >> 5;
396     uint32_t pin_idx = pin & 0x1FU;
397 
398     struct rt_pin_irq_hdr *pin_irq_hdr_tbl = lookup_pin_irq_hdr_tbl(pin);
399     if (pin_irq_hdr_tbl == RT_NULL)
400     {
401         return -RT_EINVAL;
402     }
403 
404     gpio_interrupt_trigger_t trigger;
405     if (enabled == PIN_IRQ_ENABLE)
406     {
407         switch(pin_irq_hdr_tbl[pin_idx].mode)
408         {
409         case PIN_IRQ_MODE_RISING:
410             trigger = gpio_interrupt_trigger_edge_rising;
411             break;
412         case PIN_IRQ_MODE_FALLING:
413             trigger = gpio_interrupt_trigger_edge_falling;
414             break;
415         case PIN_IRQ_MODE_HIGH_LEVEL:
416             trigger = gpio_interrupt_trigger_level_high;
417             break;
418         case PIN_IRQ_MODE_LOW_LEVEL:
419             trigger = gpio_interrupt_trigger_level_low;
420             break;
421         default:
422             trigger = gpio_interrupt_trigger_edge_rising;
423             break;
424         }
425         gpio_config_pin_interrupt(HPM_GPIO0, gpio_idx, pin_idx, trigger);
426         uint32_t irq_num = hpm_get_gpio_irq_num(gpio_idx);
427         gpio_enable_pin_interrupt(HPM_GPIO0, gpio_idx, pin_idx);
428         intc_m_enable_irq_with_priority(irq_num, 1);
429     }
430     else if (enabled == PIN_IRQ_DISABLE)
431     {
432         gpio_disable_pin_interrupt(HPM_GPIO0, gpio_idx, pin_idx);
433     }
434     else
435     {
436         return -RT_EINVAL;
437     }
438 
439     return RT_EOK;
440 }
441 
442 const static struct rt_pin_ops hpm_pin_ops = {
443         .pin_mode = hpm_pin_mode,
444         .pin_write = hpm_pin_write,
445         .pin_read = hpm_pin_read,
446         .pin_attach_irq = hpm_pin_attach_irq,
447         .pin_detach_irq = hpm_pin_detach_irq,
448         .pin_irq_enable = hpm_pin_irq_enable,
449         .pin_get = hpm_pin_get,
450 };
451 
rt_hw_pin_init(void)452 int rt_hw_pin_init(void)
453 {
454     int ret = RT_EOK;
455 
456     ret = rt_device_pin_register("pin", &hpm_pin_ops, RT_NULL);
457 
458     return ret;
459 }
460 
461 INIT_BOARD_EXPORT(rt_hw_pin_init);
462 
463 #endif /* BSP_USING_GPIO */
464