diff options
author | Stepan Moskovchenko <stepanm@codeaurora.org> | 2010-12-21 15:38:05 -0500 |
---|---|---|
committer | David Brown <davidb@codeaurora.org> | 2011-01-21 18:52:55 -0500 |
commit | ec8f29e70edceb93c021148a99a5c3889cdc1b08 (patch) | |
tree | f5089d43011477da76ba99c882d601777dbf78b6 /drivers/serial/msm_serial.c | |
parent | d41cb8c95681345ded5ef1e78d235d06d68baee2 (diff) |
serial: msm: Add support for UARTDM cores
Add support for the next-generation version of the MSM UART
to the msm_serial driver. This version of the hardware is
similar to the original version, but has some DMA
capabilities that are used in PIO mode in this driver.
Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'drivers/serial/msm_serial.c')
-rw-r--r-- | drivers/serial/msm_serial.c | 286 |
1 files changed, 247 insertions, 39 deletions
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c index 8e43a7b69e64..bfee9b4c6661 100644 --- a/drivers/serial/msm_serial.c +++ b/drivers/serial/msm_serial.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2007 Google, Inc. | 4 | * Copyright (C) 2007 Google, Inc. |
5 | * Author: Robert Love <rlove@google.com> | 5 | * Author: Robert Love <rlove@google.com> |
6 | * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | ||
6 | * | 7 | * |
7 | * This software is licensed under the terms of the GNU General Public | 8 | * This software is licensed under the terms of the GNU General Public |
8 | * License version 2, as published by the Free Software Foundation, and | 9 | * License version 2, as published by the Free Software Foundation, and |
@@ -31,6 +32,7 @@ | |||
31 | #include <linux/serial.h> | 32 | #include <linux/serial.h> |
32 | #include <linux/clk.h> | 33 | #include <linux/clk.h> |
33 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/delay.h> | ||
34 | 36 | ||
35 | #include "msm_serial.h" | 37 | #include "msm_serial.h" |
36 | 38 | ||
@@ -38,9 +40,20 @@ struct msm_port { | |||
38 | struct uart_port uart; | 40 | struct uart_port uart; |
39 | char name[16]; | 41 | char name[16]; |
40 | struct clk *clk; | 42 | struct clk *clk; |
43 | struct clk *pclk; | ||
41 | unsigned int imr; | 44 | unsigned int imr; |
45 | unsigned int *gsbi_base; | ||
46 | int is_uartdm; | ||
47 | unsigned int old_snap_state; | ||
42 | }; | 48 | }; |
43 | 49 | ||
50 | static inline void wait_for_xmitr(struct uart_port *port, int bits) | ||
51 | { | ||
52 | if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) | ||
53 | while ((msm_read(port, UART_ISR) & bits) != bits) | ||
54 | cpu_relax(); | ||
55 | } | ||
56 | |||
44 | static void msm_stop_tx(struct uart_port *port) | 57 | static void msm_stop_tx(struct uart_port *port) |
45 | { | 58 | { |
46 | struct msm_port *msm_port = UART_TO_MSM(port); | 59 | struct msm_port *msm_port = UART_TO_MSM(port); |
@@ -73,6 +86,61 @@ static void msm_enable_ms(struct uart_port *port) | |||
73 | msm_write(port, msm_port->imr, UART_IMR); | 86 | msm_write(port, msm_port->imr, UART_IMR); |
74 | } | 87 | } |
75 | 88 | ||
89 | static void handle_rx_dm(struct uart_port *port, unsigned int misr) | ||
90 | { | ||
91 | struct tty_struct *tty = port->state->port.tty; | ||
92 | unsigned int sr; | ||
93 | int count = 0; | ||
94 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
95 | |||
96 | if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { | ||
97 | port->icount.overrun++; | ||
98 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
99 | msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); | ||
100 | } | ||
101 | |||
102 | if (misr & UART_IMR_RXSTALE) { | ||
103 | count = msm_read(port, UARTDM_RX_TOTAL_SNAP) - | ||
104 | msm_port->old_snap_state; | ||
105 | msm_port->old_snap_state = 0; | ||
106 | } else { | ||
107 | count = 4 * (msm_read(port, UART_RFWR)); | ||
108 | msm_port->old_snap_state += count; | ||
109 | } | ||
110 | |||
111 | /* TODO: Precise error reporting */ | ||
112 | |||
113 | port->icount.rx += count; | ||
114 | |||
115 | while (count > 0) { | ||
116 | unsigned int c; | ||
117 | |||
118 | sr = msm_read(port, UART_SR); | ||
119 | if ((sr & UART_SR_RX_READY) == 0) { | ||
120 | msm_port->old_snap_state -= count; | ||
121 | break; | ||
122 | } | ||
123 | c = msm_read(port, UARTDM_RF); | ||
124 | if (sr & UART_SR_RX_BREAK) { | ||
125 | port->icount.brk++; | ||
126 | if (uart_handle_break(port)) | ||
127 | continue; | ||
128 | } else if (sr & UART_SR_PAR_FRAME_ERR) | ||
129 | port->icount.frame++; | ||
130 | |||
131 | /* TODO: handle sysrq */ | ||
132 | tty_insert_flip_string(tty, (char *) &c, | ||
133 | (count > 4) ? 4 : count); | ||
134 | count -= 4; | ||
135 | } | ||
136 | |||
137 | tty_flip_buffer_push(tty); | ||
138 | if (misr & (UART_IMR_RXSTALE)) | ||
139 | msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); | ||
140 | msm_write(port, 0xFFFFFF, UARTDM_DMRX); | ||
141 | msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); | ||
142 | } | ||
143 | |||
76 | static void handle_rx(struct uart_port *port) | 144 | static void handle_rx(struct uart_port *port) |
77 | { | 145 | { |
78 | struct tty_struct *tty = port->state->port.tty; | 146 | struct tty_struct *tty = port->state->port.tty; |
@@ -121,6 +189,12 @@ static void handle_rx(struct uart_port *port) | |||
121 | tty_flip_buffer_push(tty); | 189 | tty_flip_buffer_push(tty); |
122 | } | 190 | } |
123 | 191 | ||
192 | static void reset_dm_count(struct uart_port *port) | ||
193 | { | ||
194 | wait_for_xmitr(port, UART_ISR_TX_READY); | ||
195 | msm_write(port, 1, UARTDM_NCF_TX); | ||
196 | } | ||
197 | |||
124 | static void handle_tx(struct uart_port *port) | 198 | static void handle_tx(struct uart_port *port) |
125 | { | 199 | { |
126 | struct circ_buf *xmit = &port->state->xmit; | 200 | struct circ_buf *xmit = &port->state->xmit; |
@@ -128,11 +202,18 @@ static void handle_tx(struct uart_port *port) | |||
128 | int sent_tx; | 202 | int sent_tx; |
129 | 203 | ||
130 | if (port->x_char) { | 204 | if (port->x_char) { |
131 | msm_write(port, port->x_char, UART_TF); | 205 | if (msm_port->is_uartdm) |
206 | reset_dm_count(port); | ||
207 | |||
208 | msm_write(port, port->x_char, | ||
209 | msm_port->is_uartdm ? UARTDM_TF : UART_TF); | ||
132 | port->icount.tx++; | 210 | port->icount.tx++; |
133 | port->x_char = 0; | 211 | port->x_char = 0; |
134 | } | 212 | } |
135 | 213 | ||
214 | if (msm_port->is_uartdm) | ||
215 | reset_dm_count(port); | ||
216 | |||
136 | while (msm_read(port, UART_SR) & UART_SR_TX_READY) { | 217 | while (msm_read(port, UART_SR) & UART_SR_TX_READY) { |
137 | if (uart_circ_empty(xmit)) { | 218 | if (uart_circ_empty(xmit)) { |
138 | /* disable tx interrupts */ | 219 | /* disable tx interrupts */ |
@@ -140,8 +221,11 @@ static void handle_tx(struct uart_port *port) | |||
140 | msm_write(port, msm_port->imr, UART_IMR); | 221 | msm_write(port, msm_port->imr, UART_IMR); |
141 | break; | 222 | break; |
142 | } | 223 | } |
224 | msm_write(port, xmit->buf[xmit->tail], | ||
225 | msm_port->is_uartdm ? UARTDM_TF : UART_TF); | ||
143 | 226 | ||
144 | msm_write(port, xmit->buf[xmit->tail], UART_TF); | 227 | if (msm_port->is_uartdm) |
228 | reset_dm_count(port); | ||
145 | 229 | ||
146 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | 230 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
147 | port->icount.tx++; | 231 | port->icount.tx++; |
@@ -169,8 +253,12 @@ static irqreturn_t msm_irq(int irq, void *dev_id) | |||
169 | misr = msm_read(port, UART_MISR); | 253 | misr = msm_read(port, UART_MISR); |
170 | msm_write(port, 0, UART_IMR); /* disable interrupt */ | 254 | msm_write(port, 0, UART_IMR); /* disable interrupt */ |
171 | 255 | ||
172 | if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) | 256 | if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { |
173 | handle_rx(port); | 257 | if (msm_port->is_uartdm) |
258 | handle_rx_dm(port, misr); | ||
259 | else | ||
260 | handle_rx(port); | ||
261 | } | ||
174 | if (misr & UART_IMR_TXLEV) | 262 | if (misr & UART_IMR_TXLEV) |
175 | handle_tx(port); | 263 | handle_tx(port); |
176 | if (misr & UART_IMR_DELTA_CTS) | 264 | if (misr & UART_IMR_DELTA_CTS) |
@@ -192,10 +280,21 @@ static unsigned int msm_get_mctrl(struct uart_port *port) | |||
192 | return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; | 280 | return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; |
193 | } | 281 | } |
194 | 282 | ||
195 | static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) | 283 | |
284 | static void msm_reset(struct uart_port *port) | ||
196 | { | 285 | { |
197 | unsigned int mr; | 286 | /* reset everything */ |
287 | msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); | ||
288 | msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); | ||
289 | msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); | ||
290 | msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); | ||
291 | msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); | ||
292 | msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); | ||
293 | } | ||
198 | 294 | ||
295 | void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
296 | { | ||
297 | unsigned int mr; | ||
199 | mr = msm_read(port, UART_MR1); | 298 | mr = msm_read(port, UART_MR1); |
200 | 299 | ||
201 | if (!(mctrl & TIOCM_RTS)) { | 300 | if (!(mctrl & TIOCM_RTS)) { |
@@ -219,6 +318,7 @@ static void msm_break_ctl(struct uart_port *port, int break_ctl) | |||
219 | static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) | 318 | static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) |
220 | { | 319 | { |
221 | unsigned int baud_code, rxstale, watermark; | 320 | unsigned int baud_code, rxstale, watermark; |
321 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
222 | 322 | ||
223 | switch (baud) { | 323 | switch (baud) { |
224 | case 300: | 324 | case 300: |
@@ -273,6 +373,9 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) | |||
273 | break; | 373 | break; |
274 | } | 374 | } |
275 | 375 | ||
376 | if (msm_port->is_uartdm) | ||
377 | msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); | ||
378 | |||
276 | msm_write(port, baud_code, UART_CSR); | 379 | msm_write(port, baud_code, UART_CSR); |
277 | 380 | ||
278 | /* RX stale watermark */ | 381 | /* RX stale watermark */ |
@@ -288,25 +391,23 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) | |||
288 | /* set TX watermark */ | 391 | /* set TX watermark */ |
289 | msm_write(port, 10, UART_TFWR); | 392 | msm_write(port, 10, UART_TFWR); |
290 | 393 | ||
394 | if (msm_port->is_uartdm) { | ||
395 | msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); | ||
396 | msm_write(port, 0xFFFFFF, UARTDM_DMRX); | ||
397 | msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); | ||
398 | } | ||
399 | |||
291 | return baud; | 400 | return baud; |
292 | } | 401 | } |
293 | 402 | ||
294 | static void msm_reset(struct uart_port *port) | ||
295 | { | ||
296 | /* reset everything */ | ||
297 | msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); | ||
298 | msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); | ||
299 | msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); | ||
300 | msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); | ||
301 | msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); | ||
302 | msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); | ||
303 | } | ||
304 | 403 | ||
305 | static void msm_init_clock(struct uart_port *port) | 404 | static void msm_init_clock(struct uart_port *port) |
306 | { | 405 | { |
307 | struct msm_port *msm_port = UART_TO_MSM(port); | 406 | struct msm_port *msm_port = UART_TO_MSM(port); |
308 | 407 | ||
309 | clk_enable(msm_port->clk); | 408 | clk_enable(msm_port->clk); |
409 | if (!IS_ERR(msm_port->pclk)) | ||
410 | clk_enable(msm_port->pclk); | ||
310 | msm_serial_set_mnd_regs(port); | 411 | msm_serial_set_mnd_regs(port); |
311 | } | 412 | } |
312 | 413 | ||
@@ -347,15 +448,31 @@ static int msm_startup(struct uart_port *port) | |||
347 | msm_write(port, data, UART_IPR); | 448 | msm_write(port, data, UART_IPR); |
348 | } | 449 | } |
349 | 450 | ||
350 | msm_reset(port); | 451 | data = 0; |
452 | if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) { | ||
453 | msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); | ||
454 | msm_reset(port); | ||
455 | data = UART_CR_TX_ENABLE; | ||
456 | } | ||
457 | |||
458 | data |= UART_CR_RX_ENABLE; | ||
459 | msm_write(port, data, UART_CR); /* enable TX & RX */ | ||
351 | 460 | ||
352 | msm_write(port, 0x05, UART_CR); /* enable TX & RX */ | 461 | /* Make sure IPR is not 0 to start with*/ |
462 | if (msm_port->is_uartdm) | ||
463 | msm_write(port, UART_IPR_STALE_LSB, UART_IPR); | ||
353 | 464 | ||
354 | /* turn on RX and CTS interrupts */ | 465 | /* turn on RX and CTS interrupts */ |
355 | msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | | 466 | msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | |
356 | UART_IMR_CURRENT_CTS; | 467 | UART_IMR_CURRENT_CTS; |
357 | msm_write(port, msm_port->imr, UART_IMR); | ||
358 | 468 | ||
469 | if (msm_port->is_uartdm) { | ||
470 | msm_write(port, 0xFFFFFF, UARTDM_DMRX); | ||
471 | msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); | ||
472 | msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); | ||
473 | } | ||
474 | |||
475 | msm_write(port, msm_port->imr, UART_IMR); | ||
359 | return 0; | 476 | return 0; |
360 | } | 477 | } |
361 | 478 | ||
@@ -384,7 +501,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, | |||
384 | baud = msm_set_baud_rate(port, baud); | 501 | baud = msm_set_baud_rate(port, baud); |
385 | if (tty_termios_baud_rate(termios)) | 502 | if (tty_termios_baud_rate(termios)) |
386 | tty_termios_encode_baud_rate(termios, baud, baud); | 503 | tty_termios_encode_baud_rate(termios, baud, baud); |
387 | 504 | ||
388 | /* calculate parity */ | 505 | /* calculate parity */ |
389 | mr = msm_read(port, UART_MR2); | 506 | mr = msm_read(port, UART_MR2); |
390 | mr &= ~UART_MR2_PARITY_MODE; | 507 | mr &= ~UART_MR2_PARITY_MODE; |
@@ -454,48 +571,105 @@ static const char *msm_type(struct uart_port *port) | |||
454 | static void msm_release_port(struct uart_port *port) | 571 | static void msm_release_port(struct uart_port *port) |
455 | { | 572 | { |
456 | struct platform_device *pdev = to_platform_device(port->dev); | 573 | struct platform_device *pdev = to_platform_device(port->dev); |
457 | struct resource *resource; | 574 | struct msm_port *msm_port = UART_TO_MSM(port); |
575 | struct resource *uart_resource; | ||
576 | struct resource *gsbi_resource; | ||
458 | resource_size_t size; | 577 | resource_size_t size; |
459 | 578 | ||
460 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 579 | uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
461 | if (unlikely(!resource)) | 580 | if (unlikely(!uart_resource)) |
462 | return; | 581 | return; |
463 | size = resource->end - resource->start + 1; | 582 | size = resource_size(uart_resource); |
464 | 583 | ||
465 | release_mem_region(port->mapbase, size); | 584 | release_mem_region(port->mapbase, size); |
466 | iounmap(port->membase); | 585 | iounmap(port->membase); |
467 | port->membase = NULL; | 586 | port->membase = NULL; |
587 | |||
588 | if (msm_port->gsbi_base) { | ||
589 | iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base + | ||
590 | GSBI_CONTROL); | ||
591 | |||
592 | gsbi_resource = platform_get_resource_byname(pdev, | ||
593 | IORESOURCE_MEM, | ||
594 | "gsbi_resource"); | ||
595 | |||
596 | if (unlikely(!gsbi_resource)) | ||
597 | return; | ||
598 | |||
599 | size = resource_size(gsbi_resource); | ||
600 | release_mem_region(gsbi_resource->start, size); | ||
601 | iounmap(msm_port->gsbi_base); | ||
602 | msm_port->gsbi_base = NULL; | ||
603 | } | ||
468 | } | 604 | } |
469 | 605 | ||
470 | static int msm_request_port(struct uart_port *port) | 606 | static int msm_request_port(struct uart_port *port) |
471 | { | 607 | { |
608 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
472 | struct platform_device *pdev = to_platform_device(port->dev); | 609 | struct platform_device *pdev = to_platform_device(port->dev); |
473 | struct resource *resource; | 610 | struct resource *uart_resource; |
611 | struct resource *gsbi_resource; | ||
474 | resource_size_t size; | 612 | resource_size_t size; |
613 | int ret; | ||
475 | 614 | ||
476 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 615 | uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
477 | if (unlikely(!resource)) | 616 | "uart_resource"); |
617 | if (unlikely(!uart_resource)) | ||
478 | return -ENXIO; | 618 | return -ENXIO; |
479 | size = resource->end - resource->start + 1; | ||
480 | 619 | ||
481 | if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial"))) | 620 | size = resource_size(uart_resource); |
621 | |||
622 | if (!request_mem_region(port->mapbase, size, "msm_serial")) | ||
482 | return -EBUSY; | 623 | return -EBUSY; |
483 | 624 | ||
484 | port->membase = ioremap(port->mapbase, size); | 625 | port->membase = ioremap(port->mapbase, size); |
485 | if (!port->membase) { | 626 | if (!port->membase) { |
486 | release_mem_region(port->mapbase, size); | 627 | ret = -EBUSY; |
487 | return -EBUSY; | 628 | goto fail_release_port; |
629 | } | ||
630 | |||
631 | gsbi_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
632 | "gsbi_resource"); | ||
633 | /* Is this a GSBI-based port? */ | ||
634 | if (gsbi_resource) { | ||
635 | size = resource_size(gsbi_resource); | ||
636 | |||
637 | if (!request_mem_region(gsbi_resource->start, size, | ||
638 | "msm_serial")) { | ||
639 | ret = -EBUSY; | ||
640 | goto fail_release_port; | ||
641 | } | ||
642 | |||
643 | msm_port->gsbi_base = ioremap(gsbi_resource->start, size); | ||
644 | if (!msm_port->gsbi_base) { | ||
645 | ret = -EBUSY; | ||
646 | goto fail_release_gsbi; | ||
647 | } | ||
488 | } | 648 | } |
489 | 649 | ||
490 | return 0; | 650 | return 0; |
651 | |||
652 | fail_release_gsbi: | ||
653 | release_mem_region(gsbi_resource->start, size); | ||
654 | fail_release_port: | ||
655 | release_mem_region(port->mapbase, size); | ||
656 | return ret; | ||
491 | } | 657 | } |
492 | 658 | ||
493 | static void msm_config_port(struct uart_port *port, int flags) | 659 | static void msm_config_port(struct uart_port *port, int flags) |
494 | { | 660 | { |
661 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
662 | int ret; | ||
495 | if (flags & UART_CONFIG_TYPE) { | 663 | if (flags & UART_CONFIG_TYPE) { |
496 | port->type = PORT_MSM; | 664 | port->type = PORT_MSM; |
497 | msm_request_port(port); | 665 | ret = msm_request_port(port); |
666 | if (ret) | ||
667 | return; | ||
498 | } | 668 | } |
669 | |||
670 | if (msm_port->is_uartdm) | ||
671 | iowrite32(GSBI_PROTOCOL_UART, msm_port->gsbi_base + | ||
672 | GSBI_CONTROL); | ||
499 | } | 673 | } |
500 | 674 | ||
501 | static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) | 675 | static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) |
@@ -515,9 +689,13 @@ static void msm_power(struct uart_port *port, unsigned int state, | |||
515 | switch (state) { | 689 | switch (state) { |
516 | case 0: | 690 | case 0: |
517 | clk_enable(msm_port->clk); | 691 | clk_enable(msm_port->clk); |
692 | if (!IS_ERR(msm_port->pclk)) | ||
693 | clk_enable(msm_port->pclk); | ||
518 | break; | 694 | break; |
519 | case 3: | 695 | case 3: |
520 | clk_disable(msm_port->clk); | 696 | clk_disable(msm_port->clk); |
697 | if (!IS_ERR(msm_port->pclk)) | ||
698 | clk_disable(msm_port->pclk); | ||
521 | break; | 699 | break; |
522 | default: | 700 | default: |
523 | printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); | 701 | printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); |
@@ -550,7 +728,7 @@ static struct msm_port msm_uart_ports[] = { | |||
550 | .iotype = UPIO_MEM, | 728 | .iotype = UPIO_MEM, |
551 | .ops = &msm_uart_pops, | 729 | .ops = &msm_uart_pops, |
552 | .flags = UPF_BOOT_AUTOCONF, | 730 | .flags = UPF_BOOT_AUTOCONF, |
553 | .fifosize = 512, | 731 | .fifosize = 64, |
554 | .line = 0, | 732 | .line = 0, |
555 | }, | 733 | }, |
556 | }, | 734 | }, |
@@ -559,7 +737,7 @@ static struct msm_port msm_uart_ports[] = { | |||
559 | .iotype = UPIO_MEM, | 737 | .iotype = UPIO_MEM, |
560 | .ops = &msm_uart_pops, | 738 | .ops = &msm_uart_pops, |
561 | .flags = UPF_BOOT_AUTOCONF, | 739 | .flags = UPF_BOOT_AUTOCONF, |
562 | .fifosize = 512, | 740 | .fifosize = 64, |
563 | .line = 1, | 741 | .line = 1, |
564 | }, | 742 | }, |
565 | }, | 743 | }, |
@@ -585,9 +763,14 @@ static inline struct uart_port *get_port_from_line(unsigned int line) | |||
585 | 763 | ||
586 | static void msm_console_putchar(struct uart_port *port, int c) | 764 | static void msm_console_putchar(struct uart_port *port, int c) |
587 | { | 765 | { |
766 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
767 | |||
768 | if (msm_port->is_uartdm) | ||
769 | reset_dm_count(port); | ||
770 | |||
588 | while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) | 771 | while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) |
589 | ; | 772 | ; |
590 | msm_write(port, c, UART_TF); | 773 | msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); |
591 | } | 774 | } |
592 | 775 | ||
593 | static void msm_console_write(struct console *co, const char *s, | 776 | static void msm_console_write(struct console *co, const char *s, |
@@ -609,12 +792,14 @@ static void msm_console_write(struct console *co, const char *s, | |||
609 | static int __init msm_console_setup(struct console *co, char *options) | 792 | static int __init msm_console_setup(struct console *co, char *options) |
610 | { | 793 | { |
611 | struct uart_port *port; | 794 | struct uart_port *port; |
795 | struct msm_port *msm_port; | ||
612 | int baud, flow, bits, parity; | 796 | int baud, flow, bits, parity; |
613 | 797 | ||
614 | if (unlikely(co->index >= UART_NR || co->index < 0)) | 798 | if (unlikely(co->index >= UART_NR || co->index < 0)) |
615 | return -ENXIO; | 799 | return -ENXIO; |
616 | 800 | ||
617 | port = get_port_from_line(co->index); | 801 | port = get_port_from_line(co->index); |
802 | msm_port = UART_TO_MSM(port); | ||
618 | 803 | ||
619 | if (unlikely(!port->membase)) | 804 | if (unlikely(!port->membase)) |
620 | return -ENXIO; | 805 | return -ENXIO; |
@@ -638,6 +823,11 @@ static int __init msm_console_setup(struct console *co, char *options) | |||
638 | 823 | ||
639 | msm_reset(port); | 824 | msm_reset(port); |
640 | 825 | ||
826 | if (msm_port->is_uartdm) { | ||
827 | msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); | ||
828 | msm_write(port, UART_CR_TX_ENABLE, UART_CR); | ||
829 | } | ||
830 | |||
641 | printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); | 831 | printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); |
642 | 832 | ||
643 | return uart_set_options(port, co, baud, parity, bits, flow); | 833 | return uart_set_options(port, co, baud, parity, bits, flow); |
@@ -685,14 +875,32 @@ static int __init msm_serial_probe(struct platform_device *pdev) | |||
685 | port->dev = &pdev->dev; | 875 | port->dev = &pdev->dev; |
686 | msm_port = UART_TO_MSM(port); | 876 | msm_port = UART_TO_MSM(port); |
687 | 877 | ||
688 | msm_port->clk = clk_get(&pdev->dev, "uart_clk"); | 878 | if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsbi_resource")) |
689 | if (IS_ERR(msm_port->clk)) | 879 | msm_port->is_uartdm = 1; |
690 | return PTR_ERR(msm_port->clk); | 880 | else |
881 | msm_port->is_uartdm = 0; | ||
882 | |||
883 | if (msm_port->is_uartdm) { | ||
884 | msm_port->clk = clk_get(&pdev->dev, "gsbi_uart_clk"); | ||
885 | msm_port->pclk = clk_get(&pdev->dev, "gsbi_pclk"); | ||
886 | } else { | ||
887 | msm_port->clk = clk_get(&pdev->dev, "uart_clk"); | ||
888 | msm_port->pclk = ERR_PTR(-ENOENT); | ||
889 | } | ||
890 | |||
891 | if (unlikely(IS_ERR(msm_port->clk) || (IS_ERR(msm_port->pclk) && | ||
892 | msm_port->is_uartdm))) | ||
893 | return PTR_ERR(msm_port->clk); | ||
894 | |||
895 | if (msm_port->is_uartdm) | ||
896 | clk_set_rate(msm_port->clk, 7372800); | ||
897 | |||
691 | port->uartclk = clk_get_rate(msm_port->clk); | 898 | port->uartclk = clk_get_rate(msm_port->clk); |
692 | printk(KERN_INFO "uartclk = %d\n", port->uartclk); | 899 | printk(KERN_INFO "uartclk = %d\n", port->uartclk); |
693 | 900 | ||
694 | 901 | ||
695 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 902 | resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
903 | "uart_resource"); | ||
696 | if (unlikely(!resource)) | 904 | if (unlikely(!resource)) |
697 | return -ENXIO; | 905 | return -ENXIO; |
698 | port->mapbase = resource->start; | 906 | port->mapbase = resource->start; |