gpio: pca953x: Restore registers after suspend/resume cycle

It is possible that the PCA953x is powered down during suspend.
Use regmap cache to assure the registers in the PCA953x are in
line with the driver state after resume.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Marek Vasut 2018-12-12 02:40:02 +01:00 committed by Linus Walleij
parent 87813cf30a
commit b765743005

View File

@ -975,6 +975,91 @@ static int pca953x_remove(struct i2c_client *client)
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int pca953x_regcache_sync(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
int ret;
/*
* The ordering between direction and output is important,
* sync these registers first and only then sync the rest.
*/
ret = regcache_sync_region(chip->regmap, chip->regs->direction,
chip->regs->direction + NBANK(chip));
if (ret != 0) {
dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
return ret;
}
ret = regcache_sync_region(chip->regmap, chip->regs->output,
chip->regs->output + NBANK(chip));
if (ret != 0) {
dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
return ret;
}
#ifdef CONFIG_GPIO_PCA953X_IRQ
if (chip->driver_data & PCA_PCAL) {
ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH,
PCAL953X_IN_LATCH + NBANK(chip));
if (ret != 0) {
dev_err(dev, "Failed to sync INT latch registers: %d\n",
ret);
return ret;
}
ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK,
PCAL953X_INT_MASK + NBANK(chip));
if (ret != 0) {
dev_err(dev, "Failed to sync INT mask registers: %d\n",
ret);
return ret;
}
}
#endif
return 0;
}
static int pca953x_suspend(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
regcache_cache_only(chip->regmap, true);
regulator_disable(chip->regulator);
return 0;
}
static int pca953x_resume(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
int ret;
ret = regulator_enable(chip->regulator);
if (ret != 0) {
dev_err(dev, "Failed to enable regulator: %d\n", ret);
return 0;
}
regcache_cache_only(chip->regmap, false);
regcache_mark_dirty(chip->regmap);
ret = pca953x_regcache_sync(dev);
if (ret)
return ret;
ret = regcache_sync(chip->regmap);
if (ret != 0) {
dev_err(dev, "Failed to restore register map: %d\n", ret);
return ret;
}
return 0;
}
#endif
/* convenience to stop overlong match-table lines */
#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
@ -1018,9 +1103,12 @@ static const struct of_device_id pca953x_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
static SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume);
static struct i2c_driver pca953x_driver = {
.driver = {
.name = "pca953x",
.pm = &pca953x_pm_ops,
.of_match_table = pca953x_dt_ids,
.acpi_match_table = ACPI_PTR(pca953x_acpi_ids),
},