Register access must encode the channel of this multi-channel device in the lowest nibble of the register address. This is done correctly most of the time, but not when reading/writing the fifo in handle_tx/rx. It worked by fortune for channel 0, because the address happens to be 0x0, but not for any other channel. Fix this bug, and add a macro to encapsulate the address encoding, and use it everywhere. Signed-off-by: Florian Achleitner <achleitner.florian@xxxxxxxxxxx> --- drivers/tty/serial/sc16is7xx.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index d1c046d..954001c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -295,6 +295,9 @@ #define SC16IS7XX_FIFO_SIZE (64) #define SC16IS7XX_REG_SHIFT 2 +/* Build the address of a per-channel register */ +#define SC16IS7XX_LINE_REG_ADDR(reg, line) ((reg << SC16IS7XX_REG_SHIFT) | (line)) + struct sc16is7xx_devtype { char name[10]; int nr_gpio; @@ -327,8 +330,7 @@ static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val = 0; - regmap_read(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, &val); + regmap_read(s->regmap, SC16IS7XX_LINE_REG_ADDR(reg, port->line), &val); return val; } @@ -337,8 +339,7 @@ static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - regmap_write(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, val); + regmap_write(s->regmap, SC16IS7XX_LINE_REG_ADDR(reg, port->line), val); } static void sc16is7xx_port_update(struct uart_port *port, u8 reg, @@ -346,8 +347,7 @@ static void sc16is7xx_port_update(struct uart_port *port, u8 reg, { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - regmap_update_bits(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, + regmap_update_bits(s->regmap, SC16IS7XX_LINE_REG_ADDR(reg, port->line), mask, val); } @@ -496,7 +496,8 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, bytes_read = 1; } else { regcache_cache_bypass(s->regmap, true); - regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG, + regmap_raw_read(s->regmap, + SC16IS7XX_LINE_REG_ADDR(SC16IS7XX_RHR_REG, port->line), s->buf, rxlen); regcache_cache_bypass(s->regmap, false); bytes_read = rxlen; @@ -579,7 +580,9 @@ static void sc16is7xx_handle_tx(struct uart_port *port) xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); } regcache_cache_bypass(s->regmap, true); - regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send); + regmap_raw_write(s->regmap, + SC16IS7XX_LINE_REG_ADDR(SC16IS7XX_THR_REG, port->line), + s->buf, to_send); regcache_cache_bypass(s->regmap, false); } -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html