rt-thread/bsp/phytium/libraries/drivers/drv_gpio.c

340 lines
10 KiB
C

/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Email: opensource_embedded@phytium.com.cn
*
* Change Logs:
* Date Author Notes
* 2023/7/24 liqiaozhong first add, support intr
*
*/
#include "rtconfig.h"
#include <rtthread.h>
#include <rtdevice.h>
#include "interrupt.h"
#define LOG_TAG "gpio_drv"
#include "drv_log.h"
#ifdef RT_USING_SMART
#include "ioremap.h"
#endif
#include <string.h>
#if defined(TARGET_E2000)
#include "fparameters.h"
#endif
#include "fkernel.h"
#include "fcpu_info.h"
#include "ftypes.h"
#include "fio_mux.h"
#include "board.h"
#include "fiopad.h"
#include "fgpio.h"
#include "drv_gpio.h"
/**************************** Type Definitions *******************************/
typedef void (*FGpioOpsIrqHandler)(s32 vector, void *param);
typedef struct
{
FGpioDirection direction;
boolean en_irq;
FGpioIrqType irq_type;
FGpioOpsIrqHandler irq_handler;
void *irq_args;
} FGpioOpsPinConfig;
typedef struct
{
FGpio ctrl;
FGpioPin pins[FGPIO_PORT_NUM][FGPIO_PIN_NUM];
FGpioOpsPinConfig pin_config[FGPIO_PORT_NUM][FGPIO_PIN_NUM];
boolean init_ok;
} FGpioOps;
/***************** Macros (Inline Functions) Definitions *********************/
#if defined(TARGET_E2000)
#define FGPIO_VERSION_2
#endif
/************************** Variable Definitions *****************************/
static FGpioOps gpio[FGPIO_NUM];
extern FIOPadCtrl iopad_ctrl;
/*******************************Api Functions*********************************/
static void FGpioOpsSetupCtrlIRQ(FGpio *ctrl)
{
u32 cpu_id;
u32 irq_num = ctrl->config.irq_num[0];
GetCpuId(&cpu_id);
LOG_D("In FGpioOpsSetupCtrlIRQ() -> cpu_id %d, irq_num %d\r\n", cpu_id, irq_num);
rt_hw_interrupt_set_target_cpus(irq_num, cpu_id);
rt_hw_interrupt_set_priority(irq_num, ctrl->config.irq_priority); /* setup interrupt */
rt_hw_interrupt_install(irq_num, FGpioInterruptHandler, ctrl, NULL); /* register intr handler */
rt_hw_interrupt_umask(irq_num);
return;
}
/* setup gpio pin interrupt */
static void FGpioOpsSetupPinIRQ(FGpio *ctrl, FGpioPin *const pin, FGpioOpsPinConfig *config)
{
u32 cpu_id;
u32 irq_num = ctrl->config.irq_num[pin->index.pin];
GetCpuId(&cpu_id);
LOG_D("in FGpioOpsSetupPinIRQ() -> cpu_id %d, irq_num %d", cpu_id, irq_num);
rt_hw_interrupt_set_target_cpus(irq_num, cpu_id);
rt_hw_interrupt_set_priority(irq_num, ctrl->config.irq_priority); /* setup interrupt */
rt_hw_interrupt_install(irq_num, FGpioInterruptHandler, config->irq_args, NULL); /* register intr handler */
rt_hw_interrupt_umask(irq_num);
return;
}
/* on E2000, if u want use GPIO-4-11, set pin = FGPIO_OPS_PIN_INDEX(4, 0, 11) */
static void drv_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
{
u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin);
u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin);
u32 pin_id = FGPIO_OPS_PIN_ID(pin);
FGpioPinId gpio_pin_id;
FError err = FGPIO_SUCCESS;
FGpio *instance = &gpio[ctrl_id].ctrl;
FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id];
FGpioOpsPinConfig *pin_config = &gpio[ctrl_id].pin_config[port_id][pin_id];
if (ctrl_id >= FGPIO_NUM)
{
LOG_E("ctrl_id too large!!!");
return;
}
if (FALSE == gpio[ctrl_id].init_ok) /* init ctrl if needed */
{
FGpioConfig input_cfg = *FGpioLookupConfig(ctrl_id);
memset(instance, 0, sizeof(*instance));
#ifdef RT_USING_SMART
input_cfg.base_addr = (uintptr)rt_ioremap((void *)input_cfg.base_addr, 0x1000);
#endif
err = FGpioCfgInitialize(instance, &input_cfg);
if (FGPIO_SUCCESS != err)
{
LOG_E("Ctrl: %d init fail!!!\n", ctrl_id);
return;
}
gpio[ctrl_id].init_ok = TRUE;
}
FIOPadSetGpioMux(ctrl_id, pin_id);
if (FT_COMPONENT_IS_READY == pin_instance->is_ready)
{
FGpioPinDeInitialize(pin_instance);
}
gpio_pin_id.ctrl = ctrl_id;
gpio_pin_id.port = port_id;
gpio_pin_id.pin = pin_id;
err = FGpioPinInitialize(instance, pin_instance, gpio_pin_id);
if (FGPIO_SUCCESS != err)
{
LOG_E("Pin %d-%c-%d init fail!!!\n",
ctrl_id,
port_id == 0 ? 'a' : 'b',
pin_id);
return;
}
switch (mode)
{
case PIN_MODE_OUTPUT:
pin_config->direction = FGPIO_DIR_OUTPUT;
pin_config->en_irq = FALSE;
break;
case PIN_MODE_INPUT:
pin_config->direction = FGPIO_DIR_INPUT;
pin_config->en_irq = TRUE;
pin_config->irq_type = FGPIO_IRQ_TYPE_EDGE_RISING;
break;
default:
rt_kprintf("Not support mode %d!!!\n", mode);
break;
}
FGpioSetDirection(pin_instance, pin_config->direction);
rt_kprintf("Init GPIO-%d-%c-%d as an %sput pin\r\n",
ctrl_id,
port_id,
pin_id, pin_config->direction == FGPIO_DIR_OUTPUT ? "out" : "in");
}
void drv_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value)
{
u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin);
u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin);
u32 pin_id = FGPIO_OPS_PIN_ID(pin);
FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id];
if (pin_instance == RT_NULL)
{
rt_kprintf("Pin %d-%c-%d not set mode\n",
ctrl_id,
port_id == 0 ? 'a' : 'b',
pin_id);
return;
}
FGpioSetOutputValue(pin_instance, (value == PIN_HIGH) ? FGPIO_PIN_HIGH : FGPIO_PIN_LOW);
}
rt_ssize_t drv_pin_read(struct rt_device *device, rt_base_t pin)
{
u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin);
u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin);
u32 pin_id = FGPIO_OPS_PIN_ID(pin);
FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id];
if (pin_instance == RT_NULL)
{
return -RT_EINVAL;
}
return FGpioGetInputValue(pin_instance) == FGPIO_PIN_HIGH ? PIN_HIGH : PIN_LOW;
}
rt_err_t drv_pin_attach_irq(struct rt_device *device, rt_base_t pin,
rt_uint8_t mode, void (*hdr)(void *args), void *args)
{
u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin);
u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin);
u32 pin_id = FGPIO_OPS_PIN_ID(pin);
rt_base_t level;
FGpio *instance = &gpio[ctrl_id].ctrl;
FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id];
FGpioOpsPinConfig *pin_config = &gpio[ctrl_id].pin_config[port_id][pin_id];
level = rt_hw_interrupt_disable();
pin_config->irq_handler = (FGpioOpsIrqHandler)hdr;
pin_config->irq_args = args;
if (pin_instance == RT_NULL)
{
LOG_E("GPIO%d-%c-%d not init yet.\n", ctrl_id, port_id == 0 ? 'a' : 'b', pin_id);
return -RT_ERROR;
}
if (pin_config->en_irq)
{
FGpioSetInterruptMask(pin_instance, FALSE);
FGpioPinId pin_of_ctrl =
{
.ctrl = ctrl_id,
.port = FGPIO_PORT_A,
.pin = FGPIO_PIN_0
};
if (FGPIO_IRQ_BY_CONTROLLER == FGpioGetPinIrqSourceType(pin_of_ctrl)) /* setup for ctrl report interrupt */
{
FGpioOpsSetupCtrlIRQ(instance);
LOG_I("GPIO-%d report irq by controller", ctrl_id);
}
else if (FGPIO_IRQ_BY_PIN == FGpioGetPinIrqSourceType(pin_of_ctrl))
{
FGpioOpsSetupPinIRQ(instance, pin_instance, pin_config);
LOG_I("GPIO-%d report irq by pin", ctrl_id);
}
switch (mode)
{
case PIN_IRQ_MODE_RISING:
pin_config->irq_type = FGPIO_IRQ_TYPE_EDGE_RISING;
break;
case PIN_IRQ_MODE_FALLING:
pin_config->irq_type = FGPIO_IRQ_TYPE_EDGE_FALLING;
break;
case PIN_IRQ_MODE_LOW_LEVEL:
pin_config->irq_type = FGPIO_IRQ_TYPE_LEVEL_LOW;
break;
case PIN_IRQ_MODE_HIGH_LEVEL:
pin_config->irq_type = FGPIO_IRQ_TYPE_LEVEL_HIGH;
break;
default:
LOG_E("Do not spport irq_mode: %d\n", mode);
break;
}
FGpioSetInterruptType(pin_instance, pin_config->irq_type);
FGpioRegisterInterruptCB(pin_instance, pin_config->irq_handler,
pin_config->irq_args, TRUE); /* register intr callback */
}
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t drv_pin_detach_irq(struct rt_device *device, rt_base_t pin)
{
u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin);
u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin);
u32 pin_id = FGPIO_OPS_PIN_ID(pin);
rt_base_t level;
FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id];
FGpioOpsPinConfig *pin_config = &gpio[ctrl_id].pin_config[port_id][pin_id];
if (pin_instance == RT_NULL)
{
rt_kprintf("pin %d-%c-%d not set mode\n",
ctrl_id,
port_id == 0 ? 'a' : 'b',
pin_id);
return -RT_ERROR;
}
level = rt_hw_interrupt_disable();
pin_config->irq_handler = RT_NULL;
pin_config->irq_args = RT_NULL;
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t drv_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
{
u32 ctrl_id = FGPIO_OPS_PIN_CTRL_ID(pin);
u32 port_id = FGPIO_OPS_PIN_PORT_ID(pin);
u32 pin_id = FGPIO_OPS_PIN_ID(pin);
FGpioPin *pin_instance = &gpio[ctrl_id].pins[port_id][pin_id];
if (pin_instance == RT_NULL)
{
rt_kprintf("Pin %d-%c-%d not set mode\n",
ctrl_id,
port_id == 0 ? 'a' : 'b',
pin_id);
return -RT_ERROR;
}
FGpioSetInterruptMask(pin_instance, enabled);
return RT_EOK;
}
const struct rt_pin_ops drv_pin_ops =
{
.pin_mode = drv_pin_mode,
.pin_write = drv_pin_write,
.pin_read = drv_pin_read,
.pin_attach_irq = drv_pin_attach_irq,
.pin_detach_irq = drv_pin_detach_irq,
.pin_irq_enable = drv_pin_irq_enable,
.pin_get = RT_NULL
};
int ft_pin_init(void)
{
rt_err_t ret = RT_EOK;
ret = rt_device_pin_register("pin", &drv_pin_ops, RT_NULL);
rt_kprintf("Register pin with return: %d\n", ret);
return ret;
}
INIT_DEVICE_EXPORT(ft_pin_init);