1 /* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5  * 1. Redistributions of source code must retain the above copyright
6  * notice, this list of conditions and the following disclaimer.
7  * 2. Redistributions in binary form must reproduce the above copyright
8  * notice, this list of conditions and the following disclaimer in the
9  * documentation and/or other materials provided with the distribution.
10  *
11  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
12  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
16  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 /*
27  * Copyright (c) 2006-2025, RT-Thread Development Team
28  *
29  * SPDX-License-Identifier: Apache-2.0
30  */
31 
32 #include <rtthread.h>
33 #include <rthw.h>
34 #include <rtdevice.h>
35 #include <riscv_io.h>
36 #include <rtdef.h>
37 #include "ioremap.h"
38 #include "drv_gpio.h"
39 #include "drv_hardlock.h"
40 #include "board.h"
41 #include <dfs_posix.h>
42 #include <lwp_user_mm.h>
43 #include <sys/ioctl.h>
44 #include <rtdbg.h>
45 
46 #define DBG_TAG "GPIO"
47 #ifdef RT_DEBUG
48 #define DBG_LVL DBG_LOG
49 #else
50 #define DBG_LVL DBG_WARNING
51 #endif
52 #define DBG_COLOR
53 
54 struct kd_gpio_device {
55     struct rt_device dev;
56     void* base[2];
57     int hardlock;
58 };
59 
60 static struct kd_gpio_device gpio_dev;
61 
62 static struct
63 {
64     void (*hdr)(void* args);
65     void* args;
66     gpio_pin_edge_t edge;
67     int debounce;
68     struct rt_work debounce_work;
69     struct rt_work send_sig_work;
70     struct rt_lwp* lwp;
71     int lwp_ref_cnt;
72     int signo;
73     void* sigval;
74 } irq_table[GPIO_MAX_NUM];
75 
kd_gpio_reg_writel(void * reg,rt_size_t offset,rt_uint32_t value)76 static void kd_gpio_reg_writel(void* reg, rt_size_t offset, rt_uint32_t value)
77 {
78     while (0 != kd_hardlock_lock(gpio_dev.hardlock))
79         ;
80     rt_uint32_t val = readl(reg);
81     val &= ~(1 << offset);
82     val |= (value << offset);
83     writel(val, reg);
84     kd_hardlock_unlock(gpio_dev.hardlock);
85 }
86 
kd_gpio_reg_readl(void * reg,rt_size_t offset)87 static rt_uint32_t kd_gpio_reg_readl(void* reg, rt_size_t offset)
88 {
89     rt_uint32_t val = readl(reg);
90     return (val & (1 << offset)) >> offset;
91 }
92 
check_pin_valid(rt_base_t pin)93 static int check_pin_valid(rt_base_t pin)
94 {
95     if ((rt_uint16_t)pin < 0 || (rt_uint16_t)pin > GPIO_MAX_NUM)
96     {
97         LOG_E("pin %d is not valid\n", pin);
98         return -RT_EINVAL;
99     }
100     return pin;
101 }
102 
kd_pin_mode(rt_base_t pin,rt_base_t mode)103 rt_err_t kd_pin_mode(rt_base_t pin, rt_base_t mode)
104 {
105     void* reg;
106     uint32_t dir;
107 
108     if (check_pin_valid(pin) < 0)
109         return -RT_EINVAL;
110 
111     switch (mode)
112     {
113     case GPIO_DM_INPUT:
114         dir = 0;
115         break;
116     case GPIO_DM_OUTPUT:
117         dir = 1;
118         break;
119     default:
120         LOG_E("GPIO drive mode is not supported.");
121         return -RT_EINVAL;
122     }
123 
124     if (pin < 32)
125     {
126         reg = gpio_dev.base[0] + DIRECTION;
127     } else {
128         pin -= 32;
129         if (pin < 32)
130         {
131             reg = gpio_dev.base[1] + DIRECTION;
132         } else {
133             reg = gpio_dev.base[1] + DIRECTION + DIRECTION_STRIDE;
134             pin -= 32;
135         }
136     }
137 
138     kd_gpio_reg_writel(reg, pin, dir);
139 
140     return RT_EOK;
141 }
142 
kd_pin_mode_get(rt_base_t pin)143 int kd_pin_mode_get(rt_base_t pin)
144 {
145     void* reg;
146 
147     if (check_pin_valid(pin) < 0)
148         return -RT_EINVAL;
149 
150     if (pin < 32)
151     {
152         reg = gpio_dev.base[0] + DIRECTION;
153     } else {
154         pin -= 32;
155         if (pin < 32)
156         {
157             reg = gpio_dev.base[1] + DIRECTION;
158         } else {
159             reg = gpio_dev.base[1] + DIRECTION + DIRECTION_STRIDE;
160             pin -= 32;
161         }
162     }
163 
164     return kd_gpio_reg_readl(reg, pin) ? GPIO_DM_OUTPUT : GPIO_DM_INPUT;
165 }
166 
kd_pin_write(rt_base_t pin,rt_base_t value)167 rt_err_t kd_pin_write(rt_base_t pin, rt_base_t value)
168 {
169     void* reg;
170 
171     if (check_pin_valid(pin) < 0)
172         return -RT_EINVAL;
173 
174     if (pin < 32)
175     {
176         reg = gpio_dev.base[0] + DATA_OUTPUT;
177     } else {
178         pin -= 32;
179         if (pin < 32)
180         {
181             reg = gpio_dev.base[1] + DATA_OUTPUT;
182         } else {
183             reg = gpio_dev.base[1] + DATA_OUTPUT + DATA_INPUT_STRIDE;
184             pin -= 32;
185         }
186     }
187 
188     kd_gpio_reg_writel(reg, pin, value ? GPIO_PV_HIGH : GPIO_PV_LOW);
189 
190     return RT_EOK;
191 }
192 
kd_pin_read(rt_base_t pin)193 int kd_pin_read(rt_base_t pin)
194 {
195     void* reg;
196 
197     if (check_pin_valid(pin) < 0)
198         return -RT_EINVAL;
199 
200     if (pin < 32)
201     {
202         reg = gpio_dev.base[0] + DATA_INPUT;
203     } else {
204         pin -= 32;
205         if (pin < 32)
206         {
207             reg = gpio_dev.base[1] + DATA_INPUT;
208         } else {
209             reg = gpio_dev.base[1] + DATA_INPUT + DATA_INPUT_STRIDE;
210             pin -= 32;
211         }
212     }
213 
214     return kd_gpio_reg_readl(reg, pin) ? GPIO_PV_HIGH : GPIO_PV_LOW;
215 }
216 
kd_set_pin_edge(rt_int32_t pin,gpio_pin_edge_t edge)217 static int kd_set_pin_edge(rt_int32_t pin, gpio_pin_edge_t edge)
218 {
219     void* reg;
220 
221     reg = gpio_dev.base[pin >> 5];
222     pin = pin & 0x1f;
223 
224     switch (edge)
225     {
226     case GPIO_PE_RISING:
227         kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x1);
228         kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x1);
229         kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0);
230         break;
231     case GPIO_PE_FALLING:
232         kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x1);
233         kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x0);
234         kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0);
235         break;
236     case GPIO_PE_BOTH:
237         kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x1);
238         break;
239     case GPIO_PE_LOW:
240         kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x0);
241         kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x0);
242         kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0);
243         break;
244     case GPIO_PE_HIGH:
245         kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x0);
246         kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x1);
247         kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0);
248         break;
249     default:
250         break;
251     }
252 
253     kd_gpio_reg_writel(reg + INT_ENABLE, pin, 0x1);
254 
255     return RT_EOK;
256 }
257 
debounce_work(struct rt_work * work,void * param)258 static void debounce_work(struct rt_work* work, void* param)
259 {
260     void* reg;
261     rt_size_t pin = (rt_size_t)param;
262 
263     reg = gpio_dev.base[pin >> 5];
264     pin = pin & 0x1f;
265 
266     rt_base_t level = rt_hw_interrupt_disable();
267     kd_gpio_reg_writel(reg + INT_MASK, pin, 0x0);
268     rt_hw_interrupt_enable(level);
269 }
270 
pin_irq(int vector,void * param)271 static void pin_irq(int vector, void* param)
272 {
273     void* reg;
274     long pin = vector - IRQN_GPIO0_INTERRUPT;
275     gpio_pin_edge_t edge = irq_table[pin].edge;
276     long pin_offset;
277 
278     reg = gpio_dev.base[pin >> 5];
279     pin_offset = pin & 0x1f;
280 
281     switch (edge)
282     {
283     case GPIO_PE_RISING:
284     case GPIO_PE_FALLING:
285     case GPIO_PE_BOTH:
286         kd_gpio_reg_writel(reg + INT_CLEAR, pin_offset, 0x1);
287         break;
288     case GPIO_PE_LOW:
289     case GPIO_PE_HIGH:
290         kd_gpio_reg_writel(reg + INT_MASK, pin_offset, 0x1);
291         rt_work_init(&irq_table[pin].debounce_work, debounce_work, (void *)pin);
292         rt_work_submit(&irq_table[pin].debounce_work, irq_table[pin].debounce);
293         break;
294     default:
295         break;
296     }
297 
298     if (irq_table[pin].hdr)
299         irq_table[pin].hdr(irq_table[pin].args);
300 }
301 
gpio_irq_to_user(void * args)302 static void gpio_irq_to_user(void* args)
303 {
304 }
305 
kd_pin_attach_irq(rt_int32_t pin,rt_uint32_t mode,void (* hdr)(void * args),void * args)306 rt_err_t kd_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void* args), void* args)
307 {
308     char irq_name[10];
309 
310     if (check_pin_valid(pin) < 0)
311         return -RT_EINVAL;
312     if (pin >= GPIO_IRQ_MAX_NUM)
313     {
314         LOG_E("pin %d not support interrupt", pin);
315         return -RT_EINVAL;
316     }
317 
318     irq_table[pin].hdr = hdr;
319     irq_table[pin].args = args;
320     if (hdr != gpio_irq_to_user)
321     {
322         irq_table[pin].lwp = NULL;
323         irq_table[pin].lwp_ref_cnt = 0;
324     }
325 
326     if (mode < 0 || mode > 4)
327         return -RT_EINVAL;
328     irq_table[pin].edge = mode;
329     irq_table[pin].debounce = rt_tick_from_millisecond(10);
330 
331     kd_set_pin_edge(pin, irq_table[pin].edge);
332     rt_snprintf(irq_name, sizeof irq_name, "pin%d", pin);
333     rt_hw_interrupt_install(IRQN_GPIO0_INTERRUPT + pin, pin_irq, RT_NULL, irq_name);
334 
335     return RT_EOK;
336 }
337 
kd_pin_detach_irq(rt_int32_t pin)338 rt_err_t kd_pin_detach_irq(rt_int32_t pin)
339 {
340     void* reg;
341 
342     if (check_pin_valid(pin) < 0)
343         return -RT_EINVAL;
344     if (pin >= GPIO_IRQ_MAX_NUM)
345     {
346         LOG_E("pin %d not support interrupt", pin);
347         return -RT_EINVAL;
348     }
349 
350     irq_table[pin].hdr = RT_NULL;
351     irq_table[pin].args = RT_NULL;
352     irq_table[pin].lwp = NULL;
353     irq_table[pin].lwp_ref_cnt = 0;
354     irq_table[pin].signo = 0;
355     irq_table[pin].sigval = 0;
356 
357     reg = gpio_dev.base[pin >> 5];
358     pin = pin & 0x1f;
359     kd_gpio_reg_writel(reg + INT_ENABLE, pin, 0x0);
360 
361     return RT_EOK;
362 }
363 
kd_pin_irq_enable(rt_base_t pin,rt_uint32_t enabled)364 rt_err_t kd_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
365 {
366     if (check_pin_valid(pin) < 0)
367         return -RT_EINVAL;
368     if (pin >= GPIO_IRQ_MAX_NUM)
369     {
370         LOG_E("pin %d not support interrupt", pin);
371         return -RT_EINVAL;
372     }
373 
374     if (enabled)
375         rt_hw_interrupt_umask(IRQN_GPIO0_INTERRUPT + pin);
376     else
377         rt_hw_interrupt_mask(IRQN_GPIO0_INTERRUPT + pin);
378 
379     return RT_EOK;
380 }
381 
rt_hw_gpio_init(void)382 int rt_hw_gpio_init(void)
383 {
384     rt_err_t ret;
385 
386     gpio_dev.base[0] = rt_ioremap((void*)GPIO0_BASE_ADDR, GPIO0_IO_SIZE);
387     gpio_dev.base[1] = rt_ioremap((void*)GPIO1_BASE_ADDR, GPIO1_IO_SIZE);
388 
389     if (kd_request_lock(HARDLOCK_GPIO))
390     {
391         rt_kprintf("fail to request hardlock-%d\n", HARDLOCK_GPIO);
392         return -RT_ERROR;
393     }
394     gpio_dev.hardlock = HARDLOCK_GPIO;
395 
396     ret = rt_device_register(&gpio_dev.dev, "gpio", RT_DEVICE_FLAG_RDWR);
397 
398     return ret;
399 }
400 INIT_BOARD_EXPORT(rt_hw_gpio_init);