/* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Email: opensource_embedded@phytium.com.cn * * Change Logs: * Date Author Notes * 2023/7/24 liqiaozhong first add, support intr * */ #include "rtconfig.h" #include #include #include "interrupt.h" #define LOG_TAG "gpio_drv" #include "drv_log.h" #ifdef RT_USING_SMART #include "ioremap.h" #endif #include #if defined(TARGET_E2000) #include "fparameters.h" #endif #include "fkernel.h" #include "fcpu_info.h" #include "ftypes.h" #include "fio_mux.h" #include "board.h" #include "fiopad.h" #include "fgpio.h" #include "drv_gpio.h" /**************************** Type Definitions *******************************/ typedef void (*FGpioOpsIrqHandler)(s32 vector, void *param); typedef struct { FGpioDirection direction; boolean en_irq; FGpioIrqType irq_type; FGpioOpsIrqHandler irq_handler; void *irq_args; } FGpioOpsPinConfig; typedef struct { FGpio ctrl; FGpioPin pins[FGPIO_PORT_NUM][FGPIO_PIN_NUM]; FGpioOpsPinConfig pin_config[FGPIO_PORT_NUM][FGPIO_PIN_NUM]; boolean init_ok; } FGpioOps; /***************** Macros (Inline Functions) Definitions *********************/ #if defined(TARGET_E2000) #define FGPIO_VERSION_2 #endif /************************** Variable Definitions *****************************/ static FGpioOps gpio[FGPIO_NUM]; extern FIOPadCtrl iopad_ctrl; /*******************************Api Functions*********************************/ static void FGpioOpsSetupCtrlIRQ(FGpio *ctrl) { rt_uint32_t cpu_id = rt_hw_cpu_id(); u32 irq_num = ctrl->config.irq_num[0]; LOG_D("In FGpioOpsSetupCtrlIRQ() -> cpu_id %d, irq_num %d\r\n", cpu_id, irq_num); rt_hw_interrupt_set_target_cpus(irq_num, cpu_id); rt_hw_interrupt_set_priority(irq_num, ctrl->config.irq_priority); /* setup interrupt */ rt_hw_interrupt_install(irq_num, FGpioInterruptHandler, ctrl, NULL); /* register intr handler */ rt_hw_interrupt_umask(irq_num); return; } /* setup gpio pin interrupt */ static void FGpioOpsSetupPinIRQ(FGpio *ctrl, FGpioPin *const pin, FGpioOpsPinConfig *config) { rt_uint32_t cpu_id = rt_hw_cpu_id(); u32 irq_num = ctrl->config.irq_num[pin->index.pin]; LOG_D("in FGpioOpsSetupPinIRQ() -> cpu_id %d, irq_num %d", cpu_id, irq_num); rt_hw_interrupt_set_target_cpus(irq_num, cpu_id); rt_hw_interrupt_set_priority(irq_num, ctrl->config.irq_priority); /* setup interrupt */ rt_hw_interrupt_install(irq_num, FGpioInterruptHandler, config->irq_args, NULL); /* register intr handler */ rt_hw_interrupt_umask(irq_num); return; } /* on E2000, if u want use GPIO-4-11, set pin = FGPIO_OPS_PIN_INDEX(4, 0, 11) */ static void drv_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) { u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin); u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin); u32 pin_id = FGPIO_OPS_PIN_ID(pin); FGpioPinId gpio_pin_id; FError err = FGPIO_SUCCESS; FGpio *instance = &gpio[ctrl_id].ctrl; FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id]; FGpioOpsPinConfig *pin_config = &gpio[ctrl_id].pin_config[port_id][pin_id]; if (ctrl_id >= FGPIO_NUM) { LOG_E("ctrl_id too large!!!"); return; } if (FALSE == gpio[ctrl_id].init_ok) /* init ctrl if needed */ { FGpioConfig input_cfg = *FGpioLookupConfig(ctrl_id); memset(instance, 0, sizeof(*instance)); #ifdef RT_USING_SMART input_cfg.base_addr = (uintptr)rt_ioremap((void *)input_cfg.base_addr, 0x1000); #endif err = FGpioCfgInitialize(instance, &input_cfg); if (FGPIO_SUCCESS != err) { LOG_E("Ctrl: %d init fail!!!\n", ctrl_id); return; } gpio[ctrl_id].init_ok = TRUE; } FIOPadSetGpioMux(ctrl_id, pin_id); if (FT_COMPONENT_IS_READY == pin_instance->is_ready) { FGpioPinDeInitialize(pin_instance); } gpio_pin_id.ctrl = ctrl_id; gpio_pin_id.port = port_id; gpio_pin_id.pin = pin_id; err = FGpioPinInitialize(instance, pin_instance, gpio_pin_id); if (FGPIO_SUCCESS != err) { LOG_E("Pin %d-%c-%d init fail!!!\n", ctrl_id, port_id == 0 ? 'a' : 'b', pin_id); return; } switch (mode) { case PIN_MODE_OUTPUT: pin_config->direction = FGPIO_DIR_OUTPUT; pin_config->en_irq = FALSE; break; case PIN_MODE_INPUT: pin_config->direction = FGPIO_DIR_INPUT; pin_config->en_irq = TRUE; pin_config->irq_type = FGPIO_IRQ_TYPE_EDGE_RISING; break; default: rt_kprintf("Not support mode %d!!!\n", mode); break; } FGpioSetDirection(pin_instance, pin_config->direction); rt_kprintf("Init GPIO-%d-%c-%d as an %sput pin\r\n", ctrl_id, port_id, pin_id, pin_config->direction == FGPIO_DIR_OUTPUT ? "out" : "in"); } void drv_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) { u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin); u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin); u32 pin_id = FGPIO_OPS_PIN_ID(pin); FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id]; if (pin_instance == RT_NULL) { rt_kprintf("Pin %d-%c-%d not set mode\n", ctrl_id, port_id == 0 ? 'a' : 'b', pin_id); return; } FGpioSetOutputValue(pin_instance, (value == PIN_HIGH) ? FGPIO_PIN_HIGH : FGPIO_PIN_LOW); } rt_ssize_t drv_pin_read(struct rt_device *device, rt_base_t pin) { u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin); u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin); u32 pin_id = FGPIO_OPS_PIN_ID(pin); FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id]; if (pin_instance == RT_NULL) { return -RT_EINVAL; } return FGpioGetInputValue(pin_instance) == FGPIO_PIN_HIGH ? PIN_HIGH : PIN_LOW; } rt_err_t drv_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args) { u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin); u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin); u32 pin_id = FGPIO_OPS_PIN_ID(pin); rt_base_t level; FGpio *instance = &gpio[ctrl_id].ctrl; FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id]; FGpioOpsPinConfig *pin_config = &gpio[ctrl_id].pin_config[port_id][pin_id]; level = rt_hw_interrupt_disable(); pin_config->irq_handler = (FGpioOpsIrqHandler)hdr; pin_config->irq_args = args; if (pin_instance == RT_NULL) { LOG_E("GPIO%d-%c-%d not init yet.\n", ctrl_id, port_id == 0 ? 'a' : 'b', pin_id); return -RT_ERROR; } if (pin_config->en_irq) { FGpioSetInterruptMask(pin_instance, FALSE); if (FGPIO_IRQ_BY_CONTROLLER == FGpioGetPinIrqSourceType(*pin_instance)) /* setup for ctrl report interrupt */ { FGpioOpsSetupCtrlIRQ(instance); LOG_I("GPIO-%d report irq by controller", ctrl_id); } else if (FGPIO_IRQ_BY_PIN == FGpioGetPinIrqSourceType(*pin_instance)) { FGpioOpsSetupPinIRQ(instance, pin_instance, pin_config); LOG_I("GPIO-%d report irq by pin", ctrl_id); } switch (mode) { case PIN_IRQ_MODE_RISING: pin_config->irq_type = FGPIO_IRQ_TYPE_EDGE_RISING; break; case PIN_IRQ_MODE_FALLING: pin_config->irq_type = FGPIO_IRQ_TYPE_EDGE_FALLING; break; case PIN_IRQ_MODE_LOW_LEVEL: pin_config->irq_type = FGPIO_IRQ_TYPE_LEVEL_LOW; break; case PIN_IRQ_MODE_HIGH_LEVEL: pin_config->irq_type = FGPIO_IRQ_TYPE_LEVEL_HIGH; break; default: LOG_E("Do not spport irq_mode: %d\n", mode); break; } FGpioSetInterruptType(pin_instance, pin_config->irq_type); FGpioRegisterInterruptCB(pin_instance, pin_config->irq_handler, pin_config->irq_args, TRUE); /* register intr callback */ } rt_hw_interrupt_enable(level); return RT_EOK; } rt_err_t drv_pin_detach_irq(struct rt_device *device, rt_base_t pin) { u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin); u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin); u32 pin_id = FGPIO_OPS_PIN_ID(pin); rt_base_t level; FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id]; FGpioOpsPinConfig *pin_config = &gpio[ctrl_id].pin_config[port_id][pin_id]; if (pin_instance == RT_NULL) { rt_kprintf("pin %d-%c-%d not set mode\n", ctrl_id, port_id == 0 ? 'a' : 'b', pin_id); return -RT_ERROR; } level = rt_hw_interrupt_disable(); pin_config->irq_handler = RT_NULL; pin_config->irq_args = RT_NULL; rt_hw_interrupt_enable(level); return RT_EOK; } rt_err_t drv_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) { u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin); u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin); u32 pin_id = FGPIO_OPS_PIN_ID(pin); FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id]; if (pin_instance == RT_NULL) { rt_kprintf("Pin %d-%c-%d not set mode\n", ctrl_id, port_id == 0 ? 'a' : 'b', pin_id); return -RT_ERROR; } FGpioSetInterruptMask(pin_instance, enabled); return RT_EOK; } const struct rt_pin_ops drv_pin_ops = { .pin_mode = drv_pin_mode, .pin_write = drv_pin_write, .pin_read = drv_pin_read, .pin_attach_irq = drv_pin_attach_irq, .pin_detach_irq = drv_pin_detach_irq, .pin_irq_enable = drv_pin_irq_enable, .pin_get = RT_NULL }; int ft_pin_init(void) { rt_err_t ret = RT_EOK; ret = rt_device_pin_register("pin", &drv_pin_ops, RT_NULL); rt_kprintf("Register pin with return: %d\n", ret); return ret; } INIT_DEVICE_EXPORT(ft_pin_init);