blob: b3f3284bf6ba883993fdd93ce39acc53fa9bc8a9 [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>
Russell Kingf8ce2542006-01-07 16:15:52 +000022#include <linux/clk.h>
Russell Kingfced80c2008-09-06 12:10:45 +010023#include <linux/io.h>
Santosh Shilimkare03d37d2010-02-18 08:59:06 +000024#include <linux/delay.h>
Kevin Hilman6f251e92010-09-27 20:19:38 +053025#include <linux/platform_device.h>
26#include <linux/slab.h>
Kevin Hilman3244fcd2010-09-27 20:19:53 +053027#include <linux/pm_runtime.h>
Paul Walmsley0d8e2d02010-11-24 16:49:05 -070028#include <linux/console.h>
Kevin Hilman6f251e92010-09-27 20:19:38 +053029
Kevin Hilman6f251e92010-09-27 20:19:38 +053030#include <plat/omap-serial.h>
Tony Lindgren4e653312011-11-10 22:45:17 +010031#include "common.h"
Tony Lindgrence491cf2009-10-20 09:40:47 -070032#include <plat/board.h>
Kevin Hilman6f251e92010-09-27 20:19:38 +053033#include <plat/dma.h>
34#include <plat/omap_hwmod.h>
35#include <plat/omap_device.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000036
Paul Walmsley59fb6592010-12-21 15:30:55 -070037#include "prm2xxx_3xxx.h"
Kevin Hilman4af40162009-02-04 10:51:40 -080038#include "pm.h"
Paul Walmsley59fb6592010-12-21 15:30:55 -070039#include "cm2xxx_3xxx.h"
Kevin Hilman4af40162009-02-04 10:51:40 -080040#include "prm-regbits-34xx.h"
Paul Walmsley4814ced2010-10-08 11:40:20 -060041#include "control.h"
Tony Lindgren40e44392010-12-22 18:42:35 -080042#include "mux.h"
Kevin Hilman4af40162009-02-04 10:51:40 -080043
Deepak K00034502010-08-02 13:18:12 +030044#define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1)
Nishanth Menon5a927b32010-08-02 13:18:12 +030045
Tony Lindgren301fe8e2010-02-01 12:34:31 -080046/*
47 * NOTE: By default the serial timeout is disabled as it causes lost characters
48 * over the serial ports. This means that the UART clocks will stay on until
49 * disabled via sysfs. This also causes that any deeper omap sleep states are
50 * blocked.
51 */
52#define DEFAULT_TIMEOUT 0
Kevin Hilman4af40162009-02-04 10:51:40 -080053
Kevin Hilman6f251e92010-09-27 20:19:38 +053054#define MAX_UART_HWMOD_NAME_LEN 16
55
Kevin Hilman4af40162009-02-04 10:51:40 -080056struct omap_uart_state {
57 int num;
58 int can_sleep;
Kevin Hilman4af40162009-02-04 10:51:40 -080059
60 void __iomem *wk_st;
61 void __iomem *wk_en;
62 u32 wk_mask;
Kevin Hilman6f251e92010-09-27 20:19:38 +053063 u32 dma_enabled;
Kevin Hilman4af40162009-02-04 10:51:40 -080064
Kevin Hilman4af40162009-02-04 10:51:40 -080065 int clocked;
66
Kevin Hilman4af40162009-02-04 10:51:40 -080067 struct list_head node;
Kevin Hilman6f251e92010-09-27 20:19:38 +053068 struct omap_hwmod *oh;
69 struct platform_device *pdev;
Kevin Hilman4af40162009-02-04 10:51:40 -080070
Nishanth Menon5a927b32010-08-02 13:18:12 +030071 u32 errata;
Kevin Hilman4af40162009-02-04 10:51:40 -080072};
73
Kevin Hilman4af40162009-02-04 10:51:40 -080074static LIST_HEAD(uart_list);
Kevin Hilman6f251e92010-09-27 20:19:38 +053075static u8 num_uarts;
Tony Lindgren1dbae812005-11-10 14:26:51 +000076
Kevin Hilman4af40162009-02-04 10:51:40 -080077#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
78
Deepak K00034502010-08-02 13:18:12 +030079/*
80 * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
81 * The access to uart register after MDR1 Access
82 * causes UART to corrupt data.
83 *
84 * Need a delay =
85 * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
86 * give 10 times as much
87 */
88static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
89 u8 fcr_val)
90{
Deepak K00034502010-08-02 13:18:12 +030091 u8 timeout = 255;
92
Kevin Hilman6f251e92010-09-27 20:19:38 +053093 serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
Deepak K00034502010-08-02 13:18:12 +030094 udelay(2);
Kevin Hilman6f251e92010-09-27 20:19:38 +053095 serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
Deepak K00034502010-08-02 13:18:12 +030096 UART_FCR_CLEAR_RCVR);
97 /*
98 * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
99 * TX_FIFO_E bit is 1.
100 */
Kevin Hilman6f251e92010-09-27 20:19:38 +0530101 while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
Deepak K00034502010-08-02 13:18:12 +0300102 (UART_LSR_THRE | UART_LSR_DR))) {
103 timeout--;
104 if (!timeout) {
105 /* Should *never* happen. we warn and carry on */
Kevin Hilman6f251e92010-09-27 20:19:38 +0530106 dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
107 serial_read_reg(uart, UART_LSR));
Deepak K00034502010-08-02 13:18:12 +0300108 break;
109 }
110 udelay(1);
111 }
112}
113
Kevin Hilman4af40162009-02-04 10:51:40 -0800114#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
115
116static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
117{
118 if (uart->clocked)
119 return;
120
Kevin Hilman6f251e92010-09-27 20:19:38 +0530121 omap_device_enable(uart->pdev);
Kevin Hilman4af40162009-02-04 10:51:40 -0800122 uart->clocked = 1;
123 omap_uart_restore_context(uart);
124}
125
126#ifdef CONFIG_PM
127
128static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
129{
130 if (!uart->clocked)
131 return;
132
133 omap_uart_save_context(uart);
134 uart->clocked = 0;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530135 omap_device_idle(uart->pdev);
Kevin Hilman4af40162009-02-04 10:51:40 -0800136}
137
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700138static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
139{
140 /* Set wake-enable bit */
141 if (uart->wk_en && uart->wk_mask) {
142 u32 v = __raw_readl(uart->wk_en);
143 v |= uart->wk_mask;
144 __raw_writel(v, uart->wk_en);
145 }
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700146}
147
148static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
149{
150 /* Clear wake-enable bit */
151 if (uart->wk_en && uart->wk_mask) {
152 u32 v = __raw_readl(uart->wk_en);
153 v &= ~uart->wk_mask;
154 __raw_writel(v, uart->wk_en);
155 }
Kevin Hilmanfd455ea2009-04-27 12:27:36 -0700156}
157
Kevin Hilman4af40162009-02-04 10:51:40 -0800158static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
Kevin Hilman6f251e92010-09-27 20:19:38 +0530159 int enable)
Kevin Hilman4af40162009-02-04 10:51:40 -0800160{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530161 u8 idlemode;
Kevin Hilman4af40162009-02-04 10:51:40 -0800162
Kevin Hilman6f251e92010-09-27 20:19:38 +0530163 if (enable) {
164 /**
165 * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
166 * in Smartidle Mode When Configured for DMA Operations.
167 */
168 if (uart->dma_enabled)
169 idlemode = HWMOD_IDLEMODE_FORCE;
170 else
171 idlemode = HWMOD_IDLEMODE_SMART;
172 } else {
173 idlemode = HWMOD_IDLEMODE_NO;
174 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800175
Kevin Hilman6f251e92010-09-27 20:19:38 +0530176 omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
Kevin Hilman4af40162009-02-04 10:51:40 -0800177}
178
179static void omap_uart_block_sleep(struct omap_uart_state *uart)
180{
181 omap_uart_enable_clocks(uart);
182
183 omap_uart_smart_idle_enable(uart, 0);
184 uart->can_sleep = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800185}
186
Kevin Hilman4af40162009-02-04 10:51:40 -0800187int omap_uart_can_sleep(void)
188{
189 struct omap_uart_state *uart;
190 int can_sleep = 1;
191
192 list_for_each_entry(uart, &uart_list, node) {
193 if (!uart->clocked)
194 continue;
195
196 if (!uart->can_sleep) {
197 can_sleep = 0;
198 continue;
199 }
200
201 /* This UART can now safely sleep. */
202 omap_uart_allow_sleep(uart);
203 }
204
205 return can_sleep;
206}
207
Kevin Hilman4af40162009-02-04 10:51:40 -0800208static void omap_uart_idle_init(struct omap_uart_state *uart)
209{
Kevin Hilman4af40162009-02-04 10:51:40 -0800210 int ret;
211
212 uart->can_sleep = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800213 omap_uart_smart_idle_enable(uart, 0);
214
Hemant Pedanekara9203602011-12-13 10:46:44 -0800215 if (cpu_is_omap34xx() && !(cpu_is_ti81xx() || cpu_is_am33xx())) {
Govindraj.R52663ae2010-09-27 20:20:41 +0530216 u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
Kevin Hilman4af40162009-02-04 10:51:40 -0800217 u32 wk_mask = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800218
Paul Walmsleyc4d7e582010-12-21 21:05:14 -0700219 /* XXX These PRM accesses do not belong here */
Kevin Hilman4af40162009-02-04 10:51:40 -0800220 uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
221 uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
222 switch (uart->num) {
223 case 0:
224 wk_mask = OMAP3430_ST_UART1_MASK;
Kevin Hilman4af40162009-02-04 10:51:40 -0800225 break;
226 case 1:
227 wk_mask = OMAP3430_ST_UART2_MASK;
Kevin Hilman4af40162009-02-04 10:51:40 -0800228 break;
229 case 2:
230 wk_mask = OMAP3430_ST_UART3_MASK;
Kevin Hilman4af40162009-02-04 10:51:40 -0800231 break;
Govindraj.R52663ae2010-09-27 20:20:41 +0530232 case 3:
233 wk_mask = OMAP3630_ST_UART4_MASK;
Govindraj.R52663ae2010-09-27 20:20:41 +0530234 break;
Kevin Hilman4af40162009-02-04 10:51:40 -0800235 }
236 uart->wk_mask = wk_mask;
Kevin Hilman4af40162009-02-04 10:51:40 -0800237 } else if (cpu_is_omap24xx()) {
238 u32 wk_mask = 0;
Kevin Hilmancb74f022010-10-20 23:19:03 +0000239 u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
Kevin Hilman4af40162009-02-04 10:51:40 -0800240
Kevin Hilman4af40162009-02-04 10:51:40 -0800241 switch (uart->num) {
242 case 0:
243 wk_mask = OMAP24XX_ST_UART1_MASK;
244 break;
245 case 1:
246 wk_mask = OMAP24XX_ST_UART2_MASK;
247 break;
248 case 2:
Kevin Hilmancb74f022010-10-20 23:19:03 +0000249 wk_en = OMAP24XX_PM_WKEN2;
250 wk_st = OMAP24XX_PM_WKST2;
Kevin Hilman4af40162009-02-04 10:51:40 -0800251 wk_mask = OMAP24XX_ST_UART3_MASK;
252 break;
253 }
254 uart->wk_mask = wk_mask;
Kevin Hilmancb74f022010-10-20 23:19:03 +0000255 if (cpu_is_omap2430()) {
256 uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, wk_en);
257 uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, wk_st);
258 } else if (cpu_is_omap2420()) {
259 uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, wk_en);
260 uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, wk_st);
261 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800262 } else {
Nishanth Menonc54bae12010-08-02 13:18:11 +0300263 uart->wk_en = NULL;
264 uart->wk_st = NULL;
Kevin Hilman4af40162009-02-04 10:51:40 -0800265 uart->wk_mask = 0;
Kevin Hilman4af40162009-02-04 10:51:40 -0800266 }
Kevin Hilman4af40162009-02-04 10:51:40 -0800267}
268
269#else
Santosh Shilimkara1b04cc2010-10-11 11:05:18 +0000270static void omap_uart_block_sleep(struct omap_uart_state *uart)
271{
272 /* Needed to enable UART clocks when built without CONFIG_PM */
273 omap_uart_enable_clocks(uart);
274}
Kevin Hilman4af40162009-02-04 10:51:40 -0800275#endif /* CONFIG_PM */
276
Govindraj.R7496ba32011-11-07 18:55:05 +0530277#ifdef CONFIG_OMAP_MUX
278static struct omap_device_pad default_uart1_pads[] __initdata = {
279 {
280 .name = "uart1_cts.uart1_cts",
281 .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
282 },
283 {
284 .name = "uart1_rts.uart1_rts",
285 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
286 },
287 {
288 .name = "uart1_tx.uart1_tx",
289 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
290 },
291 {
292 .name = "uart1_rx.uart1_rx",
293 .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
294 .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
295 .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
296 },
297};
298
299static struct omap_device_pad default_uart2_pads[] __initdata = {
300 {
301 .name = "uart2_cts.uart2_cts",
302 .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
303 },
304 {
305 .name = "uart2_rts.uart2_rts",
306 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
307 },
308 {
309 .name = "uart2_tx.uart2_tx",
310 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
311 },
312 {
313 .name = "uart2_rx.uart2_rx",
314 .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
315 .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
316 .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
317 },
318};
319
320static struct omap_device_pad default_uart3_pads[] __initdata = {
321 {
322 .name = "uart3_cts_rctx.uart3_cts_rctx",
323 .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
324 },
325 {
326 .name = "uart3_rts_sd.uart3_rts_sd",
327 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
328 },
329 {
330 .name = "uart3_tx_irtx.uart3_tx_irtx",
331 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
332 },
333 {
334 .name = "uart3_rx_irrx.uart3_rx_irrx",
335 .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
336 .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0,
337 .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE0,
338 },
339};
340
341static struct omap_device_pad default_omap36xx_uart4_pads[] __initdata = {
342 {
343 .name = "gpmc_wait2.uart4_tx",
344 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
345 },
346 {
347 .name = "gpmc_wait3.uart4_rx",
348 .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
349 .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE2,
350 .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE2,
351 },
352};
353
354static struct omap_device_pad default_omap4_uart4_pads[] __initdata = {
355 {
356 .name = "uart4_tx.uart4_tx",
357 .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
358 },
359 {
360 .name = "uart4_rx.uart4_rx",
361 .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
362 .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0,
363 .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE0,
364 },
365};
366
367static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
368{
369 switch (bdata->id) {
370 case 0:
371 bdata->pads = default_uart1_pads;
372 bdata->pads_cnt = ARRAY_SIZE(default_uart1_pads);
373 break;
374 case 1:
375 bdata->pads = default_uart2_pads;
376 bdata->pads_cnt = ARRAY_SIZE(default_uart2_pads);
377 break;
378 case 2:
379 bdata->pads = default_uart3_pads;
380 bdata->pads_cnt = ARRAY_SIZE(default_uart3_pads);
381 break;
382 case 3:
383 if (cpu_is_omap44xx()) {
384 bdata->pads = default_omap4_uart4_pads;
385 bdata->pads_cnt =
386 ARRAY_SIZE(default_omap4_uart4_pads);
387 } else if (cpu_is_omap3630()) {
388 bdata->pads = default_omap36xx_uart4_pads;
389 bdata->pads_cnt =
390 ARRAY_SIZE(default_omap36xx_uart4_pads);
391 }
392 break;
393 default:
394 break;
395 }
396}
397#else
398static void omap_serial_fill_default_pads(struct omap_board_data *bdata) {}
399#endif
400
Tony Lindgren3e16f922011-02-14 15:40:20 -0800401static int __init omap_serial_early_init(void)
Tony Lindgren1dbae812005-11-10 14:26:51 +0000402{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530403 int i = 0;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000404
Kevin Hilman6f251e92010-09-27 20:19:38 +0530405 do {
406 char oh_name[MAX_UART_HWMOD_NAME_LEN];
407 struct omap_hwmod *oh;
408 struct omap_uart_state *uart;
Thomas Weber21b90342010-02-25 09:40:19 +0000409
Kevin Hilman6f251e92010-09-27 20:19:38 +0530410 snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
411 "uart%d", i + 1);
412 oh = omap_hwmod_lookup(oh_name);
413 if (!oh)
414 break;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000415
Kevin Hilman6f251e92010-09-27 20:19:38 +0530416 uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
417 if (WARN_ON(!uart))
Tony Lindgren3e16f922011-02-14 15:40:20 -0800418 return -ENODEV;
Tony Lindgren1dbae812005-11-10 14:26:51 +0000419
Kevin Hilman6f251e92010-09-27 20:19:38 +0530420 uart->oh = oh;
421 uart->num = i++;
422 list_add_tail(&uart->node, &uart_list);
423 num_uarts++;
424
Tony Lindgren84f90c92009-10-16 09:53:00 -0700425 /*
Paul Walmsley550c8092011-02-28 11:58:14 -0700426 * NOTE: omap_hwmod_setup*() has not yet been called,
Kevin Hilman6f251e92010-09-27 20:19:38 +0530427 * so no hwmod functions will work yet.
Tony Lindgren84f90c92009-10-16 09:53:00 -0700428 */
Tony Lindgren84f90c92009-10-16 09:53:00 -0700429
Kevin Hilman6f251e92010-09-27 20:19:38 +0530430 /*
431 * During UART early init, device need to be probed
432 * to determine SoC specific init before omap_device
433 * is ready. Therefore, don't allow idle here
434 */
435 uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
436 } while (1);
Tony Lindgren3e16f922011-02-14 15:40:20 -0800437
438 return 0;
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300439}
Tony Lindgren3e16f922011-02-14 15:40:20 -0800440core_initcall(omap_serial_early_init);
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300441
Mika Westerbergf62349e2009-12-11 16:16:35 -0800442/**
443 * omap_serial_init_port() - initialize single serial port
Tony Lindgren40e44392010-12-22 18:42:35 -0800444 * @bdata: port specific board data pointer
Mika Westerbergf62349e2009-12-11 16:16:35 -0800445 *
Tony Lindgren40e44392010-12-22 18:42:35 -0800446 * This function initialies serial driver for given port only.
Mika Westerbergf62349e2009-12-11 16:16:35 -0800447 * Platforms can call this function instead of omap_serial_init()
448 * if they don't plan to use all available UARTs as serial ports.
449 *
450 * Don't mix calls to omap_serial_init_port() and omap_serial_init(),
451 * use only one of the two.
452 */
Tony Lindgren40e44392010-12-22 18:42:35 -0800453void __init omap_serial_init_port(struct omap_board_data *bdata)
Mika Westerbergf62349e2009-12-11 16:16:35 -0800454{
455 struct omap_uart_state *uart;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530456 struct omap_hwmod *oh;
Kevin Hilman3528c582011-07-21 13:48:45 -0700457 struct platform_device *pdev;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530458 void *pdata = NULL;
459 u32 pdata_size = 0;
460 char *name;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530461 struct omap_uart_port_info omap_up;
Mika Westerbergf62349e2009-12-11 16:16:35 -0800462
Tony Lindgren40e44392010-12-22 18:42:35 -0800463 if (WARN_ON(!bdata))
Sergio Aguirree88d5562010-02-27 14:13:43 -0600464 return;
Tony Lindgren40e44392010-12-22 18:42:35 -0800465 if (WARN_ON(bdata->id < 0))
466 return;
467 if (WARN_ON(bdata->id >= num_uarts))
Mika Westerbergf62349e2009-12-11 16:16:35 -0800468 return;
469
Kevin Hilman6f251e92010-09-27 20:19:38 +0530470 list_for_each_entry(uart, &uart_list, node)
Tony Lindgren40e44392010-12-22 18:42:35 -0800471 if (bdata->id == uart->num)
Kevin Hilman6f251e92010-09-27 20:19:38 +0530472 break;
473
474 oh = uart->oh;
475 uart->dma_enabled = 0;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530476 name = DRIVER_NAME;
477
478 omap_up.dma_enabled = uart->dma_enabled;
479 omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
Govindraj.R273558b2011-09-13 14:01:01 +0530480 omap_up.flags = UPF_BOOT_AUTOCONF;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530481
482 pdata = &omap_up;
483 pdata_size = sizeof(struct omap_uart_port_info);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530484
485 if (WARN_ON(!oh))
486 return;
487
Kevin Hilman3528c582011-07-21 13:48:45 -0700488 pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size,
Benoit Coussonf718e2c2011-08-10 15:30:09 +0200489 NULL, 0, false);
Kevin Hilman3528c582011-07-21 13:48:45 -0700490 WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.\n",
Kevin Hilman6f251e92010-09-27 20:19:38 +0530491 name, oh->name);
492
Kevin Hilman9f8b6942011-08-01 09:33:13 -0700493 omap_device_disable_idle_on_suspend(pdev);
Tony Lindgren40e44392010-12-22 18:42:35 -0800494 oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
495
Kevin Hilman3528c582011-07-21 13:48:45 -0700496 uart->pdev = pdev;
Kevin Hilman6f251e92010-09-27 20:19:38 +0530497
498 oh->dev_attr = uart;
499
Torben Hohnac751ef2011-01-25 15:07:35 -0800500 console_lock(); /* in case the earlycon is on the UART */
Paul Walmsley0d8e2d02010-11-24 16:49:05 -0700501
Kevin Hilman6f251e92010-09-27 20:19:38 +0530502 /*
503 * Because of early UART probing, UART did not get idled
504 * on init. Now that omap_device is ready, ensure full idle
505 * before doing omap_device_enable().
506 */
507 omap_hwmod_idle(uart->oh);
508
509 omap_device_enable(uart->pdev);
510 omap_uart_idle_init(uart);
Kevin Hilman6f251e92010-09-27 20:19:38 +0530511 omap_hwmod_enable_wakeup(uart->oh);
512 omap_device_idle(uart->pdev);
513
Kevin Hilman6f251e92010-09-27 20:19:38 +0530514 omap_uart_block_sleep(uart);
Torben Hohnac751ef2011-01-25 15:07:35 -0800515 console_unlock();
Paul Walmsley0d8e2d02010-11-24 16:49:05 -0700516
Govindraj.R7496ba32011-11-07 18:55:05 +0530517 if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads) ||
518 (pdata->wk_en && pdata->wk_mask))
Kevin Hilman3528c582011-07-21 13:48:45 -0700519 device_init_wakeup(&pdev->dev, true);
Deepak K00034502010-08-02 13:18:12 +0300520
521 /* Enable the MDR1 errata for OMAP3 */
Hemant Pedanekara9203602011-12-13 10:46:44 -0800522 if (cpu_is_omap34xx() && !(cpu_is_ti81xx() || cpu_is_am33xx()))
Deepak K00034502010-08-02 13:18:12 +0300523 uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
Mika Westerbergf62349e2009-12-11 16:16:35 -0800524}
525
526/**
Uwe Kleine-Königb5950762010-11-01 15:38:34 -0400527 * omap_serial_init() - initialize all supported serial ports
Mika Westerbergf62349e2009-12-11 16:16:35 -0800528 *
529 * Initializes all available UARTs as serial ports. Platforms
530 * can call this function when they want to have default behaviour
531 * for serial ports (e.g initialize them all as serial ports).
532 */
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300533void __init omap_serial_init(void)
534{
Kevin Hilman6f251e92010-09-27 20:19:38 +0530535 struct omap_uart_state *uart;
Tony Lindgren40e44392010-12-22 18:42:35 -0800536 struct omap_board_data bdata;
Paul Walmsleyb3c6df32009-09-03 20:14:02 +0300537
Tony Lindgren40e44392010-12-22 18:42:35 -0800538 list_for_each_entry(uart, &uart_list, node) {
539 bdata.id = uart->num;
540 bdata.flags = 0;
541 bdata.pads = NULL;
542 bdata.pads_cnt = 0;
Govindraj.R7496ba32011-11-07 18:55:05 +0530543
544 if (cpu_is_omap44xx() || cpu_is_omap34xx())
545 omap_serial_fill_default_pads(&bdata);
546
Tony Lindgren40e44392010-12-22 18:42:35 -0800547 omap_serial_init_port(&bdata);
548
549 }
Tony Lindgren1dbae812005-11-10 14:26:51 +0000550}