Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: arizona: Add support for GPIOs that need to be maintained

The Arizona devices only maintain the state of output GPIOs whilst the
CODEC is active, this can cause issues if the CODEC suspends whilst
something is relying on the state of one of its GPIOs. However, in
many systems the CODEC GPIOs are used for audio related features
and thus the state of the GPIOs is unimportant whilst the CODEC is
suspended. Often keeping the CODEC resumed in such a system would
incur a power impact that is unacceptable.

Allow the user to select whether a GPIO output should keep the
CODEC resumed, by adding a flag through the second cell of the GPIO
specifier in device tree.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Charles Keepax and committed by
Linus Walleij
27a49ed1 05f479bf

+33 -2
+33 -2
drivers/gpio/gpio-arizona.c
··· 33 33 { 34 34 struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); 35 35 struct arizona *arizona = arizona_gpio->arizona; 36 + bool persistent = gpiochip_line_is_persistent(chip, offset); 37 + bool change; 38 + int ret; 36 39 37 - return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, 38 - ARIZONA_GPN_DIR, ARIZONA_GPN_DIR); 40 + ret = regmap_update_bits_check(arizona->regmap, 41 + ARIZONA_GPIO1_CTRL + offset, 42 + ARIZONA_GPN_DIR, ARIZONA_GPN_DIR, 43 + &change); 44 + if (ret < 0) 45 + return ret; 46 + 47 + if (change && persistent) { 48 + pm_runtime_mark_last_busy(chip->parent); 49 + pm_runtime_put_autosuspend(chip->parent); 50 + } 51 + 52 + return 0; 39 53 } 40 54 41 55 static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset) ··· 99 85 { 100 86 struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); 101 87 struct arizona *arizona = arizona_gpio->arizona; 88 + bool persistent = gpiochip_line_is_persistent(chip, offset); 89 + unsigned int val; 90 + int ret; 91 + 92 + ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val); 93 + if (ret < 0) 94 + return ret; 95 + 96 + if ((val & ARIZONA_GPN_DIR) && persistent) { 97 + ret = pm_runtime_get_sync(chip->parent); 98 + if (ret < 0) { 99 + dev_err(chip->parent, "Failed to resume: %d\n", ret); 100 + return ret; 101 + } 102 + } 102 103 103 104 if (value) 104 105 value = ARIZONA_GPN_LVL; ··· 186 157 arizona_gpio->gpio_chip.base = pdata->gpio_base; 187 158 else 188 159 arizona_gpio->gpio_chip.base = -1; 160 + 161 + pm_runtime_enable(&pdev->dev); 189 162 190 163 ret = devm_gpiochip_add_data(&pdev->dev, &arizona_gpio->gpio_chip, 191 164 arizona_gpio);