460 lines
13 KiB
C
460 lines
13 KiB
C
/*
|
||
* 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;
|
||
} |