rt-thread/bsp/phytium/libraries/standalone/drivers/serial/fpl011/fpl011.c

287 lines
8.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fpl011.c
* Date: 2021-11-02 14:53:42
* LastEditTime: 2022-02-18 09:07:24
* Description:  This file is for uart functions
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 huanghe 2021/11/2 first commit
* 1.1 liushengming 2022/02/18 fix bug
*/
/***************************** Include Files ********************************/
#include "fpl011.h"
#include "fio.h"
#include "ferror_code.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
u32 FPl011SendBuffer(FPl011 *uart_p);
u32 FPl011ReceiveBuffer(FPl011 *uart_p);
static void FPl011StubHandler(void *Args, u32 Event,
u32 ByteCount);
/*****************************************************************************/
FError FPl011CfgInitialize(FPl011 *uart_p, FPl011Config *config)
{
u32 reg_value = 0;
FError ret ;
FASSERT(uart_p != NULL);
FASSERT(config != NULL);
uart_p->config.instance_id = config->instance_id;
uart_p->config.base_address = config->base_address;
uart_p->config.ref_clock_hz = config->ref_clock_hz;
uart_p->config.irq_num = config->irq_num;
uart_p->config.baudrate = config->baudrate;
uart_p->handler = FPl011StubHandler;
uart_p->send_buffer.byte_p = NULL;
uart_p->send_buffer.requested_bytes = 0;
uart_p->send_buffer.remaining_bytes = 0;
uart_p->receive_buffer.byte_p = NULL;
uart_p->receive_buffer.requested_bytes = 0;
uart_p->receive_buffer.remaining_bytes = 0;
uart_p->rxbs_error = 0;
uart_p->is_ready = FT_COMPONENT_IS_READY;
ret = FPl011SetBaudRate(uart_p, uart_p->config.baudrate);
if (ret != FT_SUCCESS)
{
uart_p->is_ready = 0U;
}
else
{
/*
* Set up the default data format: 8 bit data, 1 stop bit, no
* parity
*/
reg_value = ((FPL011_FORMAT_WORDLENGTH_8BIT << 5) & FPL011LCR_H_WLEN); //<! 8bit word length
reg_value |= (0 << 3) & FPL011LCR_H_STP2; //<! 1 stopbit
reg_value |= (0 << 1) & FPL011LCR_H_PEN; //<! no parity
reg_value |= (1 << 4) & FPL011LCR_H_FEN; //<! fifo en
FUART_WRITEREG32(uart_p->config.base_address, FPL011LCR_H_OFFSET, reg_value);
/* Set the RX FIFO trigger at 8 data bytes.Tx FIFO trigger is 8 data bytes*/
reg_value = (1 << 3) | (1 << 0);
FUART_WRITEREG32(uart_p->config.base_address, FPL011IFLS_OFFSET, reg_value);
/* Disable all interrupts, polled mode is the default */
reg_value = 0;
FUART_WRITEREG32(uart_p->config.base_address, FPL011IMSC_OFFSET, reg_value);
}
return FT_SUCCESS;
}
/**
* @name: FPl011Send
* @msg: This functions sends the specified buffer using the device in either
* polled or interrupt driven mode.
* @return The number of bytes actually sent.
* @param uart_p is a pointer to the FPl011 instance.
* @param byte_p is pointer to a buffer of data to be sent.
* @param length ontains the number of bytes to be sent. Any data that was already put into the
* transmit FIFO will be sent.
*/
u32 FPl011Send(FPl011 *uart_p, u8 *byte_p, u32 length)
{
u32 sent_count = 0;
FASSERT(uart_p != NULL);
FASSERT(byte_p != NULL);
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
uart_p->send_buffer.byte_p = byte_p;
uart_p->send_buffer.requested_bytes = length;
uart_p->send_buffer.remaining_bytes = length;
sent_count = FPl011SendBuffer(uart_p);
return sent_count;
}
static void FPl011StubHandler(void *args, u32 event,
u32 byte_count)
{
(void)args;
(void)event;
(void)byte_count;
FASSERT(0);
}
/**
* @name: FPl011SendBuffer
* @msg: send data buffer through uart,if you close FIFO and open interrupt,recommend use FPl011BlockSend
* @return {*}
* @param uart_p
*/
u32 FPl011SendBuffer(FPl011 *uart_p)
{
u32 sent_count = 0U;
u32 isbusy;
isbusy = (u32)FUART_ISTRANSMITBUSY(uart_p->config.base_address);
while (isbusy == TRUE)
{
isbusy = (u32)FUART_ISTRANSMITBUSY(uart_p->config.base_address);
}
/*
* If the TX FIFO is full, send nothing.
* Otherwise put bytes into the TX FIFO unil it is full, or all of the
* data has been put into the FIFO.
*/
while ((!FUART_ISTRANSMITFULL(uart_p->config.base_address)) && (uart_p->send_buffer.remaining_bytes > 0))
{
sent_count = uart_p->send_buffer.requested_bytes - uart_p->send_buffer.remaining_bytes;
uart_p->send_buffer.remaining_bytes--;
FUART_WRITEREG32(uart_p->config.base_address, FPL011DR_OFFSET, (u32)uart_p->send_buffer.byte_p[sent_count]);
}
return uart_p->send_buffer.requested_bytes - uart_p->send_buffer.remaining_bytes;
}
/**
* @name: FPl011Receive
* @msg: This function attempts to receive a specified number of bytes of data
* from the device and store it into the specified buffer.
* @param uart_p is a pointer to the FPl011 instance
* @param byte_p is pointer to buffer for data to be received into
* @param length is the number of bytes to be received.
* @return The number of bytes received.
*/
u32 FPl011Receive(FPl011 *uart_p, u8 *byte_p, u32 length)
{
u32 received;
FASSERT(uart_p != NULL);
FASSERT(byte_p != NULL);
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
uart_p->receive_buffer.byte_p = byte_p;
uart_p->receive_buffer.requested_bytes = length;
uart_p->receive_buffer.remaining_bytes = length;
received = FPl011ReceiveBuffer(uart_p);
return received;
}
u32 FPl011ReceiveBuffer(FPl011 *uart_p)
{
u32 received_count = 0U;
u32 event;
u32 event_data;
u32 byte_value;
while ((received_count < uart_p->receive_buffer.remaining_bytes) && !FUART_RECEIVEDATAEMPTY(uart_p->config.base_address))
{
byte_value = FUART_READREG32(uart_p->config.base_address, FPL011DR_OFFSET);
if (uart_p->rxbs_error)
{
if ((byte_value & FPL011DR_ALLE) != 0)
{
event_data = byte_value;
event = FPL011_EVENT_PARE_FRAME_BRKE;
if (uart_p->handler)
{
uart_p->handler(uart_p->args, event, event_data);
}
}
}
uart_p->receive_buffer.byte_p[received_count] = (u8)(byte_value & 0xff);
received_count++;
}
uart_p->rxbs_error = 0;
if (uart_p->receive_buffer.byte_p != NULL)
{
uart_p->receive_buffer.byte_p += received_count;
}
uart_p->receive_buffer.remaining_bytes -= received_count;
return received_count;
}
/**
* @name: FPl011BlockSend
* @msg: initiate uart block send
* @return {*}
* @param uart_p
* @param byte_p
* @param length
*/
void FPl011BlockSend(FPl011 *uart_p, u8 *byte_p, u32 length)
{
u32 index;
FASSERT(uart_p != NULL);
FASSERT(byte_p != NULL);
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
for (index = 0; index < length; index++)
{
FPl011SendByte(uart_p->config.base_address, byte_p[index]);
}
}
/**
* @name: FPl011BlockReceive
* @msg: initiate uart block receive
* @return {*}
* @param uart_p
*/
u8 FPl011BlockReceive(FPl011 *uart_p)
{
FASSERT(uart_p != NULL);
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
return FPl011RecvByte(uart_p->config.base_address);
}
void FPl011IrqClearReciveTimeOut(FPl011 *uart_p)
{
u32 reg_temp;
reg_temp = FPl011GetInterruptMask(uart_p);
reg_temp &= ~FPL011MIS_RTMIS;
FPl011SetInterruptMask(uart_p, reg_temp);
}
void FPl011IrqEnableReciveTimeOut(FPl011 *uart_p)
{
u32 reg_temp;
reg_temp = FPl011GetInterruptMask(uart_p);
reg_temp |= FPL011MIS_RTMIS;
FPl011SetInterruptMask(uart_p, reg_temp);
}