1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2019-03-19     ZYH          first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <fpioa.h>
14 #include <gpiohs.h>
15 #include "drv_gpio.h"
16 #include "drv_io_config.h"
17 #include <plic.h>
18 #include <rthw.h>
19 #include <utils.h>
20 #include <string.h>
21 
22 #define DBG_ENABLE
23 #define DBG_TAG  "PIN"
24 #define DBG_LVL  DBG_WARNING
25 #define DBG_COLOR
26 #include <rtdbg.h>
27 
28 #define FUNC_GPIOHS(n) (FUNC_GPIOHS0 + n)
29 
30 static short pin_alloc_table[FPIOA_NUM_IO];
31 static uint32_t free_pin = 0;
32 
alloc_pin_channel(rt_base_t pin_index)33 static int alloc_pin_channel(rt_base_t pin_index)
34 {
35     if(free_pin == 32)
36     {
37         LOG_E("no free gpiohs channel to alloc");
38         return -1;
39     }
40 
41     if(pin_alloc_table[pin_index] != -1)
42     {
43         LOG_W("already alloc gpiohs channel for pin %d", pin_index);
44         return pin_alloc_table[pin_index];
45     }
46 
47     pin_alloc_table[pin_index] = free_pin;
48     free_pin++;
49 
50     fpioa_set_function(pin_index, FUNC_GPIOHS(pin_alloc_table[pin_index]));
51     return pin_alloc_table[pin_index];
52 }
53 
get_pin_channel(rt_base_t pin_index)54 int get_pin_channel(rt_base_t pin_index)
55 {
56     return pin_alloc_table[pin_index];
57 }
58 
free_pin_channel(rt_base_t pin_index)59 static void free_pin_channel(rt_base_t pin_index)
60 {
61     if(pin_alloc_table[pin_index] == -1)
62     {
63         LOG_W("free error:not alloc gpiohs channel for pin %d", pin_index);
64         return;
65     }
66     pin_alloc_table[pin_index] = -1;
67     free_pin--;
68 }
69 
70 
drv_pin_mode(struct rt_device * device,rt_base_t pin,rt_uint8_t mode)71 static void drv_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
72 {
73     int pin_channel = get_pin_channel(pin);
74     if(pin_channel == -1)
75     {
76         pin_channel = alloc_pin_channel(pin);
77         if(pin_channel == -1)
78         {
79             return;
80         }
81     }
82 
83     switch (mode)
84     {
85         case PIN_MODE_OUTPUT:
86             gpiohs_set_drive_mode(pin_channel, GPIO_DM_OUTPUT);
87             break;
88         case PIN_MODE_INPUT:
89             gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT);
90             break;
91         case PIN_MODE_INPUT_PULLUP:
92             gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT_PULL_UP);
93             break;
94         case PIN_MODE_INPUT_PULLDOWN:
95             gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT_PULL_DOWN);
96             break;
97         default:
98             LOG_E("Not support mode %d", mode);
99             break;
100     }
101 }
102 
drv_pin_write(struct rt_device * device,rt_base_t pin,rt_uint8_t value)103 static void drv_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value)
104 {
105     int pin_channel = get_pin_channel(pin);
106     if(pin_channel == -1)
107     {
108         LOG_E("pin %d not set mode", pin);
109         return;
110     }
111     gpiohs_set_pin(pin_channel, value == PIN_HIGH ? GPIO_PV_HIGH : GPIO_PV_LOW);
112 }
113 
drv_pin_read(struct rt_device * device,rt_base_t pin)114 static rt_ssize_t drv_pin_read(struct rt_device *device, rt_base_t pin)
115 {
116     int pin_channel = get_pin_channel(pin);
117     if(pin_channel == -1)
118     {
119         LOG_E("pin %d not set mode", pin);
120         return -RT_EINVAL;
121     }
122     return gpiohs_get_pin(pin_channel) == GPIO_PV_HIGH ? PIN_HIGH : PIN_LOW;
123 }
124 
125 static struct
126 {
127     void (*hdr)(void *args);
128     void* args;
129     gpio_pin_edge_t edge;
130 } irq_table[32];
131 
pin_irq(int vector,void * param)132 static void pin_irq(int vector, void *param)
133 {
134     int pin_channel = vector - IRQN_GPIOHS0_INTERRUPT;
135     if(irq_table[pin_channel].edge & GPIO_PE_FALLING)
136     {
137         set_gpio_bit(gpiohs->fall_ie.u32, pin_channel, 0);
138         set_gpio_bit(gpiohs->fall_ip.u32, pin_channel, 1);
139         set_gpio_bit(gpiohs->fall_ie.u32, pin_channel, 1);
140     }
141 
142     if(irq_table[pin_channel].edge & GPIO_PE_RISING)
143     {
144         set_gpio_bit(gpiohs->rise_ie.u32, pin_channel, 0);
145         set_gpio_bit(gpiohs->rise_ip.u32, pin_channel, 1);
146         set_gpio_bit(gpiohs->rise_ie.u32, pin_channel, 1);
147     }
148 
149     if(irq_table[pin_channel].edge & GPIO_PE_LOW)
150     {
151         set_gpio_bit(gpiohs->low_ie.u32, pin_channel, 0);
152         set_gpio_bit(gpiohs->low_ip.u32, pin_channel, 1);
153         set_gpio_bit(gpiohs->low_ie.u32, pin_channel, 1);
154     }
155 
156     if(irq_table[pin_channel].edge & GPIO_PE_HIGH)
157     {
158         set_gpio_bit(gpiohs->high_ie.u32, pin_channel, 0);
159         set_gpio_bit(gpiohs->high_ip.u32, pin_channel, 1);
160         set_gpio_bit(gpiohs->high_ie.u32, pin_channel, 1);
161     }
162     if(irq_table[pin_channel].hdr)
163     {
164         irq_table[pin_channel].hdr(irq_table[pin_channel].args);
165     }
166 }
167 
drv_pin_attach_irq(struct rt_device * device,rt_base_t pin,rt_uint8_t mode,void (* hdr)(void * args),void * args)168 static rt_err_t drv_pin_attach_irq(struct rt_device *device, rt_base_t pin,
169                                    rt_uint8_t mode, void (*hdr)(void *args), void *args)
170 {
171     int pin_channel = get_pin_channel(pin);
172     char irq_name[10];
173     if(pin_channel == -1)
174     {
175         LOG_E("pin %d not set mode", pin);
176         return -RT_ERROR;
177     }
178     irq_table[pin_channel].hdr = hdr;
179     irq_table[pin_channel].args = args;
180     switch (mode)
181     {
182         case PIN_IRQ_MODE_RISING:
183             irq_table[pin_channel].edge = GPIO_PE_RISING;
184             break;
185         case PIN_IRQ_MODE_FALLING:
186             irq_table[pin_channel].edge = GPIO_PE_FALLING;
187             break;
188         case PIN_IRQ_MODE_RISING_FALLING:
189             irq_table[pin_channel].edge = GPIO_PE_BOTH;
190             break;
191         case PIN_IRQ_MODE_HIGH_LEVEL:
192             irq_table[pin_channel].edge = GPIO_PE_LOW;
193             break;
194         case PIN_IRQ_MODE_LOW_LEVEL:
195             irq_table[pin_channel].edge = GPIO_PE_HIGH;
196             break;
197         default:
198             break;
199     }
200     gpiohs_set_pin_edge(pin_channel, irq_table[pin_channel].edge);
201     rt_snprintf(irq_name, sizeof irq_name, "pin%d", pin);
202     rt_hw_interrupt_install(IRQN_GPIOHS0_INTERRUPT + pin_channel, pin_irq, RT_NULL, irq_name);
203 
204     return RT_EOK;
205 }
206 
drv_pin_detach_irq(struct rt_device * device,rt_base_t pin)207 static rt_err_t drv_pin_detach_irq(struct rt_device *device, rt_base_t pin)
208 {
209     rt_err_t ret = RT_EOK;
210 
211     int pin_channel = get_pin_channel(pin);
212     if(pin_channel == -1)
213     {
214         LOG_E("pin %d not set mode", pin);
215         return -RT_ERROR;
216     }
217 
218     irq_table[pin_channel].hdr = RT_NULL;
219     irq_table[pin_channel].args = RT_NULL;
220 
221     return ret;
222 }
223 
drv_pin_irq_enable(struct rt_device * device,rt_base_t pin,rt_uint8_t enabled)224 static rt_err_t drv_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
225 {
226     int pin_channel = get_pin_channel(pin);
227 
228     if(pin_channel == -1)
229     {
230         LOG_E("pin %d not set mode", pin);
231         return -RT_ERROR;
232     }
233 
234     if(enabled)
235     {
236         rt_hw_interrupt_umask(IRQN_GPIOHS0_INTERRUPT + pin_channel);
237     }
238     else
239     {
240         rt_hw_interrupt_mask(IRQN_GPIOHS0_INTERRUPT + pin_channel);
241     }
242 
243     return RT_EOK;
244 }
245 
246 const static struct rt_pin_ops drv_pin_ops =
247 {
248     drv_pin_mode,
249     drv_pin_write,
250     drv_pin_read,
251     drv_pin_attach_irq,
252     drv_pin_detach_irq,
253     drv_pin_irq_enable
254 };
255 
rt_hw_pin_init(void)256 int rt_hw_pin_init(void)
257 {
258     rt_err_t ret = RT_EOK;
259     memset(pin_alloc_table, 0xff, sizeof pin_alloc_table);
260     free_pin = GPIO_ALLOC_START;
261     ret = rt_device_pin_register("pin", &drv_pin_ops, RT_NULL);
262 
263     return ret;
264 }
265 INIT_BOARD_EXPORT(rt_hw_pin_init);
266 
267