727 lines
17 KiB
C
727 lines
17 KiB
C
|
|
/**
|
|||
|
|
* @file hguart_v4.c
|
|||
|
|
* @author bxd
|
|||
|
|
* @brief simple uart
|
|||
|
|
* @version
|
|||
|
|
* TXW81X
|
|||
|
|
* @date 2023-08-02
|
|||
|
|
*
|
|||
|
|
* @copyright Copyright (c) 2023
|
|||
|
|
*
|
|||
|
|
*/
|
|||
|
|
#include "typesdef.h"
|
|||
|
|
#include "list.h"
|
|||
|
|
#include "errno.h"
|
|||
|
|
#include "dev.h"
|
|||
|
|
#include "osal/irq.h"
|
|||
|
|
#include "osal/semaphore.h"
|
|||
|
|
#include "osal/mutex.h"
|
|||
|
|
#include "osal/string.h"
|
|||
|
|
#include "hal/uart.h"
|
|||
|
|
#include "hal/gpio.h"
|
|||
|
|
#include "dev/uart/hguart_v4.h"
|
|||
|
|
#include "hguart_v4_hw.h"
|
|||
|
|
|
|||
|
|
|
|||
|
|
#define SIMPLE_UART_LOCK(mutex, flag)\
|
|||
|
|
do{\
|
|||
|
|
if(flag){\
|
|||
|
|
os_mutex_lock(mutex, osWaitForever);\
|
|||
|
|
}\
|
|||
|
|
}while(0);
|
|||
|
|
|
|||
|
|
#define SIMPLE_UART_UNLOCK(mutex, flag)\
|
|||
|
|
do{\
|
|||
|
|
if(flag){\
|
|||
|
|
os_mutex_unlock(mutex);\
|
|||
|
|
}\
|
|||
|
|
}while(0);
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
/**********************************************************************************/
|
|||
|
|
/* UART LOW LAYER FUNCTION */
|
|||
|
|
/**********************************************************************************/
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_set_dma(struct hguart_v4 *dev, uint32 enable)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
if (enable) {
|
|||
|
|
dev->use_dma = 1;
|
|||
|
|
} else {
|
|||
|
|
dev->use_dma = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_dma_rx_config(struct hguart_v4_hw *p_uart, uint8 status)
|
|||
|
|
{
|
|||
|
|
uint32 _dmacon = p_uart->DMACON;
|
|||
|
|
uint32 flag = 0;
|
|||
|
|
|
|||
|
|
if (status) {
|
|||
|
|
_dmacon = 0x5;
|
|||
|
|
} else {
|
|||
|
|
_dmacon = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*!
|
|||
|
|
* fix: kick 2 times to counteract an unnecessary rx dma done
|
|||
|
|
*/
|
|||
|
|
if (p_uart->CON & LL_SIMPLE_UART_CON_DMA_IE) {
|
|||
|
|
p_uart->CON &=~ LL_SIMPLE_UART_CON_DMA_IE;
|
|||
|
|
flag = 1;
|
|||
|
|
//printf("<%x>", *(uint32 *)(0x40004b70));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
p_uart->DMACON = _dmacon;
|
|||
|
|
|
|||
|
|
__NOP();__NOP();__NOP();__NOP();
|
|||
|
|
|
|||
|
|
//printf("<%x>", *(uint32 *)(0x40004b70));
|
|||
|
|
|
|||
|
|
//clear rx done pending
|
|||
|
|
p_uart->CON |= LL_SIMPLE_UART_CON_CLRDMAPEND;
|
|||
|
|
|
|||
|
|
//kick again
|
|||
|
|
p_uart->DMACON = _dmacon;
|
|||
|
|
|
|||
|
|
__NOP();__NOP();__NOP();__NOP();
|
|||
|
|
|
|||
|
|
//printf("<%x>", *(uint32 *)(0x40004b70));
|
|||
|
|
|
|||
|
|
//clear rx done pending
|
|||
|
|
p_uart->CON |= LL_SIMPLE_UART_CON_CLRDMAPEND;
|
|||
|
|
|
|||
|
|
//printf("<%x>", *(uint32 *)(0x40004b70));
|
|||
|
|
|
|||
|
|
if (flag) {
|
|||
|
|
flag = 0;
|
|||
|
|
p_uart->CON |= LL_SIMPLE_UART_CON_DMA_IE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_dma_tx_config(struct hguart_v4_hw *p_uart, uint8 status)
|
|||
|
|
{
|
|||
|
|
uint32 _dmacon = p_uart->DMACON;
|
|||
|
|
|
|||
|
|
if (status) {
|
|||
|
|
_dmacon = 0xA;
|
|||
|
|
} else {
|
|||
|
|
_dmacon = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
p_uart->DMACON = _dmacon;
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_set_time_out(struct hguart_v4_hw *p_uart, uint32 time_bit, uint32 enable)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
if (enable) {
|
|||
|
|
p_uart->CON |= LL_SIMPLE_UART_CON_TO_EN;
|
|||
|
|
|
|||
|
|
p_uart->TOCON = LL_SIMPLE_UART_TOCON(time_bit);
|
|||
|
|
} else {
|
|||
|
|
p_uart->CON &=~ LL_SIMPLE_UART_CON_TO_EN;
|
|||
|
|
p_uart->TOCON = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/**********************************************************************************/
|
|||
|
|
/* UART ATTCH FUNCTION */
|
|||
|
|
/**********************************************************************************/
|
|||
|
|
static int32 hguart_v4_open(struct uart_device *uart, uint32 baudrate) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if (dev->opened) {
|
|||
|
|
if (!dev->dsleep) {
|
|||
|
|
return -EBUSY;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* pin config */
|
|||
|
|
if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* reg config */
|
|||
|
|
hw->BAUD = (peripheral_clock_get(HG_APB0_PT_UART4) / baudrate) - 1;
|
|||
|
|
hw->CON = LL_SIMPLE_UART_CON_UARTEN;
|
|||
|
|
|
|||
|
|
dev->opened = 1;
|
|||
|
|
dev->irq_dma_rx = 0;
|
|||
|
|
dev->irq_dma_tx = 0;
|
|||
|
|
dev->use_dma = 0;
|
|||
|
|
dev->dsleep = 0;
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_close(struct uart_device *uart) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if (!dev->opened) {
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
irq_disable(dev->irq_num );
|
|||
|
|
pin_func(dev->dev.dev.dev_id, 0);
|
|||
|
|
hw->CON &= ~ LL_SIMPLE_UART_CON_UARTEN;
|
|||
|
|
|
|||
|
|
dev->opened = 0;
|
|||
|
|
dev->irq_dma_rx = 0;
|
|||
|
|
dev->irq_dma_tx = 0;
|
|||
|
|
dev->use_dma = 0;
|
|||
|
|
dev->dsleep = 0;
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_putc(struct uart_device *uart, int8 value) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SIMPLE_UART_LOCK(&dev->mutex_tx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
if (dev->opened && (hw->CON & LL_SIMPLE_UART_CON_UARTEN)) {
|
|||
|
|
while(!(hw->CON & LL_SIMPLE_UART_CON_TXBUFEMPTY));
|
|||
|
|
hw->DATA = value;
|
|||
|
|
SIMPLE_UART_UNLOCK(&dev->mutex_tx, dev->debug_uart);
|
|||
|
|
return RET_OK;
|
|||
|
|
} else {
|
|||
|
|
SIMPLE_UART_UNLOCK(&dev->mutex_tx, dev->debug_uart);
|
|||
|
|
return -EIO;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static uint8 hguart_v4_getc(struct uart_device *uart) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SIMPLE_UART_LOCK(&dev->mutex_rx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
while(!(hw->CON & LL_SIMPLE_UART_CON_RXBUFNOTEMPTY));
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_CLRRXDONE;
|
|||
|
|
|
|||
|
|
SIMPLE_UART_UNLOCK(&dev->mutex_rx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
return hw->DATA;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_rs485_de_set(void)
|
|||
|
|
{
|
|||
|
|
if(PIN_UART4_DE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART4_DE, 1);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(PIN_UART5_DE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART5_DE, 1);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_rs485_de_reset(void)
|
|||
|
|
{
|
|||
|
|
if(PIN_UART4_DE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART4_DE, 0);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(PIN_UART5_DE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART5_DE, 0);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_rs485_re_set(void)
|
|||
|
|
{
|
|||
|
|
if(PIN_UART4_RE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART4_RE, 1);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(PIN_UART5_RE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART5_RE, 1);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_rs485_re_reset(void)
|
|||
|
|
{
|
|||
|
|
if(PIN_UART4_RE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART4_RE, 0);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(PIN_UART5_RE != 255) {
|
|||
|
|
gpio_set_val(PIN_UART5_RE, 0);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_puts(struct uart_device *uart, uint8 *buf, uint32 size) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
uint32 i = 0;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SIMPLE_UART_LOCK(&dev->mutex_tx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
if (dev->use_dma) {
|
|||
|
|
if (dev->debug_uart) {
|
|||
|
|
//enable uart 1Byte tx done irq
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_UARTTXIE;
|
|||
|
|
|
|||
|
|
dev->p_tx_buf = (uint8 *)buf;
|
|||
|
|
dev->tx_total_byte = size;
|
|||
|
|
dev->tx_cur_byte = 0;
|
|||
|
|
|
|||
|
|
//send 1Byte to trigger 1Byte tx done irq
|
|||
|
|
hw->DATA = buf[0];
|
|||
|
|
|
|||
|
|
os_sema_down(&dev->sema_tx, osWaitForever);
|
|||
|
|
|
|||
|
|
//disable uart 1Byte tx done irq
|
|||
|
|
hw->CON &=~ LL_SIMPLE_UART_CON_UARTTXIE;
|
|||
|
|
} else if (dev->rs485_set) {
|
|||
|
|
hguart_v4_dma_tx_config(hw, 0);
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_CLRDMAPEND;
|
|||
|
|
|
|||
|
|
hguart_v4_rs485_de_set();
|
|||
|
|
hguart_v4_rs485_re_set();
|
|||
|
|
|
|||
|
|
hw->DMAADR = (uint32)buf;
|
|||
|
|
hw->DMALEN = size;
|
|||
|
|
hguart_v4_dma_tx_config(hw, 1);
|
|||
|
|
|
|||
|
|
/* waiting for tx done */
|
|||
|
|
while (!(hw->CON & LL_SIMPLE_UART_CON_DMAPEND));
|
|||
|
|
|
|||
|
|
hguart_v4_rs485_re_reset();
|
|||
|
|
hguart_v4_rs485_de_reset();
|
|||
|
|
} else {
|
|||
|
|
for (i = 0; i < size; i++) {
|
|||
|
|
hguart_v4_putc(uart, buf[i]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
for (i = 0; i < size; i++) {
|
|||
|
|
hguart_v4_putc(uart, buf[i]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SIMPLE_UART_UNLOCK(&dev->mutex_tx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_gets(struct uart_device *uart, uint8 *buf, uint32 size) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
uint32 i = 0;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SIMPLE_UART_LOCK(&dev->mutex_rx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
if (dev->use_dma) {
|
|||
|
|
hw->DMAADR = (uint32)buf;
|
|||
|
|
hw->DMALEN = size;
|
|||
|
|
hguart_v4_dma_rx_config(hw, 1);
|
|||
|
|
} else {
|
|||
|
|
for (i = 0; i < size; i++) {
|
|||
|
|
hguart_v4_getc(uart);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SIMPLE_UART_UNLOCK(&dev->mutex_rx, dev->debug_uart);
|
|||
|
|
|
|||
|
|
return i;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_ioctl(struct uart_device *uart, enum uart_ioctl_cmd ioctl_cmd, uint32 param1, uint32 param2) {
|
|||
|
|
|
|||
|
|
int32 ret_val = RET_OK;
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
switch (ioctl_cmd) {
|
|||
|
|
case (UART_IOCTL_CMD_USE_DMA):
|
|||
|
|
ret_val = hguart_v4_set_dma(dev, param1);
|
|||
|
|
break;
|
|||
|
|
case (UART_IOCTL_CMD_SET_TIME_OUT):
|
|||
|
|
ret_val = hguart_v4_set_time_out((struct hguart_v4_hw *)dev->hw, param1, param2);
|
|||
|
|
break;
|
|||
|
|
case (UART_IOCTL_CMD_DISABLE_DEBUG_SELECTION):
|
|||
|
|
dev->debug_uart = (param1) ? (1) : (0);
|
|||
|
|
ret_val = RET_OK;
|
|||
|
|
break;
|
|||
|
|
case (UART_IOCTL_CMD_SET_RS485_EN):
|
|||
|
|
dev->rs485_set = (param1) ? (1) : (0);
|
|||
|
|
ret_val = RET_OK;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
ret_val = -ENOTSUPP;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ret_val;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* interrupt handler */
|
|||
|
|
static void hguart_v4_irq_handler(void *data) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)data;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if ((hw->CON & LL_SIMPLE_UART_CON_UARTTXIE) && (hw->CON & LL_SIMPLE_UART_CON_TXDONE)) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_CLRTXDONE;
|
|||
|
|
|
|||
|
|
dev->tx_cur_byte++;
|
|||
|
|
//printf("cur len:%d\r\n", dev->tx_cur_byte);
|
|||
|
|
if (dev->tx_cur_byte == dev->tx_total_byte) {
|
|||
|
|
//printf("up\r\n");
|
|||
|
|
os_sema_up(&dev->sema_tx);
|
|||
|
|
//diable uart tx 1byte done irq
|
|||
|
|
hw->CON &=~ LL_SIMPLE_UART_CON_UARTTXIE;
|
|||
|
|
} else {
|
|||
|
|
hw->DATA = dev->p_tx_buf[dev->tx_cur_byte];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((hw->CON & LL_SIMPLE_UART_CON_UARTRXIE) && (hw->CON & LL_SIMPLE_UART_CON_RXBUFNOTEMPTY)) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_CLRRXDONE;
|
|||
|
|
if (dev->irq_hdl) {
|
|||
|
|
dev->irq_hdl(UART_IRQ_FLAG_RX_BYTE, dev->irq_data, hw->DATA, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((hw->CON & LL_SIMPLE_UART_CON_FERRIE) && (hw->CON & LL_SIMPLE_UART_CON_FERR)) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_CLRFERR;
|
|||
|
|
if (dev->irq_hdl) {
|
|||
|
|
dev->irq_hdl(UART_IRQ_FLAG_FRAME_ERR, dev->irq_data, 0, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//UART4/5 TIMEOUT来了之后,DMA DONE也会起来,故DMA DONE中断之前要判断是否TIMEOUT
|
|||
|
|
if (!(hw->CON & LL_SIMPLE_UART_CON_TO_PENDING)) {
|
|||
|
|
if ((hw->CON & LL_SIMPLE_UART_CON_DMA_IE) && (hw->CON & LL_SIMPLE_UART_CON_DMAPEND)) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_CLRDMAPEND;
|
|||
|
|
if (dev->irq_hdl) {
|
|||
|
|
if (dev->irq_dma_rx) {
|
|||
|
|
dev->irq_hdl(UART_IRQ_FLAG_DMA_RX_DONE, dev->irq_data, hw->DMACNT, 0);
|
|||
|
|
} else {
|
|||
|
|
dev->irq_hdl(UART_IRQ_FLAG_DMA_TX_DONE, dev->irq_data, hw->DMACNT, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
if ((hw->CON & LL_SIMPLE_UART_CON_TO_IE) && (hw->CON & LL_SIMPLE_UART_CON_TO_PENDING)) {
|
|||
|
|
hw->CON |= (LL_SIMPLE_UART_CON_CLRTOPEND | LL_SIMPLE_UART_CON_CLRDMAPEND);
|
|||
|
|
if (dev->irq_hdl) {
|
|||
|
|
dev->irq_hdl(UART_IRQ_FLAG_TIME_OUT, dev->irq_data, hw->DMACNT, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* request interrupt */
|
|||
|
|
static int32 hguart_v4_request_irq(struct uart_device *uart, uart_irq_hdl irqhdl, uint32 irq_flag, uint32 data) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
dev->irq_hdl = irqhdl;
|
|||
|
|
dev->irq_data = data ;
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_RX_BYTE) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_UARTRXIE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_FRAME_ERR) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_FERRIE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_DMA_RX_DONE) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_DMA_IE;
|
|||
|
|
dev->irq_dma_tx = 0;
|
|||
|
|
dev->irq_dma_rx = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_DMA_TX_DONE) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_DMA_IE;
|
|||
|
|
dev->irq_dma_tx = 1;
|
|||
|
|
dev->irq_dma_rx = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_TIME_OUT) {
|
|||
|
|
hw->CON |= LL_SIMPLE_UART_CON_TO_IE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if defined(TXW81X)
|
|||
|
|
irq_enable(dev->comm_irq_num);
|
|||
|
|
#elif defined(TXW82X)
|
|||
|
|
irq_enable(dev->irq_num);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int32 hguart_v4_release_irq(struct uart_device *uart, uint32 irq_flag) {
|
|||
|
|
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)uart;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if ((!dev->opened) || (dev->dsleep)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_RX_BYTE) {
|
|||
|
|
hw->CON &= ~ LL_SIMPLE_UART_CON_UARTRXIE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_FRAME_ERR) {
|
|||
|
|
hw->CON &= ~ LL_SIMPLE_UART_CON_FERRIE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_DMA_RX_DONE) {
|
|||
|
|
hw->CON &=~ LL_SIMPLE_UART_CON_DMA_IE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (irq_flag & UART_IRQ_FLAG_TIME_OUT) {
|
|||
|
|
hw->CON &=~ LL_SIMPLE_UART_CON_TO_IE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if defined(TXW81X)
|
|||
|
|
irq_disable(dev->comm_irq_num);
|
|||
|
|
#elif defined(TXW82X)
|
|||
|
|
irq_disable(dev->irq_num);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#ifdef CONFIG_SLEEP
|
|||
|
|
int32 hguart_v4_suspend(struct dev_obj *obj)
|
|||
|
|
{
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)obj;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
|
|||
|
|
if (!dev->opened) {
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (0 > os_mutex_lock(&dev->bp_suspend_lock, 10000)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/*!
|
|||
|
|
* Close the UART
|
|||
|
|
*/
|
|||
|
|
hw->CON &= ~ BIT(4);
|
|||
|
|
|
|||
|
|
|
|||
|
|
// pin_func(dev->dev.dev.dev_id, 0);
|
|||
|
|
|
|||
|
|
#if defined(TXW81X)
|
|||
|
|
irq_disable(dev->comm_irq_num);
|
|||
|
|
#elif defined(TXW82X)
|
|||
|
|
irq_disable(dev->irq_num);
|
|||
|
|
#endif
|
|||
|
|
/*
|
|||
|
|
* clear pending
|
|||
|
|
*/
|
|||
|
|
hw->CON |= 0x3f000000;
|
|||
|
|
|
|||
|
|
|
|||
|
|
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* save the reglist
|
|||
|
|
*/
|
|||
|
|
dev->bp_regs.con = hw->CON;
|
|||
|
|
dev->bp_regs.baud = hw->BAUD;
|
|||
|
|
dev->bp_regs.tocon = hw->TOCON;
|
|||
|
|
dev->bp_regs.dmaadr = hw->DMAADR;
|
|||
|
|
dev->bp_regs.dmalen = hw->DMALEN;
|
|||
|
|
dev->bp_regs.dmacon = hw->DMACON;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* save the irq_hdl created by user
|
|||
|
|
*/
|
|||
|
|
dev->bp_irq_hdl = dev->irq_hdl;
|
|||
|
|
dev->bp_irq_data = dev->irq_data;
|
|||
|
|
|
|||
|
|
//venus v2:uart4&5 clk and uart0 clk are share the same source
|
|||
|
|
if (UART4_BASE == (uint32)hw) {
|
|||
|
|
// sysctrl_uart4_clk_close();
|
|||
|
|
} else if (UART5_BASE == (uint32)hw) {
|
|||
|
|
// sysctrl_uart5_clk_close();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
dev->dsleep = 1;
|
|||
|
|
|
|||
|
|
os_mutex_unlock(&dev->bp_suspend_lock);
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int32 hguart_v4_resume(struct dev_obj *obj)
|
|||
|
|
{
|
|||
|
|
struct hguart_v4 *dev = (struct hguart_v4 *)obj;
|
|||
|
|
struct hguart_v4_hw *hw = (struct hguart_v4_hw *)dev->hw;
|
|||
|
|
if (!dev->opened) {
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (0 > os_mutex_lock(&dev->bp_resume_lock, 10000)) {
|
|||
|
|
return RET_ERR;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* pin config */
|
|||
|
|
// if (pin_func(dev->dev.dev.dev_id, 1) != RET_OK) {
|
|||
|
|
// return RET_ERR;
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* recovery the UART clk
|
|||
|
|
*/
|
|||
|
|
if (UART4_BASE == (uint32)hw) {
|
|||
|
|
// sysctrl_uart4_clk_open();
|
|||
|
|
} else if (UART5_BASE == (uint32)hw) {
|
|||
|
|
// sysctrl_uart5_clk_open();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* recovery the reglist from sram
|
|||
|
|
*/
|
|||
|
|
hw->CON = dev->bp_regs.con;
|
|||
|
|
hw->BAUD = dev->bp_regs.baud;
|
|||
|
|
hw->TOCON = dev->bp_regs.tocon;
|
|||
|
|
hw->DMAADR = dev->bp_regs.dmaadr;
|
|||
|
|
hw->DMALEN = dev->bp_regs.dmalen;
|
|||
|
|
hw->DMACON = dev->bp_regs.dmacon;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* recovery the irq handle and data
|
|||
|
|
*/
|
|||
|
|
dev->irq_hdl = dev->bp_irq_hdl;
|
|||
|
|
dev->irq_data = dev->bp_irq_data;
|
|||
|
|
|
|||
|
|
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
|
|||
|
|
|
|||
|
|
/*!
|
|||
|
|
* Open the UART
|
|||
|
|
*/
|
|||
|
|
hw->CON |= BIT(4);
|
|||
|
|
if (hw->DMACON & 1) {
|
|||
|
|
hguart_v4_dma_rx_config(hw, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if defined(TXW81X)
|
|||
|
|
irq_enable(dev->comm_irq_num);
|
|||
|
|
#elif defined(TXW82X)
|
|||
|
|
irq_enable(dev->irq_num);
|
|||
|
|
#endif
|
|||
|
|
dev->dsleep = 0;
|
|||
|
|
|
|||
|
|
os_mutex_unlock(&dev->bp_resume_lock);
|
|||
|
|
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
static const struct uart_hal_ops uart_v4_ops = {
|
|||
|
|
.open = hguart_v4_open,
|
|||
|
|
.close = hguart_v4_close,
|
|||
|
|
.getc = hguart_v4_getc,
|
|||
|
|
.putc = hguart_v4_putc,
|
|||
|
|
.gets = hguart_v4_gets,
|
|||
|
|
.puts = hguart_v4_puts,
|
|||
|
|
.ioctl = hguart_v4_ioctl,
|
|||
|
|
.request_irq = hguart_v4_request_irq,
|
|||
|
|
.release_irq = hguart_v4_release_irq,
|
|||
|
|
#ifdef CONFIG_SLEEP
|
|||
|
|
.ops.suspend = hguart_v4_suspend,
|
|||
|
|
.ops.resume = hguart_v4_resume,
|
|||
|
|
#endif
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
int32 hguart_v4_attach(uint32 dev_id, struct hguart_v4 *uart) {
|
|||
|
|
|
|||
|
|
uart->irq_data = 0;
|
|||
|
|
uart->irq_hdl = NULL;
|
|||
|
|
uart->opened = 0;
|
|||
|
|
uart->irq_dma_rx = 0;
|
|||
|
|
uart->irq_dma_tx = 0;
|
|||
|
|
uart->use_dma = 0;
|
|||
|
|
uart->debug_uart = 0;
|
|||
|
|
uart->rs485_set = 0;
|
|||
|
|
uart->dsleep = 0;
|
|||
|
|
uart->p_tx_buf = NULL;
|
|||
|
|
uart->tx_cur_byte = 0;
|
|||
|
|
uart->tx_total_byte = 0;
|
|||
|
|
uart->dev.dev.ops = (const struct devobj_ops *)&uart_v4_ops;
|
|||
|
|
|
|||
|
|
os_sema_init(&uart->sema_tx, 0);
|
|||
|
|
os_mutex_init(&uart->mutex_rx);
|
|||
|
|
os_mutex_init(&uart->mutex_tx);
|
|||
|
|
#ifdef CONFIG_SLEEP
|
|||
|
|
os_mutex_init(&uart->bp_suspend_lock);
|
|||
|
|
os_mutex_init(&uart->bp_resume_lock);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
request_irq(uart->irq_num, hguart_v4_irq_handler, uart);
|
|||
|
|
|
|||
|
|
dev_register(dev_id, (struct dev_obj *)uart);
|
|||
|
|
return RET_OK;
|
|||
|
|
}
|
|||
|
|
|