/* * Copyright : (C) 2022 Phytium Information Technology, Inc. * All Rights Reserved. * * This program is OPEN SOURCE software: you can redistribute it and/or modify it * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, * either version 1.0 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the Phytium Public License for more details. * * * FilePath: fgpio.c * Date: 2022-02-10 14:53:42 * LastEditTime: 2022-02-18 08:25:29 * Description:  This files is for GPIO user API implmentation * * Modify History: * Ver   Who        Date         Changes * ----- ------     --------    -------------------------------------- * 1.0 zhugengyu 2022-3-1 init commit */ /***************************** Include Files *********************************/ #include "fdebug.h" #include "fparameters.h" #include "fgpio_hw.h" #include "fgpio.h" /************************** Constant Definitions *****************************/ /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ #define FGPIO_DEBUG_TAG "FGPIO" #define FGPIO_ERROR(format, ...) FT_DEBUG_PRINT_E(FGPIO_DEBUG_TAG, format, ##__VA_ARGS__) #define FGPIO_WARN(format, ...) FT_DEBUG_PRINT_W(FGPIO_DEBUG_TAG, format, ##__VA_ARGS__) #define FGPIO_INFO(format, ...) FT_DEBUG_PRINT_I(FGPIO_DEBUG_TAG, format, ##__VA_ARGS__) #define FGPIO_DEBUG(format, ...) FT_DEBUG_PRINT_D(FGPIO_DEBUG_TAG, format, ##__VA_ARGS__) /************************** Function Prototypes ******************************/ /************************** Variable Definitions *****************************/ /*****************************************************************************/ /** * @name: FGpioCfgInitialize * @msg: 初始化GPIO控制器实例 * @return {FError} FGPIO_SUCCESS 表示初始化成功 * @param {FGpio} *instance, GPIO控制器实例 * @param {FGpioConfig} *config, GPIO控制器配置 */ FError FGpioCfgInitialize(FGpio *const instance, const FGpioConfig *const config) { FASSERT(instance && config); if (0 == config->base_addr) { FGPIO_ERROR("invalid base address !!!"); return FGPIO_ERR_INVALID_PARA; } if (config != &instance->config) { instance->config = *config; } instance->is_ready = FT_COMPONENT_IS_READY; return FGPIO_SUCCESS; } /** * @name: FGpioDeInitialize * @msg: 去初始化GPIO控制器实例 * @return {*} * @param {FGpio} *instance, GPIO控制器实例 */ void FGpioDeInitialize(FGpio *const instance) { FASSERT(instance); u32 port_id; u32 pin_id; FGpioPin *pin = NULL; for (port_id = FGPIO_PORT_A; port_id < FGPIO_PORT_NUM; port_id++) { for (pin_id = FGPIO_PIN_0; pin_id < FGPIO_PIN_NUM; pin_id++) { pin = instance->pins[port_id][pin_id]; if (NULL != pin) { FGpioPinDeInitialize(pin); } } } instance->is_ready = 0; return; } /** * @name: FGpioPinInitialize * @msg: 初始化GPIO引脚实例 * @return {FError} FGPIO_SUCCESS 表示初始化成功 * @param {FGpio} *instance, GPIO控制器实例 * @param {FGpioPin} *pin_instance, GPIO引脚实例 * @param {FGpioPinId} index, GPIO引脚索引 */ FError FGpioPinInitialize(FGpio *const instance, FGpioPin *const pin_instance, const FGpioPinId index) { FASSERT(instance && pin_instance); FASSERT_MSG(index.port < FGPIO_PORT_NUM, "invalid gpio port %d", index); FASSERT_MSG(index.pin < FGPIO_PIN_NUM, "invalid gpio pin %d", index); if (FT_COMPONENT_IS_READY != instance->is_ready) { FGPIO_ERROR("gpio instance not yet init !!!"); return FGPIO_ERR_NOT_INIT; } if (FT_COMPONENT_IS_READY == pin_instance->is_ready) { FGPIO_ERROR("gpio pin already inited !!!"); return FGPIO_ERR_ALREADY_INIT; } pin_instance->index = index; instance->pins[index.port][index.pin] = pin_instance; pin_instance->instance = instance; pin_instance->irq_cb = NULL; pin_instance->irq_cb_params = NULL; pin_instance->irq_one_time = FALSE; pin_instance->is_ready = FT_COMPONENT_IS_READY; return FGPIO_SUCCESS; } /** * @name: FGpioPinDeInitialize * @msg: 去初始化GPIO引脚实例 * @return {NONE} * @param {FGpioPin} *pin, GPIO引脚实例 */ void FGpioPinDeInitialize(FGpioPin *const pin) { FASSERT(pin); FGpio *const instance = pin->instance; if ((NULL == instance) || (FT_COMPONENT_IS_READY != instance->is_ready) || (FT_COMPONENT_IS_READY != pin->is_ready)) { FGPIO_ERROR("gpio instance not yet init !!!"); return; } if (FGPIO_DIR_INPUT == FGpioGetDirection(pin)) FGpioSetInterruptMask(pin, FALSE); /* 关闭引脚中断 */ FGpioPinId index = pin->index; FASSERT_MSG(instance->pins[index.port][index.pin] == pin, "invalid pin instance"); instance->pins[index.port][index.pin] = NULL; pin->instance = NULL; pin->is_ready = 0U; return; } /** * @name: FGpioGetPinIrqSourceType * @msg: 获取引脚中断的上报方式 * @return {FGpioIrqSourceType} 引脚中断的上报方式 * @param {FGpioPin} *pin, GPIO引脚实例 */ FGpioIrqSourceType FGpioGetPinIrqSourceType(FGpioPinId pin_id) { #if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */ if (FGPIO_PORT_B == pin_id.port) { return FGPIO_IRQ_NOT_SUPPORT; } #endif if (FGPIO_PORT_A == pin_id.port) { #if defined(FGPIO_VERSION_2) /* E2000 GPIO 0 ~ 5 */ if (pin_id.ctrl <= FGPIO_WITH_PIN_IRQ) /* 0 ~ 2 中断单独上报 */ { return FGPIO_IRQ_BY_PIN; } #endif return FGPIO_IRQ_BY_CONTROLLER; } return FGPIO_IRQ_NOT_SUPPORT; } /** * @name: FGpioReadRegDir * @msg: 从寄存器读取GPIO组的输入输出方向 * @return {u32} GPIO组的输入输出方向, bit[8:0]有效 * @param {uintptr} base_addr, GPIO控制器基地址 * @param {FGpioPortIndex} port, GPIO组, A/B */ static u32 FGpioReadRegDir(uintptr base_addr, const FGpioPortIndex port) { u32 reg_val = 0; if (FGPIO_PORT_A == port) { reg_val = FGpioReadReg32(base_addr, FGPIO_SWPORTA_DDR_OFFSET); } #if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */ else if (FGPIO_PORT_B == port) { reg_val = FGpioReadReg32(base_addr, FGPIO_SWPORTB_DDR_OFFSET); } #endif else { FASSERT(0); } return reg_val; } /** * @name: FGpioWriteRegDir * @msg: 向寄存器写入GPIO组的输入输出方向 * @return {*} * @param {uintptr} base_addr, GPIO控制器基地址 * @param {FGpioPortIndex} port, GPIO组, A/B * @param {u32} reg_val, GPIO组的输入输出方向, bit[8:0]有效 */ static void FGpioWriteRegDir(uintptr base_addr, const FGpioPortIndex port, const u32 reg_val) { if (FGPIO_PORT_A == port) { FGpioWriteReg32(base_addr, FGPIO_SWPORTA_DDR_OFFSET, reg_val); } #if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */ else if (FGPIO_PORT_B == port) { FGpioWriteReg32(base_addr, FGPIO_SWPORTB_DDR_OFFSET, reg_val); } #endif else { FASSERT(0); } return; } /** * @name: FGpioSetDirection * @msg: 设置GPIO引脚的输入输出方向 * @return {*} * @param {FGpioPin} *instance, GPIO控制器实例 * @param {FGpioDirection} dir, 待设置的GPIO的方向 * @note 初始化 GPIO 实例后使用此函数 */ void FGpioSetDirection(FGpioPin *const pin, FGpioDirection dir) { FASSERT(pin); FGpio *const instance = pin->instance; FASSERT(instance); FASSERT_MSG(instance->is_ready == FT_COMPONENT_IS_READY, "gpio instance not yet init !!!"); u32 reg_val; FGpioPinId index = pin->index; uintptr base_addr = instance->config.base_addr; reg_val = FGpioReadRegDir(base_addr, index.port); if (FGPIO_DIR_INPUT == dir) { reg_val &= ~BIT(index.pin); /* 0-Input */ } else if (FGPIO_DIR_OUTPUT == dir) { reg_val |= BIT(index.pin); /* 1-Output */ } else { FASSERT(0); } FGpioWriteRegDir(base_addr, index.port, reg_val); return; } /** * @name: FGpioGetDirection * @msg: 获取GPIO引脚的输入输出方向 * @return {FGpioDirection} GPIO引脚方向 * @param {FGpioPin} *pin, GPIO引脚实例 * @note 初始化 GPIO 实例后使用此函数 */ FGpioDirection FGpioGetDirection(FGpioPin *const pin) { FASSERT(pin); FGpio *const instance = pin->instance; FASSERT(instance); FASSERT(instance->is_ready == FT_COMPONENT_IS_READY); FGpioPinId index = pin->index; uintptr base_addr = instance->config.base_addr; u32 reg_val = FGpioReadRegDir(base_addr, index.port); return (BIT(index.pin) & reg_val) ? FGPIO_DIR_OUTPUT : FGPIO_DIR_INPUT; } /** * @name: FGpioReadRegVal * @msg: 获取GPIO组的输出寄存器值 * @return {u32} 输出寄存器值 bit[8:0]有效 * @param {uintptr} base_addr, GPIO控制器基地址 * @param {FGpioPortIndex} port, GPIO组 */ static u32 FGpioReadRegVal(uintptr base_addr, const FGpioPortIndex port) { u32 reg_val = 0; if (FGPIO_PORT_A == port) { reg_val = FGpioReadReg32(base_addr, FGPIO_SWPORTA_DR_OFFSET); } #if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */ else if (FGPIO_PORT_B == port) { reg_val = FGpioReadReg32(base_addr, FGPIO_SWPORTB_DR_OFFSET); } #endif else { FASSERT(0); } return reg_val; } /** * @name: FGpioWriteRegVal * @msg: 设置GPIO组的输出寄存器值 * @return {*} * @param {uintptr} base_addr, GPIO控制器基地址 * @param {FGpioPortIndex} port, GPIO组 * @param {u32} reg_val, 输出寄存器值 bit[8:0]有效 */ void FGpioWriteRegVal(uintptr base_addr, const FGpioPortIndex port, const u32 reg_val) { if (FGPIO_PORT_A == port) { FGpioWriteReg32(base_addr, FGPIO_SWPORTA_DR_OFFSET, reg_val); } #if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */ else if (FGPIO_PORT_B == port) { FGpioWriteReg32(base_addr, FGPIO_SWPORTB_DR_OFFSET, reg_val); } #endif else { FASSERT(0); } return; } /** * @name: FGpioSetOutputValue * @msg: 设置GPIO引脚的输出值 * @return {FError} FGPIO_SUCCESS 表示设置成功 * @param {FGpioPin} *pin, GPIO引脚实例 * @param {FGpioPinVal} output, GPIO引脚的输出值 * @note 初始化 GPIO 实例后使用此函数,先设置 GPIO 引脚为输出后调用此函数 */ FError FGpioSetOutputValue(FGpioPin *const pin, const FGpioPinVal output) { FASSERT(pin); FGpio *const instance = pin->instance; FASSERT(instance); FASSERT_MSG(instance->is_ready == FT_COMPONENT_IS_READY, "gpio instance not yet init !!!"); FGpioPinId index = pin->index; u32 base_addr = instance->config.base_addr; u32 reg_val; if (FGPIO_DIR_OUTPUT != FGpioGetDirection(pin)) { FGPIO_ERROR("need to set GPIO direction as OUTPUT first !!!"); return FGPIO_ERR_INVALID_STATE; } FGPIO_INFO("pin-%d at port %d", index.pin, index.port); reg_val = FGpioReadRegVal(base_addr, index.port); if (FGPIO_PIN_LOW == output) { reg_val &= ~BIT(index.pin); } else if (FGPIO_PIN_HIGH == output) { reg_val |= BIT(index.pin); } else { FASSERT(0); } FGPIO_INFO("output val 0x%x", reg_val); FGpioWriteRegVal(base_addr, index.port, reg_val); FGPIO_INFO("output val 0x%x", FGpioReadRegVal(base_addr, index.port)); return FGPIO_SUCCESS; } /** * @name: FGpioGetInputValue * @msg: 获取GPIO引脚的输入值 * @return {FGpioPinVal} 获取的输入值,高电平/低电平 * @param {FGpioPin} *instance, GPIO引脚实例 * @note 初始化 GPIO 实例后使用此函数,先设置 GPIO 引脚为输入后调用此函数 */ FGpioPinVal FGpioGetInputValue(FGpioPin *const pin) { FASSERT(pin); FGpio *const instance = pin->instance; FASSERT(instance); FASSERT(instance->is_ready == FT_COMPONENT_IS_READY); FGpioPinId index = pin->index; uintptr base_addr = instance->config.base_addr; u32 reg_val; if (FGPIO_DIR_INPUT != FGpioGetDirection(pin)) { FGPIO_ERROR("need to set GPIO direction as INPUT first !!!"); return FGPIO_PIN_LOW; } if (FGPIO_PORT_A == index.port) { reg_val = FGpioReadReg32(base_addr, FGPIO_EXT_PORTA_OFFSET); } #if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */ else if (FGPIO_PORT_B == index.port) { reg_val = FGpioReadReg32(base_addr, FGPIO_EXT_PORTB_OFFSET); } #endif else { FASSERT(0); } FGPIO_INFO("input val: 0x%x", reg_val); return (BIT(index.pin) & reg_val) ? FGPIO_PIN_HIGH : FGPIO_PIN_LOW; }