summaryrefslogtreecommitdiff
path: root/drivers/regulator/pfuze100-regulator.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator/pfuze100-regulator.c')
-rw-r--r--drivers/regulator/pfuze100-regulator.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 44b1da7cc374..f75b64e41faa 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -24,6 +24,15 @@
#define PFUZE100_STANDBY_OFFSET 1
#define PFUZE100_MODE_OFFSET 3
#define PFUZE100_CONF_OFFSET 4
+/*
+ * below regs will lost after exit from LPSR mode(PFUZE3000), need to be saved
+ * and restored:
+ * 0x20~0x40: 33
+ * 0x66~0x71: 12
+ * 0x7f: 1
+ * total 46 registers.
+ */
+#define PFUZE100_REG_SAVED_NUM (33 + 12 + 1)
#define PFUZE100_DEVICEID 0x0
#define PFUZE100_REVID 0x3
@@ -73,6 +82,8 @@ struct pfuze_chip {
int flags;
struct regmap *regmap;
struct device *dev;
+ bool need_restore;
+ unsigned int reg_save_array[PFUZE100_REG_SAVED_NUM];
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
struct pfuze_regulator *pfuze_regulators;
@@ -858,6 +869,9 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
}
}
+ if (of_get_property(client->dev.of_node, "fsl,lpsr-mode", NULL))
+ pfuze_chip->need_restore = true;
+
if (of_property_read_bool(client->dev.of_node,
"fsl,pmic-stby-poweroff"))
return pfuze_power_off_prepare_init(pfuze_chip);
@@ -875,11 +889,90 @@ static int pfuze100_regulator_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int pfuze_reg_save_restore(struct pfuze_chip *pfuze_chip, int start,
+ int end, int index, bool save)
+{
+ int i, ret;
+
+ for (i = 0; i < end - start + 1; i++) {
+ if (save)
+ ret = regmap_read(pfuze_chip->regmap, start + i,
+ &pfuze_chip->reg_save_array[index + i]);
+ else
+ ret = regmap_write(pfuze_chip->regmap, start + i,
+ pfuze_chip->reg_save_array[index + i]);
+
+ if (ret)
+ return ret;
+ }
+
+ return index + i;
+}
+
+static int __maybe_unused pfuze_suspend(struct device *dev)
+{
+ struct pfuze_chip *pfuze_chip = i2c_get_clientdata(to_i2c_client(dev));
+ int index = 0;
+
+ if (pfuze_chip->need_restore) {
+ /* 0x20~0x40 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x20, 0x40, index, true);
+ if (index < 0)
+ goto err_ret;
+ /* 0x66~0x71 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x66, 0x71, ++index, true);
+ if (index < 0)
+ goto err_ret;
+ /* 0x7f */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x7f, 0x7f, ++index, true);
+ if (index < 0)
+ goto err_ret;
+ }
+
+ return 0;
+
+err_ret:
+ return index;
+}
+
+static int __maybe_unused pfuze_resume(struct device *dev)
+{
+ struct pfuze_chip *pfuze_chip = i2c_get_clientdata(to_i2c_client(dev));
+ int index = 0;
+
+ if (pfuze_chip->need_restore) {
+ /* 0x20~0x40 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x20, 0x40, index, false);
+ if (index < 0)
+ goto err_ret;
+ /* 0x66~0x71 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x66, 0x71, ++index, false);
+ if (index < 0)
+ goto err_ret;
+ /* 0x7f */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x7f, 0x7f, ++index, false);
+ if (index < 0)
+ goto err_ret;
+ }
+
+ return 0;
+
+err_ret:
+ return index;
+}
+#endif
+
+static const struct dev_pm_ops pfuze_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pfuze_suspend, pfuze_resume)
+};
+
static struct i2c_driver pfuze_driver = {
.id_table = pfuze_device_id,
.driver = {
.name = "pfuze100-regulator",
.of_match_table = pfuze_dt_ids,
+ .pm = &pfuze_pm_ops,
},
.probe = pfuze100_regulator_probe,
.remove = pfuze100_regulator_remove,