Commit 27ff688a authored by Mark Brown's avatar Mark Brown

ASoC: cs35l56: Add system suspend handling

Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>:

This set of patches adds handling for system suspend.
Patches 1..4 make some code changes that simplify the
suspend implementation, mainly to avoid race conditions.

There are two seperate aspects to suspend, and these have
been done as two patches:
- the main suspend-resume handling,
- re-loading the firmware if necessary after resume.
parents b599a4d7 59322d35
......@@ -95,6 +95,7 @@
#define CS35L56_MAIN_RENDER_USER_MUTE 0x3400024
#define CS35L56_MAIN_RENDER_USER_VOLUME 0x340002C
#define CS35L56_MAIN_POSTURE_NUMBER 0x3400094
#define CS35L56_PROTECTION_STATUS 0x34000D8
#define CS35L56_TRANSDUCER_ACTUAL_PS 0x3400150
#define CS35L56_DSP1_YMEM_UNPACKED24_6141 0x3405FF4
#define CS35L56_DSP1_PMEM_0 0x3800000
......@@ -216,6 +217,9 @@
#define CS35L56_MAIN_POSTURE_MAX 255
#define CS35L56_MAIN_POSTURE_MASK CS35L56_MAIN_POSTURE_MAX
/* CS35L56_PROTECTION_STATUS */
#define CS35L56_FIRMWARE_MISSING BIT(0)
/* Software Values */
#define CS35L56_HALO_STATE_SHUTDOWN 1
#define CS35L56_HALO_STATE_BOOT_DONE 2
......
......@@ -450,6 +450,39 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
return 0;
}
static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
if (!cs35l56->init_done)
return 0;
/*
* Disable SoundWire interrupts.
* Flush - don't cancel because that could leave an unbalanced pm_runtime_get.
*/
cs35l56->sdw_irq_no_unmask = true;
flush_work(&cs35l56->sdw_irq_work);
/* Mask interrupts and flush in case sdw_irq_work was queued again */
sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
sdw_read_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1);
sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
flush_work(&cs35l56->sdw_irq_work);
return cs35l56_system_suspend(dev);
}
static int __maybe_unused cs35l56_sdw_system_resume(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
cs35l56->sdw_irq_no_unmask = false;
/* runtime_resume re-enables the interrupt */
return cs35l56_system_resume(dev);
}
static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id)
{
struct device *dev = &peripheral->dev;
......@@ -499,6 +532,9 @@ static int cs35l56_sdw_remove(struct sdw_slave *peripheral)
static const struct dev_pm_ops cs35l56_sdw_pm = {
SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_sdw_system_resume)
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
/* NOIRQ stage not needed, SoundWire doesn't use a hard IRQ */
};
static const struct sdw_device_id cs35l56_sdw_id[] = {
......
This diff is collapsed.
......@@ -49,7 +49,6 @@ struct cs35l56_private {
bool soft_resetting;
bool init_done;
bool sdw_attached;
bool removing;
bool fw_patched;
bool can_hibernate;
struct completion init_completion;
......@@ -68,6 +67,12 @@ extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
int cs35l56_runtime_suspend(struct device *dev);
int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56);
int cs35l56_system_suspend(struct device *dev);
int cs35l56_system_suspend_late(struct device *dev);
int cs35l56_system_suspend_no_irq(struct device *dev);
int cs35l56_system_resume_no_irq(struct device *dev);
int cs35l56_system_resume_early(struct device *dev);
int cs35l56_system_resume(struct device *dev);
irqreturn_t cs35l56_irq(int irq, void *data);
int cs35l56_irq_request(struct cs35l56_private *cs35l56);
int cs35l56_common_probe(struct cs35l56_private *cs35l56);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment