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