1 /*
2  *
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Change Logs:
6  * Date           Author       Notes
7  * 2020-09-05     DongBowen    first version
8  */
9 
10 #include <rtthread.h>
11 #include "rthw.h"
12 
13 #include "drv_gpio.h"
14 #include "hc32l196_sysctrl.h"
15 
16 #ifdef RT_USING_PIN
17 #ifdef BSP_USING_GPIO
18 
19 #define __GPIO_PORT(pin)                (((pin) & 0xf0) * 4)
20 #define __GPIO_PORT_L(pin)              (__GPIO_PORT(pin))
21 #define __GPIO_PORT_H(pin)              ((__GPIO_PORT(pin) & 0xff) + 0x1000)
22 #define PE0_PIN                         (4 * 15)
23 #define GPIO_PORT(pin)                  (en_gpio_port_t)((pin) < PE0_PIN ? __GPIO_PORT_L((pin)) : __GPIO_PORT_H((pin)))
24 #define GPIO_PIN(pin)                   (en_gpio_pin_t)((pin) & 0x0f)
25 
26 /* Port: PA-PF, Pin: 0-15 */
27 #define PIN_MAX_NUM                     (6 * 16)
28 
29 #define ITEM_NUM(items)                 sizeof(items) / sizeof(items[0])
30 
31 static struct rt_pin_irq_hdr pin_irq_hdr_tab[PIN_MAX_NUM];
32 
33 #define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
34 
_pin_mode(rt_device_t dev,rt_base_t pin,rt_uint8_t mode)35 static void _pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
36 {
37     en_gpio_port_t gpio_port;
38     en_gpio_pin_t gpio_pin;
39     stc_gpio_cfg_t gpio_cfg;
40 
41     if (pin >= PIN_MAX_NUM)
42     {
43         return;
44     }
45 
46     gpio_port = GPIO_PORT(pin);
47     gpio_pin  = GPIO_PIN(pin);
48 
49     gpio_cfg.bOutputVal = 0;
50     gpio_cfg.enDrv = GpioDrvH;
51     gpio_cfg.enPu = GpioPuDisable;
52     gpio_cfg.enPd = GpioPdDisable;
53     gpio_cfg.enOD = GpioOdDisable;
54     gpio_cfg.enCtrlMode = GpioAHB;
55 
56     switch (mode)
57     {
58     case PIN_MODE_OUTPUT:
59         gpio_cfg.enDir = GpioDirOut;
60         break;
61     case PIN_MODE_INPUT:
62         gpio_cfg.enDir = GpioDirIn;
63         break;
64     case PIN_MODE_INPUT_PULLUP:
65         gpio_cfg.enDir = GpioDirIn;
66         gpio_cfg.enPu = GpioPuEnable;
67         break;
68     case PIN_MODE_INPUT_PULLDOWN:
69         gpio_cfg.enDir = GpioDirIn;
70         gpio_cfg.enPd = GpioPdEnable;
71         break;
72     case PIN_MODE_OUTPUT_OD:
73         gpio_cfg.enDir = GpioDirOut;
74         gpio_cfg.enOD = GpioOdEnable;
75         break;
76     default:
77         break;
78     }
79 
80     Gpio_Init(gpio_port, gpio_pin, &gpio_cfg);
81 }
82 
_pin_write(rt_device_t dev,rt_base_t pin,rt_uint8_t value)83 static void _pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
84 {
85     en_gpio_port_t gpio_port;
86     en_gpio_pin_t gpio_pin;
87 
88     if (pin >= PIN_MAX_NUM)
89     {
90         return;
91     }
92 
93     gpio_port = GPIO_PORT(pin);
94     gpio_pin  = GPIO_PIN(pin);
95 
96     if (PIN_LOW == value)
97     {
98         Gpio_ClrIO(gpio_port, gpio_pin);
99     }
100     else
101     {
102         Gpio_SetIO(gpio_port, gpio_pin);
103     }
104 }
105 
_pin_read(rt_device_t dev,rt_base_t pin)106 static rt_ssize_t _pin_read(rt_device_t dev, rt_base_t pin)
107 {
108     en_gpio_port_t gpio_port;
109     en_gpio_pin_t gpio_pin;
110 
111     if (pin >= PIN_MAX_NUM)
112     {
113         return -RT_EINVAL;
114     }
115 
116     gpio_port = GPIO_PORT(pin);
117     gpio_pin  = GPIO_PIN(pin);
118 
119     return Gpio_GetInputIO(gpio_port, gpio_pin) ? PIN_HIGH : PIN_LOW;
120 }
121 
_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)122 static rt_err_t _pin_attach_irq(struct rt_device *device,
123                                     rt_base_t pin,
124                                     rt_uint8_t mode,
125                                     void (*hdr)(void *args),
126                                     void *args)
127 {
128     rt_base_t level;
129 
130     if (pin >= PIN_MAX_NUM)
131     {
132         return -RT_ENOSYS;
133     }
134 
135     level = rt_hw_interrupt_disable();
136     if (pin_irq_hdr_tab[pin].pin == pin &&
137             pin_irq_hdr_tab[pin].mode == mode &&
138             pin_irq_hdr_tab[pin].hdr == hdr &&
139             pin_irq_hdr_tab[pin].args == args)
140     {
141         rt_hw_interrupt_enable(level);
142         return RT_EOK;
143     }
144     pin_irq_hdr_tab[pin].pin = pin;
145     pin_irq_hdr_tab[pin].mode = mode;
146     pin_irq_hdr_tab[pin].hdr = hdr;
147     pin_irq_hdr_tab[pin].args = args;
148     rt_hw_interrupt_enable(level);
149     return RT_EOK;
150 }
151 
_pin_detach_irq(struct rt_device * device,rt_base_t pin)152 static rt_err_t _pin_detach_irq(struct rt_device *device, rt_base_t pin)
153 {
154     rt_base_t level;
155 
156     if (pin >= PIN_MAX_NUM)
157     {
158         return -RT_ENOSYS;
159     }
160 
161     level = rt_hw_interrupt_disable();
162     pin_irq_hdr_tab[pin].mode = 0;
163     pin_irq_hdr_tab[pin].hdr = RT_NULL;
164     pin_irq_hdr_tab[pin].args = RT_NULL;
165     rt_hw_interrupt_enable(level);
166     return RT_EOK;
167 }
168 
get_irqn(rt_base_t pin)169 static IRQn_Type get_irqn(rt_base_t pin)
170 {
171     en_gpio_port_t gpio_port;
172     IRQn_Type irqn = (IRQn_Type)0xff;
173 
174     if (pin >= PIN_MAX_NUM)
175     {
176         return irqn;
177     }
178 
179     gpio_port = GPIO_PORT(pin);
180     switch (gpio_port)
181     {
182     case GpioPortA:
183         irqn = PORTA_IRQn;
184         break;
185     case GpioPortB:
186         irqn = PORTB_IRQn;
187         break;
188     case GpioPortC:
189     case GpioPortE:
190         irqn = PORTC_E_IRQn;
191         break;
192     case GpioPortD:
193     case GpioPortF:
194         irqn = PORTD_F_IRQn;
195         break;
196     }
197 
198     return irqn;
199 }
200 
_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)201 static rt_err_t _pin_irq_enable(struct rt_device *device,
202                                     rt_base_t pin,
203                                     rt_uint8_t enabled)
204 {
205     rt_base_t level = 0;
206     en_gpio_port_t gpio_port;
207     en_gpio_pin_t gpio_pin;
208     IRQn_Type irqn;
209 
210     if (pin >= PIN_MAX_NUM)
211     {
212         return -RT_ENOSYS;
213     }
214 
215     gpio_port = GPIO_PORT(pin);
216     gpio_pin  = GPIO_PIN(pin);
217     irqn = get_irqn(pin);
218 
219     if (enabled == PIN_IRQ_ENABLE)
220     {
221         switch (pin_irq_hdr_tab[pin].mode)
222         {
223         case PIN_IRQ_MODE_RISING:
224             Gpio_EnableIrq(gpio_port, gpio_pin, GpioIrqRising);
225             break;
226         case PIN_IRQ_MODE_FALLING:
227             Gpio_EnableIrq(gpio_port, gpio_pin, GpioIrqFalling);
228             break;
229         case PIN_IRQ_MODE_RISING_FALLING:
230             Gpio_EnableIrq(gpio_port, gpio_pin, GpioIrqRising);
231             Gpio_EnableIrq(gpio_port, gpio_pin, GpioIrqFalling);
232             break;
233         case PIN_IRQ_MODE_HIGH_LEVEL:
234             Gpio_EnableIrq(gpio_port, gpio_pin, GpioIrqHigh);
235             break;
236         case PIN_IRQ_MODE_LOW_LEVEL:
237             Gpio_EnableIrq(gpio_port, gpio_pin, GpioIrqLow);
238             break;
239         default:
240             return -RT_EINVAL;
241         }
242 
243         level = rt_hw_interrupt_disable();
244         NVIC_ClearPendingIRQ(irqn);
245         NVIC_EnableIRQ(irqn);
246         rt_hw_interrupt_enable(level);
247     }
248     else if (enabled == PIN_IRQ_DISABLE)
249     {
250         switch (pin_irq_hdr_tab[pin].mode)
251         {
252         case PIN_IRQ_MODE_RISING:
253             Gpio_DisableIrq(gpio_port, gpio_pin, GpioIrqRising);
254             break;
255         case PIN_IRQ_MODE_FALLING:
256             Gpio_DisableIrq(gpio_port, gpio_pin, GpioIrqFalling);
257             break;
258         case PIN_IRQ_MODE_RISING_FALLING:
259             Gpio_DisableIrq(gpio_port, gpio_pin, GpioIrqRising);
260             Gpio_DisableIrq(gpio_port, gpio_pin, GpioIrqFalling);
261             break;
262         case PIN_IRQ_MODE_HIGH_LEVEL:
263             Gpio_DisableIrq(gpio_port, gpio_pin, GpioIrqHigh);
264             break;
265         case PIN_IRQ_MODE_LOW_LEVEL:
266             Gpio_DisableIrq(gpio_port, gpio_pin, GpioIrqLow);
267             break;
268         default:
269             break;
270         }
271 
272         level = rt_hw_interrupt_disable();
273         NVIC_ClearPendingIRQ(irqn);
274         NVIC_DisableIRQ(irqn);
275         rt_hw_interrupt_enable(level);
276     }
277     else
278     {
279         return -RT_ENOSYS;
280     }
281     return RT_EOK;
282 }
283 
284 const static struct rt_pin_ops _pin_ops =
285 {
286     .pin_mode = _pin_mode,
287     .pin_write = _pin_write,
288     .pin_read = _pin_read,
289     .pin_attach_irq = _pin_attach_irq,
290     .pin_detach_irq = _pin_detach_irq,
291     .pin_irq_enable = _pin_irq_enable,
292 };
293 
pin_isr(en_gpio_port_t gpio_port)294 static void pin_isr(en_gpio_port_t gpio_port)
295 {
296     en_gpio_pin_t gpio_pin = GpioPin0;
297     int pin = __GET_PIN(gpio_port, 0);
298 
299     for (; gpio_pin <= GpioPin15; gpio_pin++, pin++)
300     {
301         if (Gpio_GetIrqStatus(gpio_port, gpio_pin))
302         {
303             if (pin_irq_hdr_tab[pin].hdr)
304             {
305                 pin_irq_hdr_tab[pin].hdr(pin_irq_hdr_tab[pin].args);
306             }
307             Gpio_ClearIrq(gpio_port, gpio_pin);
308         }
309     }
310 }
311 
PortA_IRQHandler(void)312 void PortA_IRQHandler(void)
313 {
314     rt_interrupt_enter();
315     pin_isr(GpioPortA);
316     rt_interrupt_leave();
317 }
318 
PortB_IRQHandler(void)319 void PortB_IRQHandler(void)
320 {
321     rt_interrupt_enter();
322     pin_isr(GpioPortB);
323     rt_interrupt_leave();
324 }
325 
PortC_IRQHandler(void)326 void PortC_IRQHandler(void)
327 {
328     rt_interrupt_enter();
329     pin_isr(GpioPortC);
330     rt_interrupt_leave();
331 }
332 
PortD_IRQHandler(void)333 void PortD_IRQHandler(void)
334 {
335     rt_interrupt_enter();
336     pin_isr(GpioPortD);
337     rt_interrupt_leave();
338 }
339 
PortE_IRQHandler(void)340 void PortE_IRQHandler(void)
341 {
342     rt_interrupt_enter();
343     pin_isr(GpioPortE);
344     rt_interrupt_leave();
345 }
346 
PortF_IRQHandler(void)347 void PortF_IRQHandler(void)
348 {
349     rt_interrupt_enter();
350     pin_isr(GpioPortF);
351     rt_interrupt_leave();
352 }
353 
rt_hw_pin_init(void)354 int rt_hw_pin_init(void)
355 {
356     Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
357     return rt_device_pin_register("pin", &_pin_ops, RT_NULL);
358 }
359 INIT_BOARD_EXPORT(rt_hw_pin_init);
360 
361 #endif /* BSP_USING_GPIO */
362 #endif /* RT_USING_PIN */
363