blob: 2b9e47c759f7a63607bef8527c4cae158735d897 [file] [log] [blame]
/*
* Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************************************************
* @file dw_usart.c
* @brief CSI Source File for usart Driver
* @version V1.0
* @date 02. June 2017
******************************************************************************/
#include <stdbool.h>
#include "csi_core.h"
#include "drv_usart.h"
#include "dw_usart.h"
#include "soc.h"
#define ERR_USART(errno) (CSI_DRV_ERRNO_USART_BASE | errno)
/*
* setting config may be accessed when the USART is not
* busy(USR[0]=0) and the DLAB bit(LCR[7]) is set.
*/
#define WAIT_USART_IDLE(addr)\
do { \
int32_t timecount = 0; \
while ((addr->USR & USR_UART_BUSY) && (timecount < UART_BUSY_TIMEOUT)) {\
timecount++;\
}\
if (timecount >= UART_BUSY_TIMEOUT) {\
return ERR_USART(EDRV_TIMEOUT);\
} \
} while(0)
#define USART_NULL_PARAM_CHK(para) \
do { \
if (para == NULL) { \
return ERR_USART(EDRV_PARAMETER); \
} \
} while (0)
typedef struct {
uint32_t base;
} dw_usart_priv_t;
extern int32_t target_usart_init(pin_t tx, pin_t rx, uint32_t *base, uint32_t *irq);
extern int32_t target_usart_flowctrl_init(pin_t tx_flow, pin_t rx_flow, uint32_t flag);
static dw_usart_priv_t usart_instance[CONFIG_USART_NUM];
static const usart_capabilities_t usart_capabilities = {
.asynchronous = 0, /* supports USART (Asynchronous) mode */
.synchronous_master = 0, /* supports Synchronous Master mode */
.synchronous_slave = 0, /* supports Synchronous Slave mode */
.single_wire = 0, /* supports USART Single-wire mode */
.event_tx_complete = 0, /* Transmit completed event */
.event_rx_timeout = 0, /* Signal receive character timeout event */
};
/**
\brief set the baut drate of usart.
\param[in] addr usart base to operate.
\param[in] baudrate baud rate
\param[in] apbfreq the frequency of the apb.
\return error code
*/
int32_t csi_usart_config_baudrate(usart_handle_t handle, uint32_t baudrate, uint32_t apbfreq)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
#ifdef CONFIG_CHIP_HOBBIT1_2
uint8_t data[16];
csi_usart_receive_query(handle, data, 16);
#endif
WAIT_USART_IDLE(addr);
/* baudrate=(seriak clock freq)/(16*divisor); algorithm :rounding*/
uint32_t divisor = ((apbfreq * 10) / baudrate) >> 4;
if ((divisor % 10) >= 5) {
divisor = (divisor / 10) + 1;
} else {
divisor = divisor / 10;
}
addr->LCR |= LCR_SET_DLAB;
/* DLL and DLH is lower 8-bits and higher 8-bits of divisor.*/
addr->DLL = divisor & 0xff;
addr->DLH = (divisor >> 8) & 0xff;
/*
* The DLAB must be cleared after the baudrate is setted
* to access other registers.
*/
addr->LCR &= (~LCR_SET_DLAB);
return 0;
}
/**
\brief config usart mode.
\param[in] handle usart handle to operate.
\param[in] mode \ref usart_mode_e
\return error code
*/
int32_t csi_usart_config_mode(usart_handle_t handle, usart_mode_e mode)
{
if (mode == USART_MODE_ASYNCHRONOUS) {
return 0;
}
return ERR_USART(EDRV_USART_MODE);
}
/**
\brief config usart parity.
\param[in] handle usart handle to operate.
\param[in] parity \ref usart_parity_e
\return error code
*/
int32_t csi_usart_config_parity(usart_handle_t handle, usart_parity_e parity)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
WAIT_USART_IDLE(addr);
switch (parity) {
case USART_PARITY_NONE:
/*CLear the PEN bit(LCR[3]) to disable parity.*/
addr->LCR &= (~LCR_PARITY_ENABLE);
break;
case USART_PARITY_ODD:
/* Set PEN and clear EPS(LCR[4]) to set the ODD parity. */
addr->LCR |= LCR_PARITY_ENABLE;
addr->LCR &= LCR_PARITY_ODD;
break;
case USART_PARITY_EVEN:
/* Set PEN and EPS(LCR[4]) to set the EVEN parity.*/
addr->LCR |= LCR_PARITY_ENABLE;
addr->LCR |= LCR_PARITY_EVEN;
break;
default:
return ERR_USART(EDRV_USART_PARITY);
}
return 0;
}
/**
\brief config usart stop bit number.
\param[in] handle usart handle to operate.
\param[in] stopbits \ref usart_stop_bits_e
\return error code
*/
int32_t dw_usart_config_stopbits(usart_handle_t handle, usart_stop_bits_e stopbit)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
WAIT_USART_IDLE(addr);
switch (stopbit) {
case USART_STOP_BITS_1:
/* Clear the STOP bit to set 1 stop bit*/
addr->LCR &= LCR_STOP_BIT1;
break;
case USART_STOP_BITS_2:
/*
* If the STOP bit is set "1",we'd gotten 1.5 stop
* bits when DLS(LCR[1:0]) is zero, else 2 stop bits.
*/
addr->LCR |= LCR_STOP_BIT2;
break;
default:
return ERR_USART(EDRV_USART_STOP_BITS);
}
return 0;
}
/**
\brief config usart data length.
\param[in] handle usart handle to operate.
\param[in] databits \ref usart_data_bits_e
\return error code
*/
int32_t csi_usart_config_databits(usart_handle_t handle, usart_data_bits_e databits)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
#ifdef CONFIG_CHIP_HOBBIT1_2
uint8_t data[16];
csi_usart_receive_query(handle, data, 16);
#endif
WAIT_USART_IDLE(addr);
/* The word size decides by the DLS bits(LCR[1:0]), and the
* corresponding relationship between them is:
* DLS word size
* 00 -- 5 bits
* 01 -- 6 bits
* 10 -- 7 bits
* 11 -- 8 bits
*/
switch (databits) {
case USART_DATA_BITS_5:
addr->LCR &= LCR_WORD_SIZE_5;
break;
case USART_DATA_BITS_6:
addr->LCR &= 0xfd;
addr->LCR |= LCR_WORD_SIZE_6;
break;
case USART_DATA_BITS_7:
addr->LCR &= 0xfe;
addr->LCR |= LCR_WORD_SIZE_7;
break;
case USART_DATA_BITS_8:
addr->LCR |= LCR_WORD_SIZE_8;
break;
default:
return ERR_USART(EDRV_USART_DATA_BITS);
}
return 0;
}
/**
\brief get character in query mode.
\param[in] handle usart handle to operate.
\param[in] the pointer to the received character if return 0.
\return error code
*/
int32_t csi_usart_getchar(usart_handle_t handle, uint8_t *ch)
{
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
while (!(addr->LSR & LSR_DATA_READY));
*ch = addr->RBR;
return 0;
}
/**
\brief transmit character in query mode.
\param[in] handle usart handle to operate.
\param[in] ch the input character
\return error code
*/
int32_t csi_usart_putchar(usart_handle_t handle, uint8_t ch)
{
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
while ((!(addr->LSR & DW_LSR_TRANS_EMPTY)));
addr->THR = ch;
return 0;
}
/**
\brief the interrupt service function.
\param[in] index of usart instance.
*/
void dw_usart_irqhandler(int32_t idx)
{
(void)idx;
}
/**
\brief Get driver capabilities.
\param[in] handle usart handle to operate.
\return \ref usart_capabilities_t
*/
usart_capabilities_t csi_usart_get_capabilities(usart_handle_t handle)
{
return usart_capabilities;
}
/**
\brief Initialize USART Interface. 1. Initializes the resources needed for the USART interface 2.registers event callback function
\param[in] usart pin of tx
\param[in] usart pin of rx
\param[in] cb_event Pointer to \ref usart_event_cb_t
\return return usart handle if success
*/
usart_handle_t csi_usart_initialize(pin_t tx, pin_t rx, usart_event_cb_t cb_event, void *cb_arg)
{
uint32_t base = 0u;
uint32_t irq = 0u;
int32_t idx = target_usart_init(tx, rx, &base, &irq);
if (idx < 0 || idx >= CONFIG_USART_NUM) {
return NULL;
}
dw_usart_priv_t *usart_priv = &usart_instance[idx];
usart_priv->base = base;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
/* FIFO enable */
addr->FCR = DW_FCR_FIFOE | DW_FCR_RT_FIFO_HALF;
return usart_priv;
}
/**
\brief De-initialize UART Interface. stops operation and releases the software resources used by the interface
\param[in] handle usart handle to operate.
\return error code
*/
int32_t csi_usart_uninitialize(usart_handle_t handle)
{
USART_NULL_PARAM_CHK(handle);
return 0;
}
/**
\brief config usart mode.
\param[in] handle usart handle to operate.
\param[in] sysclk configured system clock.
\param[in] baud baud rate
\param[in] mode \ref usart_mode_e
\param[in] parity \ref usart_parity_e
\param[in] stopbits \ref usart_stop_bits_e
\param[in] bits \ref usart_data_bits_e
\return error code
*/
int32_t csi_usart_config(usart_handle_t handle,
uint32_t sysclk,
uint32_t baud,
usart_mode_e mode,
usart_parity_e parity,
usart_stop_bits_e stopbits,
usart_data_bits_e bits)
{
int32_t ret;
/* control the data_bit of the usart*/
ret = csi_usart_config_baudrate(handle, baud, sysclk);
if (ret < 0) {
return ret;
}
/* control mode of the usart*/
ret = csi_usart_config_mode(handle, mode);
if (ret < 0) {
return ret;
}
/* control the parity of the usart*/
ret = csi_usart_config_parity(handle, parity);
if (ret < 0) {
return ret;
}
/* control the stopbit of the usart*/
ret = dw_usart_config_stopbits(handle, stopbits);
if (ret < 0) {
return ret;
}
ret = csi_usart_config_databits(handle, bits);
if (ret < 0) {
return ret;
}
return 0;
}
/**
\brief config usart default tx value. used in syn mode
\param[in] handle usart handle to operate.
\param[in] value default tx value
\return error code
*/
int32_t csi_usart_set_default_tx_value(usart_handle_t handle, uint32_t value)
{
USART_NULL_PARAM_CHK(handle);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Start sending data to UART transmitter,(received data is ignored).
The function is non-blocking,UART_EVENT_TRANSFER_COMPLETE is signaled when transfer completes.
csi_usart_get_status can indicates if transmission is still in progress or pending
\param[in] handle usart handle to operate.
\param[in] data Pointer to buffer with data to send to UART transmitter. data_type is : uint8_t for 1..8 data bits, uint16_t for 9..16 data bits,uint32_t for 17..32 data bits,
\param[in] num Number of data items to send
\return error code
*/
int32_t csi_usart_send(usart_handle_t handle, const void *data, uint32_t num)
{
USART_NULL_PARAM_CHK(handle);
USART_NULL_PARAM_CHK(data);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Abort Send data to UART transmitter
\param[in] handle usart handle to operate.
\return error code
*/
int32_t csi_usart_abort_send(usart_handle_t handle)
{
USART_NULL_PARAM_CHK(handle);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Start receiving data from UART receiver.transmits the default value as specified by csi_usart_set_default_tx_value
\param[in] handle usart handle to operate.
\param[out] data Pointer to buffer for data to receive from UART receiver
\param[in] num Number of data items to receive
\return error code
*/
int32_t csi_usart_receive(usart_handle_t handle, void *data, uint32_t num)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief query data from UART receiver FIFO.
\param[in] handle usart handle to operate.
\param[out] data Pointer to buffer for data to receive from UART receiver
\param[in] num Number of data items to receive
\return receive fifo data num
*/
int32_t csi_usart_receive_query(usart_handle_t handle, void *data, uint32_t num)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Abort Receive data from UART receiver
\param[in] handle usart handle to operate.
\return error code
*/
int32_t csi_usart_abort_receive(usart_handle_t handle)
{
USART_NULL_PARAM_CHK(handle);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Start sending/receiving data to/from UART transmitter/receiver.
\param[in] handle usart handle to operate.
\param[in] data_out Pointer to buffer with data to send to USART transmitter
\param[out] data_in Pointer to buffer for data to receive from USART receiver
\param[in] num Number of data items to transfer
\return error code
*/
int32_t csi_usart_transfer(usart_handle_t handle, const void *data_out, void *data_in, uint32_t num)
{
USART_NULL_PARAM_CHK(handle);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief abort sending/receiving data to/from USART transmitter/receiver.
\param[in] handle usart handle to operate.
\return error code
*/
int32_t csi_usart_abort_transfer(usart_handle_t handle)
{
USART_NULL_PARAM_CHK(handle);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Get USART status.
\param[in] handle usart handle to operate.
\return USART status \ref usart_status_t
*/
usart_status_t csi_usart_get_status(usart_handle_t handle)
{
usart_status_t status = {0};
return status;
}
/**
\brief control the transmit.
\param[in] handle usart handle to operate.
\param[in] 1 - enable the transmitter. 0 - disable the transmitter
\return error code
*/
int32_t csi_usart_control_tx(usart_handle_t handle, uint32_t enable)
{
USART_NULL_PARAM_CHK(handle);
return 0;
}
/**
\brief control the receive.
\param[in] handle usart handle to operate.
\param[in] 1 - enable the receiver. 0 - disable the receiver
\return error code
*/
int32_t csi_usart_control_rx(usart_handle_t handle, uint32_t enable)
{
USART_NULL_PARAM_CHK(handle);
return 0;
}
/**
\brief control the break.
\param[in] handle usart handle to operate.
\param[in] 1- Enable continuous Break transmission,0 - disable continuous Break transmission
\return error code
*/
int32_t csi_usart_control_break(usart_handle_t handle, uint32_t enable)
{
USART_NULL_PARAM_CHK(handle);
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief flush receive/send data.
\param[in] handle usart handle to operate.
\param[in] type \ref usart_flush_type_e.
\return error code
*/
int32_t csi_usart_flush(usart_handle_t handle, usart_flush_type_e type)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
if (type == USART_FLUSH_WRITE) {
addr->FCR |= DW_FCR_XFIFOR;
while (addr->FCR & DW_FCR_XFIFOR);
} else if (type == USART_FLUSH_READ) {
addr->FCR |= DW_FCR_RFIFOR;
while (addr->FCR & DW_FCR_RFIFOR);
} else {
return ERR_USART(EDRV_PARAMETER);
}
return 0;
}
/**
\brief control interrupt on/off.
\param[in] handle usart handle to operate.
\param[in] type \ref usart_intr_type_e.
\param[in] flag 0-OFF, 1-ON.
\return error code
*/
int32_t csi_usart_interrupt_on_off(usart_handle_t handle, usart_intr_type_e type, int flag)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Get usart send data count.
\param[in] handle usart handle to operate.
\return number of data bytes transferred
*/
uint32_t csi_usart_get_tx_count(usart_handle_t handle)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief Get usart receive data count.
\param[in] handle usart handle to operate.
\return number of data bytes transferred
*/
uint32_t csi_usart_get_rx_count(usart_handle_t handle)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief control usart power.
\param[in] handle usart handle to operate.
\param[in] state power state.\ref csi_power_stat_e.
\return error code
*/
int32_t csi_usart_power_control(usart_handle_t handle, csi_power_stat_e state)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief config usart flow control type.
\param[in] handle usart handle to operate.
\param[in] flowctrl_type flow control type.\ref usart_flowctrl_type_e.
\param[in] tx_flow The TX flow pin name
\param[in] rx_flow The RX flow pin name
\return error code
*/
int32_t csi_usart_config_flowctrl(usart_handle_t handle,
usart_flowctrl_type_e flowctrl_type,
pin_t tx_flow, pin_t rx_flow)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
int32_t ret;
switch (flowctrl_type) {
case USART_FLOWCTRL_CTS:
return ERR_USART(EDRV_UNSUPPORTED);
case USART_FLOWCTRL_RTS:
return ERR_USART(EDRV_UNSUPPORTED);
case USART_FLOWCTRL_CTS_RTS:
ret = target_usart_flowctrl_init(tx_flow, rx_flow, 1);
if (ret < 0) {
return ERR_USART(EDRV_PARAMETER);
}
WAIT_USART_IDLE(addr);
addr->MCR |= DW_MCR_AFCE | DW_MCR_RTS;
break;
case USART_FLOWCTRL_NONE:
ret = target_usart_flowctrl_init(tx_flow, rx_flow, 0);
if (ret < 0) {
return ERR_USART(EDRV_PARAMETER);
}
WAIT_USART_IDLE(addr);
addr->MCR = 0;
break;
default:
return ERR_USART(EDRV_UNSUPPORTED);
}
return 0;
}
/**
\brief usart modem control.
\param[in] handle usart handle to operate.
\param[in] modem_ctrl modem control action.\ref usart_modem_ctrl_e.
\return error code
*/
int32_t csi_usart_modem_ctrl(usart_handle_t handle, usart_modem_ctrl_e modem_ctrl)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief get usart modem status.
\param[in] handle usart handle to operate.
\param[in] modem_ctrl modem control action.\ref usart_modem_ctrl_e.
\return modem status.\ref usart_modem_stat_t.
*/
usart_modem_stat_t csi_usart_get_modem_stat(usart_handle_t handle)
{
usart_modem_stat_t modem_stat = {0};
return modem_stat;
}
/**
\brief config usart clock Polarity and Phase.
\param[in] handle usart handle to operate.
\param[in] cpol Clock Polarity.\ref usart_cpol_e.
\param[in] cpha Clock Phase.\ref usart_cpha_e.
\return error code
*/
int32_t csi_usart_config_clock(usart_handle_t handle, usart_cpol_e cpol, usart_cpha_e cpha)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief config usart guard time.
\param[in] handle usart handle to operate.
\param[in] num_of_bits guard time in number of bit periods.
\return error code
*/
int32_t csi_usart_config_guard_time(usart_handle_t handle, uint32_t num_of_bits)
{
return ERR_USART(EDRV_UNSUPPORTED);
}
/**
\brief check if usart is readable(data received).
\param[in] handle usart handle to operate.
\return 1 - a character can be read, 0 if nothing to read ,negative for error code
*/
int32_t csi_usart_readable(usart_handle_t handle)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
if (addr->LSR & LSR_DATA_READY) {
return 1;
} else {
return 0;
}
}
/**
\brief check if usart is writable(free for data sending).
\param[in] handle usart handle to operate.
\return 1 - a character can be written, 0 - cannot be written ,negative for error code
*/
int32_t csi_usart_writable(usart_handle_t handle)
{
USART_NULL_PARAM_CHK(handle);
dw_usart_priv_t *usart_priv = handle;
dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
if (addr->LSR & DW_LSR_TRANS_EMPTY) {
return 1;
} else {
return 0;
}
}