diff options
| author | Thomas Richard (TI.com) <thomas.richard@bootlin.com> | 2025-10-13 15:04:44 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-11-26 15:09:30 +0100 |
| commit | 4863cb2b0f505c77f7b4632246d4de4859b86ed2 (patch) | |
| tree | 098bd25c5fdb7ba6e15121bec4a9cc909e89ce54 | |
| parent | f0fdaa4ad55b7c6e46a5ccb9102bc9a96cad360f (diff) | |
mux: mmio: Add suspend and resume support
The status of each mux is read during suspend and stored in the private
memory of the mux_chip.
Then the state is restored during the resume.
Reviewed-by: Andrew Davis <afd@ti.com>
Signed-off-by: Thomas Richard (TI.com) <thomas.richard@bootlin.com>
Link: https://patch.msgid.link/20251013-mux-mmio-resume-support-v5-1-de9467ceb2b2@bootlin.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/mux/mmio.c | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c index 9993ce38a818..e4ddb1e61923 100644 --- a/drivers/mux/mmio.c +++ b/drivers/mux/mmio.c @@ -15,11 +15,25 @@ #include <linux/property.h> #include <linux/regmap.h> +struct mux_mmio { + struct regmap_field **fields; + unsigned int *hardware_states; +}; + +static int mux_mmio_get(struct mux_control *mux, int *state) +{ + struct mux_mmio *mux_mmio = mux_chip_priv(mux->chip); + unsigned int index = mux_control_get_index(mux); + + return regmap_field_read(mux_mmio->fields[index], state); +} + static int mux_mmio_set(struct mux_control *mux, int state) { - struct regmap_field **fields = mux_chip_priv(mux->chip); + struct mux_mmio *mux_mmio = mux_chip_priv(mux->chip); + unsigned int index = mux_control_get_index(mux); - return regmap_field_write(fields[mux_control_get_index(mux)], state); + return regmap_field_write(mux_mmio->fields[index], state); } static const struct mux_control_ops mux_mmio_ops = { @@ -43,8 +57,8 @@ static int mux_mmio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct regmap_field **fields; struct mux_chip *mux_chip; + struct mux_mmio *mux_mmio; struct regmap *regmap; void __iomem *base; int num_fields; @@ -80,12 +94,20 @@ static int mux_mmio_probe(struct platform_device *pdev) } num_fields = ret / 2; - mux_chip = devm_mux_chip_alloc(dev, num_fields, num_fields * - sizeof(*fields)); + mux_chip = devm_mux_chip_alloc(dev, num_fields, sizeof(struct mux_mmio)); if (IS_ERR(mux_chip)) return PTR_ERR(mux_chip); - fields = mux_chip_priv(mux_chip); + mux_mmio = mux_chip_priv(mux_chip); + + mux_mmio->fields = devm_kmalloc(dev, num_fields * sizeof(*mux_mmio->fields), GFP_KERNEL); + if (IS_ERR(mux_mmio->fields)) + return PTR_ERR(mux_mmio->fields); + + mux_mmio->hardware_states = devm_kmalloc(dev, num_fields * + sizeof(*mux_mmio->hardware_states), GFP_KERNEL); + if (IS_ERR(mux_mmio->hardware_states)) + return PTR_ERR(mux_mmio->hardware_states); for (i = 0; i < num_fields; i++) { struct mux_control *mux = &mux_chip->mux[i]; @@ -115,9 +137,9 @@ static int mux_mmio_probe(struct platform_device *pdev) return -EINVAL; } - fields[i] = devm_regmap_field_alloc(dev, regmap, field); - if (IS_ERR(fields[i])) { - ret = PTR_ERR(fields[i]); + mux_mmio->fields[i] = devm_regmap_field_alloc(dev, regmap, field); + if (IS_ERR(mux_mmio->fields[i])) { + ret = PTR_ERR(mux_mmio->fields[i]); dev_err(dev, "bitfield %d: failed to allocate: %d\n", i, ret); return ret; @@ -141,13 +163,55 @@ static int mux_mmio_probe(struct platform_device *pdev) mux_chip->ops = &mux_mmio_ops; + dev_set_drvdata(dev, mux_chip); + return devm_mux_chip_register(dev, mux_chip); } +static int mux_mmio_suspend_noirq(struct device *dev) +{ + struct mux_chip *mux_chip = dev_get_drvdata(dev); + struct mux_mmio *mux_mmio = mux_chip_priv(mux_chip); + unsigned int state; + int ret, i; + + for (i = 0; i < mux_chip->controllers; i++) { + ret = mux_mmio_get(&mux_chip->mux[i], &state); + if (ret) { + dev_err(dev, "control %u: error saving mux: %d\n", i, ret); + return ret; + } + + mux_mmio->hardware_states[i] = state; + } + + return 0; +} + +static int mux_mmio_resume_noirq(struct device *dev) +{ + struct mux_chip *mux_chip = dev_get_drvdata(dev); + struct mux_mmio *mux_mmio = mux_chip_priv(mux_chip); + int ret, i; + + for (i = 0; i < mux_chip->controllers; i++) { + ret = mux_mmio_set(&mux_chip->mux[i], mux_mmio->hardware_states[i]); + if (ret) { + dev_err(dev, "control %u: error restoring mux: %d\n", i, ret); + return ret; + } + } + + return 0; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(mux_mmio_pm_ops, mux_mmio_suspend_noirq, mux_mmio_resume_noirq); + static struct platform_driver mux_mmio_driver = { .driver = { .name = "mmio-mux", .of_match_table = mux_mmio_dt_ids, + .pm = pm_sleep_ptr(&mux_mmio_pm_ops), }, .probe = mux_mmio_probe, }; |
