| /* |
| * Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.com> |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * 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 |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| * MA 02110-1301, USA. |
| */ |
| |
| #include <common.h> |
| #include <asm/arch/cpu.h> |
| #include <asm/arch/clk.h> |
| #include <asm/arch/uart.h> |
| #include <asm/io.h> |
| #include <serial.h> |
| #include <linux/compiler.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| static struct hsuart_regs *hsuart = (struct hsuart_regs *)HS_UART_BASE; |
| |
| static void lpc32xx_serial_setbrg(void) |
| { |
| u32 div; |
| |
| /* UART rate = PERIPH_CLK / ((HSU_RATE + 1) x 14) */ |
| div = (get_serial_clock() / 14 + gd->baudrate / 2) / gd->baudrate - 1; |
| if (div > 255) |
| div = 255; |
| |
| writel(div, &hsuart->rate); |
| } |
| |
| static int lpc32xx_serial_getc(void) |
| { |
| while (!(readl(&hsuart->level) & HSUART_LEVEL_RX)) |
| /* NOP */; |
| |
| return readl(&hsuart->rx) & HSUART_RX_DATA; |
| } |
| |
| static void lpc32xx_serial_putc(const char c) |
| { |
| writel(c, &hsuart->tx); |
| |
| /* Wait for character to be sent */ |
| while (readl(&hsuart->level) & HSUART_LEVEL_TX) |
| /* NOP */; |
| } |
| |
| static int lpc32xx_serial_tstc(void) |
| { |
| if (readl(&hsuart->level) & HSUART_LEVEL_RX) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int lpc32xx_serial_init(void) |
| { |
| lpc32xx_serial_setbrg(); |
| |
| /* Disable hardware RTS and CTS flow control, set up RX and TX FIFO */ |
| writel(HSUART_CTRL_TMO_16 | HSUART_CTRL_HSU_OFFSET(20) | |
| HSUART_CTRL_HSU_RX_TRIG_32 | HSUART_CTRL_HSU_TX_TRIG_0, |
| &hsuart->ctrl); |
| return 0; |
| } |
| |
| static void lpc32xx_serial_puts(const char *s) |
| { |
| while (*s) |
| serial_putc(*s++); |
| } |
| |
| #ifdef CONFIG_SERIAL_MULTI |
| static struct serial_device lpc32xx_serial_drv = { |
| .name = "lpc32xx_serial", |
| .start = lpc32xx_serial_init, |
| .stop = NULL, |
| .setbrg = lpc32xx_serial_setbrg, |
| .putc = lpc32xx_serial_putc, |
| .puts = lpc32xx_serial_puts, |
| .getc = lpc32xx_serial_getc, |
| .tstc = lpc32xx_serial_tstc, |
| }; |
| |
| void lpc32xx_serial_initialize(void) |
| { |
| serial_register(&lpc32xx_serial_drv); |
| } |
| |
| __weak struct serial_device *default_serial_console(void) |
| { |
| return &lpc32xx_serial_drv; |
| } |
| #else |
| int serial_init(void) |
| { |
| return lpc32xx_serial_init(); |
| } |
| |
| void serial_setbrg(void) |
| { |
| lpc32xx_serial_setbrg(); |
| } |
| |
| void serial_putc(const char c) |
| { |
| lpc32xx_serial_putc(c); |
| } |
| |
| void serial_puts(const char *s) |
| { |
| lpc32xx_serial_puts(s); |
| } |
| |
| int serial_getc(void) |
| { |
| return lpc32xx_serial_getc(); |
| } |
| |
| int serial_tstc(void) |
| { |
| return lpc32xx_serial_tstc(); |
| } |
| #endif |