xiuos/board/k210-emulator/third_party_driver/gpio/connect_gpio.c

331 lines
8.5 KiB
C

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-19 ZYH first version
*/
/**
* @file connect_gpio.c
* @brief support gpio function using bus driver framework
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
/*************************************************
File name: connect_gpio.c
Description: support gpio configure and register to bus framework
Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_gpio.c for references
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification: add bus driver framework support for gpio
*************************************************/
#include <xiuos.h>
#include <device.h>
#include <fpioa.h>
#include <gpiohs.h>
#include "drv_io_config.h"
#include <plic.h>
#include <utils.h>
#include "connect_gpio.h"
#define FUNC_GPIOHS(n) (FUNC_GPIOHS0 + n)
static int pin_alloc_table[FPIOA_NUM_IO];
static uint32_t free_pin = 0;
static int AllocPinChannel(x_base pin_index)
{
if (free_pin == 31) {
SYS_ERR("no free gpiohs channel to alloc");
return -1;
}
if (pin_alloc_table[pin_index] != -1) {
SYS_WARN("already alloc gpiohs channel for pin %d", pin_index);
return pin_alloc_table[pin_index];
}
pin_alloc_table[pin_index] = free_pin;
free_pin++;
FpioaSetFunction(pin_index, FUNC_GPIOHS(pin_alloc_table[pin_index]));
return pin_alloc_table[pin_index];
}
static int GetPinChannel(x_base pin_index)
{
return pin_alloc_table[pin_index];
}
static uint32 GpioConfigMode(int mode, uint8_t pin_channel)
{
switch (mode)
{
case GPIO_CFG_OUTPUT:
gpiohs_set_drive_mode(pin_channel, GPIO_DM_OUTPUT);
break;
case GPIO_CFG_INPUT:
gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT);
break;
case GPIO_CFG_INPUT_PULLUP:
gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT_PULL_UP);
break;
case GPIO_CFG_INPUT_PULLDOWN:
gpiohs_set_drive_mode(pin_channel, GPIO_DM_INPUT_PULL_DOWN);
break;
case GPIO_CFG_OUTPUT_OD:
break;
default:
break;
}
return EOK;
}
static struct
{
void (*hdr)(void *args);
void *args;
GpioPinEdgeT edge;
} IrqTable[32];
static void pin_irq(int vector, void *param)
{
int pin_channel = vector - IRQN_GPIOHS0_INTERRUPT;
if (IrqTable[pin_channel].edge & GPIO_PE_FALLING) {
set_gpio_bit(gpiohs->fall_ie.u32, pin_channel, 0);
set_gpio_bit(gpiohs->fall_ip.u32, pin_channel, 1);
set_gpio_bit(gpiohs->fall_ie.u32, pin_channel, 1);
}
if (IrqTable[pin_channel].edge & GPIO_PE_RISING) {
set_gpio_bit(gpiohs->rise_ie.u32, pin_channel, 0);
set_gpio_bit(gpiohs->rise_ip.u32, pin_channel, 1);
set_gpio_bit(gpiohs->rise_ie.u32, pin_channel, 1);
}
if (IrqTable[pin_channel].edge & GPIO_PE_LOW) {
set_gpio_bit(gpiohs->low_ie.u32, pin_channel, 0);
set_gpio_bit(gpiohs->low_ip.u32, pin_channel, 1);
set_gpio_bit(gpiohs->low_ie.u32, pin_channel, 1);
}
if (IrqTable[pin_channel].edge & GPIO_PE_HIGH) {
set_gpio_bit(gpiohs->high_ie.u32, pin_channel, 0);
set_gpio_bit(gpiohs->high_ip.u32, pin_channel, 1);
set_gpio_bit(gpiohs->high_ie.u32, pin_channel, 1);
}
if (IrqTable[pin_channel].hdr) {
IrqTable[pin_channel].hdr(IrqTable[pin_channel].args);
}
}
static uint32 GpioIrqRegister(int32 pin_channel, int32 mode, void (*hdr)(void *args), void *args)
{
IrqTable[pin_channel].hdr = hdr;
IrqTable[pin_channel].args = args;
switch (mode)
{
case GPIO_IRQ_EDGE_RISING:
IrqTable[pin_channel].edge = GPIO_PE_RISING;
break;
case GPIO_IRQ_EDGE_FALLING:
IrqTable[pin_channel].edge = GPIO_PE_FALLING;
break;
case GPIO_IRQ_EDGE_BOTH:
IrqTable[pin_channel].edge = GPIO_PE_BOTH;
break;
case GPIO_IRQ_LEVEL_HIGH:
IrqTable[pin_channel].edge = GPIO_PE_LOW;
break;
case GPIO_IRQ_LEVEL_LOW:
IrqTable[pin_channel].edge = GPIO_PE_HIGH;
break;
default:
break;
}
gpiohs_set_pin_edge(pin_channel, IrqTable[pin_channel].edge);
isrManager.done->registerIrq(IRQN_GPIOHS0_INTERRUPT + pin_channel, pin_irq, NONE);
return EOK;
}
static uint32 GpioIrqFree(int32 pin_channel)
{
IrqTable[pin_channel].hdr = NONE;
IrqTable[pin_channel].args = NONE;
return EOK;
}
static uint32 GpioIrqEnable(int32 pin_channel)
{
isrManager.done->enableIrq(IRQN_GPIOHS0_INTERRUPT + pin_channel);
return EOK;
}
static uint32 GpioIrqDisable(int32 pin_channel)
{
isrManager.done->disableIrq(IRQN_GPIOHS0_INTERRUPT + pin_channel);
return EOK;
}
static uint32 PinConfigure(struct PinParam *param)
{
NULL_PARAM_CHECK(param);
int ret = EOK;
int pin_channel = GetPinChannel(param->pin);
if (pin_channel == -1) {
pin_channel = AllocPinChannel(param->pin);
if (pin_channel == -1) {
return ERROR;
}
}
switch (param->cmd)
{
case GPIO_CONFIG_MODE:
GpioConfigMode(param->mode, pin_channel);
break;
case GPIO_IRQ_REGISTER:
ret = GpioIrqRegister(pin_channel,param->irq_set.irq_mode,param->irq_set.hdr,param->irq_set.args);
break;
case GPIO_IRQ_FREE:
ret = GpioIrqFree(pin_channel);
break;
case GPIO_IRQ_ENABLE:
ret = GpioIrqEnable(pin_channel);
break;
case GPIO_IRQ_DISABLE:
ret = GpioIrqDisable(pin_channel);
break;
default:
ret = -EINVALED;
break;
}
return ret;
}
static uint32 GpioDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
x_err_t ret = EOK;
struct PinParam *param;
switch (configure_info->configure_cmd)
{
case OPE_CFG:
param = (struct PinParam *)configure_info->private_data;
ret = PinConfigure(param);
break;
default:
break;
}
return ret;
}
uint32 PinWrite(void *dev, struct BusBlockWriteParam *write_param)
{
NULL_PARAM_CHECK(dev);
NULL_PARAM_CHECK(write_param);
struct PinStat *pinstat = (struct PinStat *)write_param->buffer;
int pin_channel = GetPinChannel(pinstat->pin);
if (pin_channel == -1) {
SYS_ERR("pin %d not set mode", pinstat->pin);
return ERROR;
}
gpiohs_set_pin(pin_channel, pinstat->val == GPIO_HIGH ? GPIO_PV_HIGH : GPIO_PV_LOW);
}
uint32 PinRead(void *dev, struct BusBlockReadParam *read_param)
{
NULL_PARAM_CHECK(dev);
NULL_PARAM_CHECK(read_param);
struct PinStat *pinstat = (struct PinStat *)read_param->buffer;
int pin_channel = GetPinChannel(pinstat->pin);
if (pin_channel == -1) {
SYS_ERR("pin %d not set mode", pinstat->pin);
return ERROR;
}
if (gpiohs_get_pin(pin_channel) == GPIO_PV_HIGH){
pinstat->val = GPIO_HIGH;
return GPIO_HIGH;
} else {
pinstat->val = GPIO_LOW;
return GPIO_LOW;
}
}
static const struct PinDevDone dev_done =
{
.open = NONE,
.close = NONE,
.write = PinWrite,
.read = PinRead,
};
int HwGpioInit(void)
{
x_err_t ret = EOK;
static struct PinBus pin;
memset(pin_alloc_table, -1, sizeof pin_alloc_table);
free_pin = GPIO_ALLOC_START;
ret = PinBusInit(&pin, PIN_BUS_NAME);
if (ret != EOK) {
KPrintf("gpio bus init error %d\n", ret);
return ERROR;
}
static struct PinDriver drv;
drv.configure = &GpioDrvConfigure;
ret = PinDriverInit(&drv, PIN_DRIVER_NAME, NONE);
if (ret != EOK) {
KPrintf("pin driver init error %d\n", ret);
return ERROR;
}
ret = PinDriverAttachToBus(PIN_DRIVER_NAME, PIN_BUS_NAME);
if (ret != EOK) {
KPrintf("pin driver attach error %d\n", ret);
return ERROR;
}
static struct PinHardwareDevice dev;
dev.dev_done = &dev_done;
ret = PinDeviceRegister(&dev, NONE, PIN_DEVICE_NAME);
if (ret != EOK) {
KPrintf("pin device register error %d\n", ret);
return ERROR;
}
ret = PinDeviceAttachToBus(PIN_DEVICE_NAME, PIN_BUS_NAME);
if (ret != EOK) {
KPrintf("pin device register error %d\n", ret);
return ERROR;
}
return ret;
}