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

328 lines
10 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.

This file contains Unicode characters that might be confused with other characters. 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_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;
}