pure sdk for main

This commit is contained in:
divadiow
2025-08-27 09:51:58 +01:00
parent f0d033f1c9
commit 0571416e7c
3283 changed files with 1577720 additions and 1 deletions
+998
View File
@@ -0,0 +1,998 @@
/**
* @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"
#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 (HG_UART0_BASE == (uint32)hw) {
sysctrl_uart0_clk_open();
} else if (HG_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 */
hw->BAUD = (peripheral_clock_get(HG_APB0_PT_UART0) / baudrate) - 1;
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 (HG_UART0_BASE == (uint32)hw) {
sysctrl_uart0_clk_close();
} else if (HG_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);
/* waiting for tx done */
/*在这里被调度走后,一种是另一个线程调用puts, 一种是休眠唤醒清掉了pending
第一种情况,还没有人报bug,暂时不考虑
第二种情况,休眠唤醒时会清掉TDMALEN, 然后这里等待的时候就会检测到了
*/
while (!(hw->DMASTA & LL_UART_DMASTA_TX_DMA_PEND)) {
if(!hw->TDMALEN) {
break;
}
}
irq_flag = disable_irq();
dev->flag &= ~UART_FLAG_TDMA_BUSY;
enable_irq(irq_flag);
} 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);
}
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;
}
}
}
#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;
}
//等TX DMA DONE
if(dev->flag & UART_FLAG_TDMA_BUSY) {
while (!(hw->DMASTA & LL_UART_DMASTA_TX_DMA_PEND));
hw->TDMALEN = 0;
}
/*!
* Close the UART
*/
hw->CON &= ~ BIT(0);
pin_func(dev->dev.dev.dev_id, 0);
/*
* close irq
*/
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));
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.tstadr = hw->TSTADR;
dev->bp_regs.rstadr = hw->RSTADR;
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;
/*
* save the irq_hdl created by user
*/
dev->bp_irq_hdl = dev->irq_hdl;
dev->bp_irq_data = dev->irq_data;
if (HG_UART0_BASE == (uint32)hw) {
sysctrl_uart0_clk_close();
} else if (HG_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;
}
/*
* recovery the UART clk
*/
if (HG_UART0_BASE == (uint32)hw) {
sysctrl_uart0_clk_open();
} else if (HG_UART1_BASE == (uint32)hw) {
sysctrl_uart1_clk_open();
}
/*
* 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 | BIT(8) | BIT(9);
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;
/*
* 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(0);
/*
* open irq
*/
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;
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->dev.dev.ops = (const struct devobj_ops *)&uart_v2_ops;
#ifdef CONFIG_SLEEP
uart->flag = 0;
#endif
irq_disable(uart->irq_num);
dev_register(dev_id, (struct dev_obj *)uart);
return RET_OK;
}
+250
View File
@@ -0,0 +1,250 @@
#ifndef _HGUART_V2_HW_H_
#define _HGUART_V2_HW_H_
#ifdef __cplusplus
extern "C" {
#endif
/***** UARTCON *****/
/*! RX buffer trigger threshold
*/
#define LL_UART_CON_RBUF_TRIG(n) (((n)&0x03) << 18)
/*! Singal RTS_N enable
*/
#define LL_UART_CON_RTS_EN (1UL << 17)
/*! Singal CTS_N enable
*/
#define LL_UART_CON_CTS_EN (1UL << 16)
/*! Transmission complete interrupt enable
*/
#define LL_UART_CON_TCIE_EN (1UL << 15)
/*! UART with carrier output enable.
* @note UART0 outputs pwm of TIMER0, and UART1 outputs pwm of TIMER1.
*/
#define LL_UART_CON_TMR_PWM_EN (1UL << 14)
/*! Frame error interrupt enable
* @note A frame error refers to a low-level signal received by rx during
* the stop bit.
*/
#define LL_UART_CON_FERR_IE_EN (1UL << 11)
/*! TX buffer empty interrupt enable
*/
#define LL_UART_CON_TXBUF_EMPTY_IE_EN (1UL << 10)
/*! RX buffer not empty interrupt enable
*/
#define LL_UART_CON_RXBUF_NEMPTY_IE_EN (1UL << 9)
/*! Inverted TX signal
*/
#define LL_UART_CON_TX_INV_EN (1UL << 8)
/*! Inverted RX signal
*/
#define LL_UART_CON_RX_INV_EN (1UL << 7)
/*! Odd parity
* @note Parity and 9bit data transfer cannot be used at the same time.
*/
#define LL_UART_CON_ODD_EN (1UL << 6)
/*! parity enable
* @note Parity and 9bit data transfer cannot be used at the same time.
*/
#define LL_UART_CON_PARITY_EN (1UL << 5)
/*! 9bit data transfer enable
* @note Parity and 9bit data transfer cannot be used at the same time.
*/
#define LL_UART_CON_BIT9_EN (1UL << 4)
/*! Stop bit selection
*/
#define LL_UART_CON_STOP_BIT(n) (((n)&0x01) << 3)
/*! Work mode selection
*/
#define LL_UART_CON_WORK_MODE(n) (((n)&0x03) << 1)
/*! UART module enable
*/
#define LL_UART_CON_UART_EN (1UL << 0)
/***** UARTSTA *****/
/*! Transmission complete pending
*/
#define LL_UART_STA_TC_PENDING (1UL << 12)
/*! RX timeout detection pending
* @note Only UART0 has this feature.
*/
#define LL_UART_STA_TO_PEND (1UL << 11)
/*! RX parity error pending
* @note 4 bits corrspond to 4 frame data in rx buffer.
*/
#define LL_UART_STA_PERR_PEND(n) (((n)>>7) & 0x0F)
/*! The amount of data in the rx fifo
*/
#define LL_UART_STA_RX_CNT(n) (((n)>>4) & 0x07)
/*! Frame error pending
*/
#define LL_UART_STA_FERR_PENDING (1UL << 3)
/*! RX FIFO overflow pending
*/
#define LL_UART_STA_RX_BUF_OV (1UL << 2)
/*! RX FIFO not empty pending
*/
#define LL_UART_STA_RX_BUF_NOT_EMPTY (1UL << 1)
/*! TX FIFO empty pending
*/
#define LL_UART_STA_TX_BUF_EMPTY (1UL << 0)
/***** DMACON *****/
/*! RX DMA parity error interrupt enable
* @note Only UART1 has this feature
*/
#define LL_UART_DMACON_RX_DMA_PERR_IE_EN (1UL << 4)
/*! RX DMA interrupt enable
* @note Only UART1 has this feature
*/
#define LL_UART_DMACON_RX_DMA_IE_EN (1UL << 3)
/*! TX DMA interrupt enable
* @note Only UART1 has this feature
*/
#define LL_UART_DMACON_TX_DMA_IE_EN (1UL << 2)
/*! RX DMA enable
* @note Only UART1 has this feature
*/
#define LL_UART_DMACON_RX_DMA_EN (0x0101UL << 1)
/*! TX DMA enable
* @note Only UART1 has this feature
*/
#define LL_UART_DMACON_TX_DMA_EN (0x0101UL << 0)
/***** DMASTA *****/
/*! RX DMA parity error pending
* @note Only UART1 has this feature
*/
#define LL_UART_DMASTA_RX_DMA_PERR (1UL << 2)
/*! RX DMA pending
* @note Only UART1 has this feature
*/
#define LL_UART_DMASTA_RX_DMA_PEND (1UL << 1)
/*! TX DMA pending
* @note Only UART1 has this feature
*/
#define LL_UART_DMASTA_TX_DMA_PEND (1UL << 0)
/***** UART_RS485_CON *****/
/*! RS485 RE enable
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_CON_RE_EN (1UL << 9)
/*! RS485 DE enable
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_CON_DE_EN (1UL << 8)
/*! RS485 work mode
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_CON_RS485_MODE(n) (((n)&0x01) << 3)
/*! RS485 RE polarity
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_CON_RE_POL(n) (((n)&0x01) << 2)
/*! RS485 DE polarity
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_CON_DE_POL(n) (((n)&0x01) << 1)
/*! RS485 enable
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_CON_RS485_EN (1UL << 0)
/***** UART_RS485_DET *****/
/*! The time interval between the end of STOP BIT and DE invalid. The unit
* is the uart module clock.
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_DET_DE_DAT(n) (((n)&0x01FF) << 16)
/*! The time interval between the time DE is valid and the START BIT is sent.
* The unit is the uart module clock.
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_DET_DE_AT(n) (((n)&0x01FF) << 0)
/***** UART_RS485_TAT *****/
/*! The time interval between the valid of RE and DE valid, the unit is the
* uart module clock.
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_TAT_RE2DE_T(n) (((n)&0xFFFF) << 16)
/*! The time interval between DE valid and RE valid, the unit is the uart
* module clock.
* @note Only UART1 has this feature
*/
#define LL_UART_RS485_TAT_DE2RE_T(n) (((n)&0xFFFF) << 0)
/***** UART_TOCON *****/
/*! Timeout time configure
*/
#define LL_UART_TOCON_TO_BIT_LEN(n) (((n)&0xFFFF) << 16)
/*! Timeout interrupt enable
*/
#define LL_UART_TOCON_TO_IE_EN (1UL << 1)
/*! Timeout enable
*/
#define LL_UART_TOCON_TO_EN (1UL << 0)
typedef struct hguart_v2_hw {
__IO uint32_t CON;
__IO uint32_t BAUD;
__IO uint32_t DATA;
__IO uint32_t STA;
__IO uint32_t TSTADR;
__IO uint32_t RSTADR;
__IO uint32_t TDMALEN;
__IO uint32_t RDMALEN;
__IO uint32_t TDMACNT;
__IO uint32_t RDMACNT;
__IO uint32_t DMACON;
__IO uint32_t DMASTA;
__IO uint32_t RS485_CON;
__IO uint32_t RS485_DET;
__IO uint32_t RS485_TAT;
__IO uint32_t TOCON;
}UART_TypeDef;
/**
* @brief enable RS485 RE pin
* @param p_uart : The structure pointer of the UART
* @retval None
*/
__STATIC_INLINE void ll_uart485_re_enable(UART_TypeDef *p_uart) {
p_uart->RS485_CON |= LL_UART_RS485_CON_RE_EN;
}
/**
* @brief disable RS485 RE pin
* @param p_uart : The structure pointer of the UART
* @retval None
*/
__STATIC_INLINE void ll_uart485_re_disable(UART_TypeDef *p_uart) {
p_uart->RS485_CON &= (~LL_UART_RS485_CON_RE_EN);
}
/**
* @brief enable RS485 DE pin
* @param p_uart : The structure pointer of the UART
* @retval None
*/
__STATIC_INLINE void ll_uart485_de_enable(UART_TypeDef *p_uart) {
p_uart->RS485_CON |= LL_UART_RS485_CON_DE_EN;
}
/**
* @brief disable RS485 DE pin
* @param p_uart : The structure pointer of the UART
* @retval None
*/
__STATIC_INLINE void ll_uart485_de_disable(UART_TypeDef *p_uart) {
p_uart->RS485_CON &= (~LL_UART_RS485_CON_DE_EN);
}
#ifdef __cplusplus
}
#endif
#endif /* _HGUART_V2_HW_H_ */
+719
View File
@@ -0,0 +1,719 @@
/**
* @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;
//printf("len:%d\r\n", dev->tx_total_byte);
//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 ;
//request_irq(dev->irq_num, hguart_v4_irq_handler, dev);
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;
}
//irq_enable(dev->comm_irq_num);
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;
}
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);
/*
* close irq
*/
irq_disable(dev->comm_irq_num);
/*
* 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 (HG_UART4_BASE == (uint32)hw) {
sysctrl_uart0_clk_close();
} else if (HG_UART5_BASE == (uint32)hw) {
sysctrl_uart0_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 (HG_UART4_BASE == (uint32)hw) {
sysctrl_uart0_clk_open();
} else if (HG_UART5_BASE == (uint32)hw) {
sysctrl_uart0_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);
/*
* open irq
*/
irq_enable(dev->comm_irq_num);
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);
irq_enable(uart->comm_irq_num);
dev_register(dev_id, (struct dev_obj *)uart);
return RET_OK;
}
+164
View File
@@ -0,0 +1,164 @@
#ifndef _HGUART_V4_HW_H_
#define _HGUART_V4_HW_H_
#ifdef __cplusplus
extern "C" {
#endif
/***** UARTCON *****/
/*! Timeout interrupt en
*/
#define LL_SIMPLE_UART_CON_TO_IE (1UL << 31)
/*! Timeout function en
*/
#define LL_SIMPLE_UART_CON_TO_EN (1UL << 30)
/*! Timeout pending
*/
#define LL_SIMPLE_UART_CON_CLRTOPEND (1UL << 29)
/*! Transmission completed The 1byte flag was cleared to zero
*/
#define LL_SIMPLE_UART_CON_CLRTXDONE (1UL << 28)
/*! The frame receiving error detection flag is cleared to zero
*/
#define LL_SIMPLE_UART_CON_CLRFERR (1UL << 27)
/*! The receive cache register is not null flag cleared
*/
#define LL_SIMPLE_UART_CON_CLRRXDONE (1UL << 26)
/*! DMA interrupt flag cleared to zero
*/
#define LL_SIMPLE_UART_CON_CLRDMAPEND (1UL << 25)
/*! Receive address interrupt flag cleared to zero
*/
#define LL_SIMPLE_UART_CON_CLRRXADDRPEND (1UL << 24)
/*! Transmission completed 1byte flag. This bit is 0 when the module is disabled
*/
#define LL_SIMPLE_UART_CON_TXDONE (1UL << 21)
/*! Frame receiving error detection flag
*/
#define LL_SIMPLE_UART_CON_FERR (1UL << 20)
/*! Receive cache register is not empty flag, this bit is 0 when the module is not enabled
*/
#define LL_SIMPLE_UART_CON_RXBUFNOTEMPTY (1UL << 19)
/*! The send cache register is an empty flag. This bit is 0 when the module is disabled
*/
#define LL_SIMPLE_UART_CON_TXBUFEMPTY (1UL << 18)
/*! The DMA completion flag bit, which is set to 1 when a send or receive is complete using DMA
*/
#define LL_SIMPLE_UART_CON_DMAPEND (1UL << 17)
/*! Receive address interrupt flag RXADDRPEND
*/
#define LL_SIMPLE_UART_CON_RXADDRPEND (1UL << 16)
/*! RX_TIMEOUT PENDING
*/
#define LL_SIMPLE_UART_CON_TO_PENDING (1UL << 15)
/*! Select UART output with which PWM carrier:
*/
#define LL_SIMPLE_UART_CON_CARRIER_SEL(n) (((n)&0x09) << 11)
/*! Set the CARRIER_SEL bit to the PWM carrier mode enable bit. Specify the carrier_sel bit for the specific PWM carrier of the TIMER
*/
#define LL_SIMPLE_UART_CON_PWM_CARRIER_EN (1UL << 10)
/*! The receiving address was interrupted. Procedure
*/
#define LL_SIMPLE_UART_CON_RXADDRIE (1UL << 9)
/*! Error detection interrupt enabled
*/
#define LL_SIMPLE_UART_CON_FERRIE (1UL << 8)
/*! DMA interrupt enabled
*/
#define LL_SIMPLE_UART_CON_DMA_IE (1UL << 7)
/*! Stop bit setting
*/
#define LL_SIMPLE_UART_CON_STOPBIT (1UL << 6)
/*! The 9bit function was enabled
*/
#define LL_SIMPLE_UART_CON_BIT9EN (1UL << 5)
/*! The Uart function was enabled
*/
#define LL_SIMPLE_UART_CON_UARTEN (1UL << 4)
/*! Send data inversely
*/
#define LL_SIMPLE_UART_CON_TXINV (1UL << 3)
/*! The received data is reversed
*/
#define LL_SIMPLE_UART_CON_RXINV (1UL << 2)
/*! Send 1byte to enable the interrupt
*/
#define LL_SIMPLE_UART_CON_UARTTXIE (1UL << 1)
/*! The receiving interrupt function was enabled
*/
#define LL_SIMPLE_UART_CON_UARTRXIE (1UL << 0)
/***** UARTBAUD *****/
/*! Baud rate setting
*/
#define LL_SIMPLE_UART_UARTBAUD(n) (((n)&0x0003FFFF) << 0)
/***** UARTDATA *****/
/*! Data register
*/
#define LL_SIMPLE_UART_UARTDATA(n) (((n)&0x000000FF) << 0)
/***** UARTTOCON *****/
/*! TOCON register
*/
#define LL_SIMPLE_UART_TOCON(n) (((n)&0x0000FFFF) << 0)
/***** UARTDMAADR *****/
/*! DMAADR register
*/
#define LL_SIMPLE_UART_UARTDMAADR(n) (((n)&0xFFFFFFFF) << 0)
/***** UARTDMALEN *****/
/*! DMALEN register
*/
#define LL_SIMPLE_UART_UARTDMALEN(n) (((n)&0x000007FF) << 0)
/***** UARTDMACON *****/
/*!DMACON register
*/
#define LL_SIMPLE_UART_UART_TX_USEDMA_KEY (1UL << 3)
#define LL_SIMPLE_UART_UART_RX_USEDMA_KEY (1UL << 2)
#define LL_SIMPLE_UART_UART_TX_USEDMA (1UL << 1)
#define LL_SIMPLE_UART_UART_RX_USEDMA (1UL << 0)
/**
* @brief Simple Universal Synchronous Asynchronous Receiver Transmitter
*/
struct hguart_v4_hw{
__IO uint32_t CON;
__IO uint32_t BAUD;
__IO uint32_t DATA;
__IO uint32_t TOCON;
__IO uint32_t DMAADR;
__IO uint32_t DMALEN;
__IO uint32_t DMACON;
__IO uint32_t DMACNT;
};
#ifdef __cplusplus
}
#endif
#endif /* _HGUART_V4_HW_H_ */