1 /* 2 * arch/arm/mach-lpc32xx/serial.c 3 * 4 * Author: Kevin Wells <kevin.wells@nxp.com> 5 * 6 * Copyright (C) 2010 NXP Semiconductors 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/types.h> 21 #include <linux/serial.h> 22 #include <linux/serial_core.h> 23 #include <linux/serial_reg.h> 24 #include <linux/serial_8250.h> 25 #include <linux/clk.h> 26 #include <linux/io.h> 27 28 #include <mach/hardware.h> 29 #include <mach/platform.h> 30 #include "common.h" 31 32 #define LPC32XX_SUART_FIFO_SIZE 64 33 34 /* Standard 8250/16550 compatible serial ports */ 35 static struct plat_serial8250_port serial_std_platform_data[] = { 36 #ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT 37 { 38 .membase = io_p2v(LPC32XX_UART5_BASE), 39 .mapbase = LPC32XX_UART5_BASE, 40 .irq = IRQ_LPC32XX_UART_IIR5, 41 .uartclk = LPC32XX_MAIN_OSC_FREQ, 42 .regshift = 2, 43 .iotype = UPIO_MEM32, 44 .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | 45 UPF_SKIP_TEST, 46 }, 47 #endif 48 #ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT 49 { 50 .membase = io_p2v(LPC32XX_UART3_BASE), 51 .mapbase = LPC32XX_UART3_BASE, 52 .irq = IRQ_LPC32XX_UART_IIR3, 53 .uartclk = LPC32XX_MAIN_OSC_FREQ, 54 .regshift = 2, 55 .iotype = UPIO_MEM32, 56 .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | 57 UPF_SKIP_TEST, 58 }, 59 #endif 60 #ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT 61 { 62 .membase = io_p2v(LPC32XX_UART4_BASE), 63 .mapbase = LPC32XX_UART4_BASE, 64 .irq = IRQ_LPC32XX_UART_IIR4, 65 .uartclk = LPC32XX_MAIN_OSC_FREQ, 66 .regshift = 2, 67 .iotype = UPIO_MEM32, 68 .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | 69 UPF_SKIP_TEST, 70 }, 71 #endif 72 #ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT 73 { 74 .membase = io_p2v(LPC32XX_UART6_BASE), 75 .mapbase = LPC32XX_UART6_BASE, 76 .irq = IRQ_LPC32XX_UART_IIR6, 77 .uartclk = LPC32XX_MAIN_OSC_FREQ, 78 .regshift = 2, 79 .iotype = UPIO_MEM32, 80 .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | 81 UPF_SKIP_TEST, 82 }, 83 #endif 84 { }, 85 }; 86 87 struct uartinit { 88 char *uart_ck_name; 89 u32 ck_mode_mask; 90 void __iomem *pdiv_clk_reg; 91 resource_size_t mapbase; 92 }; 93 94 static struct uartinit uartinit_data[] __initdata = { 95 #ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT 96 { 97 .uart_ck_name = "uart5_ck", 98 .ck_mode_mask = 99 LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5), 100 .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL, 101 .mapbase = LPC32XX_UART5_BASE, 102 }, 103 #endif 104 #ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT 105 { 106 .uart_ck_name = "uart3_ck", 107 .ck_mode_mask = 108 LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3), 109 .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL, 110 .mapbase = LPC32XX_UART3_BASE, 111 }, 112 #endif 113 #ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT 114 { 115 .uart_ck_name = "uart4_ck", 116 .ck_mode_mask = 117 LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4), 118 .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL, 119 .mapbase = LPC32XX_UART4_BASE, 120 }, 121 #endif 122 #ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT 123 { 124 .uart_ck_name = "uart6_ck", 125 .ck_mode_mask = 126 LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6), 127 .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL, 128 .mapbase = LPC32XX_UART6_BASE, 129 }, 130 #endif 131 }; 132 133 static struct platform_device serial_std_platform_device = { 134 .name = "serial8250", 135 .id = 0, 136 .dev = { 137 .platform_data = serial_std_platform_data, 138 }, 139 }; 140 141 static struct platform_device *lpc32xx_serial_devs[] __initdata = { 142 &serial_std_platform_device, 143 }; 144 145 void __init lpc32xx_serial_init(void) 146 { 147 u32 tmp, clkmodes = 0; 148 struct clk *clk; 149 unsigned int puart; 150 int i, j; 151 152 /* UART clocks are off, let clock driver manage them */ 153 __raw_writel(0, LPC32XX_CLKPWR_UART_CLK_CTRL); 154 155 for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) { 156 clk = clk_get(NULL, uartinit_data[i].uart_ck_name); 157 if (!IS_ERR(clk)) { 158 clk_enable(clk); 159 serial_std_platform_data[i].uartclk = 160 clk_get_rate(clk); 161 } 162 163 /* Fall back on main osc rate if clock rate return fails */ 164 if (serial_std_platform_data[i].uartclk == 0) 165 serial_std_platform_data[i].uartclk = 166 LPC32XX_MAIN_OSC_FREQ; 167 168 /* Setup UART clock modes for all UARTs, disable autoclock */ 169 clkmodes |= uartinit_data[i].ck_mode_mask; 170 171 /* pre-UART clock divider set to 1 */ 172 __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg); 173 174 /* 175 * Force a flush of the RX FIFOs to work around a 176 * HW bug 177 */ 178 puart = uartinit_data[i].mapbase; 179 __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart)); 180 __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart)); 181 j = LPC32XX_SUART_FIFO_SIZE; 182 while (j--) 183 tmp = __raw_readl( 184 LPC32XX_UART_DLL_FIFO(puart)); 185 __raw_writel(0, LPC32XX_UART_IIR_FCR(puart)); 186 } 187 188 /* This needs to be done after all UART clocks are setup */ 189 __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE); 190 for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) { 191 /* Force a flush of the RX FIFOs to work around a HW bug */ 192 puart = serial_std_platform_data[i].mapbase; 193 __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart)); 194 __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart)); 195 j = LPC32XX_SUART_FIFO_SIZE; 196 while (j--) 197 tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart)); 198 __raw_writel(0, LPC32XX_UART_IIR_FCR(puart)); 199 } 200 201 /* Disable UART5->USB transparent mode or USB won't work */ 202 tmp = __raw_readl(LPC32XX_UARTCTL_CTRL); 203 tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB; 204 __raw_writel(tmp, LPC32XX_UARTCTL_CTRL); 205 206 platform_add_devices(lpc32xx_serial_devs, 207 ARRAY_SIZE(lpc32xx_serial_devs)); 208 } 209