MLK-11550-1: regulator: pfuze100: restore some registers after LPSR for pfuze3000
authorRobin Gong <b38343@freescale.com>
Tue, 15 Sep 2015 04:46:39 +0000 (12:46 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:49:07 +0000 (14:49 -0500)
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>
Documentation/devicetree/bindings/regulator/pfuze100.txt
drivers/regulator/pfuze100-regulator.c

index 9b40db8..997174a 100644 (file)
@@ -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
index cb18b5c..aad7a6b 100644 (file)
 #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;
@@ -635,14 +646,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,
 };