rt-thread-official/bsp/nuvoton/libraries/ma35/rtt_port/drv_whc.c

269 lines
6.4 KiB
C

/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-10-5 Wayne First version
*
******************************************************************************/
#include <rtconfig.h>
#if defined(BSP_USING_WHC)
#include <rthw.h>
#include "drv_whc.h"
#include "drv_sys.h"
#include "nu_bitutil.h"
/* Private define ---------------------------------------------------------------*/
enum
{
WHC_START = -1,
#if defined(BSP_USING_WHC0)
WHC0_IDX,
#endif
#if defined(BSP_USING_WHC1)
WHC1_IDX,
#endif
WHC_CNT
};
/* Private typedef --------------------------------------------------------------*/
struct nu_whc_priv
{
char *name;
WHC_T *base;
IRQn_Type irqn;
uint32_t rstidx;
rt_device_t psChDev[WHC_CH];
};
typedef struct nu_whc_priv *nu_whc_priv_t;
struct nu_whc
{
struct rt_device dev;
nu_whc_priv_t psPriv;
uint32_t u32WhcChNum;
void *pvTxBuf;
};
typedef struct nu_whc *nu_whc_t;
static struct nu_whc_priv nu_whc_priv_arr [] =
{
#if defined(BSP_USING_WHC0)
{
.name = "whc0",
.base = WHC0,
.irqn = WHC0_IRQn,
.rstidx = WHC0_RST,
},
#endif
#if defined(BSP_USING_WHC1)
{
.name = "whc1",
.base = WHC1,
.irqn = WHC1_IRQn,
.rstidx = WHC1_RST,
},
#endif
}; /* nu_whc_priv */
/**
* All WHC interrupt service routine
*/
static void nu_whc_isr(int vector, void *param)
{
nu_whc_priv_t psNuWhcPriv = (nu_whc_priv_t)param;
volatile uint32_t vu32Intsts = psNuWhcPriv->base->INTSTS;
uint32_t irqidx;
while ((irqidx = nu_ctz(vu32Intsts)) != 32)
{
uint32_t u32IsrBitMask = 1 << irqidx ;
switch (irqidx)
{
/* Process TX-complete interrupt event */
case WHC_INTSTS_TX0IF_Pos:
case WHC_INTSTS_TX1IF_Pos:
case WHC_INTSTS_TX2IF_Pos:
case WHC_INTSTS_TX3IF_Pos:
{
uint32_t u32ChNum = irqidx - WHC_INTSTS_TX0IF_Pos;
rt_device_t device = psNuWhcPriv->psChDev[u32ChNum];
nu_whc_t psWhc = (nu_whc_t)device;
if (device->tx_complete && psWhc->pvTxBuf)
{
device->tx_complete(device, psWhc->pvTxBuf);
psWhc->pvTxBuf = RT_NULL;
}
}
break;
/* Process RX-indicate interrupt event */
case WHC_INTSTS_RX0IF_Pos:
case WHC_INTSTS_RX1IF_Pos:
case WHC_INTSTS_RX2IF_Pos:
case WHC_INTSTS_RX3IF_Pos:
{
uint32_t u32ChNum = irqidx - WHC_INTSTS_RX0IF_Pos;
rt_device_t device = psNuWhcPriv->psChDev[u32ChNum];
if (device->rx_indicate)
{
device->rx_indicate(device, 1);
}
}
break;
default:
break;
}
/* Clear interrupt bit. */
WHC_CLR_INT_FLAG(psNuWhcPriv->base, u32IsrBitMask);
/* Clear served bit */
vu32Intsts &= ~(u32IsrBitMask);
}
}
rt_err_t nu_whc_init(rt_device_t dev)
{
return RT_EOK;
}
rt_err_t nu_whc_open(rt_device_t dev, rt_uint16_t oflag)
{
nu_whc_t psWhc = (nu_whc_t)dev;
nu_whc_priv_t psWhcPriv = psWhc->psPriv;
WHC_ENABLE_INT(psWhcPriv->base, WHC_INTEN_TX0IEN_Msk << psWhc->u32WhcChNum |
WHC_INTEN_RX0IEN_Msk << psWhc->u32WhcChNum);
return RT_EOK;
}
rt_err_t nu_whc_close(rt_device_t dev)
{
nu_whc_t psWhc = (nu_whc_t)dev;
nu_whc_priv_t psWhcPriv = psWhc->psPriv;
WHC_DISABLE_INT(psWhcPriv->base, WHC_INTEN_TX0IEN_Msk << psWhc->u32WhcChNum |
WHC_INTEN_RX0IEN_Msk << psWhc->u32WhcChNum);
return RT_EOK;
}
rt_size_t nu_whc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
nu_whc_t psWhc = (nu_whc_t)dev;
nu_whc_priv_t psWhcPriv = psWhc->psPriv;
if ((sizeof(nu_whc_msg) != size) || ((uint32_t)buffer & 0x3))
goto exit_nu_whc_read;
if (WHC_Recv(psWhcPriv->base, psWhc->u32WhcChNum, (uint32_t *)buffer) < 0)
goto exit_nu_whc_read;
return size;
exit_nu_whc_read:
return 0;
}
rt_size_t nu_whc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
nu_whc_t psWhc = (nu_whc_t)dev;
nu_whc_priv_t psWhcPriv = psWhc->psPriv;
if ((sizeof(nu_whc_msg) != size) || ((uint32_t)buffer & 0x3))
goto exit_nu_whc_write;
psWhc->pvTxBuf = (void *)buffer;
if (WHC_Send(psWhcPriv->base, psWhc->u32WhcChNum, (uint32_t *)buffer) < 0)
goto exit_nu_whc_write;
return size;
exit_nu_whc_write:
return 0;
}
rt_err_t nu_whc_control(rt_device_t dev, int cmd, void *args)
{
return RT_EOK;
}
static rt_err_t whc_register(nu_whc_priv_t psWhcPriv)
{
int i;
char szDevName[16];
for (i = 0; i < WHC_CH; i++)
{
nu_whc_t psWhc;
rt_device_t device = rt_device_create(RT_Device_Class_Miscellaneous, sizeof(struct nu_whc) - sizeof(struct rt_device));
RT_ASSERT(device);
psWhcPriv->psChDev[i] = device;
psWhc = (nu_whc_t)device;
psWhc->psPriv = psWhcPriv;
psWhc->u32WhcChNum = i;
device->type = RT_Device_Class_Miscellaneous;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = RT_NULL;
#else
device->init = nu_whc_init;
device->open = nu_whc_open;
device->close = nu_whc_close;
device->read = nu_whc_read;
device->write = nu_whc_write;
device->control = nu_whc_control;
#endif
device->user_data = (void *)psWhcPriv;
rt_snprintf(szDevName, sizeof(szDevName), "%s-%d", psWhcPriv->name, psWhc->u32WhcChNum);
RT_ASSERT(rt_device_register(device, szDevName, RT_DEVICE_FLAG_STANDALONE) == RT_EOK);
}
return RT_EOK;
}
/**
* Hardware Sem Initialization
*/
int rt_hw_whc_init(void)
{
int i;
for (i = (WHC_START + 1); i < WHC_CNT; i++)
{
nu_whc_priv_t psNuWhcPriv = &nu_whc_priv_arr[i];
whc_register(psNuWhcPriv);
rt_hw_interrupt_install(psNuWhcPriv->irqn, nu_whc_isr, psNuWhcPriv, psNuWhcPriv->name);
rt_hw_interrupt_umask(nu_whc_priv_arr[i].irqn);
}
return 0;
}
INIT_BOARD_EXPORT(rt_hw_whc_init);
#endif //#if defined(BSP_USING_WHC)