diff options
Diffstat (limited to 'drivers/tty/serial/msm_serial.c')
-rw-r--r-- | drivers/tty/serial/msm_serial.c | 111 |
1 files changed, 58 insertions, 53 deletions
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 4b6c78331a64..d1bc6b6cbc70 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c | |||
@@ -54,6 +54,7 @@ struct msm_port { | |||
54 | unsigned int imr; | 54 | unsigned int imr; |
55 | int is_uartdm; | 55 | int is_uartdm; |
56 | unsigned int old_snap_state; | 56 | unsigned int old_snap_state; |
57 | bool break_detected; | ||
57 | }; | 58 | }; |
58 | 59 | ||
59 | static inline void wait_for_xmitr(struct uart_port *port) | 60 | static inline void wait_for_xmitr(struct uart_port *port) |
@@ -126,23 +127,38 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) | |||
126 | 127 | ||
127 | while (count > 0) { | 128 | while (count > 0) { |
128 | unsigned char buf[4]; | 129 | unsigned char buf[4]; |
130 | int sysrq, r_count, i; | ||
129 | 131 | ||
130 | sr = msm_read(port, UART_SR); | 132 | sr = msm_read(port, UART_SR); |
131 | if ((sr & UART_SR_RX_READY) == 0) { | 133 | if ((sr & UART_SR_RX_READY) == 0) { |
132 | msm_port->old_snap_state -= count; | 134 | msm_port->old_snap_state -= count; |
133 | break; | 135 | break; |
134 | } | 136 | } |
137 | |||
135 | ioread32_rep(port->membase + UARTDM_RF, buf, 1); | 138 | ioread32_rep(port->membase + UARTDM_RF, buf, 1); |
136 | if (sr & UART_SR_RX_BREAK) { | 139 | r_count = min_t(int, count, sizeof(buf)); |
137 | port->icount.brk++; | ||
138 | if (uart_handle_break(port)) | ||
139 | continue; | ||
140 | } else if (sr & UART_SR_PAR_FRAME_ERR) | ||
141 | port->icount.frame++; | ||
142 | 140 | ||
143 | /* TODO: handle sysrq */ | 141 | for (i = 0; i < r_count; i++) { |
144 | tty_insert_flip_string(tport, buf, min(count, 4)); | 142 | char flag = TTY_NORMAL; |
145 | count -= 4; | 143 | |
144 | if (msm_port->break_detected && buf[i] == 0) { | ||
145 | port->icount.brk++; | ||
146 | flag = TTY_BREAK; | ||
147 | msm_port->break_detected = false; | ||
148 | if (uart_handle_break(port)) | ||
149 | continue; | ||
150 | } | ||
151 | |||
152 | if (!(port->read_status_mask & UART_SR_RX_BREAK)) | ||
153 | flag = TTY_NORMAL; | ||
154 | |||
155 | spin_unlock(&port->lock); | ||
156 | sysrq = uart_handle_sysrq_char(port, buf[i]); | ||
157 | spin_lock(&port->lock); | ||
158 | if (!sysrq) | ||
159 | tty_insert_flip_char(tport, buf[i], flag); | ||
160 | } | ||
161 | count -= r_count; | ||
146 | } | 162 | } |
147 | 163 | ||
148 | spin_unlock(&port->lock); | 164 | spin_unlock(&port->lock); |
@@ -174,6 +190,7 @@ static void handle_rx(struct uart_port *port) | |||
174 | while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { | 190 | while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { |
175 | unsigned int c; | 191 | unsigned int c; |
176 | char flag = TTY_NORMAL; | 192 | char flag = TTY_NORMAL; |
193 | int sysrq; | ||
177 | 194 | ||
178 | c = msm_read(port, UART_RF); | 195 | c = msm_read(port, UART_RF); |
179 | 196 | ||
@@ -195,7 +212,10 @@ static void handle_rx(struct uart_port *port) | |||
195 | else if (sr & UART_SR_PAR_FRAME_ERR) | 212 | else if (sr & UART_SR_PAR_FRAME_ERR) |
196 | flag = TTY_FRAME; | 213 | flag = TTY_FRAME; |
197 | 214 | ||
198 | if (!uart_handle_sysrq_char(port, c)) | 215 | spin_unlock(&port->lock); |
216 | sysrq = uart_handle_sysrq_char(port, c); | ||
217 | spin_lock(&port->lock); | ||
218 | if (!sysrq) | ||
199 | tty_insert_flip_char(tport, c, flag); | 219 | tty_insert_flip_char(tport, c, flag); |
200 | } | 220 | } |
201 | 221 | ||
@@ -287,6 +307,11 @@ static irqreturn_t msm_irq(int irq, void *dev_id) | |||
287 | misr = msm_read(port, UART_MISR); | 307 | misr = msm_read(port, UART_MISR); |
288 | msm_write(port, 0, UART_IMR); /* disable interrupt */ | 308 | msm_write(port, 0, UART_IMR); /* disable interrupt */ |
289 | 309 | ||
310 | if (misr & UART_IMR_RXBREAK_START) { | ||
311 | msm_port->break_detected = true; | ||
312 | msm_write(port, UART_CR_CMD_RESET_RXBREAK_START, UART_CR); | ||
313 | } | ||
314 | |||
290 | if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { | 315 | if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { |
291 | if (msm_port->is_uartdm) | 316 | if (msm_port->is_uartdm) |
292 | handle_rx_dm(port, misr); | 317 | handle_rx_dm(port, misr); |
@@ -402,9 +427,6 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) | |||
402 | 427 | ||
403 | entry = msm_find_best_baud(port, baud); | 428 | entry = msm_find_best_baud(port, baud); |
404 | 429 | ||
405 | if (msm_port->is_uartdm) | ||
406 | msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); | ||
407 | |||
408 | msm_write(port, entry->code, UART_CSR); | 430 | msm_write(port, entry->code, UART_CSR); |
409 | 431 | ||
410 | /* RX stale watermark */ | 432 | /* RX stale watermark */ |
@@ -421,6 +443,18 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) | |||
421 | /* set TX watermark */ | 443 | /* set TX watermark */ |
422 | msm_write(port, 10, UART_TFWR); | 444 | msm_write(port, 10, UART_TFWR); |
423 | 445 | ||
446 | msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); | ||
447 | msm_reset(port); | ||
448 | |||
449 | /* Enable RX and TX */ | ||
450 | msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR); | ||
451 | |||
452 | /* turn on RX and CTS interrupts */ | ||
453 | msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | | ||
454 | UART_IMR_CURRENT_CTS | UART_IMR_RXBREAK_START; | ||
455 | |||
456 | msm_write(port, msm_port->imr, UART_IMR); | ||
457 | |||
424 | if (msm_port->is_uartdm) { | 458 | if (msm_port->is_uartdm) { |
425 | msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); | 459 | msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); |
426 | msm_write(port, 0xFFFFFF, UARTDM_DMRX); | 460 | msm_write(port, 0xFFFFFF, UARTDM_DMRX); |
@@ -467,40 +501,6 @@ static int msm_startup(struct uart_port *port) | |||
467 | data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); | 501 | data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); |
468 | data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; | 502 | data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; |
469 | msm_write(port, data, UART_MR1); | 503 | msm_write(port, data, UART_MR1); |
470 | |||
471 | /* make sure that RXSTALE count is non-zero */ | ||
472 | data = msm_read(port, UART_IPR); | ||
473 | if (unlikely(!data)) { | ||
474 | data |= UART_IPR_RXSTALE_LAST; | ||
475 | data |= UART_IPR_STALE_LSB; | ||
476 | msm_write(port, data, UART_IPR); | ||
477 | } | ||
478 | |||
479 | data = 0; | ||
480 | if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) { | ||
481 | msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); | ||
482 | msm_reset(port); | ||
483 | data = UART_CR_TX_ENABLE; | ||
484 | } | ||
485 | |||
486 | data |= UART_CR_RX_ENABLE; | ||
487 | msm_write(port, data, UART_CR); /* enable TX & RX */ | ||
488 | |||
489 | /* Make sure IPR is not 0 to start with*/ | ||
490 | if (msm_port->is_uartdm) | ||
491 | msm_write(port, UART_IPR_STALE_LSB, UART_IPR); | ||
492 | |||
493 | /* turn on RX and CTS interrupts */ | ||
494 | msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | | ||
495 | UART_IMR_CURRENT_CTS; | ||
496 | |||
497 | if (msm_port->is_uartdm) { | ||
498 | msm_write(port, 0xFFFFFF, UARTDM_DMRX); | ||
499 | msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); | ||
500 | msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); | ||
501 | } | ||
502 | |||
503 | msm_write(port, msm_port->imr, UART_IMR); | ||
504 | return 0; | 504 | return 0; |
505 | } | 505 | } |
506 | 506 | ||
@@ -1044,17 +1044,22 @@ static int msm_serial_probe(struct platform_device *pdev) | |||
1044 | struct resource *resource; | 1044 | struct resource *resource; |
1045 | struct uart_port *port; | 1045 | struct uart_port *port; |
1046 | const struct of_device_id *id; | 1046 | const struct of_device_id *id; |
1047 | int irq; | 1047 | int irq, line; |
1048 | |||
1049 | if (pdev->dev.of_node) | ||
1050 | line = of_alias_get_id(pdev->dev.of_node, "serial"); | ||
1051 | else | ||
1052 | line = pdev->id; | ||
1048 | 1053 | ||
1049 | if (pdev->id == -1) | 1054 | if (line < 0) |
1050 | pdev->id = atomic_inc_return(&msm_uart_next_id) - 1; | 1055 | line = atomic_inc_return(&msm_uart_next_id) - 1; |
1051 | 1056 | ||
1052 | if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) | 1057 | if (unlikely(line < 0 || line >= UART_NR)) |
1053 | return -ENXIO; | 1058 | return -ENXIO; |
1054 | 1059 | ||
1055 | dev_info(&pdev->dev, "msm_serial: detected port #%d\n", pdev->id); | 1060 | dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line); |
1056 | 1061 | ||
1057 | port = get_port_from_line(pdev->id); | 1062 | port = get_port_from_line(line); |
1058 | port->dev = &pdev->dev; | 1063 | port->dev = &pdev->dev; |
1059 | msm_port = UART_TO_MSM(port); | 1064 | msm_port = UART_TO_MSM(port); |
1060 | 1065 | ||