Skip to content

Commit

Permalink
serial: sc16is7xx: fix bug when first setting GPIO direction
Browse files Browse the repository at this point in the history
commit 9baeea7 upstream.

When configuring a pin as an output pin with a value of logic 0, we
end up as having a value of logic 1 on the output pin. Setting a
logic 0 a second time (or more) after that will correctly output a
logic 0 on the output pin.

By default, all GPIO pins are configured as inputs. When we enter
sc16is7xx_gpio_direction_output() for the first time, we first set the
desired value in IOSTATE, and then we configure the pin as an output.
The datasheet states that writing to IOSTATE register will trigger a
transfer of the value to the I/O pin configured as output, so if the
pin is configured as an input, nothing will be transferred.

Therefore, set the direction first in IODIR, and then set the desired
value in IOSTATE.

This is what is done in NXP application note AN10587.

Fixes: dfeae61 ("serial: sc16is7xx")
Cc: stable@vger.kernel.org
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Reviewed-by: Lech Perczak <lech.perczak@camlingroup.com>
Tested-by: Lech Perczak <lech.perczak@camlingroup.com>
Link: https://lore.kernel.org/r/20230807214556.540627-6-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
hvilleneuve29 authored and gregkh committed Sep 6, 2023
1 parent 682f9b9 commit b736642
Showing 1 changed file with 10 additions and 1 deletion.
11 changes: 10 additions & 1 deletion drivers/tty/serial/sc16is7xx.c
Expand Up @@ -1345,9 +1345,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;
}
Expand Down

0 comments on commit b736642

Please sign in to comment.