From: Richard Fitzgerald <rf@opensource.cirrus.com>
To: <tiwai@suse.com>, <broonie@kernel.org>, <perex@perex.cz>
Cc: <alsa-devel@alsa-project.org>, <linux-kernel@vger.kernel.org>,
<patches@opensource.cirrus.com>,
Richard Fitzgerald <rf@opensource.cirrus.com>
Subject: [PATCH 05/13] ASoC: cs35l56: Move runtime suspend/resume to shared library
Date: Thu, 25 May 2023 16:06:51 +0100 [thread overview]
Message-ID: <20230525150659.25409-6-rf@opensource.cirrus.com> (raw)
In-Reply-To: <20230525150659.25409-1-rf@opensource.cirrus.com>
The majority of runtime_suspend and runtime_resume handling
doesn't have anything specific to the ASoC driver, so can be
shared by the HDA driver. Move this code into the shared
library.
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
---
include/sound/cs35l56.h | 2 +
sound/soc/codecs/cs35l56-sdw.c | 4 +-
sound/soc/codecs/cs35l56-shared.c | 118 +++++++++++++++++++++++++++++
sound/soc/codecs/cs35l56.c | 120 +-----------------------------
sound/soc/codecs/cs35l56.h | 2 -
5 files changed, 126 insertions(+), 120 deletions(-)
diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 4d270eb23473..4a885c2321c1 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -281,6 +281,8 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire);
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
irqreturn_t cs35l56_irq(int irq, void *data);
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
+int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
+int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
int cs35l56_get_bclk_freq_id(unsigned int freq);
void cs35l56_fill_supply_names(struct regulator_bulk_data *data);
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index e6c9e8bce22c..09d255cc7652 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -424,7 +424,7 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev)
if (!cs35l56->base.init_done)
return 0;
- return cs35l56_runtime_suspend(dev);
+ return cs35l56_runtime_suspend_common(&cs35l56->base);
}
static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
@@ -441,7 +441,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
if (ret < 0)
return ret;
- ret = cs35l56_runtime_resume_common(cs35l56);
+ ret = cs35l56_runtime_resume_common(&cs35l56->base, true);
if (ret)
return ret;
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 93cd898dbab6..194fa08e1cc2 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -408,6 +408,124 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED);
+static const struct reg_sequence cs35l56_hibernate_seq[] = {
+ /* This must be the last register access */
+ REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW),
+};
+
+static const struct reg_sequence cs35l56_hibernate_wake_seq[] = {
+ REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP),
+};
+
+int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int val;
+ int ret;
+
+ if (!cs35l56_base->init_done)
+ return 0;
+
+ /* Firmware must have entered a power-save state */
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap,
+ CS35L56_TRANSDUCER_ACTUAL_PS,
+ val, (val >= CS35L56_PS3),
+ CS35L56_PS3_POLL_US,
+ CS35L56_PS3_TIMEOUT_US);
+ if (ret)
+ dev_warn(cs35l56_base->dev, "PS3 wait failed: %d\n", ret);
+
+ /* Clear BOOT_DONE so it can be used to detect a reboot */
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
+
+ if (!cs35l56_base->can_hibernate) {
+ regcache_cache_only(cs35l56_base->regmap, true);
+ dev_dbg(cs35l56_base->dev, "Suspended: no hibernate");
+
+ return 0;
+ }
+
+ /*
+ * Enable auto-hibernate. If it is woken by some other wake source
+ * it will automatically return to hibernate.
+ */
+ cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
+
+ /*
+ * Must enter cache-only first so there can't be any more register
+ * accesses other than the controlled hibernate sequence below.
+ */
+ regcache_cache_only(cs35l56_base->regmap, true);
+
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_hibernate_seq,
+ ARRAY_SIZE(cs35l56_hibernate_seq));
+
+ dev_dbg(cs35l56_base->dev, "Suspended: hibernate");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire)
+{
+ unsigned int val;
+ int ret;
+
+ if (!cs35l56_base->init_done)
+ return 0;
+
+ if (!cs35l56_base->can_hibernate)
+ goto out_sync;
+
+ if (!is_soundwire) {
+ /*
+ * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C.
+ * Must be done before releasing cache-only.
+ */
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_hibernate_wake_seq,
+ ARRAY_SIZE(cs35l56_hibernate_wake_seq));
+
+ usleep_range(CS35L56_CONTROL_PORT_READY_US,
+ CS35L56_CONTROL_PORT_READY_US + 400);
+ }
+
+out_sync:
+ regcache_cache_only(cs35l56_base->regmap, false);
+
+ ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ if (ret)
+ goto err;
+
+ /* BOOT_DONE will be 1 if the amp reset */
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, &val);
+ if (val & CS35L56_OTP_BOOT_DONE_MASK) {
+ dev_dbg(cs35l56_base->dev, "Registers reset in suspend\n");
+ regcache_mark_dirty(cs35l56_base->regmap);
+ }
+
+ regcache_sync(cs35l56_base->regmap);
+
+ dev_dbg(cs35l56_base->dev, "Resumed");
+
+ return 0;
+
+err:
+ regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ CS35L56_MBOX_CMD_HIBERNATE_NOW);
+
+ regcache_cache_only(cs35l56_base->regmap, true);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED);
+
const struct cs_dsp_region cs35l56_dsp1_regions[] = {
{ .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 },
{ .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 },
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index c1c7b7e408c3..ce8142249f05 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -852,132 +852,20 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l56 = {
.suspend_bias_off = 1, /* see cs35l56_system_resume() */
};
-static const struct reg_sequence cs35l56_hibernate_seq[] = {
- /* This must be the last register access */
- REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW),
-};
-
-static const struct reg_sequence cs35l56_hibernate_wake_seq[] = {
- REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP),
-};
-
-int cs35l56_runtime_suspend(struct device *dev)
+static int __maybe_unused cs35l56_runtime_suspend_i2c_spi(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
- unsigned int val;
- int ret;
- if (!cs35l56->base.init_done)
- return 0;
-
- /* Firmware must have entered a power-save state */
- ret = regmap_read_poll_timeout(cs35l56->base.regmap,
- CS35L56_TRANSDUCER_ACTUAL_PS,
- val, (val >= CS35L56_PS3),
- CS35L56_PS3_POLL_US,
- CS35L56_PS3_TIMEOUT_US);
- if (ret)
- dev_warn(cs35l56->base.dev, "PS3 wait failed: %d\n", ret);
-
- /* Clear BOOT_DONE so it can be used to detect a reboot */
- regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
-
- if (!cs35l56->base.can_hibernate) {
- regcache_cache_only(cs35l56->base.regmap, true);
- dev_dbg(dev, "Suspended: no hibernate");
-
- return 0;
- }
-
- /*
- * Enable auto-hibernate. If it is woken by some other wake source
- * it will automatically return to hibernate.
- */
- cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
-
- /*
- * Must enter cache-only first so there can't be any more register
- * accesses other than the controlled hibernate sequence below.
- */
- regcache_cache_only(cs35l56->base.regmap, true);
-
- regmap_multi_reg_write_bypassed(cs35l56->base.regmap,
- cs35l56_hibernate_seq,
- ARRAY_SIZE(cs35l56_hibernate_seq));
-
- dev_dbg(dev, "Suspended: hibernate");
-
- return 0;
+ return cs35l56_runtime_suspend_common(&cs35l56->base);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend, SND_SOC_CS35L56_CORE);
static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
- if (!cs35l56->base.init_done)
- return 0;
-
- return cs35l56_runtime_resume_common(cs35l56);
+ return cs35l56_runtime_resume_common(&cs35l56->base, false);
}
-int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
-{
- unsigned int val;
- int ret;
-
- if (!cs35l56->base.can_hibernate)
- goto out_sync;
-
- if (!cs35l56->sdw_peripheral) {
- /*
- * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C.
- * Must be done before releasing cache-only.
- */
- regmap_multi_reg_write_bypassed(cs35l56->base.regmap,
- cs35l56_hibernate_wake_seq,
- ARRAY_SIZE(cs35l56_hibernate_wake_seq));
-
- usleep_range(CS35L56_CONTROL_PORT_READY_US,
- CS35L56_CONTROL_PORT_READY_US + 400);
- }
-
-out_sync:
- regcache_cache_only(cs35l56->base.regmap, false);
-
- ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
- if (ret) {
- dev_err(cs35l56->base.dev, "Hibernate wake failed: %d\n", ret);
- goto err;
- }
-
- ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
- if (ret)
- goto err;
-
- /* BOOT_DONE will be 1 if the amp reset */
- regmap_read(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, &val);
- if (val & CS35L56_OTP_BOOT_DONE_MASK) {
- dev_dbg(cs35l56->base.dev, "Registers reset in suspend\n");
- regcache_mark_dirty(cs35l56->base.regmap);
- }
-
- regcache_sync(cs35l56->base.regmap);
-
- dev_dbg(cs35l56->base.dev, "Resumed");
-
- return 0;
-
-err:
- regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
- CS35L56_MBOX_CMD_HIBERNATE_NOW);
-
- regcache_cache_only(cs35l56->base.regmap, true);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE);
-
int cs35l56_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
@@ -1416,7 +1304,7 @@ void cs35l56_remove(struct cs35l56_private *cs35l56)
EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE);
const struct dev_pm_ops cs35l56_pm_ops_i2c_spi = {
- SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend, cs35l56_runtime_resume_i2c_spi, NULL)
+ SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend_i2c_spi, cs35l56_runtime_resume_i2c_spi, NULL)
SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend, cs35l56_system_resume)
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_no_irq, cs35l56_system_resume_no_irq)
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index f39f8fa9e37e..8159c3e217d9 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -55,8 +55,6 @@ struct cs35l56_private {
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);
--
2.30.2
next prev parent reply other threads:[~2023-05-25 15:08 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-25 15:06 [PATCH 00/13] ALSA: hda: Adding support for CS35L56 on HDA systems Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 01/13] ASoC: cs35l56: Move shared data into a common data structure Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 02/13] ASoC: cs35l56: Make cs35l56_system_reset() code more generic Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 03/13] ASoC: cs35l56: Convert utility functions to use common data structure Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 04/13] ASoC: cs35l56: Move utility functions to shared file Richard Fitzgerald
2023-05-25 15:06 ` Richard Fitzgerald [this message]
2023-05-25 15:06 ` [PATCH 06/13] ASoC: cs35l56: Move cs_dsp init into shared library Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 07/13] ASoC: cs35l56: Move part of cs35l56_init() to " Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 08/13] ASoC: cs35l56: Pass correct pointer to cs35l56_irq() Richard Fitzgerald
2023-05-25 15:14 ` Mark Brown
2023-05-25 15:20 ` Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 09/13] ASoC: cs35l56: Make common function for control port wait Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 10/13] ASoC: cs35l56: Make a common function to shutdown the DSP Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 11/13] ALSA: hda: Fix missing header dependencies Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 12/13] ALSA: hda: Add mute_hook to hda_component Richard Fitzgerald
2023-05-25 15:06 ` [PATCH 13/13] ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier Richard Fitzgerald
2023-05-26 4:40 ` Claudiu.Beznea
2023-05-26 12:20 ` Richard Fitzgerald
2023-05-26 15:25 ` Mark Brown
2023-05-25 15:43 ` [PATCH 00/13] ALSA: hda: Adding support for CS35L56 on HDA systems Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230525150659.25409-6-rf@opensource.cirrus.com \
--to=rf@opensource.cirrus.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=patches@opensource.cirrus.com \
--cc=perex@perex.cz \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox