1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <poll.h>
6
7 #include <drivers/u_ld.h>
8 #include <aos/hal/gpio.h>
9 #include <vfsdev/gpio_dev.h>
10 #include <devicevfs/devicevfs.h>
11
12
13 #ifdef CONFIG_GPIO_NUM
14 #define PLATFORM_GPIO_NUM CONFIG_GPIO_NUM
15 #else
16 #define PLATFORM_GPIO_NUM 40
17 #endif
18
19 #if (PLATFORM_GPIO_NUM > 0)
20 // UART device node will be named with "/dev/ttyUART<x>", where <x> is uart port id
21 #define GPIO_DEV_NAME_FORMAT "gpio"
22
23 static gpio_config_t gpio_hal_configs[PLATFORM_GPIO_NUM];
24
prepare_gpio_hal(gpio_dev_t * gpio_dev)25 static void prepare_gpio_hal(gpio_dev_t *gpio_dev)
26 {
27 if (gpio_dev->config == gpio_hal_configs[gpio_dev->port])
28 return;
29
30 if (gpio_hal_configs[gpio_dev->port] != -1)
31 (void)hal_gpio_finalize(gpio_dev);
32
33 (void)hal_gpio_init(gpio_dev);
34 gpio_hal_configs[gpio_dev->port] = gpio_dev->config;
35 }
36
gpio_device_read(file_t * f,void * buffer,size_t size)37 ssize_t gpio_device_read (file_t *f, void *buffer, size_t size) {
38
39 ddkc_warn("%s not implemented\r\n", __func__);
40
41 return -1;
42 }
43
gpio_device_write(file_t * f,const void * buffer,size_t size)44 ssize_t gpio_device_write (file_t *f, const void *buffer, size_t size) {
45 ddkc_warn("%s not implemented\r\n", __func__);
46
47 return -1;
48 }
49
gpio_io_set(gpio_io_config_t * config)50 int gpio_io_set (gpio_io_config_t *config) {
51 int ret = 0;
52 gpio_dev_t gpio_dev;
53
54 ddkc_dbg("%s\r\n", __func__);
55
56 if (!config || config->id >= PLATFORM_GPIO_NUM) {
57 ddkc_err("invalid param: config:%p, id:%d\r\n", config, !config ? 0 : config->id);
58 return -EINVAL;
59 }
60
61 memset(&gpio_dev, 0, sizeof(gpio_dev_t));
62
63 gpio_dev.port = config->id;
64
65 if (config->config & GPIO_IO_OUTPUT_MASK) {
66 /* check if */
67 if ((config->config & GPIO_IO_OUTPUT_MASK) == GPIO_IO_OUTPUT_TOGGLE) {
68 ret = hal_gpio_output_toggle(&gpio_dev);
69 ddkc_dbg("GPIO:%d, output toggle done, ret:%d", gpio_dev.port, ret);
70 return 0;
71 }
72
73 switch (config->config & GPIO_IO_OUTPUT_MASK) {
74 case GPIO_IO_OUTPUT_PP:
75 gpio_dev.config = OUTPUT_PUSH_PULL;
76 break;
77 case GPIO_IO_OUTPUT_ODNP:
78 gpio_dev.config = OUTPUT_OPEN_DRAIN_NO_PULL;
79 break;
80 case GPIO_IO_OUTPUT_ODPU:
81 gpio_dev.config = OUTPUT_OPEN_DRAIN_PULL_UP;
82 break;
83 default:
84 ddkc_dbg("invalid config:0x%x, set to ODNP\r\n", config->config);
85 gpio_dev.config = OUTPUT_OPEN_DRAIN_NO_PULL;
86 break;
87 }
88
89 prepare_gpio_hal(&gpio_dev);
90
91 if (config->data) {
92 ret = hal_gpio_output_high(&gpio_dev);
93 } else
94 ret = hal_gpio_output_low(&gpio_dev);
95
96 ddkc_dbg("GPIO:%d, output config:0x%x, ret:%d", gpio_dev.port, gpio_dev.config, ret);
97
98 return ret;
99 }
100
101 ddkc_warn("!!!WARNING!!! THIS SHOULD NEVER HAPPEN, config:0x%x\r\n", config->config);
102
103 return ret;
104 }
105
gpio_io_get(gpio_io_config_t * config)106 int gpio_io_get (gpio_io_config_t *config) {
107 int ret = 0;
108 gpio_dev_t gpio_dev;
109
110 ddkc_dbg("%s\r\n", __func__);
111
112 if (!config || config->id >= PLATFORM_GPIO_NUM) {
113 ddkc_err("invalid param: config:%p, id:%d\r\n", config, !config ? 0 : config->id);
114 return -EINVAL;
115 }
116
117 memset(&gpio_dev, 0, sizeof(gpio_dev_t));
118
119 gpio_dev.port = config->id;
120
121 if (config->config & GPIO_IO_INPUT_MASK) {
122 unsigned int value = 0;
123 switch (config->config & GPIO_IO_INPUT_MASK) {
124 case GPIO_IO_INPUT_HI:
125 gpio_dev.config = INPUT_HIGH_IMPEDANCE;
126 break;
127 case GPIO_IO_INPUT_PU:
128 gpio_dev.config = INPUT_PULL_UP;
129 break;
130 case GPIO_IO_INPUT_PD:
131 gpio_dev.config = INPUT_PULL_DOWN;
132 break;
133 default:
134 gpio_dev.config = INPUT_HIGH_IMPEDANCE;
135 break;
136 }
137 prepare_gpio_hal(&gpio_dev);
138 ret = hal_gpio_input_get(&gpio_dev, &value);
139 ddkc_dbg("GPIO:%d, input config:0x%x, ret:%d\r\n", gpio_dev.port, gpio_dev.config, ret);
140
141 return !ret ? value: ret;
142 }
143
144 ddkc_warn("!!!WARNING!!! THIS SHOULD NEVER HAPPEN, config:0x%x\r\n", config->config);
145
146 return ret;
147 }
148
gpio_irq_set(gpio_irq_config_t * config)149 static int gpio_irq_set (gpio_irq_config_t *config) {
150 int ret = 0;
151 gpio_dev_t gpio_dev;
152 gpio_irq_trigger_t irq_type;
153
154 ddkc_dbg("%s\r\n", __func__);
155
156 if (!config || config->id >= PLATFORM_GPIO_NUM) {
157 ddkc_err("invalid param: config:%p, id:%d\r\n", config, !config ? 0 : config->id);
158 return -EINVAL;
159 }
160
161 memset(&gpio_dev, 0, sizeof(gpio_dev_t));
162 gpio_dev.port = config->id;
163 gpio_dev.config = IRQ_MODE;
164
165 prepare_gpio_hal(&gpio_dev);
166
167 if (config->config & GPIO_IRQ_ENABLE) {
168
169 switch (config->config & GPIO_IRQ_MODE_MASK) {
170 case GPIO_IRQ_LEVEL_LOW:
171 ddkc_warn("not implemented yet\r\n");
172 return -EINVAL;
173 case GPIO_IRQ_LEVEL_HIGH:
174 ddkc_warn("not implemented yet\r\n");
175 return -EINVAL;
176 case GPIO_IRQ_EDGE_FALLING:
177 irq_type = IRQ_TRIGGER_FALLING_EDGE;
178 break;
179 case GPIO_IRQ_EDGE_RISING:
180 irq_type = IRQ_TRIGGER_RISING_EDGE;
181 break;
182 case GPIO_IRQ_EDGE_BOTH:
183 irq_type = IRQ_TRIGGER_BOTH_EDGES;
184 break;
185 default:
186 ddkc_warn("ERROR - invalid irq_type:0x%x\r\n", config->config & GPIO_IRQ_MODE_MASK);
187 return -EINVAL;
188 }
189 ret = hal_gpio_enable_irq(&gpio_dev, irq_type, (gpio_irq_handler_t)config->cb, config->arg);
190
191 } else if (config->config & GPIO_IRQ_DISABLE) {
192 ret = hal_gpio_disable_irq(&gpio_dev);
193 } else if (config->config & GPIO_IRQ_CLEAR) {
194 ret = hal_gpio_clear_irq(&gpio_dev);
195 }
196
197 return ret;
198 }
199
200
201
gpio_device_ioctl(file_t * f,int cmd,unsigned long arg)202 int gpio_device_ioctl (file_t *f, int cmd, unsigned long arg) {
203 int ret = 0;
204 gpio_io_config_t config;
205 gpio_irq_config_t irq_config;
206 ddkc_dbg("i_name:%s, cmd:%d, arg:0x%lx\r\n", f->node->i_name, cmd, arg);
207
208 switch (cmd) {
209 case IOC_GPIO_SET:
210 aos_ipc_copy(&config, (void *)arg, sizeof(gpio_io_config_t));
211 ret = gpio_io_set(&config);
212 break;
213 case IOC_GPIO_GET:
214 aos_ipc_copy(&config, (void *)arg, sizeof(gpio_io_config_t));
215 ret = gpio_io_get(&config);
216 aos_ipc_copy((void *)arg, &config, sizeof(gpio_io_config_t));
217 break;
218 case IOC_GPIO_SET_IRQ:
219 aos_ipc_copy(&irq_config, (void *)arg, sizeof(gpio_irq_config_t));
220 ret = gpio_irq_set(&irq_config);
221 break;
222
223 default:
224 ddkc_warn("invalid command:%d\r\n", cmd);
225 break;
226 }
227
228 return ret;
229 }
230
gpio_device_open(inode_t * node,file_t * f)231 int gpio_device_open (inode_t *node, file_t *f) {
232 int ret = 0;
233
234 return ret;
235 }
236
gpio_device_close(file_t * f)237 int gpio_device_close (file_t *f) {
238 int ret = 0;
239
240 return ret;
241 }
242
243 /************************** device ****************************/
244
245
246 subsys_file_ops_t gpio_device_fops = {
247 .open = gpio_device_open,
248 .close = gpio_device_close,
249 .read = gpio_device_read,
250 .write = gpio_device_write,
251 .ioctl = gpio_device_ioctl,
252 .poll = NULL,
253 .lseek = NULL,
254 };
255
gpio_device_init(struct u_platform_device * pdev)256 int gpio_device_init (struct u_platform_device *pdev) {
257 // make sure 0 is returned if init operation success
258 // or aos_dev_reg procedure will break and no device node will be registered
259 ddkc_dbg("%s\r\n", __func__);
260 return 0;
261 }
262
gpio_device_deinit(struct u_platform_device * pdev)263 int gpio_device_deinit (struct u_platform_device *pdev) {
264 ddkc_dbg("%s\r\n", __func__);
265 return 0;
266 }
267
gpio_device_pm(struct u_platform_device * pdev,u_pm_ops_t state)268 int gpio_device_pm (struct u_platform_device *pdev, u_pm_ops_t state) {
269 ddkc_dbg("%s\r\n", __func__);
270 return 0;
271 }
272
273 struct subsys_drv gpio_device_drv = {
274 .drv_name = "gpio",
275 .init = gpio_device_init,
276 .deinit = gpio_device_deinit,
277 .pm = gpio_device_pm,
278 };
279
280 struct subsys_dev g_gpio_device = {
281 .user_data = NULL,
282 .type = BUS_TYPE_PLATFORM,
283 .permission = 0,
284 .node_name = "gpio"
285 };
286
vfs_gpio_drv_init(void)287 int vfs_gpio_drv_init (void) {
288 int ret = 0;
289 int i;
290
291 for (i = 0; i < PLATFORM_GPIO_NUM; i++)
292 gpio_hal_configs[i] = -1;
293
294 ddkc_dbg("gpio vfs driver init starts\r\n");
295 ret = aos_dev_reg(&g_gpio_device, &gpio_device_fops, &gpio_device_drv);
296 if (ret) {
297 ddkc_err("aos_dev_reg for uart devices failed, ret:%d\r\n", ret);
298 goto err;
299 }
300
301 ddkc_dbg("gpio vfs driver init finish, ret:%d\r\n", ret);
302
303 return 0;
304
305 err:
306
307 ddkc_warn("gpio vfs driver init failed, ret:%d\r\n", ret);
308
309 return ret;
310 }
311
312 VFS_DRIVER_ENTRY(vfs_gpio_drv_init)
313
314 #endif
315