regulator: qcom_pm8008-regulator: avoid transactions after suspend

The I2C bus becomes unusable for transactions after it enters
suspend.  Ensure that such transactions are not attempted after
the qcom_pm8008-regulator devices have entered suspend.

Change-Id: Ib13bc2a4a12a79bfe9c8de51ba2dc1ea23fb39c5
Signed-off-by: David Collins <collinsd@codeaurora.org>
This commit is contained in:
David Collins 2020-05-01 18:15:50 -07:00
parent 492d9b26fb
commit 679a2d63cc

View File

@ -13,6 +13,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
@ -77,6 +78,7 @@ struct pm8008_chip {
unsigned int internal_enable_count;
bool framework_enabled;
bool aggr_enabled;
bool suspended;
};
struct regulator_data {
@ -102,6 +104,8 @@ struct pm8008_regulator {
int step_rate;
bool enable_ocp_broadcast;
bool chip_enabled;
int mode;
int uv;
};
static struct regulator_data reg_data[PM8008_MAX_LDO] = {
@ -237,6 +241,9 @@ static int pm8008_regulator_get_voltage(struct regulator_dev *rdev)
u8 vset_raw[2];
int rc;
if (pm8008_reg->chip->suspended)
return pm8008_reg->uv;
rc = pm8008_read(pm8008_reg->regmap,
LDO_VSET_LB_REG(pm8008_reg->base),
vset_raw, 2);
@ -270,6 +277,9 @@ static int pm8008_regulator_is_enabled(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
if (pm8008_reg->chip->suspended)
return pm8008_reg->chip_enabled;
return _pm8008_regulator_is_enabled(pm8008_reg);
}
@ -279,6 +289,12 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev)
int rc, rc2, current_uv, delay_us, delay_ms, retry_count = 10;
u8 reg;
if (pm8008_reg->chip->suspended) {
if (pm8008_reg->chip_enabled)
return 0;
return -EPERM;
}
current_uv = pm8008_regulator_get_voltage(rdev);
if (current_uv < 0) {
pm8008_err(pm8008_reg, "failed to get current voltage rc=%d\n",
@ -350,6 +366,12 @@ static int pm8008_regulator_disable(struct regulator_dev *rdev)
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc;
if (pm8008_reg->chip->suspended) {
if (!pm8008_reg->chip_enabled)
return 0;
return -EPERM;
}
rc = pm8008_masked_write(pm8008_reg->regmap,
LDO_ENABLE_REG(pm8008_reg->base),
ENABLE_BIT, 0);
@ -400,6 +422,7 @@ static int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg, int min_uv,
return rc;
}
pm8008_reg->uv = mv * 1000;
pm8008_debug(pm8008_reg, "VSET=[%x][%x]\n", vset_raw[1], vset_raw[0]);
return 0;
}
@ -418,6 +441,12 @@ static int pm8008_regulator_set_voltage(struct regulator_dev *rdev,
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc;
if (pm8008_reg->chip->suspended) {
if (min_uv <= pm8008_reg->uv && pm8008_reg->uv <= max_uv)
return 0;
return -EPERM;
}
rc = pm8008_write_voltage(pm8008_reg, min_uv, max_uv);
if (rc < 0)
return rc;
@ -436,6 +465,12 @@ static int pm8008_regulator_set_mode(struct regulator_dev *rdev,
int rc;
u8 val = LDO_MODE_LPM;
if (pm8008_reg->chip->suspended) {
if (mode == pm8008_reg->mode)
return 0;
return -EPERM;
}
if (mode == REGULATOR_MODE_NORMAL)
val = LDO_MODE_NPM;
else if (mode == REGULATOR_MODE_IDLE)
@ -444,8 +479,10 @@ static int pm8008_regulator_set_mode(struct regulator_dev *rdev,
rc = pm8008_masked_write(pm8008_reg->regmap,
LDO_MODE_CTL1_REG(pm8008_reg->base),
MODE_PRIMARY_MASK, val);
if (!rc)
if (!rc) {
pm8008_debug(pm8008_reg, "mode set to %d\n", val);
pm8008_reg->mode = mode;
}
return rc;
}
@ -456,6 +493,9 @@ static unsigned int pm8008_regulator_get_mode(struct regulator_dev *rdev)
int rc;
u8 reg;
if (pm8008_reg->chip->suspended)
return pm8008_reg->mode;
rc = pm8008_read(pm8008_reg->regmap,
LDO_STATUS1_REG(pm8008_reg->base), &reg, 1);
if (rc < 0) {
@ -676,6 +716,9 @@ static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg,
return rc;
}
pm8008_reg->uv = pm8008_regulator_get_voltage(pm8008_reg->rdev);
pm8008_reg->mode = pm8008_regulator_get_mode(pm8008_reg->rdev);
if (pm8008_reg->enable_ocp_broadcast) {
pm8008_reg->nb.notifier_call = pm8008_ldo_cb;
rc = devm_regulator_register_notifier(pm8008_reg->en_supply,
@ -772,6 +815,12 @@ static int pm8008_chip_enable(struct regulator_dev *rdev)
struct pm8008_chip *chip = rdev_get_drvdata(rdev);
int rc;
if (chip->suspended) {
if (chip->framework_enabled)
return 0;
return -EPERM;
}
mutex_lock(&chip->lock);
chip->framework_enabled = true;
rc = pm8008_chip_aggregate(chip);
@ -787,6 +836,12 @@ static int pm8008_chip_disable(struct regulator_dev *rdev)
struct pm8008_chip *chip = rdev_get_drvdata(rdev);
int rc;
if (chip->suspended) {
if (!chip->framework_enabled)
return 0;
return -EPERM;
}
mutex_lock(&chip->lock);
chip->framework_enabled = false;
rc = pm8008_chip_aggregate(chip);
@ -917,6 +972,7 @@ static int pm8008_chip_probe(struct platform_device *pdev)
}
}
platform_set_drvdata(pdev, chip);
pr_debug("PM8008 chip registered\n");
return 0;
}
@ -934,6 +990,26 @@ static int pm8008_chip_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pm8008_chip_suspend(struct device *dev)
{
struct pm8008_chip *chip = dev_get_drvdata(dev);
chip->suspended = true;
return 0;
}
static int pm8008_chip_resume(struct device *dev)
{
struct pm8008_chip *chip = dev_get_drvdata(dev);
chip->suspended = false;
return 0;
}
#endif
static const struct of_device_id pm8008_regulator_match_table[] = {
{
.compatible = "qcom,pm8008-regulator",
@ -956,9 +1032,14 @@ static const struct of_device_id pm8008_chip_match_table[] = {
{ },
};
static const struct dev_pm_ops pm8008_chip_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm8008_chip_suspend, pm8008_chip_resume)
};
static struct platform_driver pm8008_chip_driver = {
.driver = {
.name = "qcom,pm8008-chip",
.pm = &pm8008_chip_pm_ops,
.of_match_table = pm8008_chip_match_table,
},
.probe = pm8008_chip_probe,