summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpio-arizona.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-arizona.c')
-rw-r--r--drivers/gpio/gpio-arizona.c30
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