rt-thread/bsp/phytium/libraries/standalone/drivers/pin/fgpio/fgpio.c

460 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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;
}