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