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:
Haibo Chen 2025-02-24 15:00:12 +08:00 committed by Jason Liu
parent 6f6bc10c9c
commit 6cfe169543

View File

@ -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;