1 /*
2  * Copyright (C) 2017-2019 Alibaba Group Holding Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-08-20     zx.chen      gpio driver
9  */
10 
11 /******************************************************************************
12  * @file     dw_gpio.c
13  * @brief    CSI Source File for GPIO Driver
14  * @version  V1.0
15  * @date     02. June 2017
16  ******************************************************************************/
17 
18 #include <csi_config.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <drv_irq.h>
22 #include <drv_gpio.h>
23 #include <dw_gpio.h>
24 #include <csi_core.h>
25 #include <pin_name.h>
26 
27 extern int32_t drv_pin_config_mode(port_name_e port, uint8_t offset, gpio_mode_e pin_mode);
28 
29 #define ERR_GPIO(errno) (CSI_DRV_ERRNO_GPIO_BASE | errno)
30 #define GPIO_NULL_PARAM_CHK(para)    HANDLE_PARAM_CHK(para, ERR_GPIO(DRV_ERROR_PARAMETER))
31 
32 typedef void *gpio_port_handle_t;
33 
34 typedef struct
35 {
36 #ifdef CONFIG_LPM
37     uint8_t gpio_power_status;
38     uint32_t gpio_regs_saved[7];
39 #endif
40     uint32_t base;              ///< handle register base
41     uint32_t irq;               ///< irq of this handle
42     uint32_t pin_num;           ///< pin number of this handle
43     gpio_mode_e mode;           ///< gpio mode
44     gpio_direction_e dir;       ///< gpio direction
45     uint32_t mask;              ///< gpio mask bit
46     uint32_t value;             ///< gpio value
47 } dw_gpio_priv_t;
48 
49 typedef struct
50 {
51     uint8_t     portidx;
52     uint8_t     idx;
53     uint8_t     offset;
54     gpio_event_cb_t cb;
55 } dw_gpio_pin_priv_t;
56 
57 extern int32_t target_gpio_port_init(port_name_e port, uint32_t *base, uint32_t *irq, void **handler, uint32_t *pin_num);
58 extern int32_t target_gpio_pin_init(int32_t gpio_pin, uint32_t *port_idx);
59 
60 static dw_gpio_priv_t gpio_handle[CONFIG_GPIO_NUM];
61 static dw_gpio_pin_priv_t gpio_pin_handle[CONFIG_GPIO_PIN_NUM];
62 
63 //
64 // Functions
65 //
gpio_set_direction(void * port,gpio_direction_e direction)66 static int32_t gpio_set_direction(
67     void *port,
68     gpio_direction_e direction
69 )
70 {
71     dw_gpio_priv_t *gpio_priv = port;
72     dw_gpio_reg_t *gpio_reg = (dw_gpio_reg_t *)(gpio_priv->base);
73 
74     if (direction == GPIO_DIRECTION_INPUT)
75     {
76         gpio_reg->SWPORT_DDR &= (~gpio_priv->mask);
77     } else if (direction == GPIO_DIRECTION_OUTPUT)
78     {
79         gpio_reg->SWPORT_DDR |= gpio_priv->mask;
80     } else
81     {
82         return ERR_GPIO(GPIO_ERROR_DIRECTION);
83     }
84 
85     return 0;
86 }
87 
88 /*
89  * Read the statu of the Port choosed.
90  * Parameters:
91  *   port:  use to choose a I/O port among Port A, B, or C.
92  * return: the value of the corresponding Port.
93  */
94 
gpio_read(void * port,uint32_t * value)95 static int32_t gpio_read(void *port, uint32_t *value)
96 {
97     dw_gpio_priv_t *gpio_priv = port;
98     dw_gpio_control_reg_t *gpio_control_reg = (dw_gpio_control_reg_t *)(gpio_priv->base + 0x30);
99     *value = gpio_control_reg->EXT_PORTA;
100     return 0;
101 }
102 
103 
104 /*
105  * Write an output value to corresponding Port.
106  * Parameters:
107  *   port:  use to choose a I/O port among Port A, B, or C.
108  *   output: value that will be written to the corresponding Port.
109  * return: SUCCESS
110  */
111 
gpio_write(void * port,uint32_t mask)112 static int32_t gpio_write(void *port, uint32_t mask)
113 {
114     dw_gpio_priv_t *gpio_priv = port;
115     dw_gpio_reg_t *gpio_reg = (dw_gpio_reg_t *)(gpio_priv->base);
116 
117     uint32_t value = gpio_reg->SWPORT_DR;
118 
119     value &= ~(mask);
120     value |= gpio_priv->value;
121     gpio_reg->SWPORT_DR = value;
122     return 0;
123 }
124 
125 /**
126  * Configure a GPIO gpio_set_irq_mode.
127  * @param[in]   pin         the addr store the pin num.
128  * @param[in]   _irqmode    the irqmode of gpio
129  * @return      zero on success. -1 on falure.
130  */
gpio_set_irq_mode(gpio_pin_handle_t pin,gpio_irq_mode_e irq_mode)131 static int32_t gpio_set_irq_mode(gpio_pin_handle_t pin, gpio_irq_mode_e irq_mode)
132 {
133     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
134 
135     /* convert portidx to port handle */
136     dw_gpio_priv_t *port_handle = &gpio_handle[gpio_pin_priv->portidx];
137 
138     dw_gpio_control_reg_t *gpio_control_reg = (dw_gpio_control_reg_t *)(port_handle->base + 0x30);
139     uint32_t offset = gpio_pin_priv->idx;
140     uint32_t mask = 1 << offset;
141 
142     switch (irq_mode)
143     {
144         /* rising edge interrupt mode */
145         case GPIO_IRQ_MODE_RISING_EDGE:
146             gpio_control_reg->INTTYPE_LEVEL |= mask;
147             gpio_control_reg->INT_POLARITY |= mask;
148             break;
149 
150         /* falling edge interrupt mode */
151         case GPIO_IRQ_MODE_FALLING_EDGE:
152             gpio_control_reg->INTTYPE_LEVEL |= mask;
153             gpio_control_reg->INT_POLARITY &= (~mask);
154             break;
155 
156         /* low level interrupt mode */
157         case GPIO_IRQ_MODE_LOW_LEVEL:
158             gpio_control_reg->INTTYPE_LEVEL &= (~mask);
159             gpio_control_reg->INT_POLARITY &= (~mask);
160             break;
161 
162         /* high level interrupt mode */
163         case GPIO_IRQ_MODE_HIGH_LEVEL:
164             gpio_control_reg->INTTYPE_LEVEL &= (~mask);
165             gpio_control_reg->INT_POLARITY |= mask;
166             break;
167 
168         /* double edge interrupt mode */
169         case GPIO_IRQ_MODE_DOUBLE_EDGE:
170             return ERR_GPIO(DRV_ERROR_UNSUPPORTED);
171 
172         default:
173             return ERR_GPIO(GPIO_ERROR_IRQ_MODE);
174     }
175 
176     return 0;
177 }
178 
179 /*
180  * Clear one or more interrupts of PortA.
181  * Parameters:
182  *   pinno:
183  * return: SUCCESS.
184  */
185 
gpio_irq_clear(gpio_pin_handle_t pin,uint32_t idx)186 static void gpio_irq_clear(gpio_pin_handle_t pin, uint32_t idx)
187 {
188     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
189 
190     /* convert portidx to port handle */
191     dw_gpio_priv_t *port_handle = &gpio_handle[gpio_pin_priv->portidx];
192 
193     dw_gpio_control_reg_t *gpio_control_reg = (dw_gpio_control_reg_t *)(port_handle->base + 0x30);
194 
195     gpio_control_reg->PORTA_EOI = idx;
196 }
197 
198 
199 /*
200  * Enable one or more interrupts of PortA.
201  * Parameters:
202  *   pinno:
203  * return: SUCCESS.
204  */
gpio_irq_enable(gpio_pin_handle_t pin)205 static void gpio_irq_enable(gpio_pin_handle_t pin)
206 {
207     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
208 
209     /* convert portidx to port handle */
210     dw_gpio_priv_t *port_handle = &gpio_handle[gpio_pin_priv->portidx];
211 
212     dw_gpio_control_reg_t *gpio_control_reg = (dw_gpio_control_reg_t *)(port_handle->base + 0x30);
213     uint32_t offset = gpio_pin_priv->idx;
214     uint32_t val = gpio_control_reg->INTEN;
215     val |= (1 << offset);
216     gpio_control_reg->INTEN = val;
217 }
218 
219 
220 /*
221  * Disable one or more interrupts of PortA.
222  * Parameters:
223  *   pinno:
224  * return: SUCCESS.
225  */
226 
gpio_irq_disable(gpio_pin_handle_t pin)227 static void gpio_irq_disable(gpio_pin_handle_t pin)
228 {
229     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
230     uint32_t offset = gpio_pin_priv->idx;
231 
232     /* convert portidx to port handle */
233     dw_gpio_priv_t *port_handle = &gpio_handle[gpio_pin_priv->portidx];
234 
235     dw_gpio_control_reg_t *gpio_control_reg = (dw_gpio_control_reg_t *)(port_handle->base + 0x30);
236     uint32_t val = gpio_control_reg->INTEN;
237     val &= ~(1 << offset);
238     gpio_control_reg->INTEN = val;
239 }
240 
dw_gpio_irqhandler(int idx)241 void dw_gpio_irqhandler(int idx)
242 {
243     if (idx >= CONFIG_GPIO_NUM)
244     {
245         return;
246     }
247 
248     dw_gpio_control_reg_t *gpio_control_reg = (dw_gpio_control_reg_t *)(gpio_handle[idx].base + 0x30);
249 
250     uint32_t value = gpio_control_reg->INTSTATUS;
251     uint8_t i;
252 
253     /* find the interrput pin */
254     for (i = 0; i < 32; i++)
255     {
256         if (value & (1U << i))
257         {
258             uint32_t pin_idx = i;
259 
260 #ifndef CONFIG_CHIP_DANICA
261             uint8_t j;
262 
263             if (idx > 0)
264             {
265                 for (j = 0; j < idx; j++)
266                 {
267                     pin_idx += gpio_handle[j].pin_num;
268                 }
269             }
270 
271             if (pin_idx >= CONFIG_GPIO_PIN_NUM)
272             {
273                 return;
274             }
275 
276 #endif
277             dw_gpio_pin_priv_t *gpio_pin_priv = (dw_gpio_pin_priv_t *)&gpio_pin_handle[pin_idx];
278 
279             gpio_irq_clear(gpio_pin_priv, (1 << i));  //clear the gpio interrupt
280 
281             /* execute the callback function */
282             if ((gpio_event_cb_t)(gpio_pin_priv->cb))
283             {
284                 ((gpio_event_cb_t)(gpio_pin_priv->cb))(gpio_pin_priv->offset);
285             }
286         }
287     }
288 }
289 
290 /**
291   \brief       Initialize GPIO module. 1. Initializes the resources needed for the GPIO handle 2.registers event callback function
292                 3.get gpio_port_handle
293   \param[in]   port      port_name.
294   \return      gpio_port_handle
295 */
csi_gpio_port_initialize(int32_t port)296 gpio_port_handle_t csi_gpio_port_initialize(int32_t port)
297 {
298     dw_gpio_priv_t *gpio_priv = NULL;
299 
300     /* obtain the gpio port information */
301     uint32_t base = 0u;
302     uint32_t pin_num;
303     uint32_t irq;
304     void *handler;
305     int32_t idx = target_gpio_port_init(port, &base, &irq, &handler, &pin_num);
306 
307     if (idx < 0 || idx >= CONFIG_GPIO_NUM)
308     {
309         return NULL;
310     }
311 
312     gpio_priv = &gpio_handle[idx];
313 
314     gpio_priv->base = base;
315     gpio_priv->irq  = irq;
316     gpio_priv->pin_num  = pin_num;
317 
318 #ifdef CONFIG_LPM
319     csi_gpio_power_control(gpio_priv, DRV_POWER_FULL);
320 #endif
321 
322     drv_irq_register(gpio_priv->irq, handler);
323     drv_irq_enable(gpio_priv->irq);
324 
325     return (gpio_port_handle_t)gpio_priv;
326 }
327 
328 /**
329   \brief       De-initialize GPIO handle. stops operation and releases the software resources used by the handle
330   \param[in]   handle   gpio port handle to operate.
331   \return      error code
332 */
csi_gpio_port_uninitialize(gpio_port_handle_t handle)333 int32_t csi_gpio_port_uninitialize(gpio_port_handle_t handle)
334 {
335     GPIO_NULL_PARAM_CHK(handle);
336 
337     dw_gpio_priv_t *gpio_priv = handle;
338 
339     drv_irq_disable(gpio_priv->irq);
340     drv_irq_unregister(gpio_priv->irq);
341 
342 #ifdef CONFIG_LPM
343     csi_gpio_power_control(gpio_priv, DRV_POWER_OFF);
344 #endif
345 
346     return 0;
347 }
348 
349 #ifdef CONFIG_LPM
manage_clock(gpio_pin_handle_t handle,uint8_t enable)350 static void manage_clock(gpio_pin_handle_t handle, uint8_t enable)
351 {
352     dw_gpio_pin_priv_t *gpio_pin_priv = (dw_gpio_pin_priv_t *)handle;
353     uint8_t device[] = {CLOCK_MANAGER_GPIO0, CLOCK_MANAGER_GPIO1};
354 
355     drv_clock_manager_config(device[gpio_pin_priv->portidx], enable);
356 }
357 
do_prepare_sleep_action(void * handle)358 static void do_prepare_sleep_action(void *handle)
359 {
360     dw_gpio_priv_t *gpio_handle = handle;
361     uint32_t *gbase = (uint32_t *)(gpio_handle->base);
362     uint32_t *control_base = (uint32_t *)(gpio_handle->base + 0x30);
363     registers_save(gpio_handle->gpio_regs_saved, gbase, 3);
364     registers_save(&gpio_handle->gpio_regs_saved[3], control_base, 4);
365 }
366 
do_wakeup_sleep_action(void * handle)367 static void do_wakeup_sleep_action(void *handle)
368 {
369     dw_gpio_priv_t *gpio_handle = handle;
370     uint32_t *gbase = (uint32_t *)(gpio_handle->base);
371     uint32_t *control_base = (uint32_t *)(gpio_handle->base + 0x30);
372     registers_restore(gbase, gpio_handle->gpio_regs_saved, 3);
373     registers_restore(control_base, &gpio_handle->gpio_regs_saved[3], 4);
374 }
375 #endif
376 
377 /**
378   \brief       Initialize GPIO handle.
379   \param[in]   gpio_pin    Pointer to the int32_t.
380   \param[in]   cb_event    Pointer to \ref gpio_event_cb_t.
381   \param[in]   arg    Pointer to \ref arg used for the callback.
382   \return      gpio_pin_handle
383 */
csi_gpio_pin_initialize(int32_t gpio_pin,gpio_event_cb_t cb_event)384 gpio_pin_handle_t csi_gpio_pin_initialize(int32_t gpio_pin, gpio_event_cb_t cb_event)
385 {
386 
387     if (gpio_pin < 0 || gpio_pin >= CONFIG_GPIO_PIN_NUM)
388     {
389         return NULL;
390     }
391 
392     uint32_t i;
393 
394     for (i = 0; i < CONFIG_GPIO_NUM; i++)
395     {
396         csi_gpio_port_initialize(i);
397     }
398 
399     /* obtain the gpio pin information */
400     uint32_t port_idx;
401     int32_t pin_idx = target_gpio_pin_init(gpio_pin, &port_idx);
402 
403     if (pin_idx < 0)
404     {
405         return NULL;
406     }
407 
408     int32_t idx = pin_idx;
409 
410     for (i = 0; i < port_idx; i++)
411     {
412         idx += (gpio_handle[i].pin_num);
413     }
414 
415     dw_gpio_pin_priv_t *gpio_pin_priv = &(gpio_pin_handle[idx]);
416     gpio_pin_priv->portidx = port_idx;
417 
418 
419     gpio_pin_priv->idx = pin_idx;
420     gpio_pin_priv->cb = cb_event;
421     gpio_pin_priv->offset = gpio_pin;
422 
423     return (gpio_pin_handle_t)gpio_pin_priv;
424 }
425 
426 /**
427   \brief       De-initialize GPIO pin handle. stops operation and releases the software resources used by the handle
428   \param[in]   handle   gpio pin handle to operate.
429   \return      error code
430 */
csi_gpio_pin_uninitialize(gpio_pin_handle_t handle)431 int32_t csi_gpio_pin_uninitialize(gpio_pin_handle_t handle)
432 {
433     if (handle == NULL)
434     {
435         return ERR_GPIO(DRV_ERROR_PARAMETER);
436     }
437 
438     dw_gpio_pin_priv_t *gpio_pin_priv = (dw_gpio_pin_priv_t *)handle;
439     gpio_pin_priv->cb = NULL;
440 
441     gpio_irq_disable(handle);
442 
443     return 0;
444 }
445 
446 /**
447   \brief       control gpio power.
448   \param[in]   idx  gpio index.
449   \param[in]   state   power state.\ref csi_power_stat_e.
450   \return      error code
451 */
csi_gpio_power_control(gpio_pin_handle_t handle,csi_power_stat_e state)452 int32_t csi_gpio_power_control(gpio_pin_handle_t handle, csi_power_stat_e state)
453 {
454     GPIO_NULL_PARAM_CHK(handle);
455 
456 #ifdef CONFIG_LPM
457     dw_gpio_pin_priv_t *gpio_pin_priv = (dw_gpio_pin_priv_t *)handle;
458     power_cb_t callback =
459     {
460         .wakeup = do_wakeup_sleep_action,
461         .sleep = do_prepare_sleep_action,
462         .manage_clock = manage_clock
463     };
464     return drv_soc_power_control(&gpio_handle[gpio_pin_priv->portidx], state, &callback);
465 #else
466     return ERR_GPIO(DRV_ERROR_UNSUPPORTED);
467 #endif
468 }
469 
470 /**
471   \brief       config pin mode
472   \param[in]   pin       gpio pin handle to operate.
473   \param[in]   mode      \ref gpio_mode_e
474   \return      error code
475 */
csi_gpio_pin_config_mode(gpio_pin_handle_t handle,gpio_mode_e mode)476 int32_t csi_gpio_pin_config_mode(gpio_pin_handle_t handle,
477                                  gpio_mode_e mode)
478 {
479     GPIO_NULL_PARAM_CHK(handle);
480 
481     /* config the gpio pin mode direction mask bits */
482     dw_gpio_pin_priv_t *gpio_pin_priv = handle;
483 
484     uint8_t offset = gpio_pin_priv->idx;
485 
486     int32_t ret = drv_pin_config_mode(gpio_pin_priv->portidx, offset, mode);
487 
488     return ret;
489 }
490 /**
491   \brief       config pin direction
492   \param[in]   pin       gpio pin handle to operate.
493   \param[in]   dir       \ref gpio_direction_e
494   \return      error code
495 */
csi_gpio_pin_config_direction(gpio_pin_handle_t handle,gpio_direction_e dir)496 int32_t csi_gpio_pin_config_direction(gpio_pin_handle_t handle,
497                                       gpio_direction_e dir)
498 {
499     GPIO_NULL_PARAM_CHK(handle);
500 
501     /* config the gpio pin mode direction mask bits */
502     dw_gpio_pin_priv_t *gpio_pin_priv = handle;
503 
504     /* convert portidx to port handle */
505     dw_gpio_priv_t *gpio_priv = &gpio_handle[gpio_pin_priv->portidx];
506 
507     gpio_priv->dir = dir;
508     gpio_priv->mask = 1 << gpio_pin_priv->idx;
509 
510     uint32_t ret = gpio_set_direction(gpio_priv, dir);
511 
512     if (ret)
513     {
514         return ret;
515     }
516 
517     return 0;
518 }
519 
520 /**
521   \brief       config pin
522   \param[in]   handle       gpio pin handle to operate.
523   \param[in]   mode      \ref gpio_mode_e
524   \param[in]   dir       \ref gpio_direction_e
525   \return      error code
526 */
csi_gpio_pin_config(gpio_pin_handle_t handle,gpio_mode_e mode,gpio_direction_e dir)527 int32_t csi_gpio_pin_config(gpio_pin_handle_t handle,
528                             gpio_mode_e mode,
529                             gpio_direction_e dir)
530 {
531     GPIO_NULL_PARAM_CHK(handle);
532 
533     /* config the gpio pin mode direction mask bits */
534     dw_gpio_pin_priv_t *gpio_pin_priv = handle;
535 
536     /* convert portidx to port handle */
537     dw_gpio_priv_t *gpio_priv = &gpio_handle[gpio_pin_priv->portidx];
538 
539     gpio_priv->mode = mode;
540     gpio_priv->dir = dir;
541     gpio_priv->mask = 1 << gpio_pin_priv->idx;
542 
543     uint32_t ret = gpio_set_direction(gpio_priv, dir);
544 
545     if (ret)
546     {
547         return ret;
548     }
549 
550     return 0;
551 
552 }
553 
554 /**
555   \brief       Set one or zero to the selected GPIO pin.
556   \param[in]   handle       gpio pin handle to operate.
557   \param[in]   value     the value to be set
558   \return      error code
559 */
csi_gpio_pin_write(gpio_pin_handle_t handle,bool value)560 int32_t csi_gpio_pin_write(gpio_pin_handle_t handle, bool value)
561 {
562     GPIO_NULL_PARAM_CHK(handle);
563 
564     dw_gpio_pin_priv_t *gpio_pin_priv = handle;
565 
566     /* convert portidx to port handle */
567     dw_gpio_priv_t *port_handle = &gpio_handle[gpio_pin_priv->portidx];
568 
569     uint8_t offset = gpio_pin_priv->idx;
570     uint32_t port_value = value << offset;
571 
572     port_handle->value = port_value;
573     gpio_write(port_handle, (1 << offset));
574 
575     return 0;
576 
577 }
578 
579 /**
580   \brief       Get the value of  selected GPIO pin.
581   \param[in]   handle       gpio pin handle to operate.
582   \param[out]  value     buf to store the pin value
583   \return      error code
584 */
csi_gpio_pin_read(gpio_pin_handle_t handle,bool * value)585 int32_t csi_gpio_pin_read(gpio_pin_handle_t handle, bool *value)
586 {
587     GPIO_NULL_PARAM_CHK(handle);
588     GPIO_NULL_PARAM_CHK(value);
589 
590     dw_gpio_pin_priv_t *gpio_pin_priv = handle;
591     uint32_t port_value;
592     uint8_t offset = gpio_pin_priv->idx;
593 
594     /* convert portidx to port handle */
595     dw_gpio_priv_t *port_handle = &gpio_handle[gpio_pin_priv->portidx];
596 
597     gpio_read(port_handle, &port_value);
598     *value = (port_value & (1 << offset)) >> offset;
599 
600     return 0;
601 }
602 
603 /**
604   \brief       set GPIO interrupt mode.
605   \param[in]   handle       gpio pin handle to operate.
606   \param[in]   mode      the irq mode to be set
607   \param[in]   enable    the enable flag
608   \return      error code
609 */
csi_gpio_pin_set_irq(gpio_pin_handle_t handle,gpio_irq_mode_e mode,bool enable)610 int32_t csi_gpio_pin_set_irq(gpio_pin_handle_t handle, gpio_irq_mode_e mode, bool enable)
611 {
612     GPIO_NULL_PARAM_CHK(handle);
613 
614     uint32_t ret = 0;
615 
616     if (enable)
617     {
618         ret = gpio_set_irq_mode(handle, mode);
619 
620         if (ret)
621         {
622             return ret;
623         }
624 
625         gpio_irq_enable(handle);
626 
627     } else
628     {
629         gpio_irq_disable(handle);
630 
631     }
632 
633     return ret;
634 }
635 
636