1 /*
2 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include "duet_cm4.h"
18 #include "duet.h"
19 #include "duet_gpio.h"
20
21 duet_gpio_cb_t g_duet_gpio_handler[DUET_GPIO_TOTAL_NUM];
22 // gpio pinmux function table
23 const uint32_t GPIO_PINMUX_FUN[DUET_GPIO_TOTAL_NUM] = {
24 0, 0, 0, 0, 1, 1, 0, 0,
25 0, 0, 2, 0, 0, 0, 4, 4,
26 0, 0, 0, 0, 0, 0, 0, 0
27 };
28
GPIO_IRQHandler(void)29 void GPIO_IRQHandler(void)
30 {
31 // duet_intrpt_enter();
32 for (int i = 0; i < DUET_GPIO_TOTAL_NUM; i++) {
33 if (i < DUET_GPIO_NUM_PER_GROUP) {
34 // gpio group0 irq
35 if (GPIO_GROUP0->INTSTATUS & (0x0001 << i)) {
36 // clear GPIO GROUP0 interrupt
37 GPIO_GROUP0->INTSTATUS = (0x0001 << i);
38 if (g_duet_gpio_handler[i].cb) {
39 g_duet_gpio_handler[i].cb(g_duet_gpio_handler[i].arg);
40 }
41 }
42 } else {
43 // gpio group1 irq
44 if (GPIO_GROUP1->INTSTATUS & (0x0001 << (i - DUET_GPIO_NUM_PER_GROUP))) {
45 // clear GPIO GROUP1 interrupt
46 GPIO_GROUP1->INTSTATUS = (0x0001 << (i - DUET_GPIO_NUM_PER_GROUP));
47 if (g_duet_gpio_handler[i].cb) {
48 g_duet_gpio_handler[i].cb(g_duet_gpio_handler[i].arg);
49 }
50 }
51 }
52 }
53 // duet_intrpt_exit();
54 }
55
56 /**
57 * Initialises a GPIO pin
58 *
59 * @note Prepares a GPIO pin for use.
60 *
61 * @param[in] gpio the gpio pin which should be initialised
62 * @param[in] configuration A structure containing the required gpio configuration
63 *
64 * @return 0 : on success, EIO : if an error occurred with any step
65 */
duet_gpio_init(duet_gpio_dev_t * gpio)66 int32_t duet_gpio_init(duet_gpio_dev_t *gpio)
67 {
68 uint32_t reg_value;
69 if (NULL == gpio) {
70 return EIO;
71 }
72 // pinmux setting
73 if (gpio->port < 8) {
74 reg_value = REG_RD(PINMUX_CTRL_REG0) & (~(0x0000000F << (4 * gpio->port)));
75 REG_WR(PINMUX_CTRL_REG0, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * gpio->port))));
76 } else if (gpio->port < 16) {
77 reg_value = REG_RD(PINMUX_CTRL_REG1) & (~(0x0000000F << (4 * (gpio->port - 8))));
78 REG_WR(PINMUX_CTRL_REG1, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * (gpio->port - 8)))));
79 } else if (gpio->port < 24) {
80 reg_value = REG_RD(PINMUX_CTRL_REG2) & (~(0x0000000F << (4 * (gpio->port - 16))));
81 REG_WR(PINMUX_CTRL_REG2, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * (gpio->port - 16)))));
82 }
83 #if (defined DUET_A0V1)
84 else if (gpio->port < 32) {
85 reg_value = REG_RD(PINMUX_CTRL_REG3) & (~(0x0000000F << (4 * (gpio->port - 24))));
86 REG_WR(PINMUX_CTRL_REG3, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * (gpio->port - 24)))));
87 }
88 #endif
89 else {
90 return EIO;
91 }
92 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
93 switch (gpio->config) {
94 case DUET_ANALOG_MODE:
95 break;
96 case DUET_IRQ_MODE:
97 case DUET_INPUT_PULL_UP:
98 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
99 GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
100 }
101 reg_value = REG_RD(HW_CTRL_PE_PS);
102 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
103 reg_value = REG_RD(PAD_PS_REG);
104 REG_WR(PAD_PS_REG, (reg_value | (1 << gpio->port)));
105 reg_value = REG_RD(PAD_PE_REG);
106 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
107 break;
108 case DUET_INPUT_PULL_DOWN:
109 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
110 GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
111 }
112 reg_value = REG_RD(HW_CTRL_PE_PS);
113 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
114 reg_value = REG_RD(PAD_PS_REG);
115 REG_WR(PAD_PS_REG, (reg_value & (~(1 << gpio->port))));
116 reg_value = REG_RD(PAD_PE_REG);
117 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
118 break;
119 case DUET_INPUT_HIGH_IMPEDANCE:
120 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
121 GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
122 }
123 break;
124 case DUET_OUTPUT_PUSH_PULL:
125 case DUET_OUTPUT_OPEN_DRAIN_NO_PULL:
126 case DUET_OUTPUT_OPEN_DRAIN_PULL_UP:
127 if (!(GPIO_GROUP0->OUTENSET & (1 << gpio->port))) {
128 GPIO_GROUP0->OUTENSET = (1 << gpio->port);
129 }
130 break;
131 default:
132 return EIO;
133 // break;
134 }
135 } else { // if(gpio->port < 32/24)
136 switch (gpio->config) {
137 case DUET_ANALOG_MODE:
138 break;
139 case DUET_IRQ_MODE:
140 break;
141 case DUET_INPUT_PULL_UP:
142 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
143 GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
144 }
145 reg_value = REG_RD(HW_CTRL_PE_PS);
146 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
147 reg_value = REG_RD(PAD_PS_REG);
148 REG_WR(PAD_PS_REG, (reg_value | (1 << gpio->port)));
149 reg_value = REG_RD(PAD_PE_REG);
150 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
151 break;
152 case DUET_INPUT_PULL_DOWN:
153 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
154 GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
155 }
156 reg_value = REG_RD(HW_CTRL_PE_PS);
157 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
158 reg_value = REG_RD(PAD_PS_REG);
159 REG_WR(PAD_PS_REG, (reg_value & (~(1 << gpio->port))));
160 reg_value = REG_RD(PAD_PE_REG);
161 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
162 break;
163 case DUET_INPUT_HIGH_IMPEDANCE:
164 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
165 GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
166 }
167 break;
168 case DUET_OUTPUT_PUSH_PULL:
169 case DUET_OUTPUT_OPEN_DRAIN_NO_PULL:
170 case DUET_OUTPUT_OPEN_DRAIN_PULL_UP:
171 if (!(GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP)))) {
172 GPIO_GROUP1->OUTENSET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
173 }
174 break;
175 default:
176 return EIO;
177 // break;
178 }
179 }
180 return 0;
181 }
182
183 /**
184 * Sets an output GPIO pin high
185 *
186 * @note Using this function on a gpio pin which is set to input mode is undefined.
187 *
188 * @param[in] gpio the gpio pin which should be set high
189 *
190 * @return 0 : on success, EIO : if an error occurred with any step
191 */
duet_gpio_output_high(duet_gpio_dev_t * gpio)192 int32_t duet_gpio_output_high(duet_gpio_dev_t *gpio)
193 {
194 if (NULL == gpio) {
195 return EIO;
196 }
197 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
198 GPIO_GROUP0->DATAOUT |= (1 << gpio->port);
199 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
200 GPIO_GROUP1->DATAOUT |= (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
201 } else {
202 return EIO;
203 }
204 return 0;
205 }
206
207 /**
208 * Sets an output GPIO pin low
209 *
210 * @note Using this function on a gpio pin which is set to input mode is undefined.
211 *
212 * @param[in] gpio the gpio pin which should be set low
213 *
214 * @return 0 : on success, EIO : if an error occurred with any step
215 */
duet_gpio_output_low(duet_gpio_dev_t * gpio)216 int32_t duet_gpio_output_low(duet_gpio_dev_t *gpio)
217 {
218 if (NULL == gpio) {
219 return EIO;
220 }
221 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
222 GPIO_GROUP0->DATAOUT &= ~(1 << gpio->port);
223 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
224 GPIO_GROUP1->DATAOUT &= ~(1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
225 } else {
226 return EIO;
227 }
228 return 0;
229 }
230
231 /**
232 * Get the state of an output GPIO pin. Using this function on a
233 * gpio pin which is set to input mode will return an undefined value.
234 *
235 * @param[in] gpio the gpio pin which should be read
236 * @param[in] value gpio value
237 *
238 * @return 0 : on success, EIO : if an error occurred with any step
239 *
240 * note: defined by asr
241 */
duet_gpio_output_get(duet_gpio_dev_t * gpio,uint32_t * value)242 int32_t duet_gpio_output_get(duet_gpio_dev_t *gpio, uint32_t *value)
243 {
244 if (NULL == gpio) {
245 return EIO;
246 }
247 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
248 *value = (GPIO_GROUP0->DATAOUT >> (gpio->port)) & 1;
249 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
250 *value = (GPIO_GROUP1->DATAOUT >> ((gpio->port - DUET_GPIO_NUM_PER_GROUP))) & 1;
251 } else {
252 return EIO;
253 }
254 return 0;
255 }
256
257 /**
258 * Trigger an output GPIO pin's output. Using this function on a
259 * gpio pin which is set to input mode is undefined.
260 *
261 * @param[in] gpio the gpio pin which should be set low
262 *
263 * @return 0 : on success, EIO : if an error occurred with any step
264 */
duet_gpio_output_toggle(duet_gpio_dev_t * gpio)265 int32_t duet_gpio_output_toggle(duet_gpio_dev_t *gpio)
266 {
267 uint32_t value;
268 if (NULL == gpio) {
269 return EIO;
270 }
271 if (0 == duet_gpio_output_get(gpio, &value)) {
272 if (value) {
273 return duet_gpio_output_low(gpio);
274 } else {
275 return duet_gpio_output_high(gpio);
276 }
277 } else {
278 return EIO;
279 }
280 }
281
282 /**
283 * Get the state of an input GPIO pin. Using this function on a
284 * gpio pin which is set to output mode will return an undefined value.
285 *
286 * @param[in] gpio the gpio pin which should be read
287 * @param[in] value gpio value
288 *
289 * @return 0 : on success, EIO : if an error occurred with any step
290 */
duet_gpio_input_get(duet_gpio_dev_t * gpio,uint32_t * value)291 int32_t duet_gpio_input_get(duet_gpio_dev_t *gpio, uint32_t *value)
292 {
293 if (NULL == gpio) {
294 return EIO;
295 }
296 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
297 *value = (GPIO_GROUP0->DATA >> gpio->port) & 1;
298 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
299 *value = (GPIO_GROUP1->DATA >> (gpio->port - DUET_GPIO_NUM_PER_GROUP)) & 1;
300 } else {
301 return EIO;
302 }
303 return 0;
304 }
305
306 /**
307 * Enables an interrupt trigger for an input GPIO pin.
308 * Using this function on a gpio pin which is set to
309 * output mode is undefined.
310 *
311 * @param[in] gpio the gpio pin which will provide the interrupt trigger
312 * @param[in] trigger the type of trigger (rising/falling edge)
313 * @param[in] handler a function pointer to the interrupt handler
314 * @param[in] arg an argument that will be passed to the interrupt handler
315 *
316 * @return 0 : on success, EIO : if an error occurred with any step
317 */
duet_gpio_enable_irq(duet_gpio_dev_t * gpio,duet_gpio_irq_trigger_t trigger,duet_gpio_irq_handler_t handler,void * arg)318 int32_t duet_gpio_enable_irq(duet_gpio_dev_t *gpio, duet_gpio_irq_trigger_t trigger,
319 duet_gpio_irq_handler_t handler, void *arg)
320 {
321 if (NULL == gpio) {
322 return EIO;
323 }
324 g_duet_gpio_handler[gpio->port].cb = handler;
325 g_duet_gpio_handler[gpio->port].arg = arg;
326 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
327 switch (trigger) {
328 case DUET_IRQ_TRIGGER_RISING_EDGE:
329 GPIO_GROUP0->INTTYPESET = (1 << gpio->port); // edge or level trig
330 GPIO_GROUP0->INTPOLSET = (1 << gpio->port); // trig polarity
331 break;
332 case DUET_IRQ_TRIGGER_FALLING_EDGE:
333 GPIO_GROUP0->INTTYPESET = (1 << gpio->port);
334 GPIO_GROUP0->INTPOLCLR = (1 << gpio->port);
335 break;
336 case DUET_IRQ_TRIGGER_BOTH_EDGES:
337 default:
338 return EIO;
339 }
340 GPIO_GROUP0->INTENSET = (1 << gpio->port); // int enable
341 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
342 switch (trigger) {
343 case DUET_IRQ_TRIGGER_RISING_EDGE:
344 GPIO_GROUP1->INTTYPESET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
345 GPIO_GROUP1->INTPOLSET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
346 break;
347 case DUET_IRQ_TRIGGER_FALLING_EDGE:
348 GPIO_GROUP1->INTTYPESET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
349 GPIO_GROUP1->INTPOLCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
350 break;
351 case DUET_IRQ_TRIGGER_BOTH_EDGES:
352 default:
353 return EIO;
354 }
355 GPIO_GROUP1->INTENSET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
356 } else {
357 return EIO;
358 }
359 NVIC_EnableIRQ(GPIO_IRQn); // 0x10
360 return 0;
361 }
362
363 /**
364 * Disables an interrupt trigger for an input GPIO pin.
365 * Using this function on a gpio pin which has not been set up
366 * using @ref duet_gpio_input_irq_enable is undefined.
367 *
368 * @param[in] gpio the gpio pin which provided the interrupt trigger
369 *
370 * @return 0 : on success, EIO : if an error occurred with any step
371 */
duet_gpio_disable_irq(duet_gpio_dev_t * gpio)372 int32_t duet_gpio_disable_irq(duet_gpio_dev_t *gpio)
373 {
374 if (NULL == gpio) {
375 return EIO;
376 }
377 g_duet_gpio_handler[gpio->port].cb = NULL;
378 g_duet_gpio_handler[gpio->port].arg = NULL;
379 // NVIC_DisableIRQ(GPIO_IRQn); // common use
380 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
381 GPIO_GROUP0->INTENCLR = (1 << gpio->port);
382 GPIO_GROUP0->INTTYPECLR = (1 << gpio->port);
383 GPIO_GROUP0->INTPOLCLR = (1 << gpio->port);
384 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
385 GPIO_GROUP1->INTTYPECLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
386 GPIO_GROUP1->INTPOLCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
387 GPIO_GROUP1->INTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
388 } else {
389 return EIO;
390 }
391 return 0;
392 }
393
394 /**
395 * Disables an interrupt trigger for an input GPIO pin.
396 * Using this function on a gpio pin which has not been set up
397 * using @ref duet_gpio_input_irq_enable is undefined.
398 *
399 * @param[in] gpio the gpio pin which provided the interrupt trigger
400 *
401 * @return 0 : on success, EIO : if an error occurred with any step
402 */
duet_gpio_clear_irq(duet_gpio_dev_t * gpio)403 int32_t duet_gpio_clear_irq(duet_gpio_dev_t *gpio)
404 {
405 if (NULL == gpio) {
406 return EIO;
407 }
408
409 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
410 // GPIO interrupt status
411 if (GPIO_GROUP0->INTSTATUS & (1 << gpio->port)) {
412 // clear GPIO interrupt status
413 GPIO_GROUP0->INTSTATUS = (1 << gpio->port);
414 }
415 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
416 if (GPIO_GROUP1->INTSTATUS & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
417 GPIO_GROUP1->INTSTATUS = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
418 }
419 } else {
420 return EIO;
421 }
422
423 return 0;
424 }
425
426 /**
427 * Set a GPIO pin in default state.
428 *
429 * @param[in] gpio the gpio pin which should be deinitialised
430 *
431 * @return 0 : on success, EIO : if an error occurred with any step
432 */
duet_gpio_finalize(duet_gpio_dev_t * gpio)433 int32_t duet_gpio_finalize(duet_gpio_dev_t *gpio)
434 {
435 if (NULL == gpio) {
436 return EIO;
437 }
438 if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
439 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
440 GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
441 }
442 } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
443 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
444 GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
445 }
446 } else {
447 return EIO;
448 }
449 duet_gpio_disable_irq(gpio);
450 duet_gpio_clear_irq(gpio);
451 return 0;
452 }
453