1 /*
2 * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3 */
4
5 #include <aos/gpioc_csi.h>
6
gpioc_csi_unregister(aos_gpioc_t * gpioc)7 static void gpioc_csi_unregister(aos_gpioc_t *gpioc)
8 {
9 aos_gpioc_csi_t *gpioc_csi;
10
11 gpioc_csi = aos_container_of(gpioc, aos_gpioc_csi_t, gpioc);
12 (void)csi_gpio_detach_callback(&gpioc_csi->csi_gpio);
13 (void)csi_gpio_uninit(&gpioc_csi->csi_gpio);
14 }
15
set_dir(aos_gpioc_csi_t * gpioc_csi,uint32_t pin,uint32_t dir)16 static aos_status_t set_dir(aos_gpioc_csi_t *gpioc_csi, uint32_t pin, uint32_t dir)
17 {
18 uint32_t mask = (uint32_t)1 << pin;
19 csi_error_t r;
20
21 if (dir == AOS_GPIO_DIR_NONE)
22 r = CSI_OK;
23 else if (dir == AOS_GPIO_DIR_INPUT)
24 r = csi_gpio_dir(&gpioc_csi->csi_gpio, mask, GPIO_DIRECTION_INPUT);
25 else if (dir == AOS_GPIO_DIR_OUTPUT)
26 r = csi_gpio_dir(&gpioc_csi->csi_gpio, mask, GPIO_DIRECTION_OUTPUT);
27 else
28 r = CSI_ERROR;
29
30 return (r == CSI_OK) ? 0 : -EIO;
31 }
32
set_input_cfg(aos_gpioc_csi_t * gpioc_csi,uint32_t pin,uint32_t cfg)33 static aos_status_t set_input_cfg(aos_gpioc_csi_t *gpioc_csi, uint32_t pin, uint32_t cfg)
34 {
35 uint32_t mask = (uint32_t)1 << pin;
36 csi_error_t r;
37
38 if (cfg == AOS_GPIO_INPUT_CFG_HI)
39 r = csi_gpio_mode(&gpioc_csi->csi_gpio, mask, GPIO_MODE_PULLNONE);
40 else if (cfg == AOS_GPIO_INPUT_CFG_PU)
41 r = csi_gpio_mode(&gpioc_csi->csi_gpio, mask, GPIO_MODE_PULLUP);
42 else if (cfg == AOS_GPIO_INPUT_CFG_PD)
43 r = csi_gpio_mode(&gpioc_csi->csi_gpio, mask, GPIO_MODE_PULLDOWN);
44 else
45 r = CSI_ERROR;
46
47 return (r == CSI_OK) ? 0 : -EIO;
48 }
49
set_irq_trig(aos_gpioc_csi_t * gpioc_csi,uint32_t pin,uint32_t trig)50 static aos_status_t set_irq_trig(aos_gpioc_csi_t *gpioc_csi, uint32_t pin, uint32_t trig)
51 {
52 csi_gpio_t *csi_gpio = &gpioc_csi->csi_gpio;
53 uint32_t mask = (uint32_t)1 << pin;
54 csi_error_t r;
55
56 if (trig == AOS_GPIO_IRQ_TRIG_NONE)
57 r = CSI_OK;
58 else if (trig == AOS_GPIO_IRQ_TRIG_EDGE_RISING)
59 r = csi_gpio_irq_mode(csi_gpio, mask, GPIO_IRQ_MODE_RISING_EDGE);
60 else if (trig == AOS_GPIO_IRQ_TRIG_EDGE_FALLING)
61 r = csi_gpio_irq_mode(csi_gpio, mask, GPIO_IRQ_MODE_FALLING_EDGE);
62 else if (trig == AOS_GPIO_IRQ_TRIG_EDGE_BOTH)
63 r = csi_gpio_irq_mode(csi_gpio, mask, GPIO_IRQ_MODE_BOTH_EDGE);
64 else if (trig == AOS_GPIO_IRQ_TRIG_LEVEL_HIGH)
65 r = csi_gpio_irq_mode(csi_gpio, mask, GPIO_IRQ_MODE_HIGH_LEVEL);
66 else if (trig == AOS_GPIO_IRQ_TRIG_LEVEL_LOW)
67 r = csi_gpio_irq_mode(csi_gpio, mask, GPIO_IRQ_MODE_LOW_LEVEL);
68 else
69 r = CSI_ERROR;
70
71 return (r == CSI_OK) ? 0 : -EIO;
72 }
73
set_output_cfg(aos_gpioc_csi_t * gpioc_csi,uint32_t pin,uint32_t cfg)74 static aos_status_t set_output_cfg(aos_gpioc_csi_t *gpioc_csi, uint32_t pin, uint32_t cfg)
75 {
76 uint32_t mask = (uint32_t)1 << pin;
77 csi_error_t r;
78
79 if (cfg == AOS_GPIO_OUTPUT_CFG_PP)
80 r = csi_gpio_mode(&gpioc_csi->csi_gpio, mask, GPIO_MODE_PUSH_PULL);
81 else if (cfg == AOS_GPIO_OUTPUT_CFG_ODNP)
82 r = csi_gpio_mode(&gpioc_csi->csi_gpio, mask, GPIO_MODE_OPEN_DRAIN);
83 else if (cfg == AOS_GPIO_OUTPUT_CFG_ODPU)
84 r = csi_gpio_mode(&gpioc_csi->csi_gpio, mask, GPIO_MODE_OPEN_DRAIN);
85 else
86 r = CSI_ERROR;
87
88 return (r == CSI_OK) ? 0 : -EIO;
89 }
90
restore_mode(aos_gpioc_csi_t * gpioc_csi,uint32_t pin)91 static void restore_mode(aos_gpioc_csi_t *gpioc_csi, uint32_t pin)
92 {
93 uint32_t mode = gpioc_csi->modes[pin];
94 uint32_t dir = mode & AOS_GPIO_DIR_MASK;
95
96 if (dir == AOS_GPIO_DIR_INPUT) {
97 uint32_t cfg = mode & AOS_GPIO_INPUT_CFG_MASK;
98 uint32_t trig = mode & AOS_GPIO_IRQ_TRIG_MASK;
99 (void)set_dir(gpioc_csi, pin, dir);
100 (void)set_input_cfg(gpioc_csi, pin, cfg);
101 (void)set_irq_trig(gpioc_csi, pin, trig);
102 } else if (dir == AOS_GPIO_DIR_OUTPUT) {
103 uint32_t cfg = mode & AOS_GPIO_OUTPUT_CFG_MASK;
104 (void)set_dir(gpioc_csi, pin, dir);
105 (void)set_output_cfg(gpioc_csi, pin, cfg);
106 }
107 }
108
gpioc_csi_set_mode(aos_gpioc_t * gpioc,uint32_t pin)109 static aos_status_t gpioc_csi_set_mode(aos_gpioc_t *gpioc, uint32_t pin)
110 {
111 aos_gpioc_csi_t *gpioc_csi;
112 uint32_t mode;
113 uint32_t dir;
114 aos_status_t ret;
115
116 gpioc_csi = aos_container_of(gpioc, aos_gpioc_csi_t, gpioc);
117 mode = gpioc->pins[pin].mode;
118 dir = mode & AOS_GPIO_DIR_MASK;
119
120 if (dir == AOS_GPIO_DIR_INPUT) {
121 uint32_t cfg = mode & AOS_GPIO_INPUT_CFG_MASK;
122 uint32_t trig = mode & AOS_GPIO_IRQ_TRIG_MASK;
123
124 if (cfg == AOS_GPIO_INPUT_CFG_DEFAULT) {
125 cfg = gpioc_csi->default_input_cfg;
126 mode &= ~AOS_GPIO_INPUT_CFG_MASK;
127 mode |= cfg;
128 }
129
130 ret = set_dir(gpioc_csi, pin, dir);
131 if (ret) {
132 restore_mode(gpioc_csi, pin);
133 return ret;
134 }
135
136 ret = set_input_cfg(gpioc_csi, pin, cfg);
137 if (ret) {
138 restore_mode(gpioc_csi, pin);
139 return ret;
140 }
141
142 ret = set_irq_trig(gpioc_csi, pin, trig);
143 if (ret) {
144 restore_mode(gpioc_csi, pin);
145 return ret;
146 }
147 } else if (dir == AOS_GPIO_DIR_OUTPUT) {
148 uint32_t cfg = mode & AOS_GPIO_OUTPUT_CFG_MASK;
149 uint32_t mask = (uint32_t)1 << pin;
150 csi_gpio_pin_state_t val;
151
152 if (cfg == AOS_GPIO_OUTPUT_CFG_DEFAULT) {
153 cfg = gpioc_csi->default_output_cfg;
154 mode &= ~AOS_GPIO_OUTPUT_CFG_MASK;
155 mode |= cfg;
156 }
157
158 ret = set_dir(gpioc_csi, pin, dir);
159 if (ret) {
160 restore_mode(gpioc_csi, pin);
161 return ret;
162 }
163
164 ret = set_output_cfg(gpioc_csi, pin, cfg);
165 if (ret) {
166 restore_mode(gpioc_csi, pin);
167 return ret;
168 }
169
170 val = gpioc->pins[pin].value ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
171 csi_gpio_write(&gpioc_csi->csi_gpio, mask, val);
172 }
173
174 gpioc_csi->modes[pin] = mode;
175
176 return 0;
177 }
178
gpioc_csi_enable_irq(aos_gpioc_t * gpioc,uint32_t pin)179 static void gpioc_csi_enable_irq(aos_gpioc_t *gpioc, uint32_t pin)
180 {
181 aos_gpioc_csi_t *gpioc_csi;
182 uint32_t mask = (uint32_t)1 << pin;
183
184 gpioc_csi = aos_container_of(gpioc, aos_gpioc_csi_t, gpioc);
185 (void)csi_gpio_irq_enable(&gpioc_csi->csi_gpio, mask, true);
186 }
187
gpioc_csi_disable_irq(aos_gpioc_t * gpioc,uint32_t pin)188 static void gpioc_csi_disable_irq(aos_gpioc_t *gpioc, uint32_t pin)
189 {
190 aos_gpioc_csi_t *gpioc_csi;
191 uint32_t mask = (uint32_t)1 << pin;
192
193 gpioc_csi = aos_container_of(gpioc, aos_gpioc_csi_t, gpioc);
194 (void)csi_gpio_irq_enable(&gpioc_csi->csi_gpio, mask, false);
195 }
196
gpioc_csi_get_value(aos_gpioc_t * gpioc,uint32_t pin)197 static int gpioc_csi_get_value(aos_gpioc_t *gpioc, uint32_t pin)
198 {
199 aos_gpioc_csi_t *gpioc_csi;
200 uint32_t mask = (uint32_t)1 << pin;
201
202 gpioc_csi = aos_container_of(gpioc, aos_gpioc_csi_t, gpioc);
203
204 return !!(csi_gpio_read(&gpioc_csi->csi_gpio, mask) & mask);
205 }
206
gpioc_csi_set_value(aos_gpioc_t * gpioc,uint32_t pin)207 static void gpioc_csi_set_value(aos_gpioc_t *gpioc, uint32_t pin)
208 {
209 aos_gpioc_csi_t *gpioc_csi;
210 uint32_t mask = (uint32_t)1 << pin;
211 csi_gpio_pin_state_t val;
212
213 gpioc_csi = aos_container_of(gpioc, aos_gpioc_csi_t, gpioc);
214 val = gpioc->pins[pin].value ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
215 csi_gpio_write(&gpioc_csi->csi_gpio, mask, val);
216 }
217
218 static const aos_gpioc_ops_t gpioc_csi_ops = {
219 .unregister = gpioc_csi_unregister,
220 .set_mode = gpioc_csi_set_mode,
221 .enable_irq = gpioc_csi_enable_irq,
222 .disable_irq = gpioc_csi_disable_irq,
223 .get_value = gpioc_csi_get_value,
224 .set_value = gpioc_csi_set_value,
225 };
226
227 #define get_polarity(gpio, pin) (!!(csi_gpio_read(gpio, (uint32_t)1 << (pin)) & ((uint32_t)1 << (pin))))
228
irq_handler(csi_gpio_t * csi_gpio,uint32_t pin_mask,void * arg)229 static void irq_handler(csi_gpio_t *csi_gpio, uint32_t pin_mask, void *arg)
230 {
231 aos_gpioc_csi_t *gpioc_csi;
232 aos_gpioc_t *gpioc;
233
234 gpioc_csi = aos_container_of(csi_gpio, aos_gpioc_csi_t, csi_gpio);
235 gpioc = &gpioc_csi->gpioc;
236
237 for (uint32_t i = 0; i < gpioc->num_pins; i++) {
238 if (pin_mask & ((uint32_t)1 << i))
239 aos_gpioc_hard_irq_handler(gpioc, i, get_polarity(csi_gpio, i));
240 }
241 }
242
aos_gpioc_csi_register(aos_gpioc_csi_t * gpioc_csi)243 aos_status_t aos_gpioc_csi_register(aos_gpioc_csi_t *gpioc_csi)
244 {
245 aos_gpioc_t *gpioc;
246 csi_gpio_t *csi_gpio;
247 aos_status_t ret;
248
249 if (!gpioc_csi)
250 return -EINVAL;
251
252 gpioc = &gpioc_csi->gpioc;
253
254 if (gpioc->num_pins > AOS_GPIOC_CSI_MAX_NUM_PINS)
255 return -EINVAL;
256
257 gpioc->ops = &gpioc_csi_ops;
258
259 for (uint32_t i = 0; i < gpioc->num_pins; i++)
260 gpioc_csi->modes[i] = AOS_GPIO_DIR_NONE;
261
262 csi_gpio = &gpioc_csi->csi_gpio;
263
264 if (csi_gpio_init(csi_gpio, gpioc->dev.id) != CSI_OK)
265 return -EIO;
266
267 if (csi_gpio_attach_callback(csi_gpio, irq_handler, NULL) != CSI_OK) {
268 (void)csi_gpio_uninit(csi_gpio);
269 return -EIO;
270 }
271
272 ret = aos_gpioc_register(gpioc);
273 if (ret) {
274 (void)csi_gpio_detach_callback(csi_gpio);
275 (void)csi_gpio_uninit(csi_gpio);
276 return ret;
277 }
278
279 return 0;
280 }
281
aos_gpioc_csi_unregister(uint32_t id)282 aos_status_t aos_gpioc_csi_unregister(uint32_t id)
283 {
284 return aos_gpioc_unregister(id);
285 }
286