328 lines
10 KiB
C
328 lines
10 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_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;
|
||
} |