diff options
-rw-r--r-- | drivers/serial/amba-pl011.c | 61 | ||||
-rw-r--r-- | include/linux/amba/serial.h | 2 |
2 files changed, 52 insertions, 11 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index eb4cb480b93e..5644cf2385bb 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -69,9 +69,11 @@ | |||
69 | struct uart_amba_port { | 69 | struct uart_amba_port { |
70 | struct uart_port port; | 70 | struct uart_port port; |
71 | struct clk *clk; | 71 | struct clk *clk; |
72 | unsigned int im; /* interrupt mask */ | 72 | unsigned int im; /* interrupt mask */ |
73 | unsigned int old_status; | 73 | unsigned int old_status; |
74 | unsigned int ifls; /* vendor-specific */ | 74 | unsigned int ifls; /* vendor-specific */ |
75 | unsigned int lcrh_tx; /* vendor-specific */ | ||
76 | unsigned int lcrh_rx; /* vendor-specific */ | ||
75 | bool autorts; | 77 | bool autorts; |
76 | }; | 78 | }; |
77 | 79 | ||
@@ -79,16 +81,22 @@ struct uart_amba_port { | |||
79 | struct vendor_data { | 81 | struct vendor_data { |
80 | unsigned int ifls; | 82 | unsigned int ifls; |
81 | unsigned int fifosize; | 83 | unsigned int fifosize; |
84 | unsigned int lcrh_tx; | ||
85 | unsigned int lcrh_rx; | ||
82 | }; | 86 | }; |
83 | 87 | ||
84 | static struct vendor_data vendor_arm = { | 88 | static struct vendor_data vendor_arm = { |
85 | .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, | 89 | .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, |
86 | .fifosize = 16, | 90 | .fifosize = 16, |
91 | .lcrh_tx = UART011_LCRH, | ||
92 | .lcrh_rx = UART011_LCRH, | ||
87 | }; | 93 | }; |
88 | 94 | ||
89 | static struct vendor_data vendor_st = { | 95 | static struct vendor_data vendor_st = { |
90 | .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, | 96 | .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, |
91 | .fifosize = 64, | 97 | .fifosize = 64, |
98 | .lcrh_tx = ST_UART011_LCRH_TX, | ||
99 | .lcrh_rx = ST_UART011_LCRH_RX, | ||
92 | }; | 100 | }; |
93 | 101 | ||
94 | static void pl011_stop_tx(struct uart_port *port) | 102 | static void pl011_stop_tx(struct uart_port *port) |
@@ -327,12 +335,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) | |||
327 | unsigned int lcr_h; | 335 | unsigned int lcr_h; |
328 | 336 | ||
329 | spin_lock_irqsave(&uap->port.lock, flags); | 337 | spin_lock_irqsave(&uap->port.lock, flags); |
330 | lcr_h = readw(uap->port.membase + UART011_LCRH); | 338 | lcr_h = readw(uap->port.membase + uap->lcrh_tx); |
331 | if (break_state == -1) | 339 | if (break_state == -1) |
332 | lcr_h |= UART01x_LCRH_BRK; | 340 | lcr_h |= UART01x_LCRH_BRK; |
333 | else | 341 | else |
334 | lcr_h &= ~UART01x_LCRH_BRK; | 342 | lcr_h &= ~UART01x_LCRH_BRK; |
335 | writew(lcr_h, uap->port.membase + UART011_LCRH); | 343 | writew(lcr_h, uap->port.membase + uap->lcrh_tx); |
336 | spin_unlock_irqrestore(&uap->port.lock, flags); | 344 | spin_unlock_irqrestore(&uap->port.lock, flags); |
337 | } | 345 | } |
338 | 346 | ||
@@ -393,7 +401,17 @@ static int pl011_startup(struct uart_port *port) | |||
393 | writew(cr, uap->port.membase + UART011_CR); | 401 | writew(cr, uap->port.membase + UART011_CR); |
394 | writew(0, uap->port.membase + UART011_FBRD); | 402 | writew(0, uap->port.membase + UART011_FBRD); |
395 | writew(1, uap->port.membase + UART011_IBRD); | 403 | writew(1, uap->port.membase + UART011_IBRD); |
396 | writew(0, uap->port.membase + UART011_LCRH); | 404 | writew(0, uap->port.membase + uap->lcrh_rx); |
405 | if (uap->lcrh_tx != uap->lcrh_rx) { | ||
406 | int i; | ||
407 | /* | ||
408 | * Wait 10 PCLKs before writing LCRH_TX register, | ||
409 | * to get this delay write read only register 10 times | ||
410 | */ | ||
411 | for (i = 0; i < 10; ++i) | ||
412 | writew(0xff, uap->port.membase + UART011_MIS); | ||
413 | writew(0, uap->port.membase + uap->lcrh_tx); | ||
414 | } | ||
397 | writew(0, uap->port.membase + UART01x_DR); | 415 | writew(0, uap->port.membase + UART01x_DR); |
398 | while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) | 416 | while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) |
399 | barrier(); | 417 | barrier(); |
@@ -422,10 +440,19 @@ static int pl011_startup(struct uart_port *port) | |||
422 | return retval; | 440 | return retval; |
423 | } | 441 | } |
424 | 442 | ||
443 | static void pl011_shutdown_channel(struct uart_amba_port *uap, | ||
444 | unsigned int lcrh) | ||
445 | { | ||
446 | unsigned long val; | ||
447 | |||
448 | val = readw(uap->port.membase + lcrh); | ||
449 | val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); | ||
450 | writew(val, uap->port.membase + lcrh); | ||
451 | } | ||
452 | |||
425 | static void pl011_shutdown(struct uart_port *port) | 453 | static void pl011_shutdown(struct uart_port *port) |
426 | { | 454 | { |
427 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 455 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
428 | unsigned long val; | ||
429 | 456 | ||
430 | /* | 457 | /* |
431 | * disable all interrupts | 458 | * disable all interrupts |
@@ -450,9 +477,9 @@ static void pl011_shutdown(struct uart_port *port) | |||
450 | /* | 477 | /* |
451 | * disable break condition and fifos | 478 | * disable break condition and fifos |
452 | */ | 479 | */ |
453 | val = readw(uap->port.membase + UART011_LCRH); | 480 | pl011_shutdown_channel(uap, uap->lcrh_rx); |
454 | val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); | 481 | if (uap->lcrh_rx != uap->lcrh_tx) |
455 | writew(val, uap->port.membase + UART011_LCRH); | 482 | pl011_shutdown_channel(uap, uap->lcrh_tx); |
456 | 483 | ||
457 | /* | 484 | /* |
458 | * Shut down the clock producer | 485 | * Shut down the clock producer |
@@ -561,7 +588,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
561 | * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L | 588 | * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L |
562 | * ----------^----------^----------^----------^----- | 589 | * ----------^----------^----------^----------^----- |
563 | */ | 590 | */ |
564 | writew(lcr_h, port->membase + UART011_LCRH); | 591 | writew(lcr_h, port->membase + uap->lcrh_rx); |
592 | if (uap->lcrh_rx != uap->lcrh_tx) { | ||
593 | int i; | ||
594 | /* | ||
595 | * Wait 10 PCLKs before writing LCRH_TX register, | ||
596 | * to get this delay write read only register 10 times | ||
597 | */ | ||
598 | for (i = 0; i < 10; ++i) | ||
599 | writew(0xff, uap->port.membase + UART011_MIS); | ||
600 | writew(lcr_h, port->membase + uap->lcrh_tx); | ||
601 | } | ||
565 | writew(old_cr, port->membase + UART011_CR); | 602 | writew(old_cr, port->membase + UART011_CR); |
566 | 603 | ||
567 | spin_unlock_irqrestore(&port->lock, flags); | 604 | spin_unlock_irqrestore(&port->lock, flags); |
@@ -688,7 +725,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, | |||
688 | if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { | 725 | if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { |
689 | unsigned int lcr_h, ibrd, fbrd; | 726 | unsigned int lcr_h, ibrd, fbrd; |
690 | 727 | ||
691 | lcr_h = readw(uap->port.membase + UART011_LCRH); | 728 | lcr_h = readw(uap->port.membase + uap->lcrh_tx); |
692 | 729 | ||
693 | *parity = 'n'; | 730 | *parity = 'n'; |
694 | if (lcr_h & UART01x_LCRH_PEN) { | 731 | if (lcr_h & UART01x_LCRH_PEN) { |
@@ -800,6 +837,8 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) | |||
800 | } | 837 | } |
801 | 838 | ||
802 | uap->ifls = vendor->ifls; | 839 | uap->ifls = vendor->ifls; |
840 | uap->lcrh_rx = vendor->lcrh_rx; | ||
841 | uap->lcrh_tx = vendor->lcrh_tx; | ||
803 | uap->port.dev = &dev->dev; | 842 | uap->port.dev = &dev->dev; |
804 | uap->port.mapbase = dev->res.start; | 843 | uap->port.mapbase = dev->res.start; |
805 | uap->port.membase = base; | 844 | uap->port.membase = base; |
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 5a5a7fd62490..93c96a66c518 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h | |||
@@ -38,10 +38,12 @@ | |||
38 | #define UART01x_FR 0x18 /* Flag register (Read only). */ | 38 | #define UART01x_FR 0x18 /* Flag register (Read only). */ |
39 | #define UART010_IIR 0x1C /* Interrupt indentification register (Read). */ | 39 | #define UART010_IIR 0x1C /* Interrupt indentification register (Read). */ |
40 | #define UART010_ICR 0x1C /* Interrupt clear register (Write). */ | 40 | #define UART010_ICR 0x1C /* Interrupt clear register (Write). */ |
41 | #define ST_UART011_LCRH_RX 0x1C /* Rx line control register. */ | ||
41 | #define UART01x_ILPR 0x20 /* IrDA low power counter register. */ | 42 | #define UART01x_ILPR 0x20 /* IrDA low power counter register. */ |
42 | #define UART011_IBRD 0x24 /* Integer baud rate divisor register. */ | 43 | #define UART011_IBRD 0x24 /* Integer baud rate divisor register. */ |
43 | #define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */ | 44 | #define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */ |
44 | #define UART011_LCRH 0x2c /* Line control register. */ | 45 | #define UART011_LCRH 0x2c /* Line control register. */ |
46 | #define ST_UART011_LCRH_TX 0x2c /* Tx Line control register. */ | ||
45 | #define UART011_CR 0x30 /* Control register. */ | 47 | #define UART011_CR 0x30 /* Control register. */ |
46 | #define UART011_IFLS 0x34 /* Interrupt fifo level select. */ | 48 | #define UART011_IFLS 0x34 /* Interrupt fifo level select. */ |
47 | #define UART011_IMSC 0x38 /* Interrupt mask. */ | 49 | #define UART011_IMSC 0x38 /* Interrupt mask. */ |