diff options
author | Johannes Thumshirn <johannes.thumshirn@men.de> | 2015-01-19 01:44:41 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-02-02 13:11:27 -0500 |
commit | 01ba8d6af4b76aee99a8ae3a76748c8c36db49f3 (patch) | |
tree | 320426c9174014d2d23e9bef3c6fcb5bfd2020c3 /drivers/tty | |
parent | b164c9721e3ea4c08a4738cd4d0538bbb0c24419 (diff) |
tty: serial: men_z135_uart: Fix driver for changes in hardware
16z135 IP Core has changed so the driver needs to be updated to respect
these changes. The following changes have been made:
* Don't invert the 16z135 modem status register when reading.
* Add module parameter to configure the (baud rate dependent) RX timeout.
Character timeout in seconds = (timeout_reg * baud_reg * 4)/freq_reg.
* Enable the handling of UART core's automatic flow control feature.
When AFE is active disable generation of modem status IRQs.
* Rework the handling of IRQs to be conform with newer FPGA versions and
take precautions not to miss an interrupt because of the destructive read
of the IIR register.
* Correct men_z135_handle_modem_status(), MSR is stat_reg[15:8] not
stat_reg[7:0]
* Correct calling of uart_handle_{dcd,cts}_change()
* Reset CLOCAL when CRTSCTS is set
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@men.de>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/men_z135_uart.c | 155 |
1 files changed, 109 insertions, 46 deletions
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 517cd073dc08..35c55505b3eb 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #define MEN_Z135_MAX_PORTS 12 | 23 | #define MEN_Z135_MAX_PORTS 12 |
24 | #define MEN_Z135_BASECLK 29491200 | 24 | #define MEN_Z135_BASECLK 29491200 |
25 | #define MEN_Z135_FIFO_SIZE 1024 | 25 | #define MEN_Z135_FIFO_SIZE 1024 |
26 | #define MEN_Z135_NUM_MSI_VECTORS 2 | ||
27 | #define MEN_Z135_FIFO_WATERMARK 1020 | 26 | #define MEN_Z135_FIFO_WATERMARK 1020 |
28 | 27 | ||
29 | #define MEN_Z135_STAT_REG 0x0 | 28 | #define MEN_Z135_STAT_REG 0x0 |
@@ -34,12 +33,11 @@ | |||
34 | #define MEN_Z135_CONF_REG 0x808 | 33 | #define MEN_Z135_CONF_REG 0x808 |
35 | #define MEN_Z135_UART_FREQ 0x80c | 34 | #define MEN_Z135_UART_FREQ 0x80c |
36 | #define MEN_Z135_BAUD_REG 0x810 | 35 | #define MEN_Z135_BAUD_REG 0x810 |
37 | #define MENZ135_TIMEOUT 0x814 | 36 | #define MEN_Z135_TIMEOUT 0x814 |
38 | 37 | ||
39 | #define MEN_Z135_MEM_SIZE 0x818 | 38 | #define MEN_Z135_MEM_SIZE 0x818 |
40 | 39 | ||
41 | #define IS_IRQ(x) ((x) & 1) | 40 | #define IRQ_ID(x) ((x) & 0x1f) |
42 | #define IRQ_ID(x) (((x) >> 1) & 7) | ||
43 | 41 | ||
44 | #define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */ | 42 | #define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */ |
45 | #define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */ | 43 | #define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */ |
@@ -94,11 +92,11 @@ | |||
94 | #define MEN_Z135_LSR_TEXP BIT(6) | 92 | #define MEN_Z135_LSR_TEXP BIT(6) |
95 | #define MEN_Z135_LSR_RXFIFOERR BIT(7) | 93 | #define MEN_Z135_LSR_RXFIFOERR BIT(7) |
96 | 94 | ||
97 | #define MEN_Z135_IRQ_ID_MST 0 | 95 | #define MEN_Z135_IRQ_ID_RLS BIT(0) |
98 | #define MEN_Z135_IRQ_ID_TSA 1 | 96 | #define MEN_Z135_IRQ_ID_RDA BIT(1) |
99 | #define MEN_Z135_IRQ_ID_RDA 2 | 97 | #define MEN_Z135_IRQ_ID_CTI BIT(2) |
100 | #define MEN_Z135_IRQ_ID_RLS 3 | 98 | #define MEN_Z135_IRQ_ID_TSA BIT(3) |
101 | #define MEN_Z135_IRQ_ID_CTI 6 | 99 | #define MEN_Z135_IRQ_ID_MST BIT(4) |
102 | 100 | ||
103 | #define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff) | 101 | #define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff) |
104 | 102 | ||
@@ -118,12 +116,18 @@ static int align; | |||
118 | module_param(align, int, S_IRUGO); | 116 | module_param(align, int, S_IRUGO); |
119 | MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0"); | 117 | MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0"); |
120 | 118 | ||
119 | static uint rx_timeout; | ||
120 | module_param(rx_timeout, uint, S_IRUGO); | ||
121 | MODULE_PARM_DESC(rx_timeout, "RX timeout. " | ||
122 | "Timeout in seconds = (timeout_reg * baud_reg * 4) / freq_reg"); | ||
123 | |||
121 | struct men_z135_port { | 124 | struct men_z135_port { |
122 | struct uart_port port; | 125 | struct uart_port port; |
123 | struct mcb_device *mdev; | 126 | struct mcb_device *mdev; |
124 | unsigned char *rxbuf; | 127 | unsigned char *rxbuf; |
125 | u32 stat_reg; | 128 | u32 stat_reg; |
126 | spinlock_t lock; | 129 | spinlock_t lock; |
130 | bool automode; | ||
127 | }; | 131 | }; |
128 | #define to_men_z135(port) container_of((port), struct men_z135_port, port) | 132 | #define to_men_z135(port) container_of((port), struct men_z135_port, port) |
129 | 133 | ||
@@ -180,12 +184,16 @@ static inline void men_z135_reg_clr(struct men_z135_port *uart, | |||
180 | */ | 184 | */ |
181 | static void men_z135_handle_modem_status(struct men_z135_port *uart) | 185 | static void men_z135_handle_modem_status(struct men_z135_port *uart) |
182 | { | 186 | { |
183 | if (uart->stat_reg & MEN_Z135_MSR_DDCD) | 187 | u8 msr; |
188 | |||
189 | msr = (uart->stat_reg >> 8) & 0xff; | ||
190 | |||
191 | if (msr & MEN_Z135_MSR_DDCD) | ||
184 | uart_handle_dcd_change(&uart->port, | 192 | uart_handle_dcd_change(&uart->port, |
185 | uart->stat_reg & ~MEN_Z135_MSR_DCD); | 193 | msr & MEN_Z135_MSR_DCD); |
186 | if (uart->stat_reg & MEN_Z135_MSR_DCTS) | 194 | if (msr & MEN_Z135_MSR_DCTS) |
187 | uart_handle_cts_change(&uart->port, | 195 | uart_handle_cts_change(&uart->port, |
188 | uart->stat_reg & ~MEN_Z135_MSR_CTS); | 196 | msr & MEN_Z135_MSR_CTS); |
189 | } | 197 | } |
190 | 198 | ||
191 | static void men_z135_handle_lsr(struct men_z135_port *uart) | 199 | static void men_z135_handle_lsr(struct men_z135_port *uart) |
@@ -322,7 +330,8 @@ static void men_z135_handle_tx(struct men_z135_port *uart) | |||
322 | 330 | ||
323 | txfree = MEN_Z135_FIFO_WATERMARK - txc; | 331 | txfree = MEN_Z135_FIFO_WATERMARK - txc; |
324 | if (txfree <= 0) { | 332 | if (txfree <= 0) { |
325 | pr_err("Not enough room in TX FIFO have %d, need %d\n", | 333 | dev_err(&uart->mdev->dev, |
334 | "Not enough room in TX FIFO have %d, need %d\n", | ||
326 | txfree, qlen); | 335 | txfree, qlen); |
327 | goto irq_en; | 336 | goto irq_en; |
328 | } | 337 | } |
@@ -373,43 +382,54 @@ out: | |||
373 | * @irq: The IRQ number | 382 | * @irq: The IRQ number |
374 | * @data: Pointer to UART port | 383 | * @data: Pointer to UART port |
375 | * | 384 | * |
376 | * Check IIR register to see which tasklet to start. | 385 | * Check IIR register to find the cause of the interrupt and handle it. |
386 | * It is possible that multiple interrupts reason bits are set and reading | ||
387 | * the IIR is a destructive read, so we always need to check for all possible | ||
388 | * interrupts and handle them. | ||
377 | */ | 389 | */ |
378 | static irqreturn_t men_z135_intr(int irq, void *data) | 390 | static irqreturn_t men_z135_intr(int irq, void *data) |
379 | { | 391 | { |
380 | struct men_z135_port *uart = (struct men_z135_port *)data; | 392 | struct men_z135_port *uart = (struct men_z135_port *)data; |
381 | struct uart_port *port = &uart->port; | 393 | struct uart_port *port = &uart->port; |
394 | bool handled = false; | ||
395 | unsigned long flags; | ||
382 | int irq_id; | 396 | int irq_id; |
383 | 397 | ||
384 | uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); | 398 | uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); |
385 | /* IRQ pending is low active */ | ||
386 | if (IS_IRQ(uart->stat_reg)) | ||
387 | return IRQ_NONE; | ||
388 | |||
389 | irq_id = IRQ_ID(uart->stat_reg); | 399 | irq_id = IRQ_ID(uart->stat_reg); |
390 | switch (irq_id) { | 400 | |
391 | case MEN_Z135_IRQ_ID_MST: | 401 | if (!irq_id) |
392 | men_z135_handle_modem_status(uart); | 402 | goto out; |
393 | break; | 403 | |
394 | case MEN_Z135_IRQ_ID_TSA: | 404 | spin_lock_irqsave(&port->lock, flags); |
395 | men_z135_handle_tx(uart); | 405 | /* It's save to write to IIR[7:6] RXC[9:8] */ |
396 | break; | 406 | iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG); |
397 | case MEN_Z135_IRQ_ID_CTI: | 407 | |
398 | dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n"); | 408 | if (irq_id & MEN_Z135_IRQ_ID_RLS) { |
399 | /* Fallthrough */ | ||
400 | case MEN_Z135_IRQ_ID_RDA: | ||
401 | /* Reading data clears RX IRQ */ | ||
402 | men_z135_handle_rx(uart); | ||
403 | break; | ||
404 | case MEN_Z135_IRQ_ID_RLS: | ||
405 | men_z135_handle_lsr(uart); | 409 | men_z135_handle_lsr(uart); |
406 | break; | 410 | handled = true; |
407 | default: | 411 | } |
408 | dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id); | 412 | |
409 | return IRQ_NONE; | 413 | if (irq_id & (MEN_Z135_IRQ_ID_RDA | MEN_Z135_IRQ_ID_CTI)) { |
414 | if (irq_id & MEN_Z135_IRQ_ID_CTI) | ||
415 | dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n"); | ||
416 | men_z135_handle_rx(uart); | ||
417 | handled = true; | ||
418 | } | ||
419 | |||
420 | if (irq_id & MEN_Z135_IRQ_ID_TSA) { | ||
421 | men_z135_handle_tx(uart); | ||
422 | handled = true; | ||
410 | } | 423 | } |
411 | 424 | ||
412 | return IRQ_HANDLED; | 425 | if (irq_id & MEN_Z135_IRQ_ID_MST) { |
426 | men_z135_handle_modem_status(uart); | ||
427 | handled = true; | ||
428 | } | ||
429 | |||
430 | spin_unlock_irqrestore(&port->lock, flags); | ||
431 | out: | ||
432 | return IRQ_RETVAL(handled); | ||
413 | } | 433 | } |
414 | 434 | ||
415 | /** | 435 | /** |
@@ -464,21 +484,37 @@ static unsigned int men_z135_tx_empty(struct uart_port *port) | |||
464 | */ | 484 | */ |
465 | static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl) | 485 | static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl) |
466 | { | 486 | { |
467 | struct men_z135_port *uart = to_men_z135(port); | 487 | u32 old; |
468 | u32 conf_reg = 0; | 488 | u32 conf_reg; |
469 | 489 | ||
490 | conf_reg = old = ioread32(port->membase + MEN_Z135_CONF_REG); | ||
470 | if (mctrl & TIOCM_RTS) | 491 | if (mctrl & TIOCM_RTS) |
471 | conf_reg |= MEN_Z135_MCR_RTS; | 492 | conf_reg |= MEN_Z135_MCR_RTS; |
493 | else | ||
494 | conf_reg &= ~MEN_Z135_MCR_RTS; | ||
495 | |||
472 | if (mctrl & TIOCM_DTR) | 496 | if (mctrl & TIOCM_DTR) |
473 | conf_reg |= MEN_Z135_MCR_DTR; | 497 | conf_reg |= MEN_Z135_MCR_DTR; |
498 | else | ||
499 | conf_reg &= ~MEN_Z135_MCR_DTR; | ||
500 | |||
474 | if (mctrl & TIOCM_OUT1) | 501 | if (mctrl & TIOCM_OUT1) |
475 | conf_reg |= MEN_Z135_MCR_OUT1; | 502 | conf_reg |= MEN_Z135_MCR_OUT1; |
503 | else | ||
504 | conf_reg &= ~MEN_Z135_MCR_OUT1; | ||
505 | |||
476 | if (mctrl & TIOCM_OUT2) | 506 | if (mctrl & TIOCM_OUT2) |
477 | conf_reg |= MEN_Z135_MCR_OUT2; | 507 | conf_reg |= MEN_Z135_MCR_OUT2; |
508 | else | ||
509 | conf_reg &= ~MEN_Z135_MCR_OUT2; | ||
510 | |||
478 | if (mctrl & TIOCM_LOOP) | 511 | if (mctrl & TIOCM_LOOP) |
479 | conf_reg |= MEN_Z135_MCR_LOOP; | 512 | conf_reg |= MEN_Z135_MCR_LOOP; |
513 | else | ||
514 | conf_reg &= ~MEN_Z135_MCR_LOOP; | ||
480 | 515 | ||
481 | men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg); | 516 | if (conf_reg != old) |
517 | iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); | ||
482 | } | 518 | } |
483 | 519 | ||
484 | /** | 520 | /** |
@@ -490,12 +526,9 @@ static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
490 | static unsigned int men_z135_get_mctrl(struct uart_port *port) | 526 | static unsigned int men_z135_get_mctrl(struct uart_port *port) |
491 | { | 527 | { |
492 | unsigned int mctrl = 0; | 528 | unsigned int mctrl = 0; |
493 | u32 stat_reg; | ||
494 | u8 msr; | 529 | u8 msr; |
495 | 530 | ||
496 | stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); | 531 | msr = ioread8(port->membase + MEN_Z135_STAT_REG + 1); |
497 | |||
498 | msr = ~((stat_reg >> 8) & 0xff); | ||
499 | 532 | ||
500 | if (msr & MEN_Z135_MSR_CTS) | 533 | if (msr & MEN_Z135_MSR_CTS) |
501 | mctrl |= TIOCM_CTS; | 534 | mctrl |= TIOCM_CTS; |
@@ -524,6 +557,19 @@ static void men_z135_stop_tx(struct uart_port *port) | |||
524 | men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); | 557 | men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); |
525 | } | 558 | } |
526 | 559 | ||
560 | /* | ||
561 | * men_z135_disable_ms() - Disable Modem Status | ||
562 | * port: The UART port | ||
563 | * | ||
564 | * Enable Modem Status IRQ. | ||
565 | */ | ||
566 | static void men_z135_disable_ms(struct uart_port *port) | ||
567 | { | ||
568 | struct men_z135_port *uart = to_men_z135(port); | ||
569 | |||
570 | men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN); | ||
571 | } | ||
572 | |||
527 | /** | 573 | /** |
528 | * men_z135_start_tx() - Start transmitting characters | 574 | * men_z135_start_tx() - Start transmitting characters |
529 | * @port: The UART port | 575 | * @port: The UART port |
@@ -535,6 +581,9 @@ static void men_z135_start_tx(struct uart_port *port) | |||
535 | { | 581 | { |
536 | struct men_z135_port *uart = to_men_z135(port); | 582 | struct men_z135_port *uart = to_men_z135(port); |
537 | 583 | ||
584 | if (uart->automode) | ||
585 | men_z135_disable_ms(port); | ||
586 | |||
538 | men_z135_handle_tx(uart); | 587 | men_z135_handle_tx(uart); |
539 | } | 588 | } |
540 | 589 | ||
@@ -584,6 +633,9 @@ static int men_z135_startup(struct uart_port *port) | |||
584 | 633 | ||
585 | iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); | 634 | iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); |
586 | 635 | ||
636 | if (rx_timeout) | ||
637 | iowrite32(rx_timeout, port->membase + MEN_Z135_TIMEOUT); | ||
638 | |||
587 | return 0; | 639 | return 0; |
588 | } | 640 | } |
589 | 641 | ||
@@ -603,6 +655,7 @@ static void men_z135_set_termios(struct uart_port *port, | |||
603 | struct ktermios *termios, | 655 | struct ktermios *termios, |
604 | struct ktermios *old) | 656 | struct ktermios *old) |
605 | { | 657 | { |
658 | struct men_z135_port *uart = to_men_z135(port); | ||
606 | unsigned int baud; | 659 | unsigned int baud; |
607 | u32 conf_reg; | 660 | u32 conf_reg; |
608 | u32 bd_reg; | 661 | u32 bd_reg; |
@@ -643,6 +696,16 @@ static void men_z135_set_termios(struct uart_port *port, | |||
643 | } else | 696 | } else |
644 | lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT; | 697 | lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT; |
645 | 698 | ||
699 | conf_reg |= MEN_Z135_IER_MSIEN; | ||
700 | if (termios->c_cflag & CRTSCTS) { | ||
701 | conf_reg |= MEN_Z135_MCR_RCFC; | ||
702 | uart->automode = true; | ||
703 | termios->c_cflag &= ~CLOCAL; | ||
704 | } else { | ||
705 | conf_reg &= ~MEN_Z135_MCR_RCFC; | ||
706 | uart->automode = false; | ||
707 | } | ||
708 | |||
646 | termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ | 709 | termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ |
647 | 710 | ||
648 | conf_reg |= lcr << MEN_Z135_LCR_SHIFT; | 711 | conf_reg |= lcr << MEN_Z135_LCR_SHIFT; |