diff options
author | Robin Gong <b38343@freescale.com> | 2015-09-15 12:46:39 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:20:42 +0300 |
commit | 3f01a63791423137d209551a9a1fd86f9461f92a (patch) | |
tree | 4c9ac59bd919180000bdb3d0895d2dbaf7eefa00 | |
parent | 745c477cb9c82c483380915a7505be4bb339b7c5 (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.txt | 2 | ||||
-rw-r--r-- | drivers/regulator/pfuze100-regulator.c | 92 |
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, }; |