Commit | Line | Data |
---|---|---|
1dbae815 | 1 | /* |
f30c2269 | 2 | * arch/arm/mach-omap2/serial.c |
1dbae815 TL |
3 | * |
4 | * OMAP2 serial support. | |
5 | * | |
6e81176d | 6 | * Copyright (C) 2005-2008 Nokia Corporation |
1dbae815 TL |
7 | * Author: Paul Mundt <paul.mundt@nokia.com> |
8 | * | |
9 | * Based off of arch/arm/mach-omap/omap1/serial.c | |
10 | * | |
11 | * This file is subject to the terms and conditions of the GNU General Public | |
12 | * License. See the file "COPYING" in the main directory of this archive | |
13 | * for more details. | |
14 | */ | |
15 | #include <linux/kernel.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/serial_8250.h> | |
18 | #include <linux/serial_reg.h> | |
f8ce2547 | 19 | #include <linux/clk.h> |
fced80c7 | 20 | #include <linux/io.h> |
1dbae815 | 21 | |
a09e64fb RK |
22 | #include <mach/common.h> |
23 | #include <mach/board.h> | |
1dbae815 | 24 | |
6e81176d JH |
25 | static struct clk *uart_ick[OMAP_MAX_NR_PORTS]; |
26 | static struct clk *uart_fck[OMAP_MAX_NR_PORTS]; | |
1dbae815 TL |
27 | |
28 | static struct plat_serial8250_port serial_platform_data[] = { | |
29 | { | |
e8a91c95 RK |
30 | .membase = IO_ADDRESS(OMAP_UART1_BASE), |
31 | .mapbase = OMAP_UART1_BASE, | |
1dbae815 TL |
32 | .irq = 72, |
33 | .flags = UPF_BOOT_AUTOCONF, | |
34 | .iotype = UPIO_MEM, | |
35 | .regshift = 2, | |
6e81176d | 36 | .uartclk = OMAP24XX_BASE_BAUD * 16, |
1dbae815 | 37 | }, { |
e8a91c95 RK |
38 | .membase = IO_ADDRESS(OMAP_UART2_BASE), |
39 | .mapbase = OMAP_UART2_BASE, | |
1dbae815 TL |
40 | .irq = 73, |
41 | .flags = UPF_BOOT_AUTOCONF, | |
42 | .iotype = UPIO_MEM, | |
43 | .regshift = 2, | |
6e81176d | 44 | .uartclk = OMAP24XX_BASE_BAUD * 16, |
1dbae815 | 45 | }, { |
e8a91c95 RK |
46 | .membase = IO_ADDRESS(OMAP_UART3_BASE), |
47 | .mapbase = OMAP_UART3_BASE, | |
1dbae815 TL |
48 | .irq = 74, |
49 | .flags = UPF_BOOT_AUTOCONF, | |
50 | .iotype = UPIO_MEM, | |
51 | .regshift = 2, | |
6e81176d | 52 | .uartclk = OMAP24XX_BASE_BAUD * 16, |
1dbae815 TL |
53 | }, { |
54 | .flags = 0 | |
55 | } | |
56 | }; | |
57 | ||
58 | static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, | |
59 | int offset) | |
60 | { | |
61 | offset <<= up->regshift; | |
62 | return (unsigned int)__raw_readb(up->membase + offset); | |
63 | } | |
64 | ||
65 | static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, | |
66 | int value) | |
67 | { | |
68 | offset <<= p->regshift; | |
e8a91c95 | 69 | __raw_writeb(value, p->membase + offset); |
1dbae815 TL |
70 | } |
71 | ||
72 | /* | |
73 | * Internal UARTs need to be initialized for the 8250 autoconfig to work | |
74 | * properly. Note that the TX watermark initialization may not be needed | |
75 | * once the 8250.c watermark handling code is merged. | |
76 | */ | |
77 | static inline void __init omap_serial_reset(struct plat_serial8250_port *p) | |
78 | { | |
79 | serial_write_reg(p, UART_OMAP_MDR1, 0x07); | |
80 | serial_write_reg(p, UART_OMAP_SCR, 0x08); | |
81 | serial_write_reg(p, UART_OMAP_MDR1, 0x00); | |
671c7235 | 82 | serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0)); |
1dbae815 TL |
83 | } |
84 | ||
6e81176d JH |
85 | void omap_serial_enable_clocks(int enable) |
86 | { | |
87 | int i; | |
88 | for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { | |
89 | if (uart_ick[i] && uart_fck[i]) { | |
90 | if (enable) { | |
91 | clk_enable(uart_ick[i]); | |
92 | clk_enable(uart_fck[i]); | |
93 | } else { | |
94 | clk_disable(uart_ick[i]); | |
95 | clk_disable(uart_fck[i]); | |
96 | } | |
97 | } | |
98 | } | |
99 | } | |
100 | ||
101 | void __init omap_serial_init(void) | |
1dbae815 TL |
102 | { |
103 | int i; | |
104 | const struct omap_uart_config *info; | |
6e81176d | 105 | char name[16]; |
1dbae815 TL |
106 | |
107 | /* | |
108 | * Make sure the serial ports are muxed on at this point. | |
109 | * You have to mux them off in device drivers later on | |
110 | * if not needed. | |
111 | */ | |
112 | ||
6e81176d | 113 | info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); |
1dbae815 TL |
114 | |
115 | if (info == NULL) | |
116 | return; | |
117 | ||
118 | for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { | |
119 | struct plat_serial8250_port *p = serial_platform_data + i; | |
120 | ||
121 | if (!(info->enabled_uarts & (1 << i))) { | |
c0fc18c5 | 122 | p->membase = NULL; |
1dbae815 TL |
123 | p->mapbase = 0; |
124 | continue; | |
125 | } | |
126 | ||
6e81176d JH |
127 | sprintf(name, "uart%d_ick", i+1); |
128 | uart_ick[i] = clk_get(NULL, name); | |
129 | if (IS_ERR(uart_ick[i])) { | |
130 | printk(KERN_ERR "Could not get uart%d_ick\n", i+1); | |
131 | uart_ick[i] = NULL; | |
132 | } else | |
133 | clk_enable(uart_ick[i]); | |
134 | ||
135 | sprintf(name, "uart%d_fck", i+1); | |
136 | uart_fck[i] = clk_get(NULL, name); | |
137 | if (IS_ERR(uart_fck[i])) { | |
138 | printk(KERN_ERR "Could not get uart%d_fck\n", i+1); | |
139 | uart_fck[i] = NULL; | |
140 | } else | |
141 | clk_enable(uart_fck[i]); | |
1dbae815 TL |
142 | |
143 | omap_serial_reset(p); | |
144 | } | |
145 | } | |
146 | ||
147 | static struct platform_device serial_device = { | |
148 | .name = "serial8250", | |
7d420896 | 149 | .id = PLAT8250_DEV_PLATFORM, |
1dbae815 TL |
150 | .dev = { |
151 | .platform_data = serial_platform_data, | |
152 | }, | |
153 | }; | |
154 | ||
155 | static int __init omap_init(void) | |
156 | { | |
157 | return platform_device_register(&serial_device); | |
158 | } | |
159 | arch_initcall(omap_init); |