mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-10-22 23:23:03 +02:00
LF-14048 gpio: pca953x: do not enable regmap cache when there is no regulator
Regmap cache mechanism is enabled in default. Thus, IO expander wouldn't handle GPIO set really before resuming back. But there are cases need to toggle gpio in NO_IRQ stage. e.g. To align with PCIe specification, PERST# signal connected on the IO expander must be toggled during PCIe RC's NO_IRQ_RESUME. Do not enable the regmap cache when IO expander doesn't have the regulator during system PM. That means the power of IO expander would be kept on, and the GPIOs of the IO expander can be toggled really during system PM. Signed-off-by: Haibo Chen <haibo.chen@nxp.com> Reviewed-by: Richard Zhu <hongxing.zhu@nxp.com> Tested-by: Sherry Sun <sherry.sun@nxp.com> Acked-by: Jason Liu <jason.hui.liu@nxp.com>
This commit is contained in:
parent
6f6bc10c9c
commit
6cfe169543
|
@ -1097,16 +1097,20 @@ static int pca953x_probe(struct i2c_client *client)
|
|||
if (!chip->driver_data)
|
||||
return -ENODEV;
|
||||
|
||||
reg = devm_regulator_get(&client->dev, "vcc");
|
||||
if (IS_ERR(reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(reg), "reg get err\n");
|
||||
|
||||
ret = regulator_enable(reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "reg en err: %d\n", ret);
|
||||
return ret;
|
||||
reg = devm_regulator_get_optional(&client->dev, "vcc");
|
||||
if (IS_ERR(reg)) {
|
||||
if (PTR_ERR(reg) == -ENODEV)
|
||||
chip->regulator = NULL;
|
||||
else
|
||||
return dev_err_probe(&client->dev, PTR_ERR(reg), "reg get err\n");
|
||||
} else {
|
||||
ret = regulator_enable(reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "reg en err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
chip->regulator = reg;
|
||||
}
|
||||
chip->regulator = reg;
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
|
@ -1191,7 +1195,8 @@ static int pca953x_probe(struct i2c_client *client)
|
|||
return 0;
|
||||
|
||||
err_exit:
|
||||
regulator_disable(chip->regulator);
|
||||
if (chip->regulator)
|
||||
regulator_disable(chip->regulator);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1205,7 +1210,8 @@ static void pca953x_remove(struct i2c_client *client)
|
|||
chip->gpio_chip.ngpio, pdata->context);
|
||||
}
|
||||
|
||||
regulator_disable(chip->regulator);
|
||||
if (chip->regulator)
|
||||
regulator_disable(chip->regulator);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -1262,13 +1268,23 @@ static int pca953x_suspend(struct device *dev)
|
|||
{
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
regcache_cache_only(chip->regmap, true);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
/*
|
||||
* Only enable cache when regulator exist, if no
|
||||
* regulator, power keeps on, can also handle
|
||||
* gpio related operation.
|
||||
* e.g. PCIe RC needs to toggle the RST pin in
|
||||
* NOIRQ resume stage, so can't open regmap
|
||||
* cache if there is no regulator.
|
||||
*/
|
||||
if (chip->regulator) {
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
regcache_cache_only(chip->regmap, true);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
}
|
||||
|
||||
if (atomic_read(&chip->wakeup_path))
|
||||
device_set_wakeup_path(dev);
|
||||
else
|
||||
else if (chip->regulator)
|
||||
regulator_disable(chip->regulator);
|
||||
|
||||
return 0;
|
||||
|
@ -1279,7 +1295,7 @@ static int pca953x_resume(struct device *dev)
|
|||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (!atomic_read(&chip->wakeup_path)) {
|
||||
if (!atomic_read(&chip->wakeup_path) && chip->regulator) {
|
||||
ret = regulator_enable(chip->regulator);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator: %d\n", ret);
|
||||
|
@ -1287,20 +1303,22 @@ static int pca953x_resume(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
regcache_cache_only(chip->regmap, false);
|
||||
regcache_mark_dirty(chip->regmap);
|
||||
ret = pca953x_regcache_sync(dev);
|
||||
if (ret) {
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
return ret;
|
||||
}
|
||||
if (chip->regulator) {
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
regcache_cache_only(chip->regmap, false);
|
||||
regcache_mark_dirty(chip->regmap);
|
||||
ret = pca953x_regcache_sync(dev);
|
||||
if (ret) {
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regcache_sync(chip->regmap);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to restore register map: %d\n", ret);
|
||||
return ret;
|
||||
ret = regcache_sync(chip->regmap);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to restore register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue
Block a user