diff options
Diffstat (limited to 'drivers/tty')
| -rw-r--r-- | drivers/tty/serial/msm_serial.c | 286 | ||||
| -rw-r--r-- | drivers/tty/serial/msm_serial.h | 28 |
2 files changed, 269 insertions, 45 deletions
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 8e43a7b69e6..bfee9b4c666 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/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; |
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index f6ca9ca79e9..9b8dc5d0d85 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h | |||
| @@ -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 |
| @@ -54,6 +55,7 @@ | |||
| 54 | #define UART_CSR_300 0x22 | 55 | #define UART_CSR_300 0x22 |
| 55 | 56 | ||
| 56 | #define UART_TF 0x000C | 57 | #define UART_TF 0x000C |
| 58 | #define UARTDM_TF 0x0070 | ||
| 57 | 59 | ||
| 58 | #define UART_CR 0x0010 | 60 | #define UART_CR 0x0010 |
| 59 | #define UART_CR_CMD_NULL (0 << 4) | 61 | #define UART_CR_CMD_NULL (0 << 4) |
| @@ -64,14 +66,17 @@ | |||
| 64 | #define UART_CR_CMD_START_BREAK (5 << 4) | 66 | #define UART_CR_CMD_START_BREAK (5 << 4) |
| 65 | #define UART_CR_CMD_STOP_BREAK (6 << 4) | 67 | #define UART_CR_CMD_STOP_BREAK (6 << 4) |
| 66 | #define UART_CR_CMD_RESET_CTS (7 << 4) | 68 | #define UART_CR_CMD_RESET_CTS (7 << 4) |
| 69 | #define UART_CR_CMD_RESET_STALE_INT (8 << 4) | ||
| 67 | #define UART_CR_CMD_PACKET_MODE (9 << 4) | 70 | #define UART_CR_CMD_PACKET_MODE (9 << 4) |
| 68 | #define UART_CR_CMD_MODE_RESET (12 << 4) | 71 | #define UART_CR_CMD_MODE_RESET (12 << 4) |
| 69 | #define UART_CR_CMD_SET_RFR (13 << 4) | 72 | #define UART_CR_CMD_SET_RFR (13 << 4) |
| 70 | #define UART_CR_CMD_RESET_RFR (14 << 4) | 73 | #define UART_CR_CMD_RESET_RFR (14 << 4) |
| 74 | #define UART_CR_CMD_PROTECTION_EN (16 << 4) | ||
| 75 | #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) | ||
| 71 | #define UART_CR_TX_DISABLE (1 << 3) | 76 | #define UART_CR_TX_DISABLE (1 << 3) |
| 72 | #define UART_CR_TX_ENABLE (1 << 3) | 77 | #define UART_CR_TX_ENABLE (1 << 2) |
| 73 | #define UART_CR_RX_DISABLE (1 << 3) | 78 | #define UART_CR_RX_DISABLE (1 << 1) |
| 74 | #define UART_CR_RX_ENABLE (1 << 3) | 79 | #define UART_CR_RX_ENABLE (1 << 0) |
| 75 | 80 | ||
| 76 | #define UART_IMR 0x0014 | 81 | #define UART_IMR 0x0014 |
| 77 | #define UART_IMR_TXLEV (1 << 0) | 82 | #define UART_IMR_TXLEV (1 << 0) |
| @@ -110,9 +115,20 @@ | |||
| 110 | #define UART_SR_RX_FULL (1 << 1) | 115 | #define UART_SR_RX_FULL (1 << 1) |
| 111 | #define UART_SR_RX_READY (1 << 0) | 116 | #define UART_SR_RX_READY (1 << 0) |
| 112 | 117 | ||
| 113 | #define UART_RF 0x000C | 118 | #define UART_RF 0x000C |
| 114 | #define UART_MISR 0x0010 | 119 | #define UARTDM_RF 0x0070 |
| 115 | #define UART_ISR 0x0014 | 120 | #define UART_MISR 0x0010 |
| 121 | #define UART_ISR 0x0014 | ||
| 122 | #define UART_ISR_TX_READY (1 << 7) | ||
| 123 | |||
| 124 | #define GSBI_CONTROL 0x0 | ||
| 125 | #define GSBI_PROTOCOL_CODE 0x30 | ||
| 126 | #define GSBI_PROTOCOL_UART 0x40 | ||
| 127 | #define GSBI_PROTOCOL_IDLE 0x0 | ||
| 128 | |||
| 129 | #define UARTDM_DMRX 0x34 | ||
| 130 | #define UARTDM_NCF_TX 0x40 | ||
| 131 | #define UARTDM_RX_TOTAL_SNAP 0x38 | ||
| 116 | 132 | ||
| 117 | #define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) | 133 | #define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) |
| 118 | 134 | ||
