dw_gpio.c 16 KB

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