summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gong <b38343@freescale.com>2015-09-15 12:46:39 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:20:42 +0300
commit3f01a63791423137d209551a9a1fd86f9461f92a (patch)
tree4c9ac59bd919180000bdb3d0895d2dbaf7eefa00
parent745c477cb9c82c483380915a7505be4bb339b7c5 (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>
-rw-r--r--Documentation/devicetree/bindings/regulator/pfuze100.txt2
-rw-r--r--drivers/regulator/pfuze100-regulator.c92
2 files changed, 94 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
index 9b40db88f637..997174a46518 100644
--- a/Documentation/devicetree/bindings/regulator/pfuze100.txt
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt
@@ -3,6 +3,8 @@ PFUZE100 family of regulators
Required properties:
- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000"
- reg: I2C slave address
+- fsl,lpsr-mode: some registers need to be saved and restored in lpsr mode
+ for pfuze3000
Required child node:
- regulators: This is the list of child nodes that specify the regulator
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 86b348740fcd..813413792a28 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -35,6 +35,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
@@ -68,6 +77,8 @@ struct pfuze_chip {
int chip_id;
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;
@@ -636,14 +647,95 @@ 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;
+
return 0;
}
+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 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 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;
+}
+
+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,
};