diff options
Diffstat (limited to 'drivers/tty/serial/sc16is7xx.c')
-rw-r--r-- | drivers/tty/serial/sc16is7xx.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index ebea4a9d8..c65f9194a 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -694,6 +694,18 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) case SC16IS7XX_IIR_RTOI_SRC: case SC16IS7XX_IIR_XOFFI_SRC: rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); + + /* + * There is a silicon bug that makes the chip report a + * time-out interrupt but no data in the FIFO. This is + * described in errata section 18.1.4. + * + * When this happens, read one byte from the FIFO to + * clear the interrupt. + */ + if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen) + rxlen = 1; + if (rxlen) sc16is7xx_handle_rx(port, rxlen, iir); break; @@ -1166,9 +1178,18 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, state |= BIT(offset); else state &= ~BIT(offset); - sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state); + + /* + * If we write IOSTATE first, and then IODIR, the output value is not + * transferred to the corresponding I/O pin. + * The datasheet states that each register bit will be transferred to + * the corresponding I/O pin programmed as output when writing to + * IOSTATE. Therefore, configure direction first with IODIR, and then + * set value after with IOSTATE. + */ sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), BIT(offset)); + sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state); return 0; } @@ -1255,6 +1276,13 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.type = PORT_SC16IS7XX; s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; + s->p[i].port.iobase = i; + /* + * Use all ones as membase to make sure uart_configure_port() in + * serial_core.c does not abort for SPI/I2C devices where the + * membase address is not applicable. + */ + s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; s->p[i].port.rs485_config = sc16is7xx_config_rs485; |