forked from luck/tmp_suning_uos_patched
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:
parent
87813cf30a
commit
b765743005
|
@ -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),
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue
Block a user