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

328 lines
10 KiB
C
Raw Normal View History

/*
* 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_intr.c
* Date: 2022-02-10 14:53:42
* LastEditTime: 2022-02-18 08:25:29
* Description:  This files is for GPIO interrupt function implementation
*
* 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-INTR"
#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: FGpioGetInterruptMask
* @msg: GPIO A组引脚的中断屏蔽位
* @return {*}
* @param {FGpio} *instance, GPIO控制器实例
* @param {u32} *mask, GPIO A组引脚中断屏蔽位
* @param {u32} *enabled, GPIO A组中断使能位
* @note A组所有Pin的中断屏蔽位和中断使能位
*/
void FGpioGetInterruptMask(FGpio *const instance, u32 *mask, u32 *enabled)
{
FASSERT(instance);
FASSERT(instance->is_ready == FT_COMPONENT_IS_READY);
uintptr base_addr = instance->config.base_addr;
if (NULL != mask)
{
*mask = FGpioReadReg32(base_addr, FGPIO_INTMASK_OFFSET);
}
if (NULL != enabled)
{
*enabled = FGpioReadReg32(base_addr, FGPIO_INTEN_OFFSET);
}
return;
}
/**
* @name: FGpioSetInterruptMask
* @msg: GPIO A组引脚的中断屏蔽位
* @return {*}
* @param {FGpioPin} *pin, GPIO引脚实例
* @param {boolean} enable, TRUE表示使能GPIO引脚中断FALSE表示去使能GPIO引脚中断
* @note index对应的引脚必须为A组引脚B组引脚不支持中断
*/
void FGpioSetInterruptMask(FGpioPin *const pin, boolean enable)
{
FASSERT(pin);
FGpio *const instance = pin->instance;
FASSERT(instance);
FASSERT(instance->is_ready == FT_COMPONENT_IS_READY);
uintptr base_addr = instance->config.base_addr;
u32 mask_bits = 0;
u32 enable_bits = 0;
FGpioPinId index = pin->index;
#if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */
if (FGPIO_PORT_B == index.port)
{
FGPIO_ERROR("None interrupt support for PORT-B !!!");
return;
}
#endif
if (FGPIO_DIR_OUTPUT == FGpioGetDirection(pin))
{
FGPIO_ERROR("None interrupt support for output GPIO !!!");
return;
}
FGpioGetInterruptMask(instance, &mask_bits, &enable_bits);
if (TRUE == enable)
{
mask_bits &= ~BIT(index.pin); /* not mask: 0 */
enable_bits |= BIT(index.pin); /* enable pin irq: 1 */
}
else
{
mask_bits |= BIT(index.pin); /* mask: 1 */
enable_bits &= ~BIT(index.pin); /* disable pin irq: 0 */
}
FGpioWriteReg32(base_addr, FGPIO_INTMASK_OFFSET, mask_bits);
FGpioWriteReg32(base_addr, FGPIO_INTEN_OFFSET, enable_bits);
return;
}
/**
* @name: FGpioGetInterruptType
* @msg: GPIO A组引脚的中断类型和中断极性
* @return {*}
* @param {FGpio} *instance, GPIO控制器实例
* @param {u32} *levels, GPIO A组引脚中断电平类型
* @param {u32} *polarity, GPIO A组引脚中断极性类型
* @note A组所有Pin的电平和极性
*/
void FGpioGetInterruptType(FGpio *const instance, u32 *levels, u32 *polarity)
{
FASSERT(instance);
FASSERT(instance->is_ready == FT_COMPONENT_IS_READY);
uintptr base_addr = instance->config.base_addr;
if (NULL != levels)
{
*levels = FGpioReadReg32(base_addr, FGPIO_INTTYPE_LEVEL_OFFSET);
}
if (NULL != polarity)
{
*polarity = FGpioReadReg32(base_addr, FGPIO_INTTYPE_LEVEL_OFFSET);
}
return;
}
/**
* @name: FGpioSetInterruptType
* @msg: GPIO引脚的中断类型
* @return {*}
* @param {FGpioPin} *pin, GPIO引脚实例
* @param {FGpioIrqType} type, GPIO引脚中断触发类型
* @note index对应的引脚必须为A组引脚B组引脚不支持中断
*/
void FGpioSetInterruptType(FGpioPin *const pin, const FGpioIrqType type)
{
FASSERT(pin);
FGpio *const instance = pin->instance;
FASSERT(instance);
FASSERT(instance->is_ready == FT_COMPONENT_IS_READY);
uintptr base_addr = instance->config.base_addr;
u32 level = 0;
u32 polarity = 0;
FGpioPinId index = pin->index;
#if defined(FGPIO_VERSION_1) /* FT2000-4, D2000 */
if (FGPIO_PORT_B == index.port)
{
FGPIO_ERROR("None interrupt support for PORT-B !!!");
return;
}
#endif
FGpioGetInterruptType(instance, &level, &polarity);
switch (type)
{
case FGPIO_IRQ_TYPE_EDGE_FALLING:
level |= BIT(index.pin); /* 边沿敏感型 */
polarity &= ~BIT(index.pin); /* 下降沿或低电平 */
break;
case FGPIO_IRQ_TYPE_EDGE_RISING:
level |= BIT(index.pin); /* 边沿敏感型 */
polarity |= BIT(index.pin); /* 上升沿或高电平 */
break;
case FGPIO_IRQ_TYPE_LEVEL_LOW:
level &= ~BIT(index.pin); /* 电平敏感型 */
polarity &= ~BIT(index.pin); /* 下降沿或低电平 */
break;
case FGPIO_IRQ_TYPE_LEVEL_HIGH:
level &= ~BIT(index.pin); /* 电平敏感型 */
polarity |= BIT(index.pin); /* 上升沿或高电平 */
break;
default:
break;
}
FGpioWriteReg32(base_addr, FGPIO_INTTYPE_LEVEL_OFFSET, level);
FGpioWriteReg32(base_addr, FGPIO_INT_POLARITY_OFFSET, polarity);
return;
}
/**
* @name: FGpioInterruptHandler
* @msg: GPIO中断处理函数
* @return {*}
* @param {s32} vector, 1
* @param {void} *param, 2
* @note Interrtup上使GPIO中断才能生效
*/
void FGpioInterruptHandler(s32 vector, void *param)
{
FGpio *const instance = (FGpio * const)param;
FGpioPin *pin = NULL;
FASSERT(instance);
int loop;
uintptr base_addr = instance->config.base_addr;
u32 status = FGpioReadReg32(base_addr, FGPIO_INTSTATUS_OFFSET);
u32 raw_status = FGpioReadReg32(base_addr, FGPIO_RAW_INTSTATUS_OFFSET);
#if defined(FGPIO_VERSION_2) /* E2000 gpio 3 ~ 5 */
FASSERT_MSG(FGPIO_WITH_PIN_IRQ < instance->config.instance_id, "handle interrupt through pin !!!")
#endif
FGPIO_INFO("status: 0x%x, raw_status: 0x%x", status, raw_status);
for (loop = FGPIO_PIN_0; loop < FGPIO_PIN_NUM; loop++)
{
if (status & BIT(loop))
{
pin = instance->pins[FGPIO_PORT_A][loop];
if (NULL == pin)
continue;
if (pin->irq_cb)
{
pin->irq_cb(0U, pin->irq_cb_params);
/* disable pin interrupt after triggered */
if (TRUE == pin->irq_one_time)
{
FGpioSetInterruptMask(pin, FALSE);
}
}
else
{
FGPIO_WARN("no irq handler callback for GPIO-%d-A-%d",
instance->config.instance_id,
loop);
}
}
}
/* clear interrupt status */
FGpioWriteReg32(base_addr, FGPIO_PORTA_EOI_OFFSET, status);
return;
}
#if defined(FGPIO_VERSION_2) /* E2000 GPIO 0 ~ 2 */
/**
* @name: FGpioPinInterruptHandler
* @msg: GPIO引脚中断处理函数
* @return {NONE}
* @param {s32} vector, 1
* @param {void} *param, 2
*/
void FGpioPinInterruptHandler(s32 vector, void *param)
{
FGpioPin *const pin = (FGpioPin * const)param;
FASSERT(pin);
FGpio *const instance = pin->instance;
FASSERT(instance);
uintptr base_addr = instance->config.base_addr;
u32 status = FGpioReadReg32(base_addr, FGPIO_INTSTATUS_OFFSET);
u32 raw_status = FGpioReadReg32(base_addr, FGPIO_RAW_INTSTATUS_OFFSET);
FGPIO_INFO("status: 0x%x, raw_status: 0x%x", status, raw_status);
if (pin->irq_cb)
{
pin->irq_cb(0U, pin->irq_cb_params);
/* disable pin interrupt after triggered */
if (TRUE == pin->irq_one_time)
{
FGpioSetInterruptMask(pin, FALSE);
}
}
else
{
FGPIO_WARN("no irq handler callback for GPIO-%d-A-%d",
pin->index.ctrl,
pin->index.pin);
}
/* clear interrupt status */
FGpioWriteReg32(base_addr, FGPIO_PORTA_EOI_OFFSET, status);
return;
}
#endif
/**
* @name: FGpioRegisterInterruptCB
* @msg: GPIO引脚中断回调函数
* @return {*}
* @param {FGpioPin} pin, GPIO引脚实例
* @param {FGpioInterruptCallback} cb, GPIO引脚中断回调函数
* @param {void} *cb_param, GPIO引脚中断回调函数输入参数
* @param {boolean} irq_one_time, TRUE表示引脚中断触发一次后自动关闭中断
* @note FGpioInterruptHandler中被调用
*/
void FGpioRegisterInterruptCB(FGpioPin *const pin, FGpioInterruptCallback cb, void *cb_param, boolean irq_one_time)
{
FASSERT(pin);
pin->irq_cb = cb;
pin->irq_cb_params = cb_param;
pin->irq_one_time = irq_one_time;
return;
}