blob: 7cfe5bccf73246910c5516abbc7b1f9a63102e27 [file] [log] [blame]
Andreas Wass7712bbb2013-08-14 23:45:03 +02001/*
2 * Freescale i.MX23/i.MX28 AUART driver
3 *
4 * Copyright (C) 2013 Andreas Wass <andreas.wass@dalelven.com>
5 *
6 * Based on the MXC serial driver:
7 *
8 * (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>
9 *
10 * Further based on the Linux mxs-auart.c driver:
11 *
12 * Freescale STMP37XX/STMP38X Application UART drkiver
13 * Copyright 2008-2010 Freescale Semiconductor, Inc.
14 *
15 * SPDX-License-Identifier: GPL-2.0+
16 */
17#include <common.h>
18#include <asm/io.h>
19#include <serial.h>
20#include <linux/compiler.h>
21#include <asm/arch/regs-base.h>
22#include <asm/arch/regs-uartapp.h>
23#include <asm/arch/sys_proto.h>
24
25DECLARE_GLOBAL_DATA_PTR;
26
27#ifndef CONFIG_MXS_AUART_BASE
28#error "CONFIG_MXS_AUART_BASE must be set to the base UART to use"
29#endif
30
31/* AUART clock always supplied by XTAL and always 24MHz */
32#define MXS_AUART_CLK 24000000
33
34static struct mxs_uartapp_regs *get_uartapp_registers(void)
35{
36 return (struct mxs_uartapp_regs *)CONFIG_MXS_AUART_BASE;
37}
38
39/**
40 * Sets the baud rate and settings.
41 * The settings are: 8 data bits, no parit and 1 stop bit.
42 */
43void mxs_auart_setbrg(void)
44{
45 u32 div;
46 u32 linectrl = 0;
47 struct mxs_uartapp_regs *regs = get_uartapp_registers();
48
49 if (!gd->baudrate)
50 gd->baudrate = CONFIG_BAUDRATE;
51
52 /*
53 * From i.MX28 datasheet:
54 * div is calculated by calculating UARTCLK*32/baudrate, rounded to int
55 * div must be between 0xEC and 0x003FFFC0 inclusive
56 * Lowest 6 bits of div goes in BAUD_DIVFRAC part of LINECTRL register
57 * Next 16 bits goes in BAUD_DIVINT part of LINECTRL register
58 */
59 div = (MXS_AUART_CLK * 32) / gd->baudrate;
60 if (div < 0xEC || div > 0x003FFFC0)
61 return;
62
63 linectrl |= ((div & UARTAPP_LINECTRL_EXTRACT_BAUD_DIVFRAC_MASK) <<
64 UARTAPP_LINECTRL_BAUD_DIVFRAC_OFFSET) &
65 UARTAPP_LINECTRL_BAUD_DIVFRAC_MASK;
66 linectrl |= ((div >> UARTAPP_LINECTRL_EXTRACT_BAUD_DIVINT_OFFSET) <<
67 UARTAPP_LINECTRL_BAUD_DIVINT_OFFSET) &
68 UARTAPP_LINECTRL_BAUD_DIVINT_MASK;
69
70 /* Word length: 8 bits */
71 linectrl |= UARTAPP_LINECTRL_WLEN_8BITS;
72
73 /* Enable FIFOs. */
74 linectrl |= UARTAPP_LINECTRL_FEN_MASK;
75
76 /* Write above settings, no parity, 1 stop bit */
77 writel(linectrl, &regs->hw_uartapp_linectrl);
78}
79
80int mxs_auart_init(void)
81{
82 struct mxs_uartapp_regs *regs = get_uartapp_registers();
83 /* Reset everything */
84 mxs_reset_block(&regs->hw_uartapp_ctrl0_reg);
85 /* Disable interrupts */
86 writel(0, &regs->hw_uartapp_intr);
87 /* Set baud rate and settings */
88 serial_setbrg();
89 /* Disable RTS and CTS, ignore LINECTRL2 register */
90 writel(UARTAPP_CTRL2_RTSEN_MASK |
91 UARTAPP_CTRL2_CTSEN_MASK |
92 UARTAPP_CTRL2_USE_LCR2_MASK,
93 &regs->hw_uartapp_ctrl2_clr);
94 /* Enable receiver, transmitter and UART */
95 writel(UARTAPP_CTRL2_RXE_MASK |
96 UARTAPP_CTRL2_TXE_MASK |
97 UARTAPP_CTRL2_UARTEN_MASK,
98 &regs->hw_uartapp_ctrl2_set);
99 return 0;
100}
101
102void mxs_auart_putc(const char c)
103{
104 struct mxs_uartapp_regs *regs = get_uartapp_registers();
105 /* Wait in loop while the transmit FIFO is full */
106 while (readl(&regs->hw_uartapp_stat) & UARTAPP_STAT_TXFF_MASK)
107 ;
108
109 writel(c, &regs->hw_uartapp_data);
110
111 if (c == '\n')
112 mxs_auart_putc('\r');
113}
114
115int mxs_auart_tstc(void)
116{
117 struct mxs_uartapp_regs *regs = get_uartapp_registers();
118 /* Checks if receive FIFO is empty */
119 return !(readl(&regs->hw_uartapp_stat) & UARTAPP_STAT_RXFE_MASK);
120}
121
122int mxs_auart_getc(void)
123{
124 struct mxs_uartapp_regs *regs = get_uartapp_registers();
125 /* Wait until a character is available to read */
126 while (!mxs_auart_tstc())
127 ;
128 /* Read the character from the data register */
129 return readl(&regs->hw_uartapp_data) & 0xFF;
130}
131
132static struct serial_device mxs_auart_drv = {
133 .name = "mxs_auart_serial",
134 .start = mxs_auart_init,
135 .stop = NULL,
136 .setbrg = mxs_auart_setbrg,
137 .putc = mxs_auart_putc,
138 .puts = default_serial_puts,
139 .getc = mxs_auart_getc,
140 .tstc = mxs_auart_tstc,
141};
142
143void mxs_auart_initialize(void)
144{
145 serial_register(&mxs_auart_drv);
146}
147
148__weak struct serial_device *default_serial_console(void)
149{
150 return &mxs_auart_drv;
151}