1067 lines
28 KiB
C
1067 lines
28 KiB
C
/**
|
||
* @file hguart_v2.c
|
||
* @author bxd
|
||
* @brief normal uart
|
||
* @version
|
||
* TXW80X; 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/string.h"
|
||
#include "osal/semaphore.h"
|
||
#include "osal/mutex.h"
|
||
#include "hal/uart.h"
|
||
#include "dev/uart/hguart_v2.h"
|
||
#include "hguart_v2_hw.h"
|
||
#include "osal/sleep.h"
|
||
|
||
#define UART_FLAG_TDMA_BUSY (0x1)
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* LOW LAYER FUNCTION */
|
||
/**********************************************************************************/
|
||
|
||
static int32 hguart_v2_switch_hal_uart_parity(enum uart_parity param)
|
||
{
|
||
|
||
switch (param) {
|
||
case (UART_PARITY_NONE):
|
||
return 0;
|
||
break;
|
||
case (UART_PARITY_ODD):
|
||
return 1;
|
||
break;
|
||
case (UART_PARITY_EVEN):
|
||
return 2;
|
||
break;
|
||
default:
|
||
return -1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
static int32 hguart_v2_switch_hal_uart_stop_bit(enum uart_stop_bit param)
|
||
{
|
||
|
||
switch (param) {
|
||
case (UART_STOP_BIT_1):
|
||
return 0;
|
||
break;
|
||
case (UART_STOP_BIT_2):
|
||
return 1;
|
||
break;
|
||
default:
|
||
return -1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
static int32 hguart_v2_switch_hal_uart_data_bit(enum uart_data_bit param)
|
||
{
|
||
|
||
switch (param) {
|
||
case (UART_DATA_BIT_8):
|
||
return 0;
|
||
break;
|
||
case (UART_DATA_BIT_9):
|
||
return 1;
|
||
break;
|
||
default:
|
||
return -1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
static int32 hguart_v2_set_data_bit(struct hguart_v2_hw *p_uart, enum uart_data_bit data_bit)
|
||
{
|
||
|
||
int32 data_bit_to_reg = 0;
|
||
|
||
data_bit_to_reg = hguart_v2_switch_hal_uart_data_bit(data_bit);
|
||
|
||
if (((-1) == data_bit_to_reg)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if (data_bit_to_reg) {
|
||
p_uart->CON |= LL_UART_CON_BIT9_EN;
|
||
} else {
|
||
p_uart->CON &= ~ LL_UART_CON_BIT9_EN;
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_set_parity(struct hguart_v2_hw *p_uart, enum uart_parity parity)
|
||
{
|
||
|
||
int32 parity_to_reg = 0;
|
||
|
||
parity_to_reg = hguart_v2_switch_hal_uart_parity(parity);
|
||
|
||
if (((-1) == parity_to_reg)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
switch (parity_to_reg) {
|
||
case (0):
|
||
p_uart->CON &= ~(LL_UART_CON_PARITY_EN | LL_UART_CON_ODD_EN);
|
||
break;
|
||
case (1):
|
||
p_uart->CON |= LL_UART_CON_PARITY_EN | LL_UART_CON_ODD_EN;
|
||
break;
|
||
case (2):
|
||
p_uart->CON = (p_uart->CON & ~(LL_UART_CON_ODD_EN)) | LL_UART_CON_PARITY_EN;
|
||
break;
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_set_stop_bit(struct hguart_v2_hw *p_uart, enum uart_stop_bit stop_bit)
|
||
{
|
||
|
||
int32 stop_bit_to_reg = 0;
|
||
|
||
stop_bit_to_reg = hguart_v2_switch_hal_uart_stop_bit(stop_bit);
|
||
|
||
if (((-1) == stop_bit_to_reg)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if (stop_bit_to_reg) {
|
||
p_uart->CON |= LL_UART_CON_STOP_BIT(1);
|
||
} else {
|
||
p_uart->CON &= ~ LL_UART_CON_STOP_BIT(1);
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_set_time_out(struct hguart_v2_hw *p_uart, uint32 time_bit, uint32 enable)
|
||
{
|
||
|
||
if (enable) {
|
||
p_uart->TOCON = (p_uart->TOCON & ~ LL_UART_TOCON_TO_BIT_LEN(0xFFFF)) | LL_UART_TOCON_TO_BIT_LEN(time_bit) | LL_UART_TOCON_TO_EN;
|
||
} else {
|
||
p_uart->TOCON = 0;
|
||
}
|
||
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_set_dma(struct hguart_v2 *dev, uint32 enable)
|
||
{
|
||
|
||
if (enable) {
|
||
dev->use_dma = 1;
|
||
} else {
|
||
dev->use_dma = 0;
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_set_baudrate(struct hguart_v2_hw *p_uart, uint32 baudrate)
|
||
{
|
||
|
||
p_uart->BAUD = (peripheral_clock_get(HG_APB0_PT_UART0) / baudrate - 1);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_set_mode(struct hguart_v2_hw *p_uart, uint32 mode)
|
||
{
|
||
switch (mode) {
|
||
case UART_MODE_DUPLEX:
|
||
p_uart->CON &= ~ LL_UART_CON_WORK_MODE(0x3);
|
||
p_uart->CON |= LL_UART_CON_WORK_MODE(0);
|
||
break;
|
||
case UART_MODE_SIMPLEX_TX:
|
||
p_uart->CON &= ~ LL_UART_CON_WORK_MODE(0x3);
|
||
p_uart->CON |= LL_UART_CON_WORK_MODE(1);
|
||
break;
|
||
case UART_MODE_SIMPLEX_RX:
|
||
p_uart->CON &= ~ LL_UART_CON_WORK_MODE(0x3);
|
||
p_uart->CON |= LL_UART_CON_WORK_MODE(2);
|
||
break;
|
||
default:
|
||
return -ENOTSUPP;
|
||
}
|
||
return RET_OK;
|
||
}
|
||
|
||
static void hguart_v2_dma_tx_config(struct hguart_v2_hw *p_uart, uint8 status)
|
||
{
|
||
uint32 _dmacon = p_uart->DMACON;
|
||
|
||
if (status) {
|
||
_dmacon |= LL_UART_DMACON_TX_DMA_EN;
|
||
} else {
|
||
_dmacon &= ~ BIT(0);
|
||
_dmacon |= BIT(8);
|
||
}
|
||
|
||
p_uart->DMACON = _dmacon;
|
||
}
|
||
|
||
static int32 hguart_v2_dma_rx_config(struct hguart_v2_hw *p_uart, uint8 status)
|
||
{
|
||
uint32 _dmacon = p_uart->DMACON;
|
||
|
||
if (status) {
|
||
_dmacon |= LL_UART_DMACON_RX_DMA_EN;
|
||
} else {
|
||
_dmacon &= ~ BIT(1);
|
||
_dmacon |= BIT(9);
|
||
}
|
||
|
||
p_uart->DMACON = _dmacon;
|
||
|
||
return 0;
|
||
}
|
||
|
||
// static int32 hguart_v2_rs485_config(struct hguart_v2_hw *p_uart, uint8 enable,
|
||
// uint8 re_sig_active_level, uint8 de_sig_active_level,
|
||
// uint32 de_deassertion_time, uint32 de_assertion_time,
|
||
// uint32 de2re_turnaround_time, uint32 re2de_turnaround_time)
|
||
// {
|
||
// struct hguart_v2 *dev = (struct hguart_v2 *)p_uart;
|
||
// struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
// if (enable) {
|
||
// hw->RS485_DET = LL_UART_RS485_DET_DE_AT(de_assertion_time) | LL_UART_RS485_DET_DE_DAT(de_deassertion_time);
|
||
// hw->RS485_TAT = LL_UART_RS485_TAT_DE2RE_T(de2re_turnaround_time) | LL_UART_RS485_TAT_RE2DE_T(re2de_turnaround_time);
|
||
|
||
// hw->RS485_CON = LL_UART_RS485_CON_DE_EN | LL_UART_RS485_CON_RE_EN | \
|
||
// LL_UART_RS485_CON_RS485_MODE(1) | \
|
||
// LL_UART_RS485_CON_RE_POL(re_sig_active_level)| \
|
||
// LL_UART_RS485_CON_DE_POL(de_sig_active_level)| \
|
||
// LL_UART_RS485_CON_RS485_EN;
|
||
|
||
// } else {
|
||
// hw->RS485_CON = 0;
|
||
// hw->RS485_DET = 0;
|
||
// hw->RS485_TAT = 0;
|
||
// }
|
||
|
||
// // hw->RS485_DET = LL_UART_RS485_DET_DE_AT(200) | LL_UART_RS485_DET_DE_DAT(100);
|
||
// // hw->RS485_TAT = LL_UART_RS485_TAT_DE2RE_T(400) | LL_UART_RS485_TAT_RE2DE_T(300);
|
||
// //
|
||
// // hw->RS485_CON = LL_UART_RS485_CON_DE_EN | LL_UART_RS485_CON_RE_EN | \
|
||
// // LL_UART_RS485_CON_RS485_MODE(1) |\
|
||
// // LL_UART_RS485_CON_RE_POL(1)|\
|
||
// // LL_UART_RS485_CON_DE_POL(0)|\
|
||
// // LL_UART_RS485_CON_RS485_EN;
|
||
|
||
// return RET_OK;
|
||
// }
|
||
|
||
static int32 hguart_v2_rs485det_set(struct hguart_v2_hw *p_uart, uint32 de_deassertion_time, uint32 de_assertion_time)
|
||
{
|
||
struct hguart_v2_hw *hw = p_uart;
|
||
|
||
hw->RS485_DET = LL_UART_RS485_DET_DE_AT(de_assertion_time) | LL_UART_RS485_DET_DE_DAT(de_deassertion_time);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485tat_set(struct hguart_v2_hw *p_uart, uint32 de2re_turnaround_time, uint32 re2de_turnaround_time)
|
||
{
|
||
struct hguart_v2_hw *hw = p_uart;
|
||
|
||
hw->RS485_TAT = LL_UART_RS485_TAT_DE2RE_T(de2re_turnaround_time) | LL_UART_RS485_TAT_RE2DE_T(re2de_turnaround_time);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485dre_pol_set(struct hguart_v2_hw *p_uart, uint8 re_sig_active_level, uint8 de_sig_active_level)
|
||
{
|
||
struct hguart_v2_hw *hw = p_uart;
|
||
|
||
hw->RS485_CON &= ~(LL_UART_RS485_CON_RE_POL(1)|LL_UART_RS485_CON_DE_POL(1));
|
||
|
||
hw->RS485_CON |= LL_UART_RS485_CON_RE_POL(re_sig_active_level)| \
|
||
LL_UART_RS485_CON_DE_POL(de_sig_active_level);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485_en(struct hguart_v2_hw *p_uart, uint8 enable)
|
||
{
|
||
struct hguart_v2_hw *hw = p_uart;
|
||
|
||
if (enable) {
|
||
hw->RS485_DET = LL_UART_RS485_DET_DE_AT(200) | LL_UART_RS485_DET_DE_DAT(100);
|
||
hw->RS485_TAT = LL_UART_RS485_TAT_DE2RE_T(400) | LL_UART_RS485_TAT_RE2DE_T(300);
|
||
hw->RS485_CON = LL_UART_RS485_CON_DE_EN | LL_UART_RS485_CON_RE_EN | \
|
||
LL_UART_RS485_CON_RS485_MODE(1) | \
|
||
LL_UART_RS485_CON_RE_POL(1)| \
|
||
LL_UART_RS485_CON_DE_POL(0)| \
|
||
LL_UART_RS485_CON_RS485_EN;
|
||
} else {
|
||
hw->RS485_CON = 0;
|
||
hw->RS485_DET = 0;
|
||
hw->RS485_TAT = 0;
|
||
}
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_hw_control_config(struct hguart_v2_hw *p_uart, uint8 enable)
|
||
{
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)p_uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if (enable) {
|
||
hw->CON |= LL_UART_CON_CTS_EN | LL_UART_CON_RTS_EN;
|
||
hw->RS485_CON = 0;
|
||
hw->RS485_DET = 0;
|
||
hw->RS485_TAT = 0;
|
||
} else {
|
||
hw->CON &= ~(LL_UART_CON_CTS_EN | LL_UART_CON_RTS_EN);
|
||
hw->RS485_CON = 0;
|
||
hw->RS485_DET = 0;
|
||
hw->RS485_TAT = 0;
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
/**********************************************************************************/
|
||
/* ATTCH FUNCTION */
|
||
/**********************************************************************************/
|
||
|
||
static int32 hguart_v2_open(struct uart_device *uart, uint32 baudrate)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if (dev->opened) {
|
||
if (!dev->dsleep) {
|
||
return -EBUSY;
|
||
}
|
||
}
|
||
|
||
if ((baudrate < 0) || ((peripheral_clock_get(HG_APB0_PT_UART0) / baudrate) > 0x0003ffff)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* pin config */
|
||
if (pin_func(dev->dev.dev.dev_id, 1) != RET_OK) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
|
||
/*
|
||
* open UART clk
|
||
*/
|
||
if (UART0_BASE == (uint32)hw) {
|
||
sysctrl_uart0_clk_open();
|
||
} else if (UART1_BASE == (uint32)hw) {
|
||
sysctrl_uart1_clk_open();
|
||
}
|
||
|
||
/* clear reg */
|
||
hw->CON = 0;
|
||
hw->BAUD = 0;
|
||
hw->STA = 0xFFFFFFFF;
|
||
hw->DMACON = 0;
|
||
hw->DMASTA = 0xFFFFFFFF;
|
||
hw->RSTADR = 0;
|
||
hw->TSTADR = 0;
|
||
hw->RDMALEN = 0;
|
||
hw->TDMALEN = 0;
|
||
hw->TOCON = 0;
|
||
hw->RS485_CON = 0;
|
||
hw->RS485_DET = 0;
|
||
hw->RS485_TAT = 0;
|
||
|
||
|
||
/* reg config */
|
||
#ifndef FPGA_SUPPORT
|
||
hw->BAUD = (peripheral_clock_get(HG_APB0_PT_UART0) / baudrate) - 1;
|
||
#else
|
||
hw->BAUD = (96000000 / baudrate) - 1;
|
||
#endif
|
||
hw->CON = 0x1; /* Default config: 8bit + 1 stop_bit + no parity + duplex mode */
|
||
|
||
dev->opened = 1;
|
||
dev->dsleep = 0;
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_close(struct uart_device *uart)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if (!dev->opened) {
|
||
return RET_OK;
|
||
}
|
||
|
||
/*
|
||
* close UART clk
|
||
*/
|
||
if (UART0_BASE == (uint32)hw) {
|
||
sysctrl_uart0_clk_close();
|
||
} else if (UART1_BASE == (uint32)hw) {
|
||
sysctrl_uart1_clk_close();
|
||
}
|
||
|
||
hw->CON &= ~0x1;
|
||
irq_disable(dev->irq_num);
|
||
pin_func(dev->dev.dev.dev_id, 0);
|
||
|
||
dev->opened = 0;
|
||
dev->dsleep = 0;
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485_de_set(struct hguart_v2_hw *p_uart)
|
||
{
|
||
if(PIN_UART0_DE != 255) {
|
||
ll_uart485_de_enable(p_uart);
|
||
return RET_OK;
|
||
}
|
||
|
||
return RET_ERR;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485_de_reset(struct hguart_v2_hw *p_uart)
|
||
{
|
||
if(PIN_UART0_DE != 255) {
|
||
ll_uart485_de_disable(p_uart);
|
||
return RET_OK;
|
||
// p_uart->RS485_CON &= (~LL_UART_RS485_CON_DE_EN);
|
||
}
|
||
// os_printf("%s:%d\n", __FUNCTION__, __LINE__);
|
||
return RET_ERR;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485_re_set(struct hguart_v2_hw *p_uart)
|
||
{
|
||
if(PIN_UART4_RE != 255) {
|
||
ll_uart485_re_enable(p_uart);
|
||
return RET_OK;
|
||
}
|
||
|
||
return RET_ERR;
|
||
}
|
||
|
||
static int32 hguart_v2_rs485_re_reset(struct hguart_v2_hw *p_uart)
|
||
{
|
||
if(PIN_UART4_RE != 255) {
|
||
ll_uart485_re_disable(p_uart);
|
||
return RET_OK;
|
||
}
|
||
|
||
return RET_ERR;
|
||
}
|
||
|
||
static int32 hguart_v2_putc(struct uart_device *uart, int8 value)
|
||
{
|
||
uint8 rs485_en_flag = 0;
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if (dev->opened && (hw->CON & LL_UART_CON_UART_EN) && (!dev->dsleep)) {
|
||
if (hw->RS485_CON & LL_UART_RS485_CON_RS485_EN) {
|
||
hguart_v2_rs485_en(hw, 0);
|
||
rs485_en_flag = 1;
|
||
}
|
||
while (!(hw->STA & LL_UART_STA_TX_BUF_EMPTY));
|
||
hw->DATA = value;
|
||
if(rs485_en_flag) {
|
||
rs485_en_flag = 0;
|
||
hguart_v2_rs485_en(hw, 1);
|
||
}
|
||
return RET_OK;
|
||
} else {
|
||
return -EIO;
|
||
}
|
||
}
|
||
|
||
static uint8 hguart_v2_getc(struct uart_device *uart)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if (dev->opened && (hw->CON & LL_UART_CON_UART_EN) && (!dev->dsleep)) {
|
||
while (!(hw->STA & LL_UART_STA_RX_BUF_NOT_EMPTY));
|
||
}
|
||
return hw->DATA;
|
||
}
|
||
|
||
static int32 hguart_v2_puts(struct uart_device *uart, uint8 *buf, uint32 len)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
int32 i = 0;
|
||
uint32_t irq_flag;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if(hw->RS485_CON & LL_UART_RS485_CON_RS485_EN) {
|
||
hguart_v2_rs485_de_set(hw);
|
||
hguart_v2_rs485_re_set(hw);
|
||
}
|
||
|
||
if (((__PSRAM_ADDR_START <= (uint32)buf)) && (((uint32)buf) <= __PSRAM_ADDR_END)) {
|
||
for (i = 0; i < len; i++) {
|
||
hguart_v2_putc(uart, buf[i]);
|
||
}
|
||
} else {
|
||
if (dev->use_dma) {
|
||
irq_flag = disable_irq();
|
||
/* Clear the former configuration */
|
||
hguart_v2_dma_tx_config(hw, 0);
|
||
|
||
/* clear the tx dma done pending before tx kick */
|
||
hw->DMASTA = BIT(0);
|
||
|
||
hw->TSTADR = (uint32)buf;
|
||
hw->TDMALEN = len;
|
||
|
||
hguart_v2_dma_tx_config(hw, 1);
|
||
dev->flag |= UART_FLAG_TDMA_BUSY;
|
||
enable_irq(irq_flag);
|
||
|
||
|
||
//TDMA_IE_EN会造成两种情况
|
||
if ((hw->DMACON & LL_UART_DMACON_TX_DMA_IE_EN)
|
||
&& (!irq_flag)) {
|
||
while(dev->flag & UART_FLAG_TDMA_BUSY);
|
||
} else {
|
||
while (!(hw->DMASTA & LL_UART_DMASTA_TX_DMA_PEND)) {
|
||
//休眠唤醒后pending位被清零了, 防卡死
|
||
if(!hw->TDMALEN) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < len; i++) {
|
||
hguart_v2_putc(uart, buf[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
if(hw->RS485_CON & LL_UART_RS485_CON_RS485_EN) {
|
||
hguart_v2_rs485_de_reset(hw);
|
||
hguart_v2_rs485_re_reset(hw);
|
||
}
|
||
|
||
irq_flag = disable_irq();
|
||
dev->flag &= ~UART_FLAG_TDMA_BUSY;
|
||
enable_irq(irq_flag);
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_gets(struct uart_device *uart, uint8 *buf, uint32 len)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
int32 i = 0;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
|
||
if (((__PSRAM_ADDR_START <= (uint32)buf)) && (((uint32)buf) <= __PSRAM_ADDR_END)) {
|
||
for (i = 0; i < len; i++) {
|
||
buf[i] = hguart_v2_getc(uart);
|
||
}
|
||
|
||
return i;
|
||
} else {
|
||
if (dev->use_dma) {
|
||
/* Clear the former configuration */
|
||
hguart_v2_dma_rx_config(hw, 0);
|
||
|
||
hw->STA = BIT(1);
|
||
hw->RSTADR = (uint32)buf;
|
||
hw->RDMALEN = len;
|
||
|
||
hguart_v2_dma_rx_config(hw, 1);
|
||
return RET_OK;
|
||
} else {
|
||
for (i = 0; i < len; i++) {
|
||
buf[i] = hguart_v2_getc(uart);
|
||
}
|
||
|
||
return i;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
struct uart_testS {
|
||
struct uart_device *uart;
|
||
uint8_t *buf;
|
||
int len;
|
||
int id;
|
||
};
|
||
|
||
static int32 uart_test_irqhdl(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
|
||
{
|
||
struct uart_testS *tuart = (struct uart_testS *)irq_data;
|
||
int32 ret = 0;
|
||
switch (irq_flag) {
|
||
case UART_IRQ_FLAG_DMA_RX_DONE: // maybe overbuff?
|
||
case UART_IRQ_FLAG_TIME_OUT:
|
||
if (tuart->id == 1) {
|
||
if (memcmp(tuart->buf, "uart5 msg", 9) != 0) {
|
||
os_printf("uart1 recv lp err\r\n");
|
||
}
|
||
} else if (tuart->id == 5) {
|
||
if (memcmp(tuart->buf, "uart1 msg", 9) != 0) {
|
||
os_printf("uart5 recv lp err\r\n");
|
||
}
|
||
}
|
||
tuart->buf[param1] = 0;
|
||
os_printf("id = %d, recv: %s\r\n", tuart->id, tuart->buf);
|
||
uart_gets(tuart->uart, tuart->buf, tuart->len);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
void uart_sleep_test()
|
||
{
|
||
uint8_t *uart1_buf = os_malloc(32);
|
||
uint8_t *uart5_buf = os_malloc(32);
|
||
struct uart_device *uart1 = (void *)dev_get(1+1);
|
||
struct uart_device *uart5 = (void *)dev_get(1+5);
|
||
|
||
uint8_t uart1_msg[] = "uart1 msg\r\n";
|
||
//uint8_t uart5_msg[] = "uart5 msg\r\n";
|
||
struct uart_testS uart1ts = {
|
||
.uart = uart1,
|
||
.buf = uart1_buf,
|
||
.len = 32,
|
||
.id = 1,
|
||
};
|
||
struct uart_testS uart5ts = {
|
||
.uart = uart5,
|
||
.buf = uart5_buf,
|
||
.len = 32,
|
||
.id = 5,
|
||
};
|
||
|
||
uart_open(uart1, 921600);
|
||
uart_open(uart5, 921600);
|
||
|
||
uart_ioctl(uart1, UART_IOCTL_CMD_USE_DMA, 1, 0);
|
||
uart_ioctl(uart5, UART_IOCTL_CMD_USE_DMA, 1, 0);
|
||
uart_ioctl(uart1, UART_IOCTL_CMD_SET_TIME_OUT, 40, 1);
|
||
uart_ioctl(uart5, UART_IOCTL_CMD_SET_TIME_OUT, 40, 1);
|
||
|
||
uart_request_irq(uart1, uart_test_irqhdl,
|
||
UART_IRQ_FLAG_DMA_RX_DONE | UART_IRQ_FLAG_TIME_OUT, (uint32)&uart1ts);
|
||
// uart_request_irq(uart1, uart_test_irqhdl,
|
||
// UART_IRQ_FLAG_DMA_RX_DONE, (uint32)&uart1ts);
|
||
uart_request_irq(uart5, uart_test_irqhdl,
|
||
UART_IRQ_FLAG_DMA_RX_DONE | UART_IRQ_FLAG_TIME_OUT, (uint32)&uart5ts);
|
||
uart_gets(uart1, uart1_buf, 32);
|
||
uart_gets(uart5, uart5_buf, 32);
|
||
while(1)
|
||
{
|
||
// uart_puts(uart5, uart5_msg, os_strlen((const char *)uart5_msg));
|
||
|
||
uart_puts(uart1, uart1_msg, os_strlen((const char *)uart1_msg));
|
||
|
||
os_sleep_ms(1000);
|
||
}
|
||
}
|
||
|
||
#ifdef CONFIG_SLEEP
|
||
int32 hguart_v2_suspend(struct dev_obj *obj)
|
||
{
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)obj;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_OK;
|
||
}
|
||
|
||
uint32_t disable = disable_irq();
|
||
enable_irq(disable);
|
||
|
||
while(dev->flag & UART_FLAG_TDMA_BUSY);
|
||
hw->TDMALEN = 0;
|
||
|
||
/*
|
||
* save the reglist
|
||
*/
|
||
dev->bp_regs.con = hw->CON;
|
||
dev->bp_regs.baud = hw->BAUD;
|
||
dev->bp_regs.tstadr = hw->TSTADR|0x20000000;
|
||
dev->bp_regs.rstadr = hw->RSTADR|0x20000000;
|
||
dev->bp_regs.tdmalen = hw->TDMALEN;
|
||
dev->bp_regs.rdmalen = hw->RDMALEN;
|
||
dev->bp_regs.dmacon = hw->DMACON;
|
||
dev->bp_regs.rs485_con = hw->RS485_CON;
|
||
dev->bp_regs.rs485_det = hw->RS485_DET;
|
||
dev->bp_regs.rs485_tat = hw->RS485_TAT;
|
||
dev->bp_regs.tocon = hw->TOCON;
|
||
|
||
/*!
|
||
* Close the UART
|
||
*/
|
||
hw->DMACON = 0x300; //disable dma
|
||
hw->CON &= ~ BIT(0);
|
||
|
||
|
||
// pin_func(dev->dev.dev.dev_id, 0);
|
||
irq_disable(dev->irq_num);
|
||
|
||
/*
|
||
* clear pending
|
||
*/
|
||
hw->DMASTA = 0xFFFFFFFF;
|
||
hw->STA = 0xFFFFFFFF;
|
||
|
||
/*
|
||
* clear the data in the UART fifo
|
||
*/
|
||
do {
|
||
hw->DATA;
|
||
} while (hw->STA & LL_UART_STA_RX_CNT(0x7));
|
||
|
||
|
||
if (UART0_BASE == (uint32)hw) {
|
||
sysctrl_uart0_clk_close();
|
||
} else if (UART1_BASE == (uint32)hw) {
|
||
sysctrl_uart1_clk_close();
|
||
}
|
||
|
||
dev->dsleep = 1;
|
||
return RET_OK;
|
||
}
|
||
|
||
int32 hguart_v2_resume(struct dev_obj *obj)
|
||
{
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)obj;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
if ((!dev->opened) || (!dev->dsleep)) {
|
||
return RET_OK;
|
||
}
|
||
|
||
/* pin config */
|
||
if (pin_func(dev->dev.dev.dev_id, 1) != RET_OK) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if (UART0_BASE == (uint32)hw) {
|
||
sysctrl_uart0_clk_open();
|
||
} else if (UART1_BASE == (uint32)hw) {
|
||
sysctrl_uart1_clk_open();
|
||
}
|
||
|
||
/*
|
||
* clear pending
|
||
*/
|
||
hw->DMASTA = 0xFFFFFFFF;
|
||
hw->STA = 0xFFFFFFFF;
|
||
|
||
/*
|
||
* recovery the reglist from sram
|
||
*/
|
||
hw->CON = dev->bp_regs.con;
|
||
hw->BAUD = dev->bp_regs.baud;
|
||
hw->TSTADR = dev->bp_regs.tstadr;
|
||
hw->RSTADR = dev->bp_regs.rstadr;
|
||
hw->TDMALEN = dev->bp_regs.tdmalen;
|
||
hw->RDMALEN = dev->bp_regs.rdmalen;
|
||
hw->DMACON = dev->bp_regs.dmacon;
|
||
hw->RS485_CON = dev->bp_regs.rs485_con;
|
||
hw->RS485_DET = dev->bp_regs.rs485_det;
|
||
hw->RS485_TAT = dev->bp_regs.rs485_tat;
|
||
hw->TOCON = dev->bp_regs.tocon;
|
||
|
||
/*!
|
||
* Open the UART
|
||
*/
|
||
hw->CON |= BIT(0);
|
||
if (dev->bp_regs.dmacon & LL_UART_DMACON_RX_DMA_EN)
|
||
hguart_v2_dma_rx_config(hw, 1);
|
||
|
||
irq_enable(dev->irq_num);
|
||
|
||
dev->dsleep = 0;
|
||
return RET_OK;
|
||
}
|
||
#else
|
||
int32 hguart_v2_suspend(struct dev_obj *obj)
|
||
{
|
||
return RET_ERR;
|
||
}
|
||
int32 hguart_v2_resume(struct dev_obj *obj)
|
||
{
|
||
return RET_ERR;
|
||
}
|
||
#endif
|
||
|
||
static int32 hguart_v2_ioctl(struct uart_device *uart, enum uart_ioctl_cmd ioctl_cmd, uint32 param1, uint32 param2)
|
||
{
|
||
|
||
int32 ret_val = RET_OK;
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
switch (ioctl_cmd) {
|
||
case (UART_IOCTL_CMD_SET_BAUDRATE):
|
||
ret_val = hguart_v2_set_baudrate(hw, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_DATA_BIT):
|
||
ret_val = hguart_v2_set_data_bit(hw, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_PARITY):
|
||
ret_val = hguart_v2_set_parity(hw, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_STOP_BIT):
|
||
ret_val = hguart_v2_set_stop_bit(hw, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_TIME_OUT):
|
||
ret_val = hguart_v2_set_time_out(hw, param1, param2);
|
||
break;
|
||
case (UART_IOCTL_CMD_USE_DMA):
|
||
ret_val = hguart_v2_set_dma(dev, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_WORK_MODE):
|
||
ret_val = hguart_v2_set_mode(hw, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_RS485_EN):
|
||
ret_val = hguart_v2_rs485_en(hw, param1);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_RS485_DET):
|
||
ret_val = hguart_v2_rs485det_set(hw, param1, param2);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_RS485_TAT):
|
||
ret_val = hguart_v2_rs485tat_set(hw, param1, param2);
|
||
break;
|
||
case (UART_IOCTL_CMD_SET_RS485DRE_POL):
|
||
ret_val = hguart_v2_rs485dre_pol_set(hw, param1, param2);
|
||
break;
|
||
default:
|
||
ret_val = -ENOTSUPP;
|
||
break;
|
||
}
|
||
|
||
return ret_val;
|
||
}
|
||
|
||
static void hguart_v2_irq_handler(void *data)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)data;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
static uint8 rec_data_len[2] = {0};
|
||
|
||
/*------Time out interrupt-----*/
|
||
if ((hw->TOCON & LL_UART_TOCON_TO_IE_EN) &&
|
||
(hw->STA & LL_UART_STA_TO_PEND)) {
|
||
hw->STA = LL_UART_STA_TO_PEND;
|
||
|
||
if (dev->irq_hdl) {
|
||
rec_data_len[1] = hw->RDMACNT >> 8;
|
||
rec_data_len[0] = hw->RDMACNT;
|
||
dev->irq_hdl(UART_IRQ_FLAG_TIME_OUT, dev->irq_data, hw->RDMACNT, 0);
|
||
if((PIN_UART0_DE != 255) && (PIN_UART0_RE != 255)) {
|
||
uart_puts((struct uart_device *)dev, rec_data_len, sizeof(rec_data_len));
|
||
}
|
||
}
|
||
}
|
||
|
||
/*------Frame erro interrupt-----*/
|
||
if ((hw->CON & LL_UART_CON_FERR_IE_EN) &&
|
||
(hw->STA & LL_UART_STA_FERR_PENDING)) {
|
||
hw->STA = LL_UART_STA_FERR_PENDING;
|
||
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(UART_IRQ_FLAG_FRAME_ERR, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
|
||
/*------TX complete interrupt-----*/
|
||
if ((hw->CON & LL_UART_CON_TCIE_EN) &&
|
||
(hw->STA & LL_UART_STA_TC_PENDING)) {
|
||
hw->STA = LL_UART_STA_TC_PENDING;
|
||
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(UART_IRQ_FLAG_TX_BYTE, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
|
||
/*------RX_DMA_INTERRUPT-----*/
|
||
if ((hw->DMACON & LL_UART_DMACON_RX_DMA_IE_EN) &&
|
||
(hw->DMASTA & LL_UART_DMASTA_RX_DMA_PEND)) {
|
||
hw->DMASTA = LL_UART_DMASTA_RX_DMA_PEND;
|
||
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(UART_IRQ_FLAG_DMA_RX_DONE, dev->irq_data, hw->RDMACNT, 0);
|
||
}
|
||
}
|
||
|
||
/*------TX_DMA_INTERRUPT-----*/
|
||
if ((hw->DMACON & LL_UART_DMACON_TX_DMA_IE_EN) &&
|
||
(hw->DMASTA & LL_UART_DMASTA_TX_DMA_PEND)) {
|
||
hw->DMASTA = LL_UART_DMASTA_TX_DMA_PEND;
|
||
dev->flag &= ~UART_FLAG_TDMA_BUSY;
|
||
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(UART_IRQ_FLAG_DMA_TX_DONE, dev->irq_data, hw->TDMACNT, 0);
|
||
}
|
||
}
|
||
|
||
/*------RX buf not empty interrupt-----*/
|
||
if ((hw->CON & LL_UART_CON_RXBUF_NEMPTY_IE_EN) &&
|
||
(hw->STA & LL_UART_STA_RX_BUF_NOT_EMPTY)) {
|
||
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(UART_IRQ_FLAG_RX_BYTE, dev->irq_data, hw->DATA, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
static int32 hguart_v2_request_irq(struct uart_device *uart, uart_irq_hdl irq_hdl, uint32 irq_flag, uint32 irq_data)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
dev->irq_hdl = irq_hdl;
|
||
dev->irq_data = irq_data;
|
||
request_irq(dev->irq_num, hguart_v2_irq_handler, dev);
|
||
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_TX_BYTE) {
|
||
hw->CON |= LL_UART_CON_TCIE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_TIME_OUT) {
|
||
hw->TOCON |= LL_UART_TOCON_TO_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_DMA_TX_DONE) {
|
||
hw->DMACON |= LL_UART_DMACON_TX_DMA_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_DMA_RX_DONE) {
|
||
hw->DMACON |= LL_UART_DMACON_RX_DMA_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_FRAME_ERR) {
|
||
hw->CON |= LL_UART_CON_FERR_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_RX_BYTE) {
|
||
hw->CON |= LL_UART_CON_RXBUF_NEMPTY_IE_EN;
|
||
}
|
||
irq_enable(dev->irq_num);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hguart_v2_release_irq(struct uart_device *uart, uint32 irq_flag)
|
||
{
|
||
|
||
struct hguart_v2 *dev = (struct hguart_v2 *)uart;
|
||
struct hguart_v2_hw *hw = (struct hguart_v2_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_TX_BYTE) {
|
||
hw->CON &= ~ LL_UART_CON_TCIE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_TIME_OUT) {
|
||
hw->TOCON &= ~ LL_UART_TOCON_TO_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_DMA_TX_DONE) {
|
||
hw->DMACON &= ~ LL_UART_DMACON_TX_DMA_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_DMA_RX_DONE) {
|
||
hw->DMACON &= ~ LL_UART_DMACON_RX_DMA_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_FRAME_ERR) {
|
||
hw->CON &= ~ LL_UART_CON_FERR_IE_EN;
|
||
}
|
||
|
||
if (irq_flag & UART_IRQ_FLAG_RX_BYTE) {
|
||
hw->CON &= ~ LL_UART_CON_RXBUF_NEMPTY_IE_EN;
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
|
||
static const struct uart_hal_ops uart_v2_ops = {
|
||
.open = hguart_v2_open,
|
||
.close = hguart_v2_close,
|
||
.putc = hguart_v2_putc,
|
||
.getc = hguart_v2_getc,
|
||
.puts = hguart_v2_puts,
|
||
.gets = hguart_v2_gets,
|
||
.ioctl = hguart_v2_ioctl,
|
||
.request_irq = hguart_v2_request_irq,
|
||
.release_irq = hguart_v2_release_irq,
|
||
#ifdef CONFIG_SLEEP
|
||
.ops.suspend = NULL,//hguart_v2_suspend,
|
||
.ops.resume = NULL,//hguart_v2_resume,
|
||
#endif
|
||
};
|
||
|
||
int32 hguart_v2_attach(uint32 dev_id, struct hguart_v2 *uart)
|
||
{
|
||
uart->opened = 0;
|
||
uart->dsleep = 0;
|
||
uart->use_dma = 0;
|
||
uart->irq_hdl = NULL;
|
||
uart->irq_data = 0;
|
||
uart->flag = 0;
|
||
uart->dev.dev.ops = (const struct devobj_ops *)&uart_v2_ops;
|
||
#ifdef CONFIG_SLEEP
|
||
|
||
|
||
#endif
|
||
irq_disable(uart->irq_num);
|
||
dev_register(dev_id, (struct dev_obj *)uart);
|
||
return RET_OK;
|
||
}
|
||
|