drv_gpio.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. * Copyright (c) 2020-2021, Bluetrum Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-11-19 greedyhao first version
  9. * 2025-05-15 kurisaW support gpio interrupt
  10. */
  11. #include "drv_gpio.h"
  12. #ifdef RT_USING_PIN
  13. // #define DRV_DEBUG
  14. #define LOG_TAG "drv.gpio"
  15. #include <drv_log.h>
  16. struct port_info
  17. {
  18. rt_uint8_t start_pin;
  19. rt_uint8_t delta_pin;
  20. rt_uint8_t total_pin;
  21. };
  22. /* It needs to be adjusted to the hardware. */
  23. static const struct port_info port_table[] =
  24. {
  25. {0, 8, 0}, /* PA0-PA7 */
  26. {0, 5, 8}, /* PB0-PB4 */
  27. {0, 8, 13}, /* PE0-PE7 */
  28. {0, 6, 21}, /* PF0-PF5 */
  29. };
  30. static const hal_sfr_t port_sfr[] =
  31. {
  32. GPIOA_BASE,
  33. GPIOB_BASE,
  34. GPIOE_BASE,
  35. GPIOF_BASE,
  36. };
  37. static struct ab32_pin_irq pin_irq_table[8] = {0}; // For WAKEUP_CRICUIT_0 to _7
  38. static rt_mq_t gpio_irq_mq = RT_NULL;
  39. static rt_uint8_t _pin_port(rt_uint32_t pin)
  40. {
  41. rt_uint8_t port = 0;
  42. for (port = 0; port < 3; port++) {
  43. if (pin < (port_table[port].total_pin + port_table[port].delta_pin)) {
  44. break;
  45. }
  46. }
  47. return port;
  48. }
  49. #define PIN_NUM(port, no) ((rt_uint8_t)(port_table[port].total_pin + no - port_table[port].start_pin))
  50. #define PIN_PORT(pin) _pin_port(pin)
  51. #define PORT_SFR(port) (port_sfr[(port)])
  52. #define PIN_NO(pin) (rt_uint8_t)((pin) & 0xFu)
  53. static rt_base_t ab32_pin_get(const char *name)
  54. {
  55. rt_base_t pin = 0;
  56. int hw_port_num, hw_pin_num = 0;
  57. int i, name_len;
  58. name_len = rt_strlen(name);
  59. if ((name_len < 4) || (name_len >= 6))
  60. {
  61. return -RT_EINVAL;
  62. }
  63. if ((name[0] != 'P') || (name[2] != '.'))
  64. {
  65. return -RT_EINVAL;
  66. }
  67. if ((name[1] >= 'A') && (name[1] <= 'B'))
  68. {
  69. hw_port_num = (int)(name[1] - 'A');
  70. }
  71. else if ((name[1] >= 'E') && (name[1] <= 'G'))
  72. {
  73. hw_port_num = (int)(name[1] - 'A') - 2; /* Without 'C' and 'D'. */
  74. }
  75. else
  76. {
  77. return -RT_EINVAL;
  78. }
  79. for (i = 3; i < name_len; i++)
  80. {
  81. hw_pin_num *= 10;
  82. hw_pin_num += name[i] - '0';
  83. }
  84. pin = PIN_NUM(hw_port_num, hw_pin_num);
  85. LOG_D("name=%s", name);
  86. LOG_D("hw_port_num=%d hw_pin_num=%d pin=%d", hw_port_num, hw_pin_num, pin);
  87. return pin;
  88. }
  89. static void ab32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
  90. {
  91. rt_uint8_t port = PIN_PORT(pin);
  92. rt_uint8_t gpio_pin = pin - port_table[port].total_pin;
  93. hal_gpio_write(PORT_SFR(port), gpio_pin, (rt_uint8_t)value);
  94. }
  95. static rt_ssize_t ab32_pin_read(rt_device_t dev, rt_base_t pin)
  96. {
  97. rt_uint8_t port = PIN_PORT(pin);
  98. rt_uint8_t gpio_pin = pin - port_table[port].total_pin;
  99. return hal_gpio_read(PORT_SFR(port), gpio_pin);
  100. }
  101. static void ab32_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
  102. {
  103. struct gpio_init gpio_init;
  104. rt_uint8_t port = PIN_PORT(pin);
  105. gpio_init.pin = BIT(pin - port_table[port].total_pin);
  106. gpio_init.de = GPIO_DIGITAL;
  107. gpio_init.af_con = GPIO_AFDIS;
  108. LOG_D("port=%d pin=%d", port, gpio_init.pin);
  109. switch (mode)
  110. {
  111. case PIN_MODE_INPUT:
  112. gpio_init.pull = GPIO_NOPULL;
  113. gpio_init.dir = GPIO_DIR_INPUT;
  114. break;
  115. case PIN_MODE_INPUT_PULLUP:
  116. gpio_init.pull = GPIO_PULLUP;
  117. gpio_init.dir = GPIO_DIR_INPUT;
  118. break;
  119. case PIN_MODE_INPUT_PULLDOWN:
  120. gpio_init.pull = GPIO_PULLDOWN;
  121. gpio_init.dir = GPIO_DIR_INPUT;
  122. break;
  123. case PIN_MODE_OUTPUT:
  124. case PIN_MODE_OUTPUT_OD:
  125. default:
  126. gpio_init.pull = GPIO_NOPULL;
  127. gpio_init.dir = GPIO_DIR_OUTPUT;
  128. break;
  129. }
  130. hal_gpio_init(PORT_SFR(port), &gpio_init);
  131. }
  132. static rt_err_t get_port_pin(rt_base_t pin, rt_uint8_t *port, rt_uint8_t *hw_pin)
  133. {
  134. rt_uint8_t i;
  135. for (i = 0; i < sizeof(port_table) / sizeof(port_table[0]); i++)
  136. {
  137. if (pin >= port_table[i].total_pin &&
  138. pin < port_table[i].total_pin + port_table[i].delta_pin)
  139. {
  140. *port = i;
  141. *hw_pin = pin - port_table[i].total_pin + port_table[i].start_pin;
  142. return RT_EOK;
  143. }
  144. }
  145. return -RT_EINVAL;
  146. }
  147. static rt_int32_t get_wakeup_circuit(rt_base_t pin)
  148. {
  149. /* Special interrupt pins */
  150. if (pin == PIN_NUM(0, 7)) return WAKEUP_CRICUIT_0; // PA7
  151. if (pin == PIN_NUM(1, 1)) return WAKEUP_CRICUIT_1; // PB1
  152. if (pin == PIN_NUM(1, 2)) return WAKEUP_CRICUIT_2; // PB2
  153. if (pin == PIN_NUM(1, 3)) return WAKEUP_CRICUIT_3; // PB3
  154. if (pin == PIN_NUM(1, 4)) return WAKEUP_CRICUIT_4; // PB4
  155. /* WAKEUP_CRICUIT_5 is for RTC (WKO), assuming not a GPIO pin */
  156. /* Other pins use WAKEUP_CRICUIT_6 (falling) or WAKEUP_CRICUIT_7 (rising) */
  157. return -1; // Will be handled in attach_irq based on mode
  158. }
  159. static rt_uint32_t get_edge_select_bit(rt_uint8_t circuit)
  160. {
  161. switch (circuit)
  162. {
  163. case WAKEUP_CRICUIT_0: return WAKEUP_EDGE_SELECT_0;
  164. case WAKEUP_CRICUIT_1: return WAKEUP_EDGE_SELECT_1;
  165. case WAKEUP_CRICUIT_2: return WAKEUP_EDGE_SELECT_2;
  166. case WAKEUP_CRICUIT_3: return WAKEUP_EDGE_SELECT_3;
  167. case WAKEUP_CRICUIT_4: return WAKEUP_EDGE_SELECT_4;
  168. case WAKEUP_CRICUIT_5: return WAKEUP_EDGE_SELECT_5;
  169. case WAKEUP_CRICUIT_6: return WAKEUP_EDGE_SELECT_6;
  170. case WAKEUP_CRICUIT_7: return WAKEUP_EDGE_SELECT_7;
  171. default: return 0;
  172. }
  173. }
  174. void __attribute__((section(".irq.gpio"))) ab32_pin_irq_handler(void *args)
  175. {
  176. rt_interrupt_enter();
  177. rt_uint32_t pending = WKUPEDG;
  178. rt_uint8_t circuit = 0;
  179. for (circuit = 0; circuit <= WAKEUP_CRICUIT_7; circuit++)
  180. {
  181. if (pending & (BIT(circuit) << WAKEUP_INT_ENABLE))
  182. {
  183. /* clear pending interrupt */
  184. WKUPCPND = (BIT(circuit) << WAKEUP_INT_ENABLE);
  185. rt_mq_send(gpio_irq_mq, &circuit, sizeof(circuit));
  186. }
  187. }
  188. rt_interrupt_leave();
  189. }
  190. static void ab32_pin_irq_thread(void *parameter)
  191. {
  192. rt_uint8_t circuit;
  193. while (1)
  194. {
  195. if (rt_mq_recv(gpio_irq_mq, &circuit, sizeof(circuit), RT_WAITING_FOREVER) == RT_EOK)
  196. {
  197. if (circuit <= WAKEUP_CRICUIT_7 && pin_irq_table[circuit].hdr)
  198. {
  199. pin_irq_table[circuit].hdr(pin_irq_table[circuit].args);
  200. }
  201. }
  202. }
  203. }
  204. static rt_err_t ab32_pin_attach_irq(struct rt_device *device, rt_int32_t pin,
  205. rt_uint32_t mode, void (*hdr)(void *args), void *args)
  206. {
  207. rt_uint8_t port, hw_pin;
  208. rt_int32_t circuit;
  209. uint8_t pin_mode;
  210. if (get_port_pin(pin, &port, &hw_pin) != RT_EOK)
  211. {
  212. return -RT_EINVAL;
  213. }
  214. circuit = get_wakeup_circuit(pin);
  215. if(circuit == -1)
  216. {
  217. circuit = (mode == PIN_IRQ_MODE_FALLING) ? WAKEUP_CRICUIT_6 : WAKEUP_CRICUIT_7;
  218. }
  219. /* store handler and arguments */
  220. pin_irq_table[circuit].hdr = hdr;
  221. pin_irq_table[circuit].args = args;
  222. /* The interrupt source in the port is: Port_intsrc = {PG[4:0], PF[5:0], PE[7:0], PB[4:0], PA[7:0]}. */
  223. /* Such as:the interrupt source number of PA0 is 0, interrupt source number of PG4 is 31. */
  224. PORTINTEN |= BIT(pin); // Enable interrupt
  225. PORTINTEDG |= BIT(pin); // Edge trigger
  226. return RT_EOK;
  227. }
  228. static rt_err_t ab32_pin_dettach_irq(struct rt_device *device, rt_int32_t pin)
  229. {
  230. rt_uint8_t port, hw_pin;
  231. rt_int32_t circuit;
  232. if (get_port_pin(pin, &port, &hw_pin) != RT_EOK)
  233. {
  234. return -RT_EINVAL;
  235. }
  236. circuit = get_wakeup_circuit(pin);
  237. if (circuit < 0)
  238. {
  239. /* assume previously assigned to WAKEUP_CRICUIT_6 or _7 */
  240. /* check both circuits for handler */
  241. if (pin_irq_table[WAKEUP_CRICUIT_6].hdr)
  242. circuit = WAKEUP_CRICUIT_6;
  243. else if (pin_irq_table[WAKEUP_CRICUIT_7].hdr)
  244. circuit = WAKEUP_CRICUIT_7;
  245. else
  246. return RT_EOK;
  247. }
  248. PORTINTEN &= ~BIT(circuit);
  249. WKUPCON &= ~BIT(circuit);
  250. WKUPCPND = BIT(get_edge_select_bit(circuit));
  251. /* clear handler */
  252. pin_irq_table[circuit].hdr = RT_NULL;
  253. pin_irq_table[circuit].args = RT_NULL;
  254. return RT_EOK;
  255. }
  256. static rt_err_t ab32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
  257. rt_uint32_t enabled)
  258. {
  259. rt_uint8_t port, hw_pin;
  260. rt_int32_t circuit;
  261. if (get_port_pin(pin, &port, &hw_pin) != RT_EOK)
  262. {
  263. return -RT_EINVAL;
  264. }
  265. circuit = get_wakeup_circuit(pin);
  266. if (circuit < 0)
  267. {
  268. if (pin_irq_table[WAKEUP_CRICUIT_6].hdr)
  269. {
  270. circuit = WAKEUP_CRICUIT_6;
  271. }
  272. else if (pin_irq_table[WAKEUP_CRICUIT_7].hdr)
  273. {
  274. circuit = WAKEUP_CRICUIT_7;
  275. }
  276. else
  277. return -RT_EINVAL;
  278. }
  279. rt_uint32_t edge_bit = get_edge_select_bit(circuit);
  280. if (enabled == RT_TRUE)
  281. {
  282. WKUPEDG = BIT(circuit) | BIT(edge_bit);
  283. WKUPCON = BIT(circuit) | BIT(WAKEUP_INT_ENABLE);
  284. WKUPCPND = BIT(circuit);
  285. /* install interrupt handler */
  286. rt_hw_interrupt_install(IRQ_GPIO_IRQ, ab32_pin_irq_handler, RT_NULL, "gpio_isr");
  287. rt_hw_irq_enable(IRQ_GPIO_IRQ);
  288. }
  289. else
  290. {
  291. /* disable interrupt */
  292. WKUPCON &= ~BIT(circuit);
  293. }
  294. return RT_EOK;
  295. }
  296. static int ab32_pin_irq_init(void)
  297. {
  298. gpio_irq_mq = rt_mq_create("gpio_irq", sizeof(rt_uint8_t), 128, RT_IPC_FLAG_FIFO);
  299. if (gpio_irq_mq == RT_NULL)
  300. {
  301. return -RT_ENOMEM;
  302. }
  303. rt_thread_t tid = rt_thread_create("gpio_irq",
  304. ab32_pin_irq_thread,
  305. RT_NULL,
  306. 512,
  307. 15,
  308. 5);
  309. if (tid != RT_NULL)
  310. {
  311. rt_thread_startup(tid);
  312. }
  313. else
  314. {
  315. rt_mq_delete(gpio_irq_mq);
  316. return -RT_ENOMEM;
  317. }
  318. return RT_EOK;
  319. }
  320. INIT_PREV_EXPORT(ab32_pin_irq_init);
  321. const static struct rt_pin_ops _ab32_pin_ops =
  322. {
  323. ab32_pin_mode,
  324. ab32_pin_write,
  325. ab32_pin_read,
  326. ab32_pin_attach_irq,
  327. ab32_pin_dettach_irq,
  328. ab32_pin_irq_enable,
  329. ab32_pin_get,
  330. };
  331. int rt_hw_pin_init(void)
  332. {
  333. return rt_device_pin_register("pin", &_ab32_pin_ops, RT_NULL);
  334. }
  335. #endif