1 /*
2  * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /******************************************************************************
17  * @file     dw_gpio.c
18  * @brief    CSI Source File for GPIO Driver
19  * @version  V1.0
20  * @date     02. June 2017
21  ******************************************************************************/
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include "csi_core.h"
25 #include "drv_gpio.h"
26 #include "dw_gpio.h"
27 
28 
29 #define ERR_GPIO(errno) (CSI_DRV_ERRNO_GPIO_BASE | errno)
30 #define GPIO_NULL_PARAM_CHK(para)                         \
31         do {                                        \
32             if (para == NULL) {                     \
33                 return ERR_GPIO(EDRV_PARAMETER);   \
34             }                                       \
35         } while (0)
36 
37 typedef struct {
38     uint32_t base;              ///< handle register base
39     uint32_t irq;               ///< irq of this handle
40     uint32_t pin_num;           ///< pin number of this handle
41     uint32_t cb;                ///< callback function
42     gpio_mode_e mode;           ///< gpio mode
43     gpio_direction_e dir;       ///< gpio direction
44     uint32_t mask;              ///< gpio mask bit
45     uint32_t value;             ///< gpio value
46 } dw_gpio_priv_t;
47 
48 typedef struct {
49     gpio_port_handle_t handle;
50     uint8_t     idx;
51     pin_t pin_name;
52 } dw_gpio_pin_priv_t;
53 
54 static dw_gpio_priv_t gpio_handle[CONFIG_GPIO_NUM];
55 static dw_gpio_pin_priv_t gpio_pin_handle[CONFIG_GPIO_PIN_NUM];
56 
57 /* Driver Capabilities */
58 static const gpio_capabilities_t driver_capabilities = {
59     .interrupt_mode = 1, /* intrrupt mode */
60     .pull_mode = 1  /* pull mode */
61 };
62 //
63 // Functions
64 //
65 
66 static dw_gpio_reg_t *gpio_reg = NULL;
67 static dw_gpio_control_reg_t *gpio_control_reg = NULL;
68 
69 
gpio_set_direction(void * port,gpio_direction_e direction)70 static int32_t gpio_set_direction(
71     void *port,
72     gpio_direction_e direction
73 )
74 {
75     dw_gpio_priv_t *gpio_priv = port;
76 
77     if (direction == GPIO_DIRECTION_INPUT) {
78         gpio_reg->SWPORT_DDR &= (~gpio_priv->mask);
79     } else if (direction == GPIO_DIRECTION_OUTPUT) {
80         gpio_reg->SWPORT_DDR |= gpio_priv->mask;
81     } else {
82         return ERR_GPIO(EDRV_PARAMETER);
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(uint32_t * value)95 int32_t gpio_read(uint32_t *value)
96 {
97     *value = gpio_control_reg->EXT_PORTA;
98     return 0;
99 }
100 
101 
102 /*
103  * Write an output value to corresponding Port.
104  * Parameters:
105  *   port:  use to choose a I/O port among Port A, B, or C.
106  *   output: value that will be written to the corresponding Port.
107  * return: SUCCESS
108  */
109 
gpio_write(void * port,uint32_t mask)110 static int32_t gpio_write(void *port, uint32_t mask)
111 {
112     dw_gpio_priv_t *gpio_priv = port;
113     uint32_t value = gpio_reg->SWPORT_DR;
114 
115     value &= ~(mask);
116     value |= gpio_priv->value;
117     gpio_reg->SWPORT_DR = value;
118     return 0;
119 }
120 
121 /**
122  * Configure a GPIO gpio_set_irq_mode.
123  * @param[in]   pin         the addr store the pin num.
124  * @param[in]   _irqmode    the irqmode of gpio
125  * @return      zero on success. -1 on falure.
126  */
gpio_set_irq_mode(gpio_pin_handle_t pin,gpio_irq_mode_e irq_mode)127 static int32_t gpio_set_irq_mode(gpio_pin_handle_t pin, gpio_irq_mode_e irq_mode)
128 {
129     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
130     uint32_t offset = gpio_pin_priv->idx;
131     uint32_t mask = 1 << offset;
132 
133     switch (irq_mode) {
134         /* rising edge interrupt mode */
135         case GPIO_IRQ_MODE_RISING_EDGE:
136             gpio_control_reg->INTTYPE_LEVEL |= mask;
137             gpio_control_reg->INT_POLARITY |= mask;
138             break;
139 
140         /* falling edge interrupt mode */
141         case GPIO_IRQ_MODE_FALLING_EDGE:
142             gpio_control_reg->INTTYPE_LEVEL |= mask;
143             gpio_control_reg->INT_POLARITY &= (~mask);
144             break;
145 
146         /* low level interrupt mode */
147         case GPIO_IRQ_MODE_LOW_LEVEL:
148             gpio_control_reg->INTTYPE_LEVEL &= (~mask);
149             gpio_control_reg->INT_POLARITY &= (~mask);
150             break;
151 
152         /* high level interrupt mode */
153         case GPIO_IRQ_MODE_HIGH_LEVEL:
154             gpio_control_reg->INTTYPE_LEVEL &= (~mask);
155             gpio_control_reg->INT_POLARITY |= mask;
156             break;
157 
158         /* double edge interrupt mode */
159         case GPIO_IRQ_MODE_DOUBLE_EDGE:
160             return ERR_GPIO(EDRV_UNSUPPORTED);
161 
162         default:
163             return ERR_GPIO(EDRV_PARAMETER);
164     }
165 
166     return 0;
167 }
168 
169 /*
170  * Clear one or more interrupts of PortA.
171  * Parameters:
172  *   pinno:
173  * return: SUCCESS.
174  */
175 
gpio_irq_clear(uint32_t idx)176 static void gpio_irq_clear(uint32_t idx)
177 {
178     gpio_control_reg->PORTA_EOI = idx;
179 }
180 
181 
182 /*
183  * Enable one or more interrupts of PortA.
184  * Parameters:
185  *   pinno:
186  * return: SUCCESS.
187  */
gpio_irq_enable(gpio_pin_handle_t pin)188 static void gpio_irq_enable(gpio_pin_handle_t pin)
189 {
190     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
191     uint32_t offset = gpio_pin_priv->idx;
192     uint32_t val = gpio_control_reg->INTEN;
193     val |= (1 << offset);
194     gpio_control_reg->INTEN = val;
195 }
196 
197 
198 /*
199  * Disable one or more interrupts of PortA.
200  * Parameters:
201  *   pinno:
202  * return: SUCCESS.
203  */
204 
gpio_irq_disable(gpio_pin_handle_t pin)205 static void gpio_irq_disable(gpio_pin_handle_t pin)
206 {
207     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
208     uint32_t offset = gpio_pin_priv->idx;
209 
210     uint32_t val = gpio_control_reg->INTEN;
211     val &= ~(1 << offset);
212     gpio_control_reg->INTEN = val;
213 }
214 
dw_gpio_irqhandler(int idx)215 void dw_gpio_irqhandler(int idx)
216 {
217     dw_gpio_priv_t *gpio_priv = &gpio_handle[idx];
218     uint32_t value = gpio_control_reg->INTSTATUS;
219     uint8_t i;
220 
221     /* find the interrput pin */
222     for (i = 0; i < 32; i++) {
223         if (value == (1 << i)) {
224             break;
225         }
226     }
227 
228     uint32_t offset = i;
229     uint32_t pin_idx = offset;
230 
231     for (i = 0; i < idx; i++) {
232         pin_idx += gpio_handle[i].pin_num;
233     }
234 
235     gpio_pin_handle_t pin = (gpio_pin_handle_t) &gpio_pin_handle[pin_idx];
236 
237     /* execute the callback function */
238     if ((gpio_event_cb_t)(gpio_priv->cb)) {
239         ((gpio_event_cb_t)(gpio_priv->cb))(pin);
240     }
241     gpio_irq_clear(value);  //clear the gpio interrupt
242 }
243 
target_gpio_port_init(port_name_t port,uint32_t * base,uint32_t * irq,uint32_t * pin_num)244 int32_t __attribute__((weak)) target_gpio_port_init(port_name_t port, uint32_t *base, uint32_t *irq, uint32_t *pin_num)
245 {
246     return -1;
247 }
248 
249 /**
250   \brief       Initialize GPIO module. 1. Initializes the resources needed for the GPIO handle 2.registers event callback function
251                 3.get gpio_port_handle
252   \param[in]   port      port_name.
253   \param[in]   cb_event  Pointer to \ref gpio_event_cb_t
254   \return      gpio_port_handle
255 */
csi_gpio_port_initialize(port_name_t port,gpio_event_cb_t cb_event)256 gpio_port_handle_t csi_gpio_port_initialize(port_name_t port, gpio_event_cb_t cb_event)
257 {
258     uint32_t i;
259     dw_gpio_priv_t *gpio_priv;
260 
261     for (i = 0; i <= port; i++) {
262         /* obtain the gpio port information */
263         uint32_t base = 0u;
264         uint32_t pin_num;
265         uint32_t irq;
266         uint32_t idx = target_gpio_port_init(i, &base, &irq, &pin_num);
267 
268         if (idx < 0 || idx >= CONFIG_GPIO_NUM) {
269             return NULL;
270         }
271 
272         gpio_priv = &gpio_handle[idx];
273 
274         gpio_priv->base = base;
275         gpio_priv->irq  = irq;
276         gpio_priv->pin_num  = pin_num;
277     }
278 
279     gpio_reg = (dw_gpio_reg_t *)(gpio_priv->base);
280     gpio_control_reg = (dw_gpio_control_reg_t *)(gpio_priv->base + 0x30);
281 
282     gpio_priv->cb = (uint32_t)cb_event;
283 
284     drv_nvic_enable_irq(gpio_priv->irq);
285 
286     return (gpio_port_handle_t)gpio_priv;
287 }
288 
289 /**
290   \brief       De-initialize GPIO handle. stops operation and releases the software resources used by the handle
291   \param[in]   handle   gpio port handle to operate.
292   \return      error code
293 */
csi_gpio_port_uninitialize(gpio_port_handle_t handle)294 int32_t csi_gpio_port_uninitialize(gpio_port_handle_t handle)
295 {
296     GPIO_NULL_PARAM_CHK(handle);
297 
298     dw_gpio_priv_t *gpio_priv = handle;
299 
300     gpio_priv->cb = NULL;
301 
302     drv_nvic_disable_irq(gpio_priv->irq);
303 
304     return 0;
305 }
306 
307 /**
308   \brief       Get driver capabilities.
309   \param[in]   handle instance to operate.
310   \return      \ref gpio_capabilities_t
311 */
csi_gpio_get_io_capabilities(gpio_port_handle_t handle)312 gpio_capabilities_t csi_gpio_get_io_capabilities(gpio_port_handle_t handle)
313 {
314     return driver_capabilities;
315 }
316 
317 /**
318   \brief       config multiple pin within one handle
319   \param[in]   handle    gpio port handle to operate.
320   \param[in]   mask      the bitmask to identify which bits in the handle should be included (0 - ignore)
321   \param[in]   mode      \ref gpio_mode_e
322   \param[in]   dir       \ref gpio_direction_e
323   \return      error code
324 */
csi_gpio_port_config(gpio_port_handle_t handle,uint32_t mask,gpio_mode_e mode,gpio_direction_e dir)325 int32_t csi_gpio_port_config(gpio_port_handle_t handle, uint32_t mask, gpio_mode_e mode, gpio_direction_e dir)
326 {
327     if (mask < 0) {
328         return ERR_GPIO(EDRV_PARAMETER);
329     }
330     GPIO_NULL_PARAM_CHK(handle);
331 
332     dw_gpio_priv_t *gpio_priv = handle;
333     /*config the gpio mode direction mask bits */
334     gpio_priv->mode = mode;
335     gpio_priv->dir = dir;
336     gpio_priv->mask = mask;
337     uint32_t ret = gpio_set_direction(gpio_priv, dir);
338 
339     return ret;
340 }
341 
342 /**
343   \brief       Write value to the handle(write value to multiple pins on one handle at the same time)
344   \param[in]   handle    gpio port handle to operate.
345   \param[in]   mask      The bitmask to identify which bits in the handle should be included (0 - ignore)
346   \param[in]   value     the value to be set
347   \return      error code
348 */
csi_gpio_port_write(gpio_port_handle_t handle,uint32_t mask,uint32_t value)349 int32_t csi_gpio_port_write(gpio_port_handle_t handle, uint32_t mask, uint32_t value)
350 {
351     if (mask < 0 || value < 0) {
352         return ERR_GPIO(EDRV_PARAMETER);
353     }
354     GPIO_NULL_PARAM_CHK(handle);
355 
356     uint32_t port_value = mask & value;
357 
358     dw_gpio_priv_t *gpio_priv = handle;
359     gpio_priv->value = port_value;
360     gpio_write(gpio_priv, mask);
361 
362     return 0;
363 
364 }
365 
366 /**
367   \brief       Read the current value on the handle(read value of multiple pins on one handle at the same time)
368   \param[in]   handle    gpio port handle to operate.
369   \param[in]   mask      The bitmask to identify which bits in the handle should be included (0 - ignore)
370   \param[out]  value     an integer with each bit corresponding to an associated handle pin setting
371   \return      error code
372 */
csi_gpio_port_read(gpio_port_handle_t handle,uint32_t mask,uint32_t * value)373 int32_t csi_gpio_port_read(gpio_port_handle_t handle, uint32_t mask, uint32_t *value)
374 {
375     if (mask < 0) {
376         return ERR_GPIO(EDRV_PARAMETER);
377     }
378     GPIO_NULL_PARAM_CHK(handle);
379     GPIO_NULL_PARAM_CHK(value);
380 
381     uint32_t port_value = 0;
382 
383     gpio_read(&port_value);
384     *value = (mask & port_value);
385 
386     return 0;
387 
388 }
389 
target_gpio_pin_init(pin_t gpio_pin,uint32_t * port_idx)390 int32_t __attribute__((weak)) target_gpio_pin_init(pin_t gpio_pin, uint32_t *port_idx)
391 {
392     return -1;
393 }
394 
395 /**
396   \brief       Initialize GPIO handle.
397   \param[in]   gpio_pin    Pointer to the pin_t.
398   \return      gpio_pin_handle
399 */
csi_gpio_pin_initialize(pin_t gpio_pin)400 gpio_pin_handle_t csi_gpio_pin_initialize(pin_t gpio_pin)
401 {
402     /* obtain the gpio pin information */
403     uint32_t port_idx;
404     uint32_t pin_idx = target_gpio_pin_init(gpio_pin, &port_idx);
405 
406     dw_gpio_pin_priv_t *gpio_pin_priv = &(gpio_pin_handle[pin_idx]);
407     gpio_pin_priv->handle = (gpio_port_handle_t)&gpio_handle[port_idx];
408 
409     uint32_t idx = pin_idx;
410     uint32_t i;
411 
412     for (i = 0; i < port_idx; i++) {
413         idx = pin_idx - (gpio_handle[i].pin_num);
414     }
415 
416     gpio_pin_priv->idx = idx;
417 
418     return (gpio_pin_handle_t)gpio_pin_priv;
419 }
420 
421 /**
422   \brief       config pin
423   \param[in]   pin       gpio pin handle to operate.
424   \param[in]   mode      \ref gpio_mode_e
425   \param[in]   dir       \ref gpio_direction_e
426   \return      error code
427 */
csi_gpio_pin_config(gpio_pin_handle_t pin,gpio_mode_e mode,gpio_direction_e dir)428 int32_t csi_gpio_pin_config(gpio_pin_handle_t pin,
429                             gpio_mode_e mode,
430                             gpio_direction_e dir)
431 {
432     GPIO_NULL_PARAM_CHK(pin);
433 
434     /* config the gpio pin mode direction mask bits */
435     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
436     dw_gpio_priv_t *gpio_priv = gpio_pin_priv->handle;
437 
438     gpio_priv->mode = mode;
439     gpio_priv->dir = dir;
440     gpio_priv->mask = 1 << gpio_pin_priv->idx;
441 
442     uint32_t ret = gpio_set_direction(gpio_priv, dir);
443     if(ret) {
444         return ret;
445     }
446 
447     return 0;
448 
449 }
450 
451 /**
452   \brief       Set one or zero to the selected GPIO pin.
453   \param[in]   pin       gpio pin handle to operate.
454   \param[in]   value     the value to be set
455   \return      error code
456 */
csi_gpio_pin_write(gpio_pin_handle_t pin,bool value)457 int32_t csi_gpio_pin_write(gpio_pin_handle_t pin, bool value)
458 {
459     GPIO_NULL_PARAM_CHK(pin);
460     if (value < 0) {
461         return ERR_GPIO(EDRV_PARAMETER);
462     }
463 
464     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
465     dw_gpio_priv_t *gpio_priv = gpio_pin_priv->handle;
466     uint8_t offset = gpio_pin_priv->idx;
467     uint32_t port_value = value << offset;
468 
469     gpio_priv->value = port_value;
470     gpio_write(gpio_priv, (1 << offset));
471 
472     return 0;
473 
474 }
475 
476 /**
477   \brief       Get the value of  selected GPIO pin.
478   \param[in]   pin       gpio pin handle to operate.
479   \param[out]  value     buf to store the pin value
480   \return      error code
481 */
csi_gpio_pin_read(gpio_pin_handle_t pin,bool * value)482 int32_t csi_gpio_pin_read(gpio_pin_handle_t pin, bool *value)
483 {
484     GPIO_NULL_PARAM_CHK(pin);
485     if (value <= 0) {
486         return ERR_GPIO(EDRV_PARAMETER);
487     }
488 
489     dw_gpio_pin_priv_t *gpio_pin_priv = pin;
490     uint32_t port_value;
491     uint8_t offset = gpio_pin_priv->idx;
492 
493     gpio_read(&port_value);
494     *value = (port_value & (1 << offset)) >> offset;
495 
496     return 0;
497 }
498 
499 /**
500   \brief       set GPIO interrupt mode.
501   \param[in]   pin       gpio pin handle to operate.
502   \param[in]   mode      the irq mode to be set
503   \param[in]   enable    the enable flag
504   \return      error code
505 */
csi_gpio_pin_irq_set(gpio_pin_handle_t pin,gpio_irq_mode_e mode,bool enable)506 int32_t csi_gpio_pin_irq_set(gpio_pin_handle_t pin, gpio_irq_mode_e mode, bool enable)
507 {
508     GPIO_NULL_PARAM_CHK(pin);
509 
510     uint32_t ret = 0;
511 
512     if (enable) {
513         ret = gpio_set_irq_mode(pin, mode);
514 
515         if (ret) {
516             return ret;
517         }
518         gpio_irq_enable(pin);
519 
520     } else {
521         gpio_irq_disable(pin);
522 
523     }
524 
525     return ret;
526 
527 }
528 
529