blob: ae2186892c85f9728e1cfdee07861412281ae0f4 [file] [log] [blame]
Tony Lindgren1dbae812005-11-10 14:26:51 +00001/*
Uwe Zeisbergerf30c2262006-10-03 23:01:26 +02002 * arch/arm/mach-omap2/serial.c
Tony Lindgren1dbae812005-11-10 14:26:51 +00003 *
4 * OMAP2 serial support.
5 *
Jouni Hogander6e811762008-10-06 15:49:15 +03006 * Copyright (C) 2005-2008 Nokia Corporation
Tony Lindgren1dbae812005-11-10 14:26:51 +00007 * Author: Paul Mundt <paul.mundt@nokia.com>
8 *
Kevin Hilman4af40162009-02-04 10:51:40 -08009 * Major rework for PM support by Kevin Hilman
10 *
Tony Lindgren1dbae812005-11-10 14:26:51 +000011 * Based off of arch/arm/mach-omap/omap1/serial.c
12 *
Santosh Shilimkar44169072009-05-28 14:16:04 -070013 * Copyright (C) 2009 Texas Instruments
14 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com
15 *
Tony Lindgren1dbae812005-11-10 14:26:51 +000016 * This file is subject to the terms and conditions of the GNU General Public
17 * License. See the file "COPYING" in the main directory of this archive
18 * for more details.
19 */
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/serial_8250.h>
23#include <linux/serial_reg.h>
Russell Kingf8ce2542006-01-07 16:15:52 +000024#include <linux/clk.h>
Russell Kingfced80c2008-09-06 12:10:45 +010025#include <linux/io.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000026
Russell Kinga09e64f2008-08-05 16:14:15 +010027#include <mach/common.h>
28#include <mach/board.h>
Kevin Hilman4af40162009-02-04 10:51:40 -080029#include <mach/clock.h>
30#include <mach/control.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000031
Kevin Hilman4af40162009-02-04 10:51:40 -080032#include "prm.h"
33#include "pm.h"
34#include "prm-regbits-34xx.h"
35
36#define UART_OMAP_WER 0x17 /* Wake-up enable register */
37
Jouni Hoganderba87a9b2008-12-09 13:36:50 +020038#define DEFAULT_TIMEOUT (5 * HZ)
Kevin Hilman4af40162009-02-04 10:51:40 -080039
40struct omap_uart_state {
41 int num;
42 int can_sleep;
43 struct timer_list timer;
44 u32 timeout;
45
46 void __iomem *wk_st;
47 void __iomem *wk_en;
48 u32 wk_mask;
49 u32 padconf;
50
51 struct clk *ick;
52 struct clk *fck;
53 int clocked;
54
55 struct plat_serial8250_port *p;
56 struct list_head node;
Kevin Hilmanfd455ea2009-04-27 12:27:36 -070057 struct platform_device pdev;
Kevin Hilman4af40162009-02-04 10:51:40 -080058
59#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
60 int context_valid;
61
62 /* Registers to be saved/restored for OFF-mode */
63 u16 dll;
64 u16 dlh;
65 u16 ier;
66 u16 sysc;
67 u16 scr;
68 u16 wer;
69#endif
70};
71
Kevin Hilman4af40162009-02-04 10:51:40 -080072static LIST_HEAD(uart_list);
Tony Lindgren1dbae812005-11-10 14:26:51 +000073
Kevin Hilmanfd455ea2009-04-27 12:27:36 -070074static struct plat_serial8250_port serial_platform_data0[] = {
Tony Lindgren1dbae812005-11-10 14:26:51 +000075 {
Tony Lindgren94113262009-08-28 10:50:33 -070076 .membase = OMAP2_IO_ADDRESS(OMAP_UART1_BASE),
Russell Kinge8a91c92008-09-01 22:07:37 +010077 .mapbase = OMAP_UART1_BASE,
Tony Lindgren1dbae812005-11-10 14:26:51 +000078 .irq = 72,
79 .flags = UPF_BOOT_AUTOCONF,
80 .iotype = UPIO_MEM,
81 .regshift = 2,
Jouni Hogander6e811762008-10-06 15:49:15 +030082 .uartclk = OMAP24XX_BASE_BAUD * 16,
Tony Lindgren1dbae812005-11-10 14:26:51 +000083 }, {
Kevin Hilmanfd455ea2009-04-27 12:27:36 -070084 .flags = 0
85 }
86};
87
88static struct plat_serial8250_port serial_platform_data1[] = {
89 {
Tony Lindgren94113262009-08-28 10:50:33 -070090 .membase = OMAP2_IO_ADDRESS(OMAP_UART2_BASE),
Russell Kinge8a91c92008-09-01 22:07:37 +010091 .mapbase = OMAP_UART2_BASE,
Tony Lindgren1dbae812005-11-10 14:26:51 +000092 .irq = 73,
93 .flags = UPF_BOOT_AUTOCONF,
94 .iotype = UPIO_MEM,
95 .regshift = 2,
Jouni Hogander6e811762008-10-06 15:49:15 +030096 .uartclk = OMAP24XX_BASE_BAUD * 16,
Tony Lindgren1dbae812005-11-10 14:26:51 +000097 }, {
Kevin Hilmanfd455ea2009-04-27 12:27:36 -070098 .flags = 0
99 }
100};
101
102static struct plat_serial8250_port serial_platform_data2[] = {
103 {
Tony Lindgren94113262009-08-28 10:50:33 -0700104 .membase = OMAP2_IO_ADDRESS(OMAP_UART3_BASE),
Russell Kinge8a91c92008-09-01 22:07:37 +0100105 .mapbase = OMAP_UART3_BASE,
Tony Lindgren1dbae812005-11-10 14:26:51 +0000106 .irq = 74,
107 .flags = UPF_BOOT_AUTOCONF,
108 .iotype = UPIO_MEM,
109 .regshift = 2,
Jouni Hogander6e811762008-10-06 15:49:15 +0300110 .uartclk = OMAP24XX_BASE_BAUD * 16,
Tony Lindgren1dbae812005-11-10 14:26:51 +0000111 }, {
Syed Rafiuddin085b54d2009-07-28 18:57:22 +0530112#ifdef CONFIG_ARCH_OMAP4
Tony Lindgren5328ae32009-09-24 16:23:04 -0700113 .membase = OMAP2_IO_ADDRESS(OMAP_UART4_BASE),
Syed Rafiuddin085b54d2009-07-28 18:57:22 +0530114 .mapbase = OMAP_UART4_BASE,
115 .irq = 70,
116 .flags = UPF_BOOT_AUTOCONF,
117 .iotype = UPIO_MEM,
118 .regshift = 2,
119 .uartclk = OMAP24XX_BASE_BAUD * 16,
120 }, {
121#endif
Tony Lindgren1dbae812005-11-10 14:26:51 +0000122 .flags = 0
123 }
124};
125
Santosh Shilimkar0e3eaad2009-08-22 13:30:11 +0530126#ifdef CONFIG_ARCH_OMAP4
127static struct plat_serial8250_port serial_platform_data3[] = {
128 {
Tony Lindgren5328ae32009-09-24 16:23:04 -0700129 .membase = OMAP2_IO_ADDRESS(OMAP_UART4_BASE),
Santosh Shilimkar0e3eaad2009-08-22 13:30:11 +0530130 .mapbase = OMAP_UART4_BASE,
131 .irq = 70,
132 .flags = UPF_BOOT_AUTOCONF,
133 .iotype = UPIO_MEM,
134 .regshift = 2,
135 .uartclk = OMAP24XX_BASE_BAUD * 16,
136 }, {
137 .flags = 0
138 }
139};
140#endif
Tony Lindgren1dbae812005-11-10 14:26:51 +0000141static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
142 int offset)
143{
144 offset <<= up->regshift;
145 return (unsigned int)__raw_readb(up->membase + offset);
146}
147
148static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
149 int value)
150{
151 offset <<= p->regshift;
Russell Kinge8a91c92008-09-01 22:07:37 +0100152 __raw_writeb(value, p->membase + offset);
Tony Lindgren1dbae812005-11-10 14:26:51 +0000153}
154
155/*
156 * Internal UARTs need to be initialized for the 8250 autoconfig to work
157 * properly. Note that the TX watermark initialization may not be needed
158 * once the 8250.c watermark handling code is merged.
159 */
Kevin Hilman4af40162009-02-04 10:51:40 -0800160static inline void __init omap_uart_reset(struct omap_uart_state *uart)
Tony Lindgren1dbae812005-11-10 14:26:51 +0000161{
Kevin Hilman4af40162009-02-04 10:51:40 -0800162 struct plat_serial8250_port *p = uart->p;
163
Tony Lindgren1dbae812005-11-10 14:26:51 +0000164 serial_write_reg(p, UART_OMAP_MDR1, 0x07);
165 serial_write_reg(p, UART_OMAP_SCR, 0x08);
166 serial_write_reg(p, UART_OMAP_MDR1, 0x00);
Juha Yrjola671c7232006-12-06 17:13:49 -0800167 serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
Tony Lindgren1dbae812005-11-10 14:26:51 +0000168}
169
Kevin Hilman4af40162009-02-04 10:51:40 -0800170#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
171
172static int enable_off_mode; /* to be removed by full off-mode patches */
173
174static void omap_uart_save_context(struct omap_uart_state *uart)
Jouni Hogander6e811762008-10-06 15:49:15 +0300175{
Kevin Hilman4af40162009-02-04 10:51:40 -0800176 u16 lcr = 0;
177 struct plat_serial8250_port *p = uart->p;
178
179 if (!enable_off_mode)
180 return;
181
182 lcr = serial_read_reg(p, UART_LCR);
183 serial_write_reg(p, UART_LCR, 0xBF);
184 uart->dll = serial_read_reg(p, UART_DLL);
185 uart->dlh = serial_read_reg(p, UART_DLM);
186 serial_write_reg(p, UART_LCR, lcr);
187 uart->ier = serial_read_reg(p, UART_IER);
188 uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
189 uart->scr = serial_read_reg(p, UART_OMAP_SCR);
190 uart->wer = serial_read_reg(p, UART_OMAP_WER);
191
192 uart->context_valid = 1;
193}
194
195static void omap_uart_restore_context(struct omap_uart_state *uart)
196{
197 u16 efr = 0;
198 struct plat_serial8250_port *p = uart->p;
199
200 if (!enable_off_mode)
201 return;
202
203 if (!uart->context_valid)
204 return;
205
206 uart->context_valid = 0;
207
208 serial_write_reg(p, UART_OMAP_MDR1, 0x7);
209 serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
210 efr = serial_read_reg(p, UART_EFR);
211 serial_write_reg(p, UART_EFR, UART_EFR_ECB);
212 serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
213 serial_write_reg(p, UART_IER, 0x0);
214 serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
215 serial_write_reg(p, UART_DLL, uart->dll);
216 serial_write_reg(p, UART_DLM, uart->dlh);
217 serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
218 serial_write_reg(p, UART_IER, uart->ier);
219 serial_write_reg(p, UART_FCR, 0xA1);
220 serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
221 serial_write_reg(p, UART_EFR, efr);
222 serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
223 serial_write_reg(p, UART_OMAP_SCR, uart->scr);
224 serial_write_reg(p, UART_OMAP_WER, uart->wer);
225 serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
226 serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
227}
228#else
229static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
230static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
231#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
232
233static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
234{
235 if (uart->clocked)
236 return;
237
238 clk_enable(uart->ick);
239 clk_enable(uart->fck);
240 uart->clocked = 1;
241 omap_uart_restore_context(uart);
242}
243
244#ifdef CONFIG_PM
245
246static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
247{
248 if (!uart->clocked)
249 return;
250
251 omap_uart_save_context(uart);
252 uart->clocked = 0;
253 clk_disable(uart->ick);
254 clk_disable(uart->fck);
255}
256
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700257static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
258{
259 /* Set wake-enable bit */
260 if (uart->wk_en && uart->wk_mask) {
261 u32 v = __raw_readl(uart->wk_en);
262 v |= uart->wk_mask;
263 __raw_writel(v, uart->wk_en);
264 }
265
266 /* Ensure IOPAD wake-enables are set */
267 if (cpu_is_omap34xx() && uart->padconf) {
268 u16 v = omap_ctrl_readw(uart->padconf);
269 v |= OMAP3_PADCONF_WAKEUPENABLE0;
270 omap_ctrl_writew(v, uart->padconf);
271 }
272}
273
274static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
275{
276 /* Clear wake-enable bit */
277 if (uart->wk_en && uart->wk_mask) {
278 u32 v = __raw_readl(uart->wk_en);
279 v &= ~uart->wk_mask;
280 __raw_writel(v, uart->wk_en);
281 }
282
283 /* Ensure IOPAD wake-enables are cleared */
284 if (cpu_is_omap34xx() && uart->padconf) {
285 u16 v = omap_ctrl_readw(uart->padconf);
286 v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
287 omap_ctrl_writew(v, uart->padconf);
288 }
289}
290
Kevin Hilman4af40162009-02-04 10:51:40 -0800291static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
292 int enable)
293{
294 struct plat_serial8250_port *p = uart->p;
295 u16 sysc;
296
297 sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
298 if (enable)
299 sysc |= 0x2 << 3;
300 else
301 sysc |= 0x1 << 3;
302
303 serial_write_reg(p, UART_OMAP_SYSC, sysc);
304}
305
306static void omap_uart_block_sleep(struct omap_uart_state *uart)
307{
308 omap_uart_enable_clocks(uart);
309
310 omap_uart_smart_idle_enable(uart, 0);
311 uart->can_sleep = 0;
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200312 if (uart->timeout)
313 mod_timer(&uart->timer, jiffies + uart->timeout);
314 else
315 del_timer(&uart->timer);
Kevin Hilman4af40162009-02-04 10:51:40 -0800316}
317
318static void omap_uart_allow_sleep(struct omap_uart_state *uart)
319{
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700320 if (device_may_wakeup(&uart->pdev.dev))
321 omap_uart_enable_wakeup(uart);
322 else
323 omap_uart_disable_wakeup(uart);
324
Kevin Hilman4af40162009-02-04 10:51:40 -0800325 if (!uart->clocked)
326 return;
327
328 omap_uart_smart_idle_enable(uart, 1);
329 uart->can_sleep = 1;
330 del_timer(&uart->timer);
331}
332
333static void omap_uart_idle_timer(unsigned long data)
334{
335 struct omap_uart_state *uart = (struct omap_uart_state *)data;
336
337 omap_uart_allow_sleep(uart);
338}
339
340void omap_uart_prepare_idle(int num)
341{
342 struct omap_uart_state *uart;
343
344 list_for_each_entry(uart, &uart_list, node) {
345 if (num == uart->num && uart->can_sleep) {
346 omap_uart_disable_clocks(uart);
347 return;
Jouni Hogander6e811762008-10-06 15:49:15 +0300348 }
349 }
350}
351
Kevin Hilman4af40162009-02-04 10:51:40 -0800352void omap_uart_resume_idle(int num)
353{
354 struct omap_uart_state *uart;
355
356 list_for_each_entry(uart, &uart_list, node) {
357 if (num == uart->num) {
358 omap_uart_enable_clocks(uart);
359
360 /* Check for IO pad wakeup */
361 if (cpu_is_omap34xx() && uart->padconf) {
362 u16 p = omap_ctrl_readw(uart->padconf);
363
364 if (p & OMAP3_PADCONF_WAKEUPEVENT0)
365 omap_uart_block_sleep(uart);
366 }
367
368 /* Check for normal UART wakeup */
369 if (__raw_readl(uart->wk_st) & uart->wk_mask)
370 omap_uart_block_sleep(uart);
Kevin Hilman4af40162009-02-04 10:51:40 -0800371 return;
372 }
373 }
374}
375
376void omap_uart_prepare_suspend(void)
377{
378 struct omap_uart_state *uart;
379
380 list_for_each_entry(uart, &uart_list, node) {
381 omap_uart_allow_sleep(uart);
382 }
383}
384
385int omap_uart_can_sleep(void)
386{
387 struct omap_uart_state *uart;
388 int can_sleep = 1;
389
390 list_for_each_entry(uart, &uart_list, node) {
391 if (!uart->clocked)
392 continue;
393
394 if (!uart->can_sleep) {
395 can_sleep = 0;
396 continue;
397 }
398
399 /* This UART can now safely sleep. */
400 omap_uart_allow_sleep(uart);
401 }
402
403 return can_sleep;
404}
405
406/**
407 * omap_uart_interrupt()
408 *
409 * This handler is used only to detect that *any* UART interrupt has
410 * occurred. It does _nothing_ to handle the interrupt. Rather,
411 * any UART interrupt will trigger the inactivity timer so the
412 * UART will not idle or sleep for its timeout period.
413 *
414 **/
415static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
416{
417 struct omap_uart_state *uart = dev_id;
418
419 omap_uart_block_sleep(uart);
420
421 return IRQ_NONE;
422}
423
424static void omap_uart_idle_init(struct omap_uart_state *uart)
425{
Kevin Hilman4af40162009-02-04 10:51:40 -0800426 struct plat_serial8250_port *p = uart->p;
427 int ret;
428
429 uart->can_sleep = 0;
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700430 uart->timeout = DEFAULT_TIMEOUT;
Kevin Hilman4af40162009-02-04 10:51:40 -0800431 setup_timer(&uart->timer, omap_uart_idle_timer,
432 (unsigned long) uart);
433 mod_timer(&uart->timer, jiffies + uart->timeout);
434 omap_uart_smart_idle_enable(uart, 0);
435
436 if (cpu_is_omap34xx()) {
437 u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
438 u32 wk_mask = 0;
439 u32 padconf = 0;
440
441 uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
442 uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
443 switch (uart->num) {
444 case 0:
445 wk_mask = OMAP3430_ST_UART1_MASK;
446 padconf = 0x182;
447 break;
448 case 1:
449 wk_mask = OMAP3430_ST_UART2_MASK;
450 padconf = 0x17a;
451 break;
452 case 2:
453 wk_mask = OMAP3430_ST_UART3_MASK;
454 padconf = 0x19e;
455 break;
456 }
457 uart->wk_mask = wk_mask;
458 uart->padconf = padconf;
459 } else if (cpu_is_omap24xx()) {
460 u32 wk_mask = 0;
461
462 if (cpu_is_omap2430()) {
463 uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
464 uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
465 } else if (cpu_is_omap2420()) {
466 uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
467 uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
468 }
469 switch (uart->num) {
470 case 0:
471 wk_mask = OMAP24XX_ST_UART1_MASK;
472 break;
473 case 1:
474 wk_mask = OMAP24XX_ST_UART2_MASK;
475 break;
476 case 2:
477 wk_mask = OMAP24XX_ST_UART3_MASK;
478 break;
479 }
480 uart->wk_mask = wk_mask;
481 } else {
482 uart->wk_en = 0;
483 uart->wk_st = 0;
484 uart->wk_mask = 0;
485 uart->padconf = 0;
486 }
487
Vikram Panditac426df82009-08-28 11:24:08 -0700488 p->irqflags |= IRQF_SHARED;
Kevin Hilman4af40162009-02-04 10:51:40 -0800489 ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
490 "serial idle", (void *)uart);
491 WARN_ON(ret);
492}
493
Tero Kristo24662112009-03-05 16:32:23 +0200494void omap_uart_enable_irqs(int enable)
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200495{
Tero Kristo24662112009-03-05 16:32:23 +0200496 int ret;
497 struct omap_uart_state *uart;
498
499 list_for_each_entry(uart, &uart_list, node) {
500 if (enable)
501 ret = request_irq(uart->p->irq, omap_uart_interrupt,
502 IRQF_SHARED, "serial idle", (void *)uart);
503 else
504 free_irq(uart->p->irq, (void *)uart);
505 }
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200506}
507
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700508static ssize_t sleep_timeout_show(struct device *dev,
509 struct device_attribute *attr,
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200510 char *buf)
511{
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700512 struct platform_device *pdev = container_of(dev,
513 struct platform_device, dev);
514 struct omap_uart_state *uart = container_of(pdev,
515 struct omap_uart_state, pdev);
516
517 return sprintf(buf, "%u\n", uart->timeout / HZ);
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200518}
519
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700520static ssize_t sleep_timeout_store(struct device *dev,
521 struct device_attribute *attr,
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200522 const char *buf, size_t n)
523{
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700524 struct platform_device *pdev = container_of(dev,
525 struct platform_device, dev);
526 struct omap_uart_state *uart = container_of(pdev,
527 struct omap_uart_state, pdev);
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200528 unsigned int value;
529
530 if (sscanf(buf, "%u", &value) != 1) {
531 printk(KERN_ERR "sleep_timeout_store: Invalid value\n");
532 return -EINVAL;
533 }
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700534
535 uart->timeout = value * HZ;
536 if (uart->timeout)
537 mod_timer(&uart->timer, jiffies + uart->timeout);
538 else
539 /* A zero value means disable timeout feature */
540 omap_uart_block_sleep(uart);
541
Jouni Hoganderba87a9b2008-12-09 13:36:50 +0200542 return n;
543}
544
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700545DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store);
546#define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr))
Kevin Hilman4af40162009-02-04 10:51:40 -0800547#else
548static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700549#define DEV_CREATE_FILE(dev, attr)
Kevin Hilman4af40162009-02-04 10:51:40 -0800550#endif /* CONFIG_PM */
551
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700552static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = {
553 {
554 .pdev = {
555 .name = "serial8250",
556 .id = PLAT8250_DEV_PLATFORM,
557 .dev = {
558 .platform_data = serial_platform_data0,
559 },
560 },
561 }, {
562 .pdev = {
563 .name = "serial8250",
564 .id = PLAT8250_DEV_PLATFORM1,
565 .dev = {
566 .platform_data = serial_platform_data1,
567 },
568 },
569 }, {
570 .pdev = {
571 .name = "serial8250",
572 .id = PLAT8250_DEV_PLATFORM2,
573 .dev = {
574 .platform_data = serial_platform_data2,
575 },
576 },
Vikram Pandita2aa57be2009-05-28 14:03:59 -0700577 },
Santosh Shilimkar0e3eaad2009-08-22 13:30:11 +0530578#ifdef CONFIG_ARCH_OMAP4
579 {
580 .pdev = {
581 .name = "serial8250",
Tony Lindgren61f04ee2009-09-24 16:23:07 -0700582 .id = 3,
Santosh Shilimkar0e3eaad2009-08-22 13:30:11 +0530583 .dev = {
584 .platform_data = serial_platform_data3,
585 },
586 },
587 },
588#endif
Vikram Pandita2aa57be2009-05-28 14:03:59 -0700589};
590
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300591void __init omap_serial_early_init(void)
Tony Lindgren1dbae812005-11-10 14:26:51 +0000592{
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700593 int i;
Jouni Hogander6e811762008-10-06 15:49:15 +0300594 char name[16];
Tony Lindgren1dbae812005-11-10 14:26:51 +0000595
596 /*
597 * Make sure the serial ports are muxed on at this point.
598 * You have to mux them off in device drivers later on
599 * if not needed.
600 */
601
Tony Lindgren1dbae812005-11-10 14:26:51 +0000602 for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
Kevin Hilman4af40162009-02-04 10:51:40 -0800603 struct omap_uart_state *uart = &omap_uart[i];
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700604 struct platform_device *pdev = &uart->pdev;
605 struct device *dev = &pdev->dev;
606 struct plat_serial8250_port *p = dev->platform_data;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000607
Jouni Hogander6e811762008-10-06 15:49:15 +0300608 sprintf(name, "uart%d_ick", i+1);
Kevin Hilman4af40162009-02-04 10:51:40 -0800609 uart->ick = clk_get(NULL, name);
610 if (IS_ERR(uart->ick)) {
Jouni Hogander6e811762008-10-06 15:49:15 +0300611 printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
Kevin Hilman4af40162009-02-04 10:51:40 -0800612 uart->ick = NULL;
613 }
Tony Lindgren1dbae812005-11-10 14:26:51 +0000614
Jouni Hogander6e811762008-10-06 15:49:15 +0300615 sprintf(name, "uart%d_fck", i+1);
Kevin Hilman4af40162009-02-04 10:51:40 -0800616 uart->fck = clk_get(NULL, name);
617 if (IS_ERR(uart->fck)) {
Jouni Hogander6e811762008-10-06 15:49:15 +0300618 printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
Kevin Hilman4af40162009-02-04 10:51:40 -0800619 uart->fck = NULL;
620 }
Tony Lindgren1dbae812005-11-10 14:26:51 +0000621
Santosh Shilimkaraae290f2009-08-22 13:30:12 +0530622 /* FIXME: Remove this once the clkdev is ready */
623 if (!cpu_is_omap44xx()) {
624 if (!uart->ick || !uart->fck)
625 continue;
626 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800627
628 uart->num = i;
629 p->private_data = uart;
630 uart->p = p;
Kevin Hilmanbcf396c2009-06-30 21:02:45 -0700631 list_add_tail(&uart->node, &uart_list);
Kevin Hilman4af40162009-02-04 10:51:40 -0800632
Kevin Hilman47899982009-06-24 10:32:03 -0700633 if (cpu_is_omap44xx())
634 p->irq += 32;
Kevin Hilman4af40162009-02-04 10:51:40 -0800635
636 omap_uart_enable_clocks(uart);
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300637 }
638}
639
640void __init omap_serial_init(void)
641{
642 int i;
643
644 for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
645 struct omap_uart_state *uart = &omap_uart[i];
646 struct platform_device *pdev = &uart->pdev;
647 struct device *dev = &pdev->dev;
648
Kevin Hilman4af40162009-02-04 10:51:40 -0800649 omap_uart_reset(uart);
650 omap_uart_idle_init(uart);
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700651
652 if (WARN_ON(platform_device_register(pdev)))
653 continue;
654 if ((cpu_is_omap34xx() && uart->padconf) ||
655 (uart->wk_en && uart->wk_mask)) {
656 device_init_wakeup(dev, true);
657 DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);
658 }
Tony Lindgren1dbae812005-11-10 14:26:51 +0000659 }
Tony Lindgren1dbae812005-11-10 14:26:51 +0000660}