1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023/01/5      chushicheng  first version
9  *
10  */
11 
12 #include "drv_gpio.h"
13 #include <stdbool.h>
14 
15 #ifdef BSP_USING_GPIO
16 
17 #define DBG_TAG              "drv.gpio"
18 #define DBG_LVL               DBG_INFO
19 #include <rtdbg.h>
20 
21 static struct bflb_device_s *gpio;
22 
23 static struct rt_pin_irq_hdr pin_irq_hdr_tab[GPIO_MAX];
24 
gpio_isr(int irq,void * arg)25 static void gpio_isr(int irq, void *arg)
26 {
27     rt_base_t i;
28     for(i = 0; i < GPIO_MAX; i ++)
29     {
30         if(pin_irq_hdr_tab[i].pin != -1)
31         {
32             bool intstatus = bflb_gpio_get_intstatus(gpio, i);
33             if (intstatus) {
34                 bflb_gpio_int_clear(gpio, i);
35                 if(pin_irq_hdr_tab[i].hdr)
36                     pin_irq_hdr_tab[i].hdr(pin_irq_hdr_tab[i].args);
37             }
38         }
39     }
40 
41 }
42 
_pin_write(rt_device_t dev,rt_base_t pin,rt_uint8_t value)43 static void _pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
44 {
45     if(value)
46         bflb_gpio_set(gpio, pin);
47     else
48         bflb_gpio_reset(gpio, pin);
49 }
50 
_pin_read(rt_device_t dev,rt_base_t pin)51 static rt_ssize_t _pin_read(rt_device_t dev, rt_base_t pin)
52 {
53     return bflb_gpio_read(gpio, pin);
54 }
55 
_pin_mode(rt_device_t dev,rt_base_t pin,rt_uint8_t mode)56 static void _pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
57 {
58     rt_uint32_t cfgset = 0;
59 
60     switch(mode)
61     {
62         case PIN_MODE_OUTPUT:
63             cfgset = GPIO_OUTPUT;
64             break;
65 
66         case PIN_MODE_INPUT:
67             cfgset = GPIO_INPUT;
68             break;
69 
70         case PIN_MODE_INPUT_PULLUP:
71             cfgset = GPIO_INPUT | GPIO_PULLUP;
72             break;
73 
74         case PIN_MODE_INPUT_PULLDOWN:
75             cfgset =  GPIO_INPUT | GPIO_PULLDOWN;
76             break;
77 
78         case PIN_MODE_OUTPUT_OD:
79             cfgset = GPIO_OUTPUT | GPIO_FLOAT;
80             break;
81 
82         default:
83             cfgset = GPIO_OUTPUT | GPIO_FLOAT;
84             break;
85     }
86 
87     cfgset |= GPIO_SMT_EN | GPIO_DRV_0;
88     bflb_gpio_init(gpio, pin, cfgset);
89 }
90 
_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t irq_mode,void (* hdr)(void * args),void * args)91 static rt_err_t _pin_attach_irq(struct rt_device *device, rt_base_t pin,
92                                 rt_uint8_t irq_mode, void (*hdr)(void *args), void *args)
93 {
94     rt_base_t level;
95 
96     level = rt_hw_interrupt_disable();
97     if(pin_irq_hdr_tab[pin].pin == pin &&
98         pin_irq_hdr_tab[pin].hdr == hdr &&
99         pin_irq_hdr_tab[pin].mode == irq_mode &&
100         pin_irq_hdr_tab[pin].args == args)
101     {
102         rt_hw_interrupt_enable(level);
103         return RT_EOK;
104     }
105 
106     if(pin_irq_hdr_tab[pin].pin != -1)
107     {
108         rt_hw_interrupt_enable(level);
109         return -RT_EBUSY;
110     }
111 
112     pin_irq_hdr_tab[pin].pin = pin;
113     pin_irq_hdr_tab[pin].mode = irq_mode;
114     pin_irq_hdr_tab[pin].hdr = hdr;
115     pin_irq_hdr_tab[pin].args = args;
116 
117     rt_hw_interrupt_enable(level);
118 
119     return RT_EOK;
120 }
121 
_pin_detach_irq(struct rt_device * device,rt_base_t pin)122 static rt_err_t _pin_detach_irq(struct rt_device *device, rt_base_t pin)
123 {
124     rt_base_t level;
125 
126     level = rt_hw_interrupt_disable();
127 
128     if(pin_irq_hdr_tab[pin].pin == -1)
129     {
130         rt_hw_interrupt_enable(level);
131 
132         return RT_EOK;
133     }
134 
135     pin_irq_hdr_tab[pin].pin = -1;
136     pin_irq_hdr_tab[pin].mode = 0;
137     pin_irq_hdr_tab[pin].hdr = RT_NULL;
138     pin_irq_hdr_tab[pin].args = RT_NULL;
139 
140     rt_hw_interrupt_enable(level);
141 
142     return RT_EOK;
143 }
144 
_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)145 static rt_err_t _pin_irq_enable(struct rt_device *device, rt_base_t pin,
146                                 rt_uint8_t enabled)
147 {
148     rt_base_t level;
149     rt_uint8_t trig_mode = 0;
150 
151     if (enabled == PIN_IRQ_ENABLE)
152     {
153         level = rt_hw_interrupt_disable();
154 
155         if(pin_irq_hdr_tab[pin].pin == -1)
156         {
157             rt_hw_interrupt_enable(level);
158             return -RT_ENOSYS;
159         }
160 
161         switch (pin_irq_hdr_tab[pin].mode)
162         {
163             case PIN_IRQ_MODE_RISING:
164                 trig_mode = GPIO_INT_TRIG_MODE_SYNC_RISING_EDGE;
165                 break;
166 
167             case PIN_IRQ_MODE_FALLING:
168                 trig_mode = GPIO_INT_TRIG_MODE_SYNC_FALLING_EDGE;
169                 break;
170 
171             case PIN_IRQ_MODE_RISING_FALLING:
172                 trig_mode = GPIO_INT_TRIG_MODE_ASYNC_FALLING_EDGE;
173                 break;
174 
175             case PIN_IRQ_MODE_HIGH_LEVEL:
176                 trig_mode = GPIO_INT_TRIG_MODE_SYNC_HIGH_LEVEL;
177                 break;
178 
179             case PIN_IRQ_MODE_LOW_LEVEL:
180                 trig_mode = GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL;
181                 break;
182         }
183 
184         bflb_gpio_int_init(gpio, pin, trig_mode);
185         bflb_gpio_int_mask(gpio, pin, false);
186 
187         rt_hw_interrupt_enable(level);
188     }
189     else if(enabled == PIN_IRQ_DISABLE)
190     {
191         level = rt_hw_interrupt_disable();
192         bflb_gpio_int_mask(gpio, pin, true);
193 
194         rt_hw_interrupt_enable(level);
195     }
196     else
197     {
198         return -RT_ENOSYS;
199     }
200     return RT_EOK;
201 }
202 
203 const static struct rt_pin_ops bl_drv_pin_ops =
204 {
205     _pin_mode,
206     _pin_write,
207     _pin_read,
208     _pin_attach_irq,
209     _pin_detach_irq,
210     _pin_irq_enable,
211     NULL,
212 };
213 
rt_hw_pin_init(void)214 int rt_hw_pin_init(void)
215 {
216     rt_uint8_t i;
217 
218     for(i = 0; i < GPIO_MAX; i ++)
219     {
220         pin_irq_hdr_tab[i].pin = -1;
221     }
222     gpio = bflb_device_get_by_name("gpio");
223     bflb_irq_attach(gpio->irq_num, gpio_isr, gpio);
224     bflb_irq_enable(gpio->irq_num);
225 
226     return rt_device_pin_register("pin", &bl_drv_pin_ops, RT_NULL);
227 }
228 INIT_BOARD_EXPORT(rt_hw_pin_init);
229 
230 #endif /*BSP_USING_GPIO */
231