1 /*
2  * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <drv/gpio.h>
6 #include <hal_gpio.h>
7 #include <aos/gpioc_csi.h>
8 
9 #define GPIO_PINS_PER_PORT      (sizeof(uint32_t) * 8)
10 #define GPIO_NUM_PORTS          ((HAL_GPIO_PIN_LED_NUM + GPIO_PINS_PER_PORT - 1) / GPIO_PINS_PER_PORT)
11 
12 static aos_gpioc_csi_t gpioc_csi[GPIO_NUM_PORTS];
13 static csi_gpio_irq_mode_t irq_modes[GPIO_NUM_PORTS][GPIO_PINS_PER_PORT];
14 
csi_gpio_init(csi_gpio_t * gpio,uint32_t port_idx)15 csi_error_t csi_gpio_init(csi_gpio_t *gpio, uint32_t port_idx)
16 {
17     if (!gpio)
18         return CSI_ERROR;
19 
20     if (port_idx >= GPIO_NUM_PORTS)
21         return CSI_ERROR;
22 
23     gpio->dev.idx = port_idx;
24     gpio->callback = NULL;
25     gpio->arg = NULL;
26 
27     return CSI_OK;
28 }
29 
csi_gpio_uninit(csi_gpio_t * gpio)30 void csi_gpio_uninit(csi_gpio_t *gpio)
31 {
32 }
33 
csi_gpio_dir(csi_gpio_t * gpio,uint32_t pin_mask,csi_gpio_dir_t dir)34 csi_error_t csi_gpio_dir(csi_gpio_t *gpio, uint32_t pin_mask, csi_gpio_dir_t dir)
35 {
36     if (!gpio)
37         return CSI_ERROR;
38 
39     if (gpio->dev.idx >= GPIO_NUM_PORTS)
40         return CSI_ERROR;
41 
42     for (uint32_t i = 0; i < GPIO_PINS_PER_PORT; i++) {
43         if (pin_mask & ((uint32_t)1 << i)) {
44             struct HAL_IOMUX_PIN_FUNCTION_MAP cfg;
45             enum HAL_GPIO_DIR_T d;
46             cfg.pin = gpio->dev.idx * GPIO_PINS_PER_PORT + i;
47             cfg.function = HAL_IOMUX_FUNC_AS_GPIO;
48             cfg.volt = HAL_IOMUX_PIN_VOLTAGE_VIO;
49             cfg.pull_sel = HAL_IOMUX_PIN_PULLUP_ENALBE;
50             hal_iomux_init(&cfg, 1);
51             d = (dir == GPIO_DIRECTION_INPUT) ? HAL_GPIO_DIR_IN : HAL_GPIO_DIR_OUT;
52             hal_gpio_pin_set_dir(cfg.pin, d, 0);
53         }
54     }
55 
56     return CSI_OK;
57 }
58 
csi_gpio_mode(csi_gpio_t * gpio,uint32_t pin_mask,csi_gpio_mode_t mode)59 csi_error_t csi_gpio_mode(csi_gpio_t *gpio, uint32_t pin_mask, csi_gpio_mode_t mode)
60 {
61     if (!gpio)
62         return CSI_ERROR;
63 
64     if (gpio->dev.idx >= GPIO_NUM_PORTS)
65         return CSI_ERROR;
66 
67     for (uint32_t i = 0; i < GPIO_PINS_PER_PORT; i++) {
68         if (pin_mask & ((uint32_t)1 << i)) {
69             struct HAL_IOMUX_PIN_FUNCTION_MAP cfg;
70             enum HAL_GPIO_DIR_T d;
71             cfg.pin = gpio->dev.idx * GPIO_PINS_PER_PORT + i;
72             cfg.function = HAL_IOMUX_FUNC_AS_GPIO;
73             cfg.volt = HAL_IOMUX_PIN_VOLTAGE_VIO;
74             switch (mode) {
75             case GPIO_MODE_PULLNONE:
76                 cfg.pull_sel = HAL_IOMUX_PIN_NOPULL;
77                 d = HAL_GPIO_DIR_IN;
78                 break;
79             case GPIO_MODE_PULLUP:
80                 cfg.pull_sel = HAL_IOMUX_PIN_PULLUP_ENALBE;
81                 d = HAL_GPIO_DIR_IN;
82                 break;
83             case GPIO_MODE_PULLDOWN:
84                 cfg.pull_sel = HAL_IOMUX_PIN_PULLDOWN_ENALBE;
85                 d = HAL_GPIO_DIR_IN;
86                 break;
87             case GPIO_MODE_OPEN_DRAIN:
88                 cfg.pull_sel = HAL_IOMUX_PIN_NOPULL;
89                 d = HAL_GPIO_DIR_OUT;
90                 break;
91             case GPIO_MODE_PUSH_PULL:
92                 cfg.pull_sel = HAL_IOMUX_PIN_PULLDOWN_ENALBE;
93                 d = HAL_GPIO_DIR_OUT;
94                 break;
95             default:
96                 cfg.pull_sel = HAL_IOMUX_PIN_NOPULL;
97                 d = HAL_GPIO_DIR_IN;
98                 break;
99             }
100             hal_iomux_init(&cfg, 1);
101             hal_gpio_pin_set_dir(cfg.pin, d, 0);
102         }
103     }
104 
105     return CSI_OK;
106 }
107 
csi_gpio_irq_mode(csi_gpio_t * gpio,uint32_t pin_mask,csi_gpio_irq_mode_t mode)108 csi_error_t csi_gpio_irq_mode(csi_gpio_t *gpio, uint32_t pin_mask, csi_gpio_irq_mode_t mode)
109 {
110     if (!gpio)
111         return CSI_ERROR;
112 
113     if (gpio->dev.idx >= GPIO_NUM_PORTS)
114         return CSI_ERROR;
115 
116     switch (mode) {
117     case GPIO_IRQ_MODE_RISING_EDGE:
118     case GPIO_IRQ_MODE_FALLING_EDGE:
119         break;
120     default:
121         return CSI_ERROR;
122     }
123 
124     for (uint32_t i = 0; i < GPIO_PINS_PER_PORT; i++) {
125         if (pin_mask & ((uint32_t)1 << i))
126             irq_modes[gpio->dev.idx][i] = mode;
127     }
128 
129     return CSI_OK;
130 }
131 
irq_handler(enum HAL_GPIO_PIN_T pin)132 static void irq_handler(enum HAL_GPIO_PIN_T pin)
133 {
134     uint32_t port = pin / GPIO_PINS_PER_PORT;
135     csi_gpio_t *gpio;
136 
137     if (port >= GPIO_NUM_PORTS || pin % GPIO_PINS_PER_PORT >= gpioc_csi[port].gpioc.num_pins)
138         return;
139 
140     gpio = &gpioc_csi[port].csi_gpio;
141     gpio->callback(gpio, (uint32_t)1 << (pin % GPIO_PINS_PER_PORT), gpio->arg);
142 }
143 
csi_gpio_irq_enable(csi_gpio_t * gpio,uint32_t pin_mask,bool enable)144 csi_error_t csi_gpio_irq_enable(csi_gpio_t *gpio, uint32_t pin_mask, bool enable)
145 {
146     if (!gpio)
147         return CSI_ERROR;
148 
149     if (gpio->dev.idx >= GPIO_NUM_PORTS)
150         return CSI_ERROR;
151 
152     for (uint32_t i = 0; i < GPIO_PINS_PER_PORT; i++) {
153         if (pin_mask & ((uint32_t)1 << i)) {
154             uint32_t pin = gpio->dev.idx * GPIO_PINS_PER_PORT + i;
155             struct HAL_GPIO_IRQ_CFG_T cfg;
156             if (enable) {
157                 csi_gpio_irq_mode_t mode;
158                 cfg.irq_enable = true;
159                 cfg.irq_debounce = true;
160                 mode = irq_modes[gpio->dev.idx][i];
161                 cfg.irq_polarity = (mode == GPIO_IRQ_MODE_RISING_EDGE) ? HAL_GPIO_IRQ_POLARITY_HIGH_RISING :
162                                                                          HAL_GPIO_IRQ_POLARITY_LOW_FALLING;
163                 cfg.irq_handler = irq_handler;
164                 cfg.irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE;
165             } else {
166                 cfg.irq_enable = false;
167                 cfg.irq_debounce = false;
168                 cfg.irq_polarity = HAL_GPIO_IRQ_POLARITY_LOW_FALLING;
169                 cfg.irq_handler = NULL;
170                 cfg.irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE;
171             }
172             hal_gpio_setup_irq(pin, &cfg);
173         }
174     }
175 
176     return CSI_OK;
177 }
178 
csi_gpio_write(csi_gpio_t * gpio,uint32_t pin_mask,csi_gpio_pin_state_t value)179 void csi_gpio_write(csi_gpio_t *gpio, uint32_t pin_mask, csi_gpio_pin_state_t value)
180 {
181     if (!gpio)
182         return;
183 
184     if (gpio->dev.idx >= GPIO_NUM_PORTS)
185         return;
186 
187     for (uint32_t i = 0; i < GPIO_PINS_PER_PORT; i++) {
188         if (pin_mask & ((uint32_t)1 << i)) {
189             uint32_t pin = gpio->dev.idx * GPIO_PINS_PER_PORT + i;
190             hal_gpio_pin_set_dir(pin, HAL_GPIO_DIR_OUT, !!value);
191         }
192     }
193 }
194 
csi_gpio_read(csi_gpio_t * gpio,uint32_t pin_mask)195 uint32_t csi_gpio_read(csi_gpio_t *gpio, uint32_t pin_mask)
196 {
197     uint32_t ret = 0;
198 
199     if (!gpio)
200         return CSI_ERROR;
201 
202     if (gpio->dev.idx >= GPIO_NUM_PORTS)
203         return CSI_ERROR;
204 
205     for (uint32_t i = 0; i < GPIO_PINS_PER_PORT; i++) {
206         if (pin_mask & ((uint32_t)1 << i)) {
207             uint32_t pin = gpio->dev.idx * GPIO_PINS_PER_PORT + i;
208             ret |= (uint32_t)!!hal_gpio_pin_get_val(pin) << i;
209         }
210     }
211 
212     return ret;
213 }
214 
csi_gpio_attach_callback(csi_gpio_t * gpio,void * callback,void * arg)215 csi_error_t csi_gpio_attach_callback(csi_gpio_t *gpio, void *callback, void *arg)
216 {
217     if (!gpio)
218         return CSI_ERROR;
219 
220     if (gpio->dev.idx >= GPIO_NUM_PORTS)
221         return CSI_ERROR;
222 
223     gpio->callback = callback;
224     gpio->arg = arg;
225 
226     return CSI_OK;
227 }
228 
csi_gpio_detach_callback(csi_gpio_t * gpio)229 void csi_gpio_detach_callback(csi_gpio_t *gpio)
230 {
231     if (!gpio)
232         return;
233 
234     if (gpio->dev.idx >= GPIO_NUM_PORTS)
235         return;
236 
237     gpio->callback = NULL;
238     gpio->arg = NULL;
239 }
240 
gpioc_csi_init(void)241 static int gpioc_csi_init(void)
242 {
243     for (uint32_t i = 0; i < GPIO_NUM_PORTS; i++) {
244         uint32_t num_pins;
245         int ret;
246 
247         gpioc_csi[i].gpioc.dev.id = i;
248         num_pins = HAL_GPIO_PIN_LED_NUM - GPIO_PINS_PER_PORT * i;
249         if (num_pins > GPIO_PINS_PER_PORT)
250             num_pins = GPIO_PINS_PER_PORT;
251         gpioc_csi[i].gpioc.num_pins = num_pins;
252         gpioc_csi[i].default_input_cfg = AOS_GPIO_INPUT_CFG_PU;
253         gpioc_csi[i].default_output_cfg = AOS_GPIO_OUTPUT_CFG_PP;
254         ret = (int)aos_gpioc_csi_register(&gpioc_csi[i]);
255         if (ret) {
256             for (uint32_t j = 0; j < i; j++)
257                 (void)aos_gpioc_csi_unregister(j);
258             return ret;
259         }
260     }
261 
262     return 0;
263 }
264 
265 LEVEL1_DRIVER_ENTRY(gpioc_csi_init)
266