ASoC: SDCA: Add basic system suspend support

Add basic system suspend support. Disable the IRQs and force runtime
suspend, during system suspend, because the device will likely fully
power down during suspend.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://patch.msgid.link/20260109145206.3456151-3-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Charles Keepax 2026-01-09 14:52:04 +00:00 committed by Mark Brown
parent 9e3d4f794c
commit 7a5214f769
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 84 additions and 0 deletions

View File

@ -238,6 +238,38 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id
return 0;
}
static int class_suspend(struct device *dev)
{
struct sdca_class_drv *drv = dev_get_drvdata(dev);
int ret;
disable_irq(drv->sdw->irq);
ret = pm_runtime_force_suspend(dev);
if (ret) {
dev_err(dev, "failed to force suspend: %d\n", ret);
return ret;
}
return 0;
}
static int class_resume(struct device *dev)
{
struct sdca_class_drv *drv = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret) {
dev_err(dev, "failed to force resume: %d\n", ret);
return ret;
}
enable_irq(drv->sdw->irq);
return 0;
}
static int class_runtime_suspend(struct device *dev)
{
struct sdca_class_drv *drv = dev_get_drvdata(dev);
@ -278,6 +310,7 @@ static int class_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops class_pm_ops = {
SYSTEM_SLEEP_PM_OPS(class_suspend, class_resume)
RUNTIME_PM_OPS(class_runtime_suspend, class_runtime_resume, NULL)
};

View File

@ -33,6 +33,7 @@ struct class_function_drv {
struct sdca_class_drv *core;
struct sdca_function_data *function;
bool suspended;
};
static void class_function_regmap_lock(void *data)
@ -417,6 +418,14 @@ static int class_function_runtime_resume(struct device *dev)
regcache_mark_dirty(drv->regmap);
regcache_cache_only(drv->regmap, false);
if (drv->suspended) {
sdca_irq_enable_early(drv->function, drv->core->irq_info);
/* TODO: Add FDL process between early and late IRQs */
sdca_irq_enable(drv->function, drv->core->irq_info);
drv->suspended = false;
}
ret = regcache_sync(drv->regmap);
if (ret) {
dev_err(drv->dev, "failed to restore register cache: %d\n", ret);
@ -431,7 +440,49 @@ static int class_function_runtime_resume(struct device *dev)
return ret;
}
static int class_function_suspend(struct device *dev)
{
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
int ret;
drv->suspended = true;
/* Ensure runtime resume runs on resume */
ret = pm_runtime_resume_and_get(dev);
if (ret) {
dev_err(dev, "failed to resume for suspend: %d\n", ret);
return ret;
}
sdca_irq_disable(drv->function, drv->core->irq_info);
ret = pm_runtime_force_suspend(dev);
if (ret) {
dev_err(dev, "failed to force suspend: %d\n", ret);
return ret;
}
pm_runtime_put_noidle(dev);
return 0;
}
static int class_function_resume(struct device *dev)
{
int ret;
ret = pm_runtime_force_resume(dev);
if (ret) {
dev_err(dev, "failed to force resume: %d\n", ret);
return ret;
}
return 0;
}
static const struct dev_pm_ops class_function_pm_ops = {
SYSTEM_SLEEP_PM_OPS(class_function_suspend, class_function_resume)
RUNTIME_PM_OPS(class_function_runtime_suspend,
class_function_runtime_resume, NULL)
};