mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-12 00:38:55 +00:00
gpio: rcar: Optimize GPIO pin state read on R-Car Gen3
Currently, the R-Car GPIO driver treats R-Car Gen2 and R-Car Gen3 GPIO controllers the same. However, there exist small differences, like the behavior of the General Input Register (INDT): - On R-Car Gen1, R-Car Gen2, and RZ/G1, INDT only reflects the state of an input pin if the GPIO is configured for input, - On R-Car Gen3 and RZ/G2, INDT always reflects the state of the input pins. Hence to accommodate all variants, the driver does not use the INDT register to read the status of a GPIO line when configured for output, at the expense of doing 2 or 3 register reads instead of 1. Given register accesses are slow, change the .get() and .get_multiple() callbacks to always use INDT to read pin state on SoCs where this is supported. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
parent
2a84708c2f
commit
ecba1eaa79
@ -35,6 +35,7 @@ struct gpio_rcar_bank_info {
|
||||
struct gpio_rcar_info {
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
bool has_always_in;
|
||||
};
|
||||
|
||||
struct gpio_rcar_priv {
|
||||
@ -302,9 +303,11 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
|
||||
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
|
||||
u32 bit = BIT(offset);
|
||||
|
||||
/* testing on r8a7790 shows that INDT does not show correct pin state
|
||||
* when configured as output, so use OUTDT in case of output pins */
|
||||
if (gpio_rcar_read(p, INOUTSEL) & bit)
|
||||
/*
|
||||
* Before R-Car Gen3, INDT does not show correct pin state when
|
||||
* configured as output, so use OUTDT in case of output pins
|
||||
*/
|
||||
if (!p->info.has_always_in && (gpio_rcar_read(p, INOUTSEL) & bit))
|
||||
return !!(gpio_rcar_read(p, OUTDT) & bit);
|
||||
else
|
||||
return !!(gpio_rcar_read(p, INDT) & bit);
|
||||
@ -324,6 +327,11 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
if (!bankmask)
|
||||
return 0;
|
||||
|
||||
if (p->info.has_always_in) {
|
||||
bits[0] = gpio_rcar_read(p, INDT) & bankmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
outputs = gpio_rcar_read(p, INOUTSEL);
|
||||
m = outputs & bankmask;
|
||||
@ -383,11 +391,19 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
|
||||
.has_outdtsel = false,
|
||||
.has_both_edge_trigger = false,
|
||||
.has_always_in = false,
|
||||
};
|
||||
|
||||
static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
|
||||
.has_outdtsel = true,
|
||||
.has_both_edge_trigger = true,
|
||||
.has_always_in = false,
|
||||
};
|
||||
|
||||
static const struct gpio_rcar_info gpio_rcar_info_gen3 = {
|
||||
.has_outdtsel = true,
|
||||
.has_both_edge_trigger = true,
|
||||
.has_always_in = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id gpio_rcar_of_table[] = {
|
||||
@ -399,8 +415,7 @@ static const struct of_device_id gpio_rcar_of_table[] = {
|
||||
.data = &gpio_rcar_info_gen2,
|
||||
}, {
|
||||
.compatible = "renesas,rcar-gen3-gpio",
|
||||
/* Gen3 GPIO is identical to Gen2. */
|
||||
.data = &gpio_rcar_info_gen2,
|
||||
.data = &gpio_rcar_info_gen3,
|
||||
}, {
|
||||
.compatible = "renesas,gpio-rcar",
|
||||
.data = &gpio_rcar_info_gen1,
|
||||
|
Loading…
x
Reference in New Issue
Block a user