/** * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd * * SPDX-License-Identifier: Apache-2.0 ****************************************************************************** * @file drv_gpio.c * @author Jay Xu * @version V0.1 * @date 2019/5/15 * @brief GPIO Driver * ****************************************************************************** */ /** @addtogroup RKBSP_Driver_Reference * @{ */ /** @addtogroup GPIO * @{ */ /** @defgroup GPIO_How_To_Use How To Use * @{ The GPIO driver use to configure or control GPIO pins on SoCs, it can be used in the following three scenarios: - (A) The GPIO PIN APIs provide by pin component: - 1) rt_pin_read - get pin level, pin number caculated by BANK_PIN(banknum, pinnum); - 2) rt_pin_write- set pin level, pin number caculated by BANK_PIN(banknum, pinnum); - 3) rt_pin_mode - set pin input/output, pin number caculated by BANK_PIN(banknum, pinnum); - (B) The GPIO IRQ APIs provide by pin component: - 1) pin_attach_irq; - 2) pin_detach_irq; - 3) pin_irq_enable; - (C) The GPIO PIN NUMBER calculated by BANK_PIN(b,p), such as BANK_PIN(0, 5) means GPIO0_A5 BANK_PIN(1, 8) means GPIO1_B0 See more information, click [here](http://www.rt-thread.org/document/site/programming-manual/device/pin/pin/) @} */ #include <rthw.h> #include <rtdevice.h> #include <rtthread.h> #ifdef RT_USING_PIN #include "hal_base.h" #include "drv_gpio.h" /********************* Private MACRO Definition ******************************/ #define PIN_NUM(p) ((p & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT) #define PIN_BANK(p) ((p & GPIO_BANK_MASK) >> GPIO_BANK_SHIFT) #define BANK_PIN_DEFAULT (-1) /********************* Private Structure Definition **************************/ static struct GPIO_REG *GPIO_GROUP[] = { #ifdef GPIO0 GPIO0, #endif #ifdef GPIO1 GPIO1, #endif #ifdef GPIO2 GPIO2, #endif #ifdef GPIO3 GPIO3, #endif #ifdef GPIO4 GPIO4, #endif }; #define GPIO_BANK_NUM HAL_ARRAY_SIZE(GPIO_GROUP) #define get_st_gpio(p) (GPIO_GROUP[PIN_BANK(p)]) #define get_st_pin(p) (HAL_BIT(PIN_NUM(p))) static struct rt_pin_irq_hdr pin_irq_hdr_tab[GPIO_BANK_NUM * PIN_NUMBER_PER_BANK]; /********************* Private Function Definition ***************************/ /** @defgroup GPIO_Private_Function Private Function * @{ */ static rt_err_t pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args) { rt_base_t level; if (pin < 0 || pin >= HAL_ARRAY_SIZE(pin_irq_hdr_tab)) { return -RT_ENOSYS; } level = rt_hw_interrupt_disable(); if (pin_irq_hdr_tab[pin].pin == pin && pin_irq_hdr_tab[pin].hdr == hdr && pin_irq_hdr_tab[pin].mode == mode && pin_irq_hdr_tab[pin].args == args) { rt_hw_interrupt_enable(level); return RT_EOK; } if (pin_irq_hdr_tab[pin].pin != BANK_PIN_DEFAULT && pin_irq_hdr_tab[pin].hdr != RT_NULL) { rt_hw_interrupt_enable(level); return -RT_EBUSY; } pin_irq_hdr_tab[pin].pin = pin; pin_irq_hdr_tab[pin].hdr = hdr; pin_irq_hdr_tab[pin].mode = mode; pin_irq_hdr_tab[pin].args = args; rt_hw_interrupt_enable(level); return RT_EOK; } static rt_err_t pin_detach_irq(struct rt_device *device, rt_int32_t pin) { rt_base_t level; if (pin < 0 || pin >= HAL_ARRAY_SIZE(pin_irq_hdr_tab)) { return -RT_ENOSYS; } level = rt_hw_interrupt_disable(); if (pin_irq_hdr_tab[pin].pin == BANK_PIN_DEFAULT) { rt_hw_interrupt_enable(level); return RT_EOK; } pin_irq_hdr_tab[pin].pin = BANK_PIN_DEFAULT; pin_irq_hdr_tab[pin].hdr = RT_NULL; pin_irq_hdr_tab[pin].mode = 0; pin_irq_hdr_tab[pin].args = RT_NULL; rt_hw_interrupt_enable(level); return RT_EOK; } static rt_err_t pin_irq_enable(struct rt_device *dev, rt_base_t pin, rt_uint32_t enabled) { rt_base_t level; eGPIO_intType mode; RT_ASSERT(PIN_BANK(pin) < GPIO_BANK_NUM); if (enabled == PIN_IRQ_ENABLE) { if (pin < 0 || pin >= HAL_ARRAY_SIZE(pin_irq_hdr_tab)) { return -RT_ENOSYS; } level = rt_hw_interrupt_disable(); if (pin_irq_hdr_tab[pin].pin == BANK_PIN_DEFAULT) { rt_hw_interrupt_enable(level); return -RT_ENOSYS; } switch (pin_irq_hdr_tab[pin].mode) { case PIN_IRQ_MODE_RISING: mode = GPIO_INT_TYPE_EDGE_RISING; break; case PIN_IRQ_MODE_FALLING: mode = GPIO_INT_TYPE_EDGE_FALLING; break; case PIN_IRQ_MODE_RISING_FALLING: mode = GPIO_INT_TYPE_EDGE_BOTH; break; case PIN_IRQ_MODE_LOW_LEVEL: mode = GPIO_INT_TYPE_LEVEL_LOW; break; case PIN_IRQ_MODE_HIGH_LEVEL: mode = GPIO_INT_TYPE_LEVEL_HIGH; break; default: rt_hw_interrupt_enable(level); return -RT_EINVAL; } HAL_GPIO_SetIntType(get_st_gpio(pin), get_st_pin(pin), mode); HAL_GPIO_EnableIRQ(get_st_gpio(pin), get_st_pin(pin)); rt_hw_interrupt_enable(level); } else if (enabled == PIN_IRQ_DISABLE) { HAL_GPIO_DisableIRQ(get_st_gpio(pin), get_st_pin(pin)); } else { return -RT_ENOSYS; } return RT_EOK; } static void pin_mode(struct rt_device *dev, rt_base_t pin, rt_uint8_t mode) { RT_ASSERT(PIN_BANK(pin) < GPIO_BANK_NUM); switch (mode) { case PIN_MODE_OUTPUT: case PIN_MODE_OUTPUT_OD: #ifdef HAL_PINCTRL_MODULE_ENABLED #ifdef RK_BSP_TEMP HAL_PINCTRL_SetIOMUX(PIN_BANK(pin), HAL_BIT(pin), PIN_CONFIG_MUX_FUNC0); #endif #endif HAL_GPIO_SetPinDirection(get_st_gpio(pin), get_st_pin(pin), GPIO_OUT); break; case PIN_MODE_INPUT: case PIN_MODE_INPUT_PULLUP: case PIN_MODE_INPUT_PULLDOWN: #ifdef HAL_PINCTRL_MODULE_ENABLED #ifdef RK_BSP_TEMP HAL_PINCTRL_SetIOMUX(PIN_BANK(pin), HAL_BIT(pin), PIN_CONFIG_MUX_FUNC0); #endif #endif HAL_GPIO_SetPinDirection(get_st_gpio(pin), get_st_pin(pin), GPIO_IN); break; default: break; } } static void pin_write(struct rt_device *dev, rt_base_t pin, rt_uint8_t value) { RT_ASSERT(PIN_BANK(pin) < GPIO_BANK_NUM); HAL_GPIO_SetPinLevel(get_st_gpio(pin), get_st_pin(pin), value); } static rt_int8_t pin_read(struct rt_device *dev, rt_base_t pin) { RT_ASSERT(PIN_BANK(pin) < GPIO_BANK_NUM); return HAL_GPIO_GetPinLevel(get_st_gpio(pin), get_st_pin(pin));; } /** @} */ #ifdef GPIO0 void pin_gpio0_handler(void) { rt_interrupt_enter(); HAL_GPIO_IRQHandler(GPIO0, GPIO_BANK0); rt_interrupt_leave(); } #endif #ifdef GPIO1 void pin_gpio1_handler(void) { rt_interrupt_enter(); HAL_GPIO_IRQHandler(GPIO1, GPIO_BANK1); rt_interrupt_leave(); } #endif #ifdef GPIO2 void pin_gpio2_handler(void) { rt_interrupt_enter(); HAL_GPIO_IRQHandler(GPIO2, GPIO_BANK2); rt_interrupt_leave(); } #endif #ifdef GPIO3 void pin_gpio3_handler(void) { rt_interrupt_enter(); HAL_GPIO_IRQHandler(GPIO3, GPIO_BANK3); rt_interrupt_leave(); } #endif #ifdef GPIO4 void pin_gpio4_handler(void) { rt_interrupt_enter(); HAL_GPIO_IRQHandler(GPIO4, GPIO_BANK4); rt_interrupt_leave(); } #endif static const struct rt_pin_ops pin_ops = { pin_mode, pin_write, pin_read, pin_attach_irq, pin_detach_irq, pin_irq_enable, }; /** @defgroup GPIO_Public_Functions Public Functions * @{ */ int rt_hw_gpio_init(void) { #ifdef GPIO0 rt_hw_interrupt_install(GPIO0_IRQn, (void *)pin_gpio0_handler, RT_NULL, RT_NULL); rt_hw_interrupt_umask(GPIO0_IRQn); #endif #ifdef GPIO1 rt_hw_interrupt_install(GPIO1_IRQn, (void *)pin_gpio1_handler, RT_NULL, RT_NULL); rt_hw_interrupt_umask(GPIO1_IRQn); #endif #ifdef GPIO2 rt_hw_interrupt_install(GPIO2_IRQn, (void *)pin_gpio2_handler, RT_NULL, RT_NULL); rt_hw_interrupt_umask(GPIO2_IRQn); #endif #ifdef GPIO3 rt_hw_interrupt_install(GPIO3_IRQn, (void *)pin_gpio3_handler, RT_NULL, RT_NULL); rt_hw_interrupt_umask(GPIO3_IRQn); #endif #ifdef GPIO4 rt_hw_interrupt_install(GPIO4_IRQn, (void *)pin_gpio4_handler, RT_NULL, RT_NULL); rt_hw_interrupt_umask(GPIO4_IRQn); #endif rt_device_pin_register("pin", &pin_ops, RT_NULL); return 0; } INIT_BOARD_EXPORT(rt_hw_gpio_init); /** @} */ static void pin_irq_hdr(uint32_t pin) { RT_ASSERT(pin >= 0); RT_ASSERT(pin < HAL_ARRAY_SIZE(pin_irq_hdr_tab)); RT_ASSERT(pin_irq_hdr_tab[pin].hdr != RT_NULL); pin_irq_hdr_tab[pin].hdr(pin_irq_hdr_tab[pin].args); } void HAL_GPIO_IRQDispatch(eGPIO_bankId bank, uint32_t pin) { RT_ASSERT(bank < GPIO_BANK_NUM); pin_irq_hdr(BANK_PIN(bank, pin)); } #endif /** @} */ /** @} */