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