Commit | Line | Data |
---|---|---|
1dbae815 TL |
1 | /* |
2 | * arch/arm/mach-omap/omap2/serial.c | |
3 | * | |
4 | * OMAP2 serial support. | |
5 | * | |
6 | * Copyright (C) 2005 Nokia Corporation | |
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> |
1dbae815 TL |
20 | |
21 | #include <asm/io.h> | |
1dbae815 TL |
22 | |
23 | #include <asm/arch/common.h> | |
24 | #include <asm/arch/board.h> | |
25 | ||
26 | static struct clk * uart1_ick = NULL; | |
27 | static struct clk * uart1_fck = NULL; | |
28 | static struct clk * uart2_ick = NULL; | |
29 | static struct clk * uart2_fck = NULL; | |
30 | static struct clk * uart3_ick = NULL; | |
31 | static struct clk * uart3_fck = NULL; | |
32 | ||
33 | static struct plat_serial8250_port serial_platform_data[] = { | |
34 | { | |
35 | .membase = (char *)IO_ADDRESS(OMAP_UART1_BASE), | |
36 | .mapbase = (unsigned long)OMAP_UART1_BASE, | |
37 | .irq = 72, | |
38 | .flags = UPF_BOOT_AUTOCONF, | |
39 | .iotype = UPIO_MEM, | |
40 | .regshift = 2, | |
41 | .uartclk = OMAP16XX_BASE_BAUD * 16, | |
42 | }, { | |
43 | .membase = (char *)IO_ADDRESS(OMAP_UART2_BASE), | |
44 | .mapbase = (unsigned long)OMAP_UART2_BASE, | |
45 | .irq = 73, | |
46 | .flags = UPF_BOOT_AUTOCONF, | |
47 | .iotype = UPIO_MEM, | |
48 | .regshift = 2, | |
49 | .uartclk = OMAP16XX_BASE_BAUD * 16, | |
50 | }, { | |
51 | .membase = (char *)IO_ADDRESS(OMAP_UART3_BASE), | |
52 | .mapbase = (unsigned long)OMAP_UART3_BASE, | |
53 | .irq = 74, | |
54 | .flags = UPF_BOOT_AUTOCONF, | |
55 | .iotype = UPIO_MEM, | |
56 | .regshift = 2, | |
57 | .uartclk = OMAP16XX_BASE_BAUD * 16, | |
58 | }, { | |
59 | .flags = 0 | |
60 | } | |
61 | }; | |
62 | ||
63 | static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, | |
64 | int offset) | |
65 | { | |
66 | offset <<= up->regshift; | |
67 | return (unsigned int)__raw_readb(up->membase + offset); | |
68 | } | |
69 | ||
70 | static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, | |
71 | int value) | |
72 | { | |
73 | offset <<= p->regshift; | |
74 | __raw_writeb(value, (unsigned long)(p->membase + offset)); | |
75 | } | |
76 | ||
77 | /* | |
78 | * Internal UARTs need to be initialized for the 8250 autoconfig to work | |
79 | * properly. Note that the TX watermark initialization may not be needed | |
80 | * once the 8250.c watermark handling code is merged. | |
81 | */ | |
82 | static inline void __init omap_serial_reset(struct plat_serial8250_port *p) | |
83 | { | |
84 | serial_write_reg(p, UART_OMAP_MDR1, 0x07); | |
85 | serial_write_reg(p, UART_OMAP_SCR, 0x08); | |
86 | serial_write_reg(p, UART_OMAP_MDR1, 0x00); | |
87 | serial_write_reg(p, UART_OMAP_SYSC, 0x01); | |
88 | } | |
89 | ||
90 | void __init omap_serial_init() | |
91 | { | |
92 | int i; | |
93 | const struct omap_uart_config *info; | |
94 | ||
95 | /* | |
96 | * Make sure the serial ports are muxed on at this point. | |
97 | * You have to mux them off in device drivers later on | |
98 | * if not needed. | |
99 | */ | |
100 | ||
101 | info = omap_get_config(OMAP_TAG_UART, | |
102 | struct omap_uart_config); | |
103 | ||
104 | if (info == NULL) | |
105 | return; | |
106 | ||
107 | for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { | |
108 | struct plat_serial8250_port *p = serial_platform_data + i; | |
109 | ||
110 | if (!(info->enabled_uarts & (1 << i))) { | |
111 | p->membase = 0; | |
112 | p->mapbase = 0; | |
113 | continue; | |
114 | } | |
115 | ||
116 | switch (i) { | |
117 | case 0: | |
118 | uart1_ick = clk_get(NULL, "uart1_ick"); | |
119 | if (IS_ERR(uart1_ick)) | |
120 | printk("Could not get uart1_ick\n"); | |
121 | else { | |
122 | clk_use(uart1_ick); | |
123 | } | |
124 | ||
125 | uart1_fck = clk_get(NULL, "uart1_fck"); | |
126 | if (IS_ERR(uart1_fck)) | |
127 | printk("Could not get uart1_fck\n"); | |
128 | else { | |
129 | clk_use(uart1_fck); | |
130 | } | |
131 | break; | |
132 | case 1: | |
133 | uart2_ick = clk_get(NULL, "uart2_ick"); | |
134 | if (IS_ERR(uart2_ick)) | |
135 | printk("Could not get uart2_ick\n"); | |
136 | else { | |
137 | clk_use(uart2_ick); | |
138 | } | |
139 | ||
140 | uart2_fck = clk_get(NULL, "uart2_fck"); | |
141 | if (IS_ERR(uart2_fck)) | |
142 | printk("Could not get uart2_fck\n"); | |
143 | else { | |
144 | clk_use(uart2_fck); | |
145 | } | |
146 | break; | |
147 | case 2: | |
148 | uart3_ick = clk_get(NULL, "uart3_ick"); | |
149 | if (IS_ERR(uart3_ick)) | |
150 | printk("Could not get uart3_ick\n"); | |
151 | else { | |
152 | clk_use(uart3_ick); | |
153 | } | |
154 | ||
155 | uart3_fck = clk_get(NULL, "uart3_fck"); | |
156 | if (IS_ERR(uart3_fck)) | |
157 | printk("Could not get uart3_fck\n"); | |
158 | else { | |
159 | clk_use(uart3_fck); | |
160 | } | |
161 | break; | |
162 | } | |
163 | ||
164 | omap_serial_reset(p); | |
165 | } | |
166 | } | |
167 | ||
168 | static struct platform_device serial_device = { | |
169 | .name = "serial8250", | |
170 | .id = 0, | |
171 | .dev = { | |
172 | .platform_data = serial_platform_data, | |
173 | }, | |
174 | }; | |
175 | ||
176 | static int __init omap_init(void) | |
177 | { | |
178 | return platform_device_register(&serial_device); | |
179 | } | |
180 | arch_initcall(omap_init); |