]>
Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e6e912c4 KW |
2 | /* |
3 | * arch/arm/mach-lpc32xx/serial.c | |
4 | * | |
5 | * Author: Kevin Wells <kevin.wells@nxp.com> | |
6 | * | |
7 | * Copyright (C) 2010 NXP Semiconductors | |
e6e912c4 KW |
8 | */ |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/types.h> | |
12 | #include <linux/serial.h> | |
13 | #include <linux/serial_core.h> | |
14 | #include <linux/serial_reg.h> | |
15 | #include <linux/serial_8250.h> | |
16 | #include <linux/clk.h> | |
17 | #include <linux/io.h> | |
18 | ||
19 | #include <mach/hardware.h> | |
20 | #include <mach/platform.h> | |
21 | #include "common.h" | |
22 | ||
23 | #define LPC32XX_SUART_FIFO_SIZE 64 | |
24 | ||
e6e912c4 KW |
25 | struct uartinit { |
26 | char *uart_ck_name; | |
27 | u32 ck_mode_mask; | |
28 | void __iomem *pdiv_clk_reg; | |
2707208e | 29 | resource_size_t mapbase; |
e6e912c4 KW |
30 | }; |
31 | ||
32 | static struct uartinit uartinit_data[] __initdata = { | |
e6e912c4 KW |
33 | { |
34 | .uart_ck_name = "uart5_ck", | |
35 | .ck_mode_mask = | |
36 | LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5), | |
37 | .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL, | |
2707208e | 38 | .mapbase = LPC32XX_UART5_BASE, |
e6e912c4 | 39 | }, |
e6e912c4 KW |
40 | { |
41 | .uart_ck_name = "uart3_ck", | |
42 | .ck_mode_mask = | |
43 | LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3), | |
44 | .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL, | |
2707208e | 45 | .mapbase = LPC32XX_UART3_BASE, |
e6e912c4 | 46 | }, |
e6e912c4 KW |
47 | { |
48 | .uart_ck_name = "uart4_ck", | |
49 | .ck_mode_mask = | |
50 | LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4), | |
51 | .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL, | |
2707208e | 52 | .mapbase = LPC32XX_UART4_BASE, |
e6e912c4 | 53 | }, |
e6e912c4 KW |
54 | { |
55 | .uart_ck_name = "uart6_ck", | |
56 | .ck_mode_mask = | |
57 | LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6), | |
58 | .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL, | |
2707208e | 59 | .mapbase = LPC32XX_UART6_BASE, |
e6e912c4 | 60 | }, |
e6e912c4 KW |
61 | }; |
62 | ||
63 | void __init lpc32xx_serial_init(void) | |
64 | { | |
65 | u32 tmp, clkmodes = 0; | |
66 | struct clk *clk; | |
67 | unsigned int puart; | |
68 | int i, j; | |
69 | ||
e6e912c4 KW |
70 | for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) { |
71 | clk = clk_get(NULL, uartinit_data[i].uart_ck_name); | |
72 | if (!IS_ERR(clk)) { | |
73 | clk_enable(clk); | |
e6e912c4 KW |
74 | } |
75 | ||
e6e912c4 KW |
76 | /* Setup UART clock modes for all UARTs, disable autoclock */ |
77 | clkmodes |= uartinit_data[i].ck_mode_mask; | |
78 | ||
79 | /* pre-UART clock divider set to 1 */ | |
80 | __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg); | |
2707208e RS |
81 | |
82 | /* | |
83 | * Force a flush of the RX FIFOs to work around a | |
84 | * HW bug | |
85 | */ | |
86 | puart = uartinit_data[i].mapbase; | |
87 | __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart)); | |
88 | __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart)); | |
89 | j = LPC32XX_SUART_FIFO_SIZE; | |
90 | while (j--) | |
91 | tmp = __raw_readl( | |
92 | LPC32XX_UART_DLL_FIFO(puart)); | |
93 | __raw_writel(0, LPC32XX_UART_IIR_FCR(puart)); | |
e6e912c4 KW |
94 | } |
95 | ||
96 | /* This needs to be done after all UART clocks are setup */ | |
97 | __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE); | |
ff424aa4 | 98 | for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) { |
e6e912c4 | 99 | /* Force a flush of the RX FIFOs to work around a HW bug */ |
c70426f1 | 100 | puart = uartinit_data[i].mapbase; |
e6e912c4 KW |
101 | __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart)); |
102 | __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart)); | |
103 | j = LPC32XX_SUART_FIFO_SIZE; | |
104 | while (j--) | |
105 | tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart)); | |
106 | __raw_writel(0, LPC32XX_UART_IIR_FCR(puart)); | |
107 | } | |
108 | ||
5fe8f11c APS |
109 | /* Disable IrDA pulsing support on UART6 */ |
110 | tmp = __raw_readl(LPC32XX_UARTCTL_CTRL); | |
111 | tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS; | |
112 | __raw_writel(tmp, LPC32XX_UARTCTL_CTRL); | |
113 | ||
e6e912c4 KW |
114 | /* Disable UART5->USB transparent mode or USB won't work */ |
115 | tmp = __raw_readl(LPC32XX_UARTCTL_CTRL); | |
116 | tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB; | |
117 | __raw_writel(tmp, LPC32XX_UARTCTL_CTRL); | |
e6e912c4 | 118 | } |