summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gong <b38343@freescale.com>2015-09-15 12:46:39 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2021-11-02 17:10:32 +0800
commitf8fe3db53da43684f74a503f4416dad6b21a0d00 (patch)
treeceada09d051157a9885b44603b308ac3086dec78
parentd753ee2fe546da9fff5f8f8ea79c3226331e9643 (diff)
MLK-11550-1: regulator: pfuze100: restore some registers after LPSR for pfuze3000
Some registers on pfuze3000 will lost after exit from LPSR, need restore them, otherwise system may reboot with below command after system enter LPSR one time: root@imx7d_all:~# echo enabled > /sys/class/tty/ttymxc0/power/wakeup root@imx7d_all:~# echo mem > /sys/power/state because LDOGCTL not recover as 1. Add 'fsl,lpsr-mode' property to this case, please add this property if your board support LPSR mode as imx7d-12x12-lpddr3-arm2 board. Signed-off-by: Robin Gong <b38343@freescale.com> Reviewed-by: Anson Huang <Anson.Huang@nxp.com> (cherry picked from commit 4aa2a2a92814433d76de1bf6ae8902e46fb87961) [ Aisheng: change dt binding part to json schema ] Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
-rw-r--r--Documentation/devicetree/bindings/regulator/pfuze100.yaml5
-rw-r--r--drivers/regulator/pfuze100-regulator.c93
2 files changed, 98 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.yaml b/Documentation/devicetree/bindings/regulator/pfuze100.yaml
index f578e72778a7..5fda194ec3cb 100644
--- a/Documentation/devicetree/bindings/regulator/pfuze100.yaml
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.yaml
@@ -56,6 +56,11 @@ properties:
IC (PMIC) on PMIC_STBY_REQ signal.
As opposite to PMIC_STBY_REQ boards can implement PMIC_ON_REQ signal.
+ fsl,lpsr-mode:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ some registers need to be saved and restored in lpsr mode for pfuze3000.
+
regulators:
type: object
description: |
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index d60d7d1b7fa2..2ce2f5ad9266 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;
@@ -830,6 +841,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);
@@ -847,10 +861,89 @@ 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 = {
.driver = {
.name = "pfuze100-regulator",
.of_match_table = pfuze_dt_ids,
+ .pm = &pfuze_pm_ops,
},
.probe = pfuze100_regulator_probe,
.remove = pfuze100_regulator_remove,