diff options
Diffstat (limited to 'drivers/gpio/gpio-arizona.c')
-rw-r--r-- | drivers/gpio/gpio-arizona.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 1f91557717a6..60b3102279f3 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/mfd/arizona/core.h> @@ -41,13 +42,38 @@ static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset) { struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); struct arizona *arizona = arizona_gpio->arizona; - unsigned int val; + unsigned int reg, val; int ret; - ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val); + reg = ARIZONA_GPIO1_CTRL + offset; + ret = regmap_read(arizona->regmap, reg, &val); if (ret < 0) return ret; + /* Resume to read actual registers for input pins */ + if (!(val & ARIZONA_GPN_DIR)) { + ret = pm_runtime_get_sync(chip->parent); + if (ret < 0) { + dev_err(chip->parent, "Failed to resume: %d\n", ret); + return ret; + } + + /* Register is cached, drop it to ensure a physical read */ + ret = regcache_drop_region(arizona->regmap, reg, reg); + if (ret < 0) { + dev_err(chip->parent, "Failed to drop cache: %d\n", + ret); + return ret; + } + + ret = regmap_read(arizona->regmap, reg, &val); + if (ret < 0) + return ret; + + pm_runtime_mark_last_busy(chip->parent); + pm_runtime_put_autosuspend(chip->parent); + } + if (val & ARIZONA_GPN_LVL) return 1; else |