rt-thread-official/bsp/imx6ul/platform/drivers/imx_uart.c

220 lines
7.8 KiB
C

/*
* Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*!
* @file imx_uart.c
* @brief UART driver.
* @ingroup diag_uart
*/
#include "sdk.h"
#include "registers/regsuart.h"
#include "imx_uart.h"
#include "ccm_pll.h"
#include "interrupt.h"
#define UART_UFCR_RFDIV BF_UART_UFCR_RFDIV(4)
//#define UART_UFCR_RFDIV UART_UFCR_RFDIV_4
//#define UART_UFCR_RFDIV UART_UFCR_RFDIV_7
uint32_t uart_get_reffreq(uint32_t instance)
{
uint32_t div = UART_UFCR_RFDIV;
uint32_t ret = 0;
uint32_t freq = get_peri_clock(UART_MODULE_CLK(instance));
if (div == BF_UART_UFCR_RFDIV(4))
ret = freq / 2;
else if (div == BF_UART_UFCR_RFDIV(2))
ret = freq / 4;
else if (div == BF_UART_UFCR_RFDIV(6))
ret = freq / 7;
return ret;
}
uint8_t uart_putchar(uint32_t instance, uint8_t * ch)
{
/* Wait for Tx FIFO not full */
while (HW_UART_UTS(instance).B.TXFULL);
HW_UART_UTXD_WR(instance, *ch);
return *ch;
}
uint8_t uart_getchar(uint32_t instance)
{
uint32_t read_data;
/* If Rx FIFO has no data ready */
if (!(HW_UART_USR2(instance).B.RDR))
return NONE_CHAR;
read_data = HW_UART_URXD_RD(instance);
/* If error are detected */
if (read_data & 0x7C00)
return NONE_CHAR;
return (uint8_t) read_data;
}
void uart_set_FIFO_mode(uint32_t instance, uint8_t fifo, uint8_t trigger_level,
uint8_t service_mode)
{
if (fifo == TX_FIFO) {
/* Configure the TX_FIFO trigger level */
HW_UART_UFCR_CLR(instance,BM_UART_UFCR_TXTL);
HW_UART_UFCR_SET(instance, BF_UART_UFCR_TXTL(trigger_level));
/* Configure the TX_FIFO service mode */
/* Default mode is polling: IRQ and DMA requests are disabled */
HW_UART_UCR1_CLR(instance,(BM_UART_UCR1_TRDYEN | BM_UART_UCR1_TXDMAEN));
if (service_mode == DMA_MODE)
HW_UART_UCR1_SET(instance,BM_UART_UCR1_TXDMAEN);
else if (service_mode == IRQ_MODE)
HW_UART_UCR1_SET(instance,BM_UART_UCR1_TRDYEN);
} else { /* fifo = RX_FIFO */
/* Configure the RX_FIFO trigger level */
HW_UART_UFCR_CLR(instance,BM_UART_UFCR_RXTL);
HW_UART_UFCR_SET(instance,BF_UART_UFCR_RXTL(trigger_level));
/* Configure the RX_FIFO service mode */
/* Default mode is polling: IRQ and DMA requests are disabled */
HW_UART_UCR1_CLR(instance,(BM_UART_UCR1_RRDYEN | BM_UART_UCR1_RXDMAEN));
if (service_mode == DMA_MODE)
HW_UART_UCR1_SET(instance,BM_UART_UCR1_RXDMAEN);
else if (service_mode == IRQ_MODE)
HW_UART_UCR1_SET(instance,BM_UART_UCR1_RRDYEN);
}
}
void uart_set_loopback_mode(uint32_t instance, uint8_t state)
{
if (state == TRUE)
HW_UART_UTS_SET(instance, BM_UART_UTS_LOOP);
else
HW_UART_UTS_CLR(instance, BM_UART_UTS_LOOP);
}
void uart_setup_interrupt(uint32_t instance, void (*irq_subroutine)(void), uint8_t state)
{
uint32_t irq_id = UART_IRQS(instance);
if (state == TRUE) {
/* register the IRQ sub-routine */
register_interrupt_routine(irq_id, irq_subroutine);
/* enable the IRQ */
enable_interrupt(irq_id, CPU_0, 0);
} else
/* disable the IRQ */
disable_interrupt(irq_id, CPU_0);
}
void uart_init(uint32_t instance, uint32_t baudrate, uint8_t parity,
uint8_t stopbits, uint8_t datasize, uint8_t flowcontrol)
{
uint32_t base = REGS_UART_BASE(instance);
/* configure the I/O for the port */
uart_iomux_config(instance);
/* enable the source clocks to the UART port */
clock_gating_config(base, CLOCK_ON);
/* Wait for UART to finish transmitting before changing the configuration */
while (!(HW_UART_UTS(instance).B.TXEMPTY)) ;
/* Disable UART */
HW_UART_UCR1_CLR(instance,BM_UART_UCR1_UARTEN );
/* Configure FIFOs trigger level to half-full and half-empty */
HW_UART_UFCR_WR(instance, BF_UART_UFCR_RXTL(16) | UART_UFCR_RFDIV | BF_UART_UFCR_TXTL(16));
/* Setup One Millisecond timer */
HW_UART_ONEMS_WR(instance, uart_get_reffreq(instance) / 1000);
/* Set parity */
if (parity == PARITY_NONE)
HW_UART_UCR2_CLR(instance,(BM_UART_UCR2_PREN| BM_UART_UCR2_PROE));
else if (parity == PARITY_ODD)
HW_UART_UCR2_SET(instance,(BM_UART_UCR2_PREN| BM_UART_UCR2_PROE));
else { /* parity == PARITY_EVEN */
HW_UART_UCR2_SET(instance, BM_UART_UCR2_PREN);
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_PROE);
}
/* Set stop bit */
if (stopbits == STOPBITS_ONE)
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_STPB);
else /* stopbits == STOPBITS_TWO */
HW_UART_UCR2_SET(instance, BM_UART_UCR2_STPB);
/* Set data size */
if (datasize == EIGHTBITS)
HW_UART_UCR2_SET(instance, BM_UART_UCR2_WS);
else /* stopbits == STOPBITS_TWO */
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_WS);
/* Configure the flow control */
if (flowcontrol == FLOWCTRL_ON) {
/* transmit done when RTS asserted */
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_IRTS );
/* CTS controlled by the receiver */
HW_UART_UCR2_SET(instance, BM_UART_UCR2_CTSC );
} else { /* flowcontrol == FLOWCTRL_OFF */
/* Ignore RTS */
HW_UART_UCR2_SET(instance, BM_UART_UCR2_IRTS);
/* CTS controlled by the CTS bit */
HW_UART_UCR2_CLR(instance, BM_UART_UCR2_CTSC);
}
/* the reference manual says that this bit must always be set */
HW_UART_UCR3_SET(instance, BM_UART_UCR3_RXDMUXSEL);
/* Enable UART */
HW_UART_UCR1_SET(instance, BM_UART_UCR1_UARTEN);
/* Enable FIFOs and does software reset to clear status flags, reset
the transmit and receive state machine, and reset the FIFOs */
HW_UART_UCR2_SET(instance, BM_UART_UCR2_TXEN | BM_UART_UCR2_RXEN | BM_UART_UCR2_SRST);
/* Set the numerator value minus one of the BRM ratio */
HW_UART_UBIR_WR(instance, (baudrate / 100) - 1);
/* Set the denominator value minus one of the BRM ratio */
HW_UART_UBMR_WR(instance, ((uart_get_reffreq(instance) / 1600) - 1));
/* Optional: prevent the UART to enter debug state. Useful when debugging
the code with a JTAG and without active IRQ */
HW_UART_UTS_SET(instance, BM_UART_UTS_DBGEN);
}