1*427eba70SAlison Wang /*
2*427eba70SAlison Wang  * Copyright 2013 Freescale Semiconductor, Inc.
3*427eba70SAlison Wang  *
4*427eba70SAlison Wang  * This program is free software; you can redistribute it and/or modify
5*427eba70SAlison Wang  * it under the terms of the GNU General Public License as published by
6*427eba70SAlison Wang  * the Free Software Foundation; either version 2 of the License, or
7*427eba70SAlison Wang  * (at your option) any later version.
8*427eba70SAlison Wang  *
9*427eba70SAlison Wang  * This program is distributed in the hope that it will be useful,
10*427eba70SAlison Wang  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*427eba70SAlison Wang  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*427eba70SAlison Wang  * GNU General Public License for more details.
13*427eba70SAlison Wang  *
14*427eba70SAlison Wang  * You should have received a copy of the GNU General Public License
15*427eba70SAlison Wang  * along with this program; if not, write to the Free Software
16*427eba70SAlison Wang  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17*427eba70SAlison Wang  *
18*427eba70SAlison Wang  */
19*427eba70SAlison Wang 
20*427eba70SAlison Wang #include <common.h>
21*427eba70SAlison Wang #include <watchdog.h>
22*427eba70SAlison Wang #include <asm/io.h>
23*427eba70SAlison Wang #include <serial.h>
24*427eba70SAlison Wang #include <linux/compiler.h>
25*427eba70SAlison Wang #include <asm/arch/imx-regs.h>
26*427eba70SAlison Wang #include <asm/arch/clock.h>
27*427eba70SAlison Wang 
28*427eba70SAlison Wang #define US1_TDRE        (1 << 7)
29*427eba70SAlison Wang #define US1_RDRF        (1 << 5)
30*427eba70SAlison Wang #define UC2_TE          (1 << 3)
31*427eba70SAlison Wang #define UC2_RE          (1 << 2)
32*427eba70SAlison Wang 
33*427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR;
34*427eba70SAlison Wang 
35*427eba70SAlison Wang struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE;
36*427eba70SAlison Wang 
37*427eba70SAlison Wang static void lpuart_serial_setbrg(void)
38*427eba70SAlison Wang {
39*427eba70SAlison Wang 	u32 clk = mxc_get_clock(MXC_UART_CLK);
40*427eba70SAlison Wang 	u16 sbr;
41*427eba70SAlison Wang 
42*427eba70SAlison Wang 	if (!gd->baudrate)
43*427eba70SAlison Wang 		gd->baudrate = CONFIG_BAUDRATE;
44*427eba70SAlison Wang 
45*427eba70SAlison Wang 	sbr = (u16)(clk / (16 * gd->baudrate));
46*427eba70SAlison Wang 	/* place adjustment later - n/32 BRFA */
47*427eba70SAlison Wang 
48*427eba70SAlison Wang 	__raw_writeb(sbr >> 8, &base->ubdh);
49*427eba70SAlison Wang 	__raw_writeb(sbr & 0xff, &base->ubdl);
50*427eba70SAlison Wang }
51*427eba70SAlison Wang 
52*427eba70SAlison Wang static int lpuart_serial_getc(void)
53*427eba70SAlison Wang {
54*427eba70SAlison Wang 	u8 status;
55*427eba70SAlison Wang 
56*427eba70SAlison Wang 	while (!(__raw_readb(&base->us1) & US1_RDRF))
57*427eba70SAlison Wang 		WATCHDOG_RESET();
58*427eba70SAlison Wang 
59*427eba70SAlison Wang 	status = __raw_readb(&base->us1);
60*427eba70SAlison Wang 	status |= US1_RDRF;
61*427eba70SAlison Wang 	__raw_writeb(status, &base->us1);
62*427eba70SAlison Wang 
63*427eba70SAlison Wang 	return __raw_readb(&base->ud);
64*427eba70SAlison Wang }
65*427eba70SAlison Wang 
66*427eba70SAlison Wang static void lpuart_serial_putc(const char c)
67*427eba70SAlison Wang {
68*427eba70SAlison Wang 	if (c == '\n')
69*427eba70SAlison Wang 		serial_putc('\r');
70*427eba70SAlison Wang 
71*427eba70SAlison Wang 	while (!(__raw_readb(&base->us1) & US1_TDRE))
72*427eba70SAlison Wang 		WATCHDOG_RESET();
73*427eba70SAlison Wang 
74*427eba70SAlison Wang 	__raw_writeb(c, &base->ud);
75*427eba70SAlison Wang }
76*427eba70SAlison Wang 
77*427eba70SAlison Wang /*
78*427eba70SAlison Wang  * Test whether a character is in the RX buffer
79*427eba70SAlison Wang  */
80*427eba70SAlison Wang static int lpuart_serial_tstc(void)
81*427eba70SAlison Wang {
82*427eba70SAlison Wang 	if (__raw_readb(&base->urcfifo) == 0)
83*427eba70SAlison Wang 		return 0;
84*427eba70SAlison Wang 
85*427eba70SAlison Wang 	return 1;
86*427eba70SAlison Wang }
87*427eba70SAlison Wang 
88*427eba70SAlison Wang /*
89*427eba70SAlison Wang  * Initialise the serial port with the given baudrate. The settings
90*427eba70SAlison Wang  * are always 8 data bits, no parity, 1 stop bit, no start bits.
91*427eba70SAlison Wang  */
92*427eba70SAlison Wang static int lpuart_serial_init(void)
93*427eba70SAlison Wang {
94*427eba70SAlison Wang 	u8 ctrl;
95*427eba70SAlison Wang 
96*427eba70SAlison Wang 	ctrl = __raw_readb(&base->uc2);
97*427eba70SAlison Wang 	ctrl &= ~UC2_RE;
98*427eba70SAlison Wang 	ctrl &= ~UC2_TE;
99*427eba70SAlison Wang 	__raw_writeb(ctrl, &base->uc2);
100*427eba70SAlison Wang 
101*427eba70SAlison Wang 	__raw_writeb(0, &base->umodem);
102*427eba70SAlison Wang 	__raw_writeb(0, &base->uc1);
103*427eba70SAlison Wang 
104*427eba70SAlison Wang 	/* provide data bits, parity, stop bit, etc */
105*427eba70SAlison Wang 
106*427eba70SAlison Wang 	serial_setbrg();
107*427eba70SAlison Wang 
108*427eba70SAlison Wang 	__raw_writeb(UC2_RE | UC2_TE, &base->uc2);
109*427eba70SAlison Wang 
110*427eba70SAlison Wang 	return 0;
111*427eba70SAlison Wang }
112*427eba70SAlison Wang 
113*427eba70SAlison Wang static struct serial_device lpuart_serial_drv = {
114*427eba70SAlison Wang 	.name = "lpuart_serial",
115*427eba70SAlison Wang 	.start = lpuart_serial_init,
116*427eba70SAlison Wang 	.stop = NULL,
117*427eba70SAlison Wang 	.setbrg = lpuart_serial_setbrg,
118*427eba70SAlison Wang 	.putc = lpuart_serial_putc,
119*427eba70SAlison Wang 	.puts = default_serial_puts,
120*427eba70SAlison Wang 	.getc = lpuart_serial_getc,
121*427eba70SAlison Wang 	.tstc = lpuart_serial_tstc,
122*427eba70SAlison Wang };
123*427eba70SAlison Wang 
124*427eba70SAlison Wang void lpuart_serial_initialize(void)
125*427eba70SAlison Wang {
126*427eba70SAlison Wang 	serial_register(&lpuart_serial_drv);
127*427eba70SAlison Wang }
128*427eba70SAlison Wang 
129*427eba70SAlison Wang __weak struct serial_device *default_serial_console(void)
130*427eba70SAlison Wang {
131*427eba70SAlison Wang 	return &lpuart_serial_drv;
132*427eba70SAlison Wang }
133