summarylogtreecommitdiffstats
path: root/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch
diff options
context:
space:
mode:
Diffstat (limited to '0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch')
-rw-r--r--0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch114
1 files changed, 114 insertions, 0 deletions
diff --git a/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch b/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch
new file mode 100644
index 000000000000..02d98e408b9f
--- /dev/null
+++ b/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch
@@ -0,0 +1,114 @@
+From 5091ba7ad9ea6a88db464b84b4993cc9e5033a84 Mon Sep 17 00:00:00 2001
+From: Stefan Binding <sbinding@opensource.cirrus.com>
+Date: Fri, 21 Jul 2023 16:18:14 +0100
+Subject: [PATCH 09/11] ALSA: hda: cs35l41: Rework System Suspend to ensure
+ correct call separation
+
+In order to correctly pause audio on suspend, amps using external boost
+require parts of the pause sequence to be called for all amps before moving
+on to the next steps.
+For example, as part of pausing the audio, the VSPK GPIO must be disabled,
+but since this GPIO is controlled by one amp, but controls the boost for
+all amps, it is required to separate the calls.
+During playback this is achieved by using the pre and post playback hooks,
+however during system suspend, this is not possible, so to separate the
+calls, we use both the .prepare and .suspend calls to pause the audio.
+
+Currently, for this reason, we do not restart audio on system resume.
+However, we can support this by relying on the playback hook to resume
+playback after system suspend.
+
+Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
+---
+ sound/pci/hda/cs35l41_hda.c | 40 ++++++++++++++++++++++++++++++++-----
+ 1 file changed, 35 insertions(+), 5 deletions(-)
+
+diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
+index a482d4752b3f..70aa819cfbd6 100644
+--- a/sound/pci/hda/cs35l41_hda.c
++++ b/sound/pci/hda/cs35l41_hda.c
+@@ -595,6 +595,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
+ mutex_unlock(&cs35l41->fw_mutex);
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
++ mutex_lock(&cs35l41->fw_mutex);
++ if (!cs35l41->firmware_running && cs35l41->request_fw_load &&
++ !cs35l41->fw_request_ongoing) {
++ dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n");
++ cs35l41->fw_request_ongoing = true;
++ schedule_work(&cs35l41->fw_load_work);
++ }
++ mutex_unlock(&cs35l41->fw_mutex);
++
+ /*
+ * Playback must be finished for all amps before we start runtime suspend.
+ * This ensures no amps are playing back when we start putting them to sleep.
+@@ -681,6 +690,25 @@ static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
+ return ret;
+ }
+
++static int cs35l41_system_suspend_prep(struct device *dev)
++{
++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
++
++ dev_dbg(cs35l41->dev, "System Suspend Prepare\n");
++
++ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
++ dev_err_once(cs35l41->dev, "System Suspend not supported\n");
++ return 0; /* don't block the whole system suspend */
++ }
++
++ mutex_lock(&cs35l41->fw_mutex);
++ if (cs35l41->playback_started)
++ cs35l41_hda_pause_start(dev);
++ mutex_unlock(&cs35l41->fw_mutex);
++
++ return 0;
++}
++
+ static int cs35l41_system_suspend(struct device *dev)
+ {
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+@@ -693,6 +721,11 @@ static int cs35l41_system_suspend(struct device *dev)
+ return 0; /* don't block the whole system suspend */
+ }
+
++ mutex_lock(&cs35l41->fw_mutex);
++ if (cs35l41->playback_started)
++ cs35l41_hda_pause_done(dev);
++ mutex_unlock(&cs35l41->fw_mutex);
++
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret);
+@@ -738,6 +771,7 @@ static int cs35l41_system_resume(struct device *dev)
+ }
+
+ mutex_lock(&cs35l41->fw_mutex);
++
+ if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
+ cs35l41->fw_request_ongoing = true;
+ schedule_work(&cs35l41->fw_load_work);
+@@ -770,11 +804,6 @@ static int cs35l41_runtime_suspend(struct device *dev)
+
+ mutex_lock(&cs35l41->fw_mutex);
+
+- if (cs35l41->playback_started) {
+- cs35l41_hda_pause_start(dev);
+- cs35l41_hda_pause_done(dev);
+- }
+-
+ if (cs35l41->firmware_running) {
+ ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap,
+ cs35l41->hw_cfg.bst_type);
+@@ -1641,6 +1670,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
+ const struct dev_pm_ops cs35l41_hda_pm_ops = {
+ RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
+ cs35l41_runtime_idle)
++ .prepare = cs35l41_system_suspend_prep,
+ SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
+ };
+ EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
+--
+2.41.0
+