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