Files
TAIXIN/sdk/driver/uart/hguart_v2.c

1067 lines
28 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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;
}