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