2023-07-21 13:50:51

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

This set of patches adds support for using the CS35L56 boosted smart
amplifier on HDA systems. In these systems the CS35L56 audio is
routed through a HDA-to-I2S bridge codec.

This doesn't include the changes to the Realtek driver to actually hook
up the CS35L56 driver, because we don't yet have the QUIRK IDs to
associate it with. But we want to publish the driver now so that it is
available for bringing up hardware with the CS35L56.

The first 9 patches are moving code out of the ASoC driver and into the
shared library so that it can be shared with the HDA driver.

Patch #10 fixes missing #includes in the HDA headers so that the CS35L56
driver doesn't have to #include headers that it doesn't use.

CHANGES SINCE V5
The series has been rebased onto commit df4167d658d4
("ASoC: cs35l56: Patch soft registers to defaults"), which removes
cs35l56_reread_firmware_registers() and adds cs35l56_set_patch().

Changes are trivial so I have carried forward Mark's and Takashi's acks.

Patch 01:
- Also changes cs35l56_set_patch() argument to new struct cs35l56_base.

Patch 11:
- Remove call to cs35l56_reread_firmware_registers()
- Add call to cs35l56_set_patch() in cs35l56_hda_common_probe()
- Do not add mute_hook to struct hda_component. This was for use with
CS8409 as an HDA bridge, but production systems will use Realtek,
which has its own mute control.
- Use strscpy() instead of strcpy() in cs35l56_hda_mixer_info()
- Fix missing word in Kconfig option title

Richard Fitzgerald (4):
ASoC: cs35l56: Move runtime suspend/resume to shared library
ASoC: cs35l56: Move cs_dsp init into shared library
ASoC: cs35l56: Move part of cs35l56_init() to shared library
ALSA: hda: Fix missing header dependencies

Simon Trimmer (7):
ASoC: cs35l56: Move shared data into a common data structure
ASoC: cs35l56: Make cs35l56_system_reset() code more generic
ASoC: cs35l56: Convert utility functions to use common data structure
ASoC: cs35l56: Move utility functions to shared file
ASoC: cs35l56: Make common function for control port wait
ASoC: cs35l56: Make a common function to shutdown the DSP
ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier

include/sound/cs35l56.h | 29 +-
sound/pci/hda/Kconfig | 31 +
sound/pci/hda/Makefile | 6 +
sound/pci/hda/cs35l56_hda.c | 995 ++++++++++++++++++++++++++++++
sound/pci/hda/cs35l56_hda.h | 48 ++
sound/pci/hda/cs35l56_hda_i2c.c | 69 +++
sound/pci/hda/cs35l56_hda_spi.c | 68 ++
sound/pci/hda/hda_auto_parser.h | 2 +
sound/pci/hda/hda_generic.h | 3 +
sound/soc/codecs/cs35l56-i2c.c | 14 +-
sound/soc/codecs/cs35l56-sdw.c | 72 +--
sound/soc/codecs/cs35l56-shared.c | 458 +++++++++++++-
sound/soc/codecs/cs35l56-spi.c | 10 +-
sound/soc/codecs/cs35l56.c | 648 ++++---------------
sound/soc/codecs/cs35l56.h | 15 +-
15 files changed, 1877 insertions(+), 591 deletions(-)
create mode 100644 sound/pci/hda/cs35l56_hda.c
create mode 100644 sound/pci/hda/cs35l56_hda.h
create mode 100644 sound/pci/hda/cs35l56_hda_i2c.c
create mode 100644 sound/pci/hda/cs35l56_hda_spi.c

--
2.30.2



2023-07-21 13:50:56

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 04/11] ASoC: cs35l56: Move utility functions to shared file

From: Simon Trimmer <[email protected]>

Move the cs35l56 utility functions into the shared file so they are
available for use in HDA.

Signed-off-by: Simon Trimmer <[email protected]>
Signed-off-by: Richard Fitzgerald <[email protected]>
Acked-by: Mark Brown <[email protected]>
---
include/sound/cs35l56.h | 7 +
sound/soc/codecs/cs35l56-shared.c | 208 ++++++++++++++++++++++++++++++
sound/soc/codecs/cs35l56.c | 203 -----------------------------
3 files changed, 215 insertions(+), 203 deletions(-)

diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 532796efdaa5..3d2875094a21 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -274,6 +274,13 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];

int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
+int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
+int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);
+void cs35l56_wait_min_reset_pulse(void);
+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_get_bclk_freq_id(unsigned int freq);
void cs35l56_fill_supply_names(struct regulator_bulk_data *data);

diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 47b915f33f52..d22aede1ee8d 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -195,6 +195,214 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
}
}

+int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
+{
+ unsigned int val;
+ int ret;
+
+ regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ val, (val == 0),
+ CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
+ if (ret) {
+ dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int reg;
+ unsigned int val;
+ int ret;
+
+ if (cs35l56_base->rev < CS35L56_REVID_B0)
+ reg = CS35L56_DSP1_HALO_STATE_A1;
+ else
+ reg = CS35L56_DSP1_HALO_STATE;
+
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
+ val,
+ (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
+ CS35L56_HALO_STATE_POLL_US,
+ CS35L56_HALO_STATE_TIMEOUT_US);
+
+ if ((ret < 0) && (ret != -ETIMEDOUT)) {
+ dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret);
+ return ret;
+ }
+
+ if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
+ dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED);
+
+void cs35l56_wait_min_reset_pulse(void)
+{
+ /* Satisfy minimum reset pulse width spec */
+ usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED);
+
+static const struct reg_sequence cs35l56_system_reset_seq[] = {
+ REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
+};
+
+void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
+{
+ /*
+ * Must enter cache-only first so there can't be any more register
+ * accesses other than the controlled system reset sequence below.
+ */
+ regcache_cache_only(cs35l56_base->regmap, true);
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_system_reset_seq,
+ ARRAY_SIZE(cs35l56_system_reset_seq));
+
+ /* On SoundWire the registers won't be accessible until it re-enumerates. */
+ if (is_soundwire)
+ return;
+
+ usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
+ regcache_cache_only(cs35l56_base->regmap, false);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
+{
+ int ret;
+
+ if (!irq)
+ return 0;
+
+ ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "cs35l56", cs35l56_base);
+ if (!ret)
+ cs35l56_base->irq = irq;
+ else
+ dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED);
+
+irqreturn_t cs35l56_irq(int irq, void *data)
+{
+ struct cs35l56_base *cs35l56_base = data;
+ unsigned int status1 = 0, status8 = 0, status20 = 0;
+ unsigned int mask1, mask8, mask20;
+ unsigned int val;
+ int rv;
+
+ irqreturn_t ret = IRQ_NONE;
+
+ if (!cs35l56_base->init_done)
+ return IRQ_NONE;
+
+ mutex_lock(&cs35l56_base->irq_lock);
+
+ rv = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (rv < 0) {
+ dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
+ goto err_unlock;
+ }
+
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
+ if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
+ dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
+ goto err;
+ }
+
+ /* Ack interrupts */
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1);
+ status1 &= ~mask1;
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1);
+
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8);
+ status8 &= ~mask8;
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8);
+
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20);
+ status20 &= ~mask20;
+ /* We don't want EINT20 but they default to unmasked: force mask */
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+
+ dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8);
+
+ /* Check to see if unmasked bits are active */
+ if (!status1 && !status8 && !status20)
+ goto err;
+
+ if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
+ dev_crit(cs35l56_base->dev, "Amp short error\n");
+
+ if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
+ dev_crit(cs35l56_base->dev, "Overtemp error\n");
+
+ ret = IRQ_HANDLED;
+
+err:
+ pm_runtime_put(cs35l56_base->dev);
+err_unlock:
+ mutex_unlock(&cs35l56_base->irq_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int val;
+ int ret;
+
+ /* Nothing to re-patch if we haven't done any patching yet. */
+ if (!cs35l56_base->fw_patched)
+ return false;
+
+ /*
+ * If we have control of RESET we will have asserted it so the firmware
+ * will need re-patching.
+ */
+ if (cs35l56_base->reset_gpio)
+ return true;
+
+ /*
+ * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
+ * can't be used here to test for memory retention.
+ * Assume that tuning must be re-loaded.
+ */
+ if (cs35l56_base->secured)
+ return true;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val);
+ if (ret)
+ dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+ else
+ ret = !!(val & CS35L56_FIRMWARE_MISSING);
+
+ pm_runtime_put_autosuspend(cs35l56_base->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, 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 87e2f618850b..5598000187a7 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -34,23 +34,6 @@
static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);

-static int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
-{
- unsigned int val;
- int ret;
-
- regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
- ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
- val, (val == 0),
- CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
- if (ret) {
- dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret);
- return ret;
- }
-
- return 0;
-}
-
static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56)
{
/* Wait for patching to complete */
@@ -315,92 +298,6 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
return wm_adsp_event(w, kcontrol, event);
}

-irqreturn_t cs35l56_irq(int irq, void *data)
-{
- struct cs35l56_base *cs35l56_base = data;
- unsigned int status1 = 0, status8 = 0, status20 = 0;
- unsigned int mask1, mask8, mask20;
- unsigned int val;
- int rv;
-
- irqreturn_t ret = IRQ_NONE;
-
- if (!cs35l56_base->init_done)
- return IRQ_NONE;
-
- mutex_lock(&cs35l56_base->irq_lock);
-
- rv = pm_runtime_resume_and_get(cs35l56_base->dev);
- if (rv < 0) {
- dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
- goto err_unlock;
- }
-
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
- if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
- dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
- goto err;
- }
-
- /* Ack interrupts */
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1);
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1);
- status1 &= ~mask1;
- regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1);
-
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8);
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8);
- status8 &= ~mask8;
- regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8);
-
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20);
- regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20);
- status20 &= ~mask20;
- /* We don't want EINT20 but they default to unmasked: force mask */
- regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
-
- dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8);
-
- /* Check to see if unmasked bits are active */
- if (!status1 && !status8 && !status20)
- goto err;
-
- if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
- dev_crit(cs35l56_base->dev, "Amp short error\n");
-
- if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
- dev_crit(cs35l56_base->dev, "Overtemp error\n");
-
- ret = IRQ_HANDLED;
-
-err:
- pm_runtime_put(cs35l56_base->dev);
-err_unlock:
- mutex_unlock(&cs35l56_base->irq_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE);
-
-int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
-{
- int ret;
-
- if (!irq)
- return 0;
-
- ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
- IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
- "cs35l56", cs35l56_base);
- if (!ret)
- cs35l56_base->irq = irq;
- else
- dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_CORE);
-
static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
@@ -762,65 +659,6 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
}
};

-static int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
-{
- unsigned int reg;
- unsigned int val;
- int ret;
-
- if (cs35l56_base->rev < CS35L56_REVID_B0)
- reg = CS35L56_DSP1_HALO_STATE_A1;
- else
- reg = CS35L56_DSP1_HALO_STATE;
-
- ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
- val,
- (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
- CS35L56_HALO_STATE_POLL_US,
- CS35L56_HALO_STATE_TIMEOUT_US);
-
- if ((ret < 0) && (ret != -ETIMEDOUT)) {
- dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret);
- return ret;
- }
-
- if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
- dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
- return -EIO;
- }
-
- return 0;
-}
-
-static inline void cs35l56_wait_min_reset_pulse(void)
-{
- /* Satisfy minimum reset pulse width spec */
- usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
-}
-
-static const struct reg_sequence cs35l56_system_reset_seq[] = {
- REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
-};
-
-static void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
-{
- /*
- * Must enter cache-only first so there can't be any more register
- * accesses other than the controlled system reset sequence below.
- */
- regcache_cache_only(cs35l56_base->regmap, true);
- regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
- cs35l56_system_reset_seq,
- ARRAY_SIZE(cs35l56_system_reset_seq));
-
- /* On SoundWire the registers won't be accessible until it re-enumerates. */
- if (is_soundwire)
- return;
-
- usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
- regcache_cache_only(cs35l56_base->regmap, false);
-}
-
static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
{
int ret;
@@ -1137,47 +975,6 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE);

-static int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
-{
- unsigned int val;
- int ret;
-
- /* Nothing to re-patch if we haven't done any patching yet. */
- if (!cs35l56_base->fw_patched)
- return false;
-
- /*
- * If we have control of RESET we will have asserted it so the firmware
- * will need re-patching.
- */
- if (cs35l56_base->reset_gpio)
- return true;
-
- /*
- * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
- * can't be used here to test for memory retention.
- * Assume that tuning must be re-loaded.
- */
- if (cs35l56_base->secured)
- return true;
-
- ret = pm_runtime_resume_and_get(cs35l56_base->dev);
- if (ret) {
- dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret);
- return ret;
- }
-
- ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val);
- if (ret)
- dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
- else
- ret = !!(val & CS35L56_FIRMWARE_MISSING);
-
- pm_runtime_put_autosuspend(cs35l56_base->dev);
-
- return ret;
-}
-
int cs35l56_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
--
2.30.2


2023-07-21 13:51:17

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 01/11] ASoC: cs35l56: Move shared data into a common data structure

From: Simon Trimmer <[email protected]>

The ASoC and HDA drivers have structures that contain some of the same
information - instead of maintaining two locations for this data the
drivers should share a common data structure as this will enable common
utility functions to be created.

The first step is to move the location of these members in the ASoC
driver.

Signed-off-by: Simon Trimmer <[email protected]>
Signed-off-by: Richard Fitzgerald <[email protected]>
Acked-by: Mark Brown <[email protected]>
---
include/sound/cs35l56.h | 15 +-
sound/soc/codecs/cs35l56-i2c.c | 14 +-
sound/soc/codecs/cs35l56-sdw.c | 68 ++---
sound/soc/codecs/cs35l56-shared.c | 5 +-
sound/soc/codecs/cs35l56-spi.c | 10 +-
sound/soc/codecs/cs35l56.c | 404 +++++++++++++++---------------
sound/soc/codecs/cs35l56.h | 13 +-
7 files changed, 270 insertions(+), 259 deletions(-)

diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index ec672daa36cf..532796efdaa5 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -252,6 +252,19 @@
#define CS35L56_NUM_BULK_SUPPLIES 3
#define CS35L56_NUM_DSP_REGIONS 5

+struct cs35l56_base {
+ struct device *dev;
+ struct regmap *regmap;
+ int irq;
+ struct mutex irq_lock;
+ u8 rev;
+ bool init_done;
+ bool fw_patched;
+ bool secured;
+ bool can_hibernate;
+ struct gpio_desc *reset_gpio;
+};
+
extern struct regmap_config cs35l56_regmap_i2c;
extern struct regmap_config cs35l56_regmap_spi;
extern struct regmap_config cs35l56_regmap_sdw;
@@ -260,7 +273,7 @@ extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS];
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];

-int cs35l56_set_patch(struct regmap *regmap);
+int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
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-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
index ed2a41943d97..888fdfa5f5db 100644
--- a/sound/soc/codecs/cs35l56-i2c.c
+++ b/sound/soc/codecs/cs35l56-i2c.c
@@ -26,14 +26,14 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
if (!cs35l56)
return -ENOMEM;

- cs35l56->dev = dev;
- cs35l56->can_hibernate = true;
+ cs35l56->base.dev = dev;
+ cs35l56->base.can_hibernate = true;

i2c_set_clientdata(client, cs35l56);
- cs35l56->regmap = devm_regmap_init_i2c(client, regmap_config);
- if (IS_ERR(cs35l56->regmap)) {
- ret = PTR_ERR(cs35l56->regmap);
- return dev_err_probe(cs35l56->dev, ret, "Failed to allocate register map\n");
+ cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n");
}

ret = cs35l56_common_probe(cs35l56);
@@ -42,7 +42,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)

ret = cs35l56_init(cs35l56);
if (ret == 0)
- ret = cs35l56_irq_request(cs35l56, client->irq);
+ ret = cs35l56_irq_request(&cs35l56->base, client->irq);
if (ret < 0)
cs35l56_remove(cs35l56);

diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 2cde78605ba9..98be005b8787 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -166,13 +166,13 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
int ret;

- pm_runtime_get_noresume(cs35l56->dev);
+ pm_runtime_get_noresume(cs35l56->base.dev);

- regcache_cache_only(cs35l56->regmap, false);
+ regcache_cache_only(cs35l56->base.regmap, false);

ret = cs35l56_init(cs35l56);
if (ret < 0) {
- regcache_cache_only(cs35l56->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);
goto out;
}

@@ -180,15 +180,15 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
* cs35l56_init can return with !init_done if it triggered
* a soft reset.
*/
- if (cs35l56->init_done) {
+ if (cs35l56->base.init_done) {
/* Enable SoundWire interrupts */
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1,
CS35L56_SDW_INT_MASK_CODEC_IRQ);
}

out:
- pm_runtime_mark_last_busy(cs35l56->dev);
- pm_runtime_put_autosuspend(cs35l56->dev);
+ pm_runtime_mark_last_busy(cs35l56->base.dev);
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
}

static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
@@ -198,7 +198,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,

/* SoundWire core holds our pm_runtime when calling this function. */

- dev_dbg(cs35l56->dev, "int control_port=%#x\n", status->control_port);
+ dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port);

if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0)
return 0;
@@ -207,7 +207,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
* Prevent bus manager suspending and possibly issuing a
* bus-reset before the queued work has run.
*/
- pm_runtime_get_noresume(cs35l56->dev);
+ pm_runtime_get_noresume(cs35l56->base.dev);

/*
* Mask and clear until it has been handled. The read of GEN_INT_STAT_1
@@ -230,14 +230,14 @@ static void cs35l56_sdw_irq_work(struct work_struct *work)
struct cs35l56_private,
sdw_irq_work);

- cs35l56_irq(-1, cs35l56);
+ cs35l56_irq(-1, &cs35l56->base);

/* unmask interrupts */
if (!cs35l56->sdw_irq_no_unmask)
sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1,
CS35L56_SDW_INT_MASK_CODEC_IRQ);

- pm_runtime_put_autosuspend(cs35l56->dev);
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
}

static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
@@ -246,7 +246,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
struct sdw_slave_prop *prop = &peripheral->prop;
struct sdw_dpn_prop *ports;

- ports = devm_kcalloc(cs35l56->dev, 2, sizeof(*ports), GFP_KERNEL);
+ ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL);
if (!ports)
return -ENOMEM;

@@ -279,17 +279,17 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,

switch (status) {
case SDW_SLAVE_ATTACHED:
- dev_dbg(cs35l56->dev, "%s: ATTACHED\n", __func__);
+ dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__);
if (cs35l56->sdw_attached)
break;

- if (!cs35l56->init_done || cs35l56->soft_resetting)
+ if (!cs35l56->base.init_done || cs35l56->soft_resetting)
cs35l56_sdw_init(peripheral);

cs35l56->sdw_attached = true;
break;
case SDW_SLAVE_UNATTACHED:
- dev_dbg(cs35l56->dev, "%s: UNATTACHED\n", __func__);
+ dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__);
cs35l56->sdw_attached = false;
break;
default:
@@ -305,7 +305,7 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
unsigned int curr_scale_reg, next_scale_reg;
int curr_scale, next_scale, ret;

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;

if (peripheral->bus->params.curr_bank) {
@@ -324,13 +324,13 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
*/
curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg);
if (curr_scale < 0) {
- dev_err(cs35l56->dev, "Failed to read current clock scale: %d\n", curr_scale);
+ dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale);
return curr_scale;
}

next_scale = sdw_read_no_pm(peripheral, next_scale_reg);
if (next_scale < 0) {
- dev_err(cs35l56->dev, "Failed to read next clock scale: %d\n", next_scale);
+ dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale);
return next_scale;
}

@@ -338,7 +338,8 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
next_scale = cs35l56->old_sdw_clock_scale;
ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale);
if (ret < 0) {
- dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret);
+ dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n",
+ ret);
return ret;
}
}
@@ -346,11 +347,11 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
cs35l56->old_sdw_clock_scale = curr_scale;
ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE);
if (ret < 0) {
- dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret);
+ dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret);
return ret;
}

- dev_dbg(cs35l56->dev, "Next bus scale: %#x\n", next_scale);
+ dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale);

return 0;
}
@@ -362,9 +363,10 @@ static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
int sclk;

sclk = params->curr_dr_freq / 2;
- dev_dbg(cs35l56->dev, "%s: sclk=%u c=%u r=%u\n", __func__, sclk, params->col, params->row);
+ dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n",
+ __func__, sclk, params->col, params->row);

- if (cs35l56->rev < 0xb0)
+ if (cs35l56->base.rev < 0xb0)
return cs35l56_a1_kick_divider(cs35l56, peripheral);

return 0;
@@ -376,7 +378,7 @@ static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);

- dev_dbg(cs35l56->dev, "%s: mode:%d type:%d\n", __func__, mode, type);
+ dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type);

return 0;
}
@@ -397,10 +399,10 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs

if (peripheral->unattach_request) {
/* Cannot access registers until bus is re-initialized. */
- dev_dbg(cs35l56->dev, "Wait for initialization_complete\n");
+ dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n");
if (!wait_for_completion_timeout(&peripheral->initialization_complete,
msecs_to_jiffies(5000))) {
- dev_err(cs35l56->dev, "initialization_complete timed out\n");
+ dev_err(cs35l56->base.dev, "initialization_complete timed out\n");
return -ETIMEDOUT;
}

@@ -419,7 +421,7 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;

return cs35l56_runtime_suspend(dev);
@@ -432,7 +434,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)

dev_dbg(dev, "Runtime resume\n");

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;

ret = cs35l56_sdw_handle_unattach(cs35l56);
@@ -454,7 +456,7 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;

/*
@@ -493,21 +495,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
if (!cs35l56)
return -ENOMEM;

- cs35l56->dev = dev;
+ cs35l56->base.dev = dev;
cs35l56->sdw_peripheral = peripheral;
INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work);

dev_set_drvdata(dev, cs35l56);

- cs35l56->regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw,
+ cs35l56->base.regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw,
peripheral, &cs35l56_regmap_sdw);
- if (IS_ERR(cs35l56->regmap)) {
- ret = PTR_ERR(cs35l56->regmap);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
return dev_err_probe(dev, ret, "Failed to allocate register map\n");
}

/* Start in cache-only until device is enumerated */
- regcache_cache_only(cs35l56->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);

ret = cs35l56_common_probe(cs35l56);
if (ret != 0)
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index cb0130d1e7e9..47b915f33f52 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -18,9 +18,10 @@ static const struct reg_sequence cs35l56_patch[] = {
{ CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 },
};

-int cs35l56_set_patch(struct regmap *regmap)
+int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
{
- return regmap_register_patch(regmap, cs35l56_patch, ARRAY_SIZE(cs35l56_patch));
+ return regmap_register_patch(cs35l56_base->regmap, cs35l56_patch,
+ ARRAY_SIZE(cs35l56_patch));
}
EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);

diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
index 996aab10500e..2057fce435be 100644
--- a/sound/soc/codecs/cs35l56-spi.c
+++ b/sound/soc/codecs/cs35l56-spi.c
@@ -25,13 +25,13 @@ static int cs35l56_spi_probe(struct spi_device *spi)
return -ENOMEM;

spi_set_drvdata(spi, cs35l56);
- cs35l56->regmap = devm_regmap_init_spi(spi, regmap_config);
- if (IS_ERR(cs35l56->regmap)) {
- ret = PTR_ERR(cs35l56->regmap);
+ cs35l56->base.regmap = devm_regmap_init_spi(spi, regmap_config);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
return dev_err_probe(&spi->dev, ret, "Failed to allocate register map\n");
}

- cs35l56->dev = &spi->dev;
+ cs35l56->base.dev = &spi->dev;

ret = cs35l56_common_probe(cs35l56);
if (ret != 0)
@@ -39,7 +39,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)

ret = cs35l56_init(cs35l56);
if (ret == 0)
- ret = cs35l56_irq_request(cs35l56, spi->irq);
+ ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
if (ret < 0)
cs35l56_remove(cs35l56);

diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index e046fdd26b74..4eb8e5b09bfd 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -34,17 +34,17 @@
static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);

-static int cs35l56_mbox_send(struct cs35l56_private *cs35l56, unsigned int command)
+static int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
{
unsigned int val;
int ret;

- regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
- ret = regmap_read_poll_timeout(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
val, (val == 0),
CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
if (ret) {
- dev_warn(cs35l56->dev, "MBOX command %#x failed: %d\n", command, ret);
+ dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret);
return ret;
}

@@ -174,25 +174,25 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
unsigned int val;
int ret;

- dev_dbg(cs35l56->dev, "play: %d\n", event);
+ dev_dbg(cs35l56->base.dev, "play: %d\n", event);

switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Don't wait for ACK, we check in POST_PMU that it completed */
- return regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
CS35L56_MBOX_CMD_AUDIO_PLAY);
case SND_SOC_DAPM_POST_PMU:
/* Wait for firmware to enter PS0 power state */
- ret = regmap_read_poll_timeout(cs35l56->regmap,
+ ret = regmap_read_poll_timeout(cs35l56->base.regmap,
CS35L56_TRANSDUCER_ACTUAL_PS,
val, (val == CS35L56_PS0),
CS35L56_PS0_POLL_US,
CS35L56_PS0_TIMEOUT_US);
if (ret)
- dev_err(cs35l56->dev, "PS0 wait failed: %d\n", ret);
+ dev_err(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
return ret;
case SND_SOC_DAPM_POST_PMD:
- return cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_PAUSE);
+ return cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
default:
return 0;
}
@@ -310,14 +310,14 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);

- dev_dbg(cs35l56->dev, "%s: %d\n", __func__, event);
+ dev_dbg(cs35l56->base.dev, "%s: %d\n", __func__, event);

return wm_adsp_event(w, kcontrol, event);
}

irqreturn_t cs35l56_irq(int irq, void *data)
{
- struct cs35l56_private *cs35l56 = data;
+ struct cs35l56_base *cs35l56_base = data;
unsigned int status1 = 0, status8 = 0, status20 = 0;
unsigned int mask1, mask8, mask20;
unsigned int val;
@@ -325,77 +325,77 @@ irqreturn_t cs35l56_irq(int irq, void *data)

irqreturn_t ret = IRQ_NONE;

- if (!cs35l56->init_done)
+ if (!cs35l56_base->init_done)
return IRQ_NONE;

- mutex_lock(&cs35l56->irq_lock);
+ mutex_lock(&cs35l56_base->irq_lock);

- rv = pm_runtime_resume_and_get(cs35l56->dev);
+ rv = pm_runtime_resume_and_get(cs35l56_base->dev);
if (rv < 0) {
- dev_err(cs35l56->dev, "irq: failed to get pm_runtime: %d\n", rv);
+ dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
goto err_unlock;
}

- regmap_read(cs35l56->regmap, CS35L56_IRQ1_STATUS, &val);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
- dev_dbg(cs35l56->dev, "Spurious IRQ: no pending interrupt\n");
+ dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
goto err;
}

/* Ack interrupts */
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_1, &status1);
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_1, &mask1);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1);
status1 &= ~mask1;
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_1, status1);
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1);

- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_8, &status8);
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_8, &mask8);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8);
status8 &= ~mask8;
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_8, status8);
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8);

- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_20, &status20);
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_20, &mask20);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20);
status20 &= ~mask20;
/* We don't want EINT20 but they default to unmasked: force mask */
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);

- dev_dbg(cs35l56->dev, "%s: %#x %#x\n", __func__, status1, status8);
+ dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8);

/* Check to see if unmasked bits are active */
if (!status1 && !status8 && !status20)
goto err;

if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
- dev_crit(cs35l56->dev, "Amp short error\n");
+ dev_crit(cs35l56_base->dev, "Amp short error\n");

if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
- dev_crit(cs35l56->dev, "Overtemp error\n");
+ dev_crit(cs35l56_base->dev, "Overtemp error\n");

ret = IRQ_HANDLED;

err:
- pm_runtime_put(cs35l56->dev);
+ pm_runtime_put(cs35l56_base->dev);
err_unlock:
- mutex_unlock(&cs35l56->irq_lock);
+ mutex_unlock(&cs35l56_base->irq_lock);

return ret;
}
EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE);

-int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq)
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
{
int ret;

if (!irq)
return 0;

- ret = devm_request_threaded_irq(cs35l56->dev, irq, NULL, cs35l56_irq,
+ ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
- "cs35l56", cs35l56);
+ "cs35l56", cs35l56_base);
if (!ret)
- cs35l56->irq = irq;
+ cs35l56_base->irq = irq;
else
- dev_err(cs35l56->dev, "Failed to get IRQ: %d\n", ret);
+ dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);

return ret;
}
@@ -406,13 +406,13 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
unsigned int val;

- dev_dbg(cs35l56->dev, "%s: %#x\n", __func__, fmt);
+ dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);

switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- dev_err(cs35l56->dev, "Unsupported clock source mode\n");
+ dev_err(cs35l56->base.dev, "Unsupported clock source mode\n");
return -EINVAL;
}

@@ -426,7 +426,7 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
cs35l56->tdm_mode = false;
break;
default:
- dev_err(cs35l56->dev, "Unsupported DAI format\n");
+ dev_err(cs35l56->base.dev, "Unsupported DAI format\n");
return -EINVAL;
}

@@ -443,18 +443,18 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
case SND_SOC_DAIFMT_NB_NF:
break;
default:
- dev_err(cs35l56->dev, "Invalid clock invert\n");
+ dev_err(cs35l56->base.dev, "Invalid clock invert\n");
return -EINVAL;
}

- regmap_update_bits(cs35l56->regmap,
+ regmap_update_bits(cs35l56->base.regmap,
CS35L56_ASP1_CONTROL2,
CS35L56_ASP_FMT_MASK |
CS35L56_ASP_BCLK_INV_MASK | CS35L56_ASP_FSYNC_INV_MASK,
val);

/* Hi-Z DOUT in unused slots and when all TX are disabled */
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL3,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
CS35L56_ASP1_DOUT_HIZ_CTRL_MASK,
CS35L56_ASP_UNUSED_HIZ_OFF_HIZ);

@@ -485,7 +485,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
channel_shift += 8;
}

- regmap_write(cs35l56->regmap, reg, reg_val);
+ regmap_write(cs35l56->base.regmap, reg, reg_val);
}

static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -494,20 +494,20 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);

if ((slots == 0) || (slot_width == 0)) {
- dev_dbg(cs35l56->dev, "tdm config cleared\n");
+ dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
cs35l56->asp_slot_width = 0;
cs35l56->asp_slot_count = 0;
return 0;
}

if (slot_width > (CS35L56_ASP_RX_WIDTH_MASK >> CS35L56_ASP_RX_WIDTH_SHIFT)) {
- dev_err(cs35l56->dev, "tdm invalid slot width %d\n", slot_width);
+ dev_err(cs35l56->base.dev, "tdm invalid slot width %d\n", slot_width);
return -EINVAL;
}

/* More than 32 slots would give an unsupportable BCLK frequency */
if (slots > 32) {
- dev_err(cs35l56->dev, "tdm invalid slot count %d\n", slots);
+ dev_err(cs35l56->base.dev, "tdm invalid slot count %d\n", slots);
return -EINVAL;
}

@@ -524,7 +524,7 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask);
cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask);

- dev_dbg(cs35l56->dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
+ dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask);

return 0;
@@ -544,7 +544,8 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
else
asp_width = asp_wl;

- dev_dbg(cs35l56->dev, "%s: wl=%d, width=%d, rate=%d", __func__, asp_wl, asp_width, rate);
+ dev_dbg(cs35l56->base.dev, "%s: wl=%d, width=%d, rate=%d",
+ __func__, asp_wl, asp_width, rate);

if (!cs35l56->sysclk_set) {
unsigned int slots = cs35l56->asp_slot_count;
@@ -562,26 +563,26 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
bclk_freq = asp_width * slots * rate;
freq_id = cs35l56_get_bclk_freq_id(bclk_freq);
if (freq_id < 0) {
- dev_err(cs35l56->dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
+ dev_err(cs35l56->base.dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
return -EINVAL;
}

- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
CS35L56_ASP_BCLK_FREQ_MASK,
freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
}

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
CS35L56_ASP_RX_WIDTH_MASK, asp_width <<
CS35L56_ASP_RX_WIDTH_SHIFT);
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL5,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL5,
CS35L56_ASP_RX_WL_MASK, asp_wl);
} else {
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
CS35L56_ASP_TX_WIDTH_MASK, asp_width <<
CS35L56_ASP_TX_WIDTH_SHIFT);
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL1,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL1,
CS35L56_ASP_TX_WL_MASK, asp_wl);
}

@@ -603,7 +604,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
if (freq_id < 0)
return freq_id;

- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
CS35L56_ASP_BCLK_FREQ_MASK,
freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
cs35l56->sysclk_set = true;
@@ -646,9 +647,9 @@ static int cs35l56_sdw_dai_hw_params(struct snd_pcm_substream *substream,
struct sdw_port_config pconfig;
int ret;

- dev_dbg(cs35l56->dev, "%s: rate %d\n", __func__, params_rate(params));
+ dev_dbg(cs35l56->base.dev, "%s: rate %d\n", __func__, params_rate(params));

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return -ENODEV;

if (!sdw_stream)
@@ -761,30 +762,30 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
}
};

-static int cs35l56_wait_for_firmware_boot(struct cs35l56_private *cs35l56)
+static int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
{
unsigned int reg;
unsigned int val;
int ret;

- if (cs35l56->rev < CS35L56_REVID_B0)
+ if (cs35l56_base->rev < CS35L56_REVID_B0)
reg = CS35L56_DSP1_HALO_STATE_A1;
else
reg = CS35L56_DSP1_HALO_STATE;

- ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
val,
(val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
CS35L56_HALO_STATE_POLL_US,
CS35L56_HALO_STATE_TIMEOUT_US);

if ((ret < 0) && (ret != -ETIMEDOUT)) {
- dev_err(cs35l56->dev, "Failed to read HALO_STATE: %d\n", ret);
+ dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret);
return ret;
}

if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
- dev_err(cs35l56->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
+ dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
return -EIO;
}

@@ -809,8 +810,8 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
* Must enter cache-only first so there can't be any more register
* accesses other than the controlled system reset sequence below.
*/
- regcache_cache_only(cs35l56->regmap, true);
- regmap_multi_reg_write_bypassed(cs35l56->regmap,
+ regcache_cache_only(cs35l56->base.regmap, true);
+ regmap_multi_reg_write_bypassed(cs35l56->base.regmap,
cs35l56_system_reset_seq,
ARRAY_SIZE(cs35l56_system_reset_seq));

@@ -819,7 +820,7 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
return;

usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
- regcache_cache_only(cs35l56->regmap, false);
+ regcache_cache_only(cs35l56->base.regmap, false);
}

static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
@@ -829,9 +830,9 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
/* Use wm_adsp to load and apply the firmware patch and coefficient files */
ret = wm_adsp_power_up(&cs35l56->dsp);
if (ret)
- dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
+ dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
else
- cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT);
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
}

static void cs35l56_patch(struct cs35l56_private *cs35l56)
@@ -854,31 +855,31 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
flush_work(&cs35l56->sdw_irq_work);
}

- ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_SHUTDOWN);
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_SHUTDOWN);
if (ret)
goto err;

- if (cs35l56->rev < CS35L56_REVID_B0)
+ if (cs35l56->base.rev < CS35L56_REVID_B0)
reg = CS35L56_DSP1_PM_CUR_STATE_A1;
else
reg = CS35L56_DSP1_PM_CUR_STATE;

- ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
+ ret = regmap_read_poll_timeout(cs35l56->base.regmap, reg,
val, (val == CS35L56_HALO_STATE_SHUTDOWN),
CS35L56_HALO_STATE_POLL_US,
CS35L56_HALO_STATE_TIMEOUT_US);
if (ret < 0)
- dev_err(cs35l56->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
+ dev_err(cs35l56->base.dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
val, ret);

/* Use wm_adsp to load and apply the firmware patch and coefficient files */
ret = wm_adsp_power_up(&cs35l56->dsp);
if (ret) {
- dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
+ dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
goto err;
}

- mutex_lock(&cs35l56->irq_lock);
+ mutex_lock(&cs35l56->base.irq_lock);

init_completion(&cs35l56->init_completion);

@@ -892,18 +893,20 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
*/
if (!wait_for_completion_timeout(&cs35l56->init_completion,
msecs_to_jiffies(5000))) {
- dev_err(cs35l56->dev, "%s: init_completion timed out (SDW)\n", __func__);
+ dev_err(cs35l56->base.dev, "%s: init_completion timed out (SDW)\n",
+ __func__);
goto err_unlock;
}
} else if (cs35l56_init(cs35l56)) {
goto err_unlock;
}

- regmap_clear_bits(cs35l56->regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING);
- cs35l56->fw_patched = true;
+ regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS,
+ CS35L56_FIRMWARE_MISSING);
+ cs35l56->base.fw_patched = true;

err_unlock:
- mutex_unlock(&cs35l56->irq_lock);
+ mutex_unlock(&cs35l56->base.irq_lock);
err:
/* Re-enable SoundWire interrupts */
if (cs35l56->sdw_peripheral) {
@@ -919,10 +922,10 @@ static void cs35l56_dsp_work(struct work_struct *work)
struct cs35l56_private,
dsp_work);

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return;

- pm_runtime_get_sync(cs35l56->dev);
+ pm_runtime_get_sync(cs35l56->base.dev);

/*
* When the device is running in secure mode the firmware files can
@@ -930,13 +933,13 @@ static void cs35l56_dsp_work(struct work_struct *work)
* shutdown the firmware to apply them and can use the lower cost
* reinit sequence instead.
*/
- if (cs35l56->secured)
+ if (cs35l56->base.secured)
cs35l56_secure_patch(cs35l56);
else
cs35l56_patch(cs35l56);

- pm_runtime_mark_last_busy(cs35l56->dev);
- pm_runtime_put_autosuspend(cs35l56->dev);
+ pm_runtime_mark_last_busy(cs35l56->base.dev);
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
}

static int cs35l56_component_probe(struct snd_soc_component *component)
@@ -948,16 +951,16 @@ static int cs35l56_component_probe(struct snd_soc_component *component)

if (!wait_for_completion_timeout(&cs35l56->init_completion,
msecs_to_jiffies(5000))) {
- dev_err(cs35l56->dev, "%s: init_completion timed out\n", __func__);
+ dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__);
return -ENODEV;
}

cs35l56->component = component;
wm_adsp2_component_probe(&cs35l56->dsp, component);

- debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->init_done);
- debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->can_hibernate);
- debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->fw_patched);
+ debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done);
+ debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
+ debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);

queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);

@@ -1024,23 +1027,23 @@ int cs35l56_runtime_suspend(struct device *dev)
unsigned int val;
int ret;

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;

/* Firmware must have entered a power-save state */
- ret = regmap_read_poll_timeout(cs35l56->regmap,
+ 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->dev, "PS3 wait failed: %d\n", 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->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
+ regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);

- if (!cs35l56->can_hibernate) {
- regcache_cache_only(cs35l56->regmap, true);
+ if (!cs35l56->base.can_hibernate) {
+ regcache_cache_only(cs35l56->base.regmap, true);
dev_dbg(dev, "Suspended: no hibernate");

return 0;
@@ -1050,15 +1053,15 @@ int cs35l56_runtime_suspend(struct device *dev)
* Enable auto-hibernate. If it is woken by some other wake source
* it will automatically return to hibernate.
*/
- cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_ALLOW_AUTO_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->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);

- regmap_multi_reg_write_bypassed(cs35l56->regmap,
+ regmap_multi_reg_write_bypassed(cs35l56->base.regmap,
cs35l56_hibernate_seq,
ARRAY_SIZE(cs35l56_hibernate_seq));

@@ -1072,7 +1075,7 @@ static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);

- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;

return cs35l56_runtime_resume_common(cs35l56);
@@ -1083,7 +1086,7 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
unsigned int val;
int ret;

- if (!cs35l56->can_hibernate)
+ if (!cs35l56->base.can_hibernate)
goto out_sync;

if (!cs35l56->sdw_peripheral) {
@@ -1091,7 +1094,7 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
* 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->regmap,
+ regmap_multi_reg_write_bypassed(cs35l56->base.regmap,
cs35l56_hibernate_wake_seq,
ARRAY_SIZE(cs35l56_hibernate_wake_seq));

@@ -1100,36 +1103,36 @@ int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
}

out_sync:
- regcache_cache_only(cs35l56->regmap, false);
+ regcache_cache_only(cs35l56->base.regmap, false);

- ret = cs35l56_wait_for_firmware_boot(cs35l56);
+ ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
if (ret) {
- dev_err(cs35l56->dev, "Hibernate wake failed: %d\n", ret);
+ dev_err(cs35l56->base.dev, "Hibernate wake failed: %d\n", ret);
goto err;
}

- ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ 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->regmap, CS35L56_IRQ1_EINT_4, &val);
+ regmap_read(cs35l56->base.regmap, CS35L56_IRQ1_EINT_4, &val);
if (val & CS35L56_OTP_BOOT_DONE_MASK) {
- dev_dbg(cs35l56->dev, "Registers reset in suspend\n");
- regcache_mark_dirty(cs35l56->regmap);
+ dev_dbg(cs35l56->base.dev, "Registers reset in suspend\n");
+ regcache_mark_dirty(cs35l56->base.regmap);
}

- regcache_sync(cs35l56->regmap);
+ regcache_sync(cs35l56->base.regmap);

- dev_dbg(cs35l56->dev, "Resumed");
+ dev_dbg(cs35l56->base.dev, "Resumed");

return 0;

err:
- regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
CS35L56_MBOX_CMD_HIBERNATE_NOW);

- regcache_cache_only(cs35l56->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);

return ret;
}
@@ -1141,14 +1144,14 @@ static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56)
int ret;

/* Nothing to re-patch if we haven't done any patching yet. */
- if (!cs35l56->fw_patched)
+ if (!cs35l56->base.fw_patched)
return false;

/*
* If we have control of RESET we will have asserted it so the firmware
* will need re-patching.
*/
- if (cs35l56->reset_gpio)
+ if (cs35l56->base.reset_gpio)
return true;

/*
@@ -1156,22 +1159,22 @@ static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56)
* can't be used here to test for memory retention.
* Assume that tuning must be re-loaded.
*/
- if (cs35l56->secured)
+ if (cs35l56->base.secured)
return true;

- ret = pm_runtime_resume_and_get(cs35l56->dev);
+ ret = pm_runtime_resume_and_get(cs35l56->base.dev);
if (ret) {
- dev_err(cs35l56->dev, "Failed to runtime_get: %d\n", ret);
+ dev_err(cs35l56->base.dev, "Failed to runtime_get: %d\n", ret);
return ret;
}

- ret = regmap_read(cs35l56->regmap, CS35L56_PROTECTION_STATUS, &val);
+ ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &val);
if (ret)
- dev_err(cs35l56->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+ dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
else
ret = !!(val & CS35L56_FIRMWARE_MISSING);

- pm_runtime_put_autosuspend(cs35l56->dev);
+ pm_runtime_put_autosuspend(cs35l56->base.dev);

return ret;
}
@@ -1191,8 +1194,8 @@ int cs35l56_system_suspend(struct device *dev)
* clear it. Prevent this race by temporarily disabling the parent irq
* until we reach _no_irq.
*/
- if (cs35l56->irq)
- disable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);

return pm_runtime_force_suspend(dev);
}
@@ -1209,8 +1212,8 @@ int cs35l56_system_suspend_late(struct device *dev)
* RESET is usually shared by all amps so it must not be asserted until
* all driver instances have done their suspend() stage.
*/
- if (cs35l56->reset_gpio) {
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ if (cs35l56->base.reset_gpio) {
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
cs35l56_wait_min_reset_pulse();
}

@@ -1227,8 +1230,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev)
dev_dbg(dev, "system_suspend_no_irq\n");

/* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
- if (cs35l56->irq)
- enable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ enable_irq(cs35l56->base.irq);

return 0;
}
@@ -1247,8 +1250,8 @@ int cs35l56_system_resume_no_irq(struct device *dev)
* clear it, until it has fully resumed. Prevent this race by temporarily
* disabling the parent irq until we complete resume().
*/
- if (cs35l56->irq)
- disable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);

return 0;
}
@@ -1262,8 +1265,8 @@ int cs35l56_system_resume_early(struct device *dev)
dev_dbg(dev, "system_resume_early\n");

/* Ensure a spec-compliant RESET pulse. */
- if (cs35l56->reset_gpio) {
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ if (cs35l56->base.reset_gpio) {
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
cs35l56_wait_min_reset_pulse();
}

@@ -1275,7 +1278,7 @@ int cs35l56_system_resume_early(struct device *dev)
}

/* Release shared RESET before drivers start resume(). */
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);

return 0;
}
@@ -1290,8 +1293,8 @@ int cs35l56_system_resume(struct device *dev)

/* Undo pm_runtime_force_suspend() before re-enabling the irq */
ret = pm_runtime_force_resume(dev);
- if (cs35l56->irq)
- enable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ enable_irq(cs35l56->base.irq);

if (ret)
return ret;
@@ -1301,11 +1304,11 @@ int cs35l56_system_resume(struct device *dev)
return 0;

ret = cs35l56_is_fw_reload_needed(cs35l56);
- dev_dbg(cs35l56->dev, "fw_reload_needed: %d\n", ret);
+ dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
if (ret < 1)
return ret;

- cs35l56->fw_patched = false;
+ cs35l56->base.fw_patched = false;
queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);

/*
@@ -1334,8 +1337,8 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
dsp->cs_dsp.type = WMFW_HALO;
dsp->cs_dsp.rev = 0;
dsp->fw = 12;
- dsp->cs_dsp.dev = cs35l56->dev;
- dsp->cs_dsp.regmap = cs35l56->regmap;
+ dsp->cs_dsp.dev = cs35l56->base.dev;
+ dsp->cs_dsp.regmap = cs35l56->base.regmap;
dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE;
dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID;
dsp->cs_dsp.mem = cs35l56_dsp1_regions;
@@ -1343,11 +1346,11 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
dsp->cs_dsp.no_core_startstop = true;
dsp->wmfw_optional = true;

- dev_dbg(cs35l56->dev, "DSP system name: '%s'\n", dsp->system_name);
+ dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name);

ret = wm_halo_init(dsp);
if (ret != 0) {
- dev_err(cs35l56->dev, "wm_halo_init failed\n");
+ dev_err(cs35l56->base.dev, "wm_halo_init failed\n");
return ret;
}

@@ -1356,7 +1359,7 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)

static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56)
{
- acpi_handle handle = ACPI_HANDLE(cs35l56->dev);
+ acpi_handle handle = ACPI_HANDLE(cs35l56->base.dev);
const char *sub;

/* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
@@ -1373,7 +1376,7 @@ static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56)
}

cs35l56->dsp.system_name = sub;
- dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name);
+ dev_dbg(cs35l56->base.dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name);

return 0;
}
@@ -1383,38 +1386,39 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
int ret;

init_completion(&cs35l56->init_completion);
- mutex_init(&cs35l56->irq_lock);
+ mutex_init(&cs35l56->base.irq_lock);

- dev_set_drvdata(cs35l56->dev, cs35l56);
+ dev_set_drvdata(cs35l56->base.dev, cs35l56);

cs35l56_fill_supply_names(cs35l56->supplies);
- ret = devm_regulator_bulk_get(cs35l56->dev, ARRAY_SIZE(cs35l56->supplies),
+ ret = devm_regulator_bulk_get(cs35l56->base.dev, ARRAY_SIZE(cs35l56->supplies),
cs35l56->supplies);
if (ret != 0)
- return dev_err_probe(cs35l56->dev, ret, "Failed to request supplies\n");
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to request supplies\n");

/* Reset could be controlled by the BIOS or shared by multiple amps */
- cs35l56->reset_gpio = devm_gpiod_get_optional(cs35l56->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(cs35l56->reset_gpio)) {
- ret = PTR_ERR(cs35l56->reset_gpio);
+ cs35l56->base.reset_gpio = devm_gpiod_get_optional(cs35l56->base.dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cs35l56->base.reset_gpio)) {
+ ret = PTR_ERR(cs35l56->base.reset_gpio);
/*
* If RESET is shared the first amp to probe will grab the reset
* line and reset all the amps
*/
if (ret != -EBUSY)
- return dev_err_probe(cs35l56->dev, ret, "Failed to get reset GPIO\n");
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");

- dev_info(cs35l56->dev, "Reset GPIO busy, assume shared reset\n");
- cs35l56->reset_gpio = NULL;
+ dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
+ cs35l56->base.reset_gpio = NULL;
}

ret = regulator_bulk_enable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
if (ret != 0)
- return dev_err_probe(cs35l56->dev, ret, "Failed to enable supplies\n");
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n");

- if (cs35l56->reset_gpio) {
+ if (cs35l56->base.reset_gpio) {
cs35l56_wait_min_reset_pulse();
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
}

ret = cs35l56_acpi_get_name(cs35l56);
@@ -1423,22 +1427,22 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)

ret = cs35l56_dsp_init(cs35l56);
if (ret < 0) {
- dev_err_probe(cs35l56->dev, ret, "DSP init failed\n");
+ dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n");
goto err;
}

- ret = devm_snd_soc_register_component(cs35l56->dev,
+ ret = devm_snd_soc_register_component(cs35l56->base.dev,
&soc_component_dev_cs35l56,
cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
- dev_err_probe(cs35l56->dev, ret, "Register codec failed\n");
+ dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
goto err;
}

return 0;

err:
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);

return ret;
@@ -1457,20 +1461,20 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
if (cs35l56->soft_resetting)
goto post_soft_reset;

- if (cs35l56->init_done)
+ if (cs35l56->base.init_done)
return 0;

- pm_runtime_set_autosuspend_delay(cs35l56->dev, 100);
- pm_runtime_use_autosuspend(cs35l56->dev);
- pm_runtime_set_active(cs35l56->dev);
- pm_runtime_enable(cs35l56->dev);
+ pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 100);
+ pm_runtime_use_autosuspend(cs35l56->base.dev);
+ pm_runtime_set_active(cs35l56->base.dev);
+ pm_runtime_enable(cs35l56->base.dev);

/*
* If the system is not using a reset_gpio then issue a
* dummy read to force a wakeup.
*/
- if (!cs35l56->reset_gpio)
- regmap_read(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
+ if (!cs35l56->base.reset_gpio)
+ regmap_read(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);

/* Wait for control port to be ready (datasheet tIRS). */
usleep_range(CS35L56_CONTROL_PORT_READY_US,
@@ -1481,20 +1485,20 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
* devices so the REVID needs to be determined before waiting for the
* firmware to boot.
*/
- ret = regmap_read(cs35l56->regmap, CS35L56_REVID, &revid);
+ ret = regmap_read(cs35l56->base.regmap, CS35L56_REVID, &revid);
if (ret < 0) {
- dev_err(cs35l56->dev, "Get Revision ID failed\n");
+ dev_err(cs35l56->base.dev, "Get Revision ID failed\n");
return ret;
}
- cs35l56->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
+ cs35l56->base.rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);

- ret = cs35l56_wait_for_firmware_boot(cs35l56);
+ ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
if (ret)
return ret;

- ret = regmap_read(cs35l56->regmap, CS35L56_DEVID, &devid);
+ ret = regmap_read(cs35l56->base.regmap, CS35L56_DEVID, &devid);
if (ret < 0) {
- dev_err(cs35l56->dev, "Get Device ID failed\n");
+ dev_err(cs35l56->base.dev, "Get Device ID failed\n");
return ret;
}
devid &= CS35L56_DEVID_MASK;
@@ -1503,50 +1507,50 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
case 0x35A56:
break;
default:
- dev_err(cs35l56->dev, "Unknown device %x\n", devid);
+ dev_err(cs35l56->base.dev, "Unknown device %x\n", devid);
return ret;
}

- ret = regmap_read(cs35l56->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
+ ret = regmap_read(cs35l56->base.regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
if (ret) {
- dev_err(cs35l56->dev, "Get Secure status failed\n");
+ dev_err(cs35l56->base.dev, "Get Secure status failed\n");
return ret;
}

/* When any bus is restricted treat the device as secured */
if (secured & CS35L56_RESTRICTED_MASK)
- cs35l56->secured = true;
+ cs35l56->base.secured = true;

- ret = regmap_read(cs35l56->regmap, CS35L56_OTPID, &otpid);
+ ret = regmap_read(cs35l56->base.regmap, CS35L56_OTPID, &otpid);
if (ret < 0) {
- dev_err(cs35l56->dev, "Get OTP ID failed\n");
+ dev_err(cs35l56->base.dev, "Get OTP ID failed\n");
return ret;
}

- dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
- cs35l56->secured ? "s" : "", cs35l56->rev, otpid);
+ dev_info(cs35l56->base.dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
+ cs35l56->base.secured ? "s" : "", cs35l56->base.rev, otpid);

/* Populate the DSP information with the revision and security state */
- cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x",
- cs35l56->secured ? "s" : "", cs35l56->rev);
+ cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x",
+ cs35l56->base.secured ? "s" : "", cs35l56->base.rev);
if (!cs35l56->dsp.part)
return -ENOMEM;

/* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
- regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1,
+ regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_1,
CS35L56_AMP_SHORT_ERR_EINT1_MASK,
0);
- regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_8,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_8,
CS35L56_TEMP_ERR_EINT1_MASK,
0);

- if (!cs35l56->reset_gpio) {
- dev_dbg(cs35l56->dev, "No reset gpio: using soft reset\n");
+ if (!cs35l56->base.reset_gpio) {
+ dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
cs35l56_system_reset(cs35l56);
if (cs35l56->sdw_peripheral) {
/* Keep alive while we wait for re-enumeration */
- pm_runtime_get_noresume(cs35l56->dev);
+ pm_runtime_get_noresume(cs35l56->base.dev);
return 0;
}
}
@@ -1556,30 +1560,30 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
cs35l56->soft_resetting = false;

/* Done re-enumerating after one-time init so release the keep-alive */
- if (cs35l56->sdw_peripheral && !cs35l56->init_done)
- pm_runtime_put_noidle(cs35l56->dev);
+ if (cs35l56->sdw_peripheral && !cs35l56->base.init_done)
+ pm_runtime_put_noidle(cs35l56->base.dev);

- regcache_mark_dirty(cs35l56->regmap);
- ret = cs35l56_wait_for_firmware_boot(cs35l56);
+ regcache_mark_dirty(cs35l56->base.regmap);
+ ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
if (ret)
return ret;

- dev_dbg(cs35l56->dev, "Firmware rebooted after soft reset\n");
+ dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n");
}

/* Disable auto-hibernate so that runtime_pm has control */
- ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
if (ret)
return ret;

- ret = cs35l56_set_patch(cs35l56->regmap);
+ ret = cs35l56_set_patch(&cs35l56->base);
if (ret)
return ret;

/* Registers could be dirty after soft reset or SoundWire enumeration */
- regcache_sync(cs35l56->regmap);
+ regcache_sync(cs35l56->base.regmap);

- cs35l56->init_done = true;
+ cs35l56->base.init_done = true;
complete(&cs35l56->init_completion);

return 0;
@@ -1588,26 +1592,26 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE);

void cs35l56_remove(struct cs35l56_private *cs35l56)
{
- cs35l56->init_done = false;
+ cs35l56->base.init_done = false;

/*
* WAKE IRQs unmask if CS35L56 hibernates so free the handler to
* prevent it racing with remove().
*/
- if (cs35l56->irq)
- devm_free_irq(cs35l56->dev, cs35l56->irq, cs35l56);
+ if (cs35l56->base.irq)
+ devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base);

flush_workqueue(cs35l56->dsp_wq);
destroy_workqueue(cs35l56->dsp_wq);

- pm_runtime_suspend(cs35l56->dev);
- pm_runtime_disable(cs35l56->dev);
+ pm_runtime_suspend(cs35l56->base.dev);
+ pm_runtime_disable(cs35l56->base.dev);

- regcache_cache_only(cs35l56->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);

kfree(cs35l56->dsp.system_name);

- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
}
EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE);
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index 1f7894662fcb..f39f8fa9e37e 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -32,26 +32,17 @@ struct sdw_slave;

struct cs35l56_private {
struct wm_adsp dsp; /* must be first member */
+ struct cs35l56_base base;
struct work_struct dsp_work;
struct workqueue_struct *dsp_wq;
- struct mutex irq_lock;
struct snd_soc_component *component;
- struct device *dev;
- struct regmap *regmap;
struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
- int irq;
struct sdw_slave *sdw_peripheral;
- u8 rev;
struct work_struct sdw_irq_work;
- bool secured;
bool sdw_irq_no_unmask;
bool soft_resetting;
- bool init_done;
bool sdw_attached;
- bool fw_patched;
- bool can_hibernate;
struct completion init_completion;
- struct gpio_desc *reset_gpio;

u32 rx_mask;
u32 tx_mask;
@@ -73,7 +64,7 @@ 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 irq);
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
int cs35l56_common_probe(struct cs35l56_private *cs35l56);
int cs35l56_init(struct cs35l56_private *cs35l56);
void cs35l56_remove(struct cs35l56_private *cs35l56);
--
2.30.2


2023-07-21 13:59:08

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 07/11] ASoC: cs35l56: Move part of cs35l56_init() to shared library

Part of the initialization code in cs35l56_init() can be re-used
by the HDA driver so move it into a new function in the shared
library.

Signed-off-by: Richard Fitzgerald <[email protected]>
Acked-by: Mark Brown <[email protected]>
---
include/sound/cs35l56.h | 1 +
sound/soc/codecs/cs35l56-shared.c | 79 +++++++++++++++++++++++++++++++
sound/soc/codecs/cs35l56.c | 71 +--------------------------
3 files changed, 82 insertions(+), 69 deletions(-)

diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 6ab12e2035cd..0d6cdfb6107b 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -283,6 +283,7 @@ 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);
void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
+int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
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-shared.c b/sound/soc/codecs/cs35l56-shared.c
index fe8df04951f3..8a98070ece5e 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -544,6 +544,85 @@ void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_ds
}
EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED);

+int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
+{
+ int ret;
+ unsigned int devid, revid, otpid, secured;
+
+ /*
+ * If the system is not using a reset_gpio then issue a
+ * dummy read to force a wakeup.
+ */
+ if (!cs35l56_base->reset_gpio)
+ regmap_read(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
+
+ /* Wait for control port to be ready (datasheet tIRS). */
+ usleep_range(CS35L56_CONTROL_PORT_READY_US,
+ CS35L56_CONTROL_PORT_READY_US + 400);
+
+ /*
+ * The HALO_STATE register is in different locations on Ax and B0
+ * devices so the REVID needs to be determined before waiting for the
+ * firmware to boot.
+ */
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_REVID, &revid);
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Get Revision ID failed\n");
+ return ret;
+ }
+ cs35l56_base->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
+
+ ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_DEVID, &devid);
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Get Device ID failed\n");
+ return ret;
+ }
+ devid &= CS35L56_DEVID_MASK;
+
+ switch (devid) {
+ case 0x35A56:
+ break;
+ default:
+ dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
+ return ret;
+ }
+
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Get Secure status failed\n");
+ return ret;
+ }
+
+ /* When any bus is restricted treat the device as secured */
+ if (secured & CS35L56_RESTRICTED_MASK)
+ cs35l56_base->secured = true;
+
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_OTPID, &otpid);
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Get OTP ID failed\n");
+ return ret;
+ }
+
+ dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
+ cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid);
+
+ /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+ regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1,
+ CS35L56_AMP_SHORT_ERR_EINT1_MASK,
+ 0);
+ regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8,
+ CS35L56_TEMP_ERR_EINT1_MASK,
+ 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
+
static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = {
[0x0C] = 128000,
[0x0F] = 256000,
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 430829f8a320..d06b83dfc462 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -1127,7 +1127,6 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE);
int cs35l56_init(struct cs35l56_private *cs35l56)
{
int ret;
- unsigned int devid, revid, otpid, secured;

/*
* Check whether the actions associated with soft reset or one time
@@ -1144,66 +1143,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
pm_runtime_set_active(cs35l56->base.dev);
pm_runtime_enable(cs35l56->base.dev);

- /*
- * If the system is not using a reset_gpio then issue a
- * dummy read to force a wakeup.
- */
- if (!cs35l56->base.reset_gpio)
- regmap_read(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
-
- /* Wait for control port to be ready (datasheet tIRS). */
- usleep_range(CS35L56_CONTROL_PORT_READY_US,
- CS35L56_CONTROL_PORT_READY_US + 400);
-
- /*
- * The HALO_STATE register is in different locations on Ax and B0
- * devices so the REVID needs to be determined before waiting for the
- * firmware to boot.
- */
- ret = regmap_read(cs35l56->base.regmap, CS35L56_REVID, &revid);
- if (ret < 0) {
- dev_err(cs35l56->base.dev, "Get Revision ID failed\n");
+ ret = cs35l56_hw_init(&cs35l56->base);
+ if (ret < 0)
return ret;
- }
- cs35l56->base.rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
-
- ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
- if (ret)
- return ret;
-
- ret = regmap_read(cs35l56->base.regmap, CS35L56_DEVID, &devid);
- if (ret < 0) {
- dev_err(cs35l56->base.dev, "Get Device ID failed\n");
- return ret;
- }
- devid &= CS35L56_DEVID_MASK;
-
- switch (devid) {
- case 0x35A56:
- break;
- default:
- dev_err(cs35l56->base.dev, "Unknown device %x\n", devid);
- return ret;
- }
-
- ret = regmap_read(cs35l56->base.regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
- if (ret) {
- dev_err(cs35l56->base.dev, "Get Secure status failed\n");
- return ret;
- }
-
- /* When any bus is restricted treat the device as secured */
- if (secured & CS35L56_RESTRICTED_MASK)
- cs35l56->base.secured = true;
-
- ret = regmap_read(cs35l56->base.regmap, CS35L56_OTPID, &otpid);
- if (ret < 0) {
- dev_err(cs35l56->base.dev, "Get OTP ID failed\n");
- return ret;
- }
-
- dev_info(cs35l56->base.dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
- cs35l56->base.secured ? "s" : "", cs35l56->base.rev, otpid);

/* Populate the DSP information with the revision and security state */
cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x",
@@ -1211,15 +1153,6 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
if (!cs35l56->dsp.part)
return -ENOMEM;

- /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
- regmap_write(cs35l56->base.regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
- regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_1,
- CS35L56_AMP_SHORT_ERR_EINT1_MASK,
- 0);
- regmap_update_bits(cs35l56->base.regmap, CS35L56_IRQ1_MASK_8,
- CS35L56_TEMP_ERR_EINT1_MASK,
- 0);
-
if (!cs35l56->base.reset_gpio) {
dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
cs35l56->soft_resetting = true;
--
2.30.2


2023-07-21 14:05:11

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 05/11] ASoC: cs35l56: Move runtime suspend/resume to shared library

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 <[email protected]>
Acked-by: Mark Brown <[email protected]>
---
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 3d2875094a21..e48f662dcbce 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 98be005b8787..b433266b7844 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 d22aede1ee8d..737a9ea27495 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -403,6 +403,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 5598000187a7..701f1072a609 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -849,132 +849,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);
@@ -1414,7 +1302,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


2023-07-21 14:07:47

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 02/11] ASoC: cs35l56: Make cs35l56_system_reset() code more generic

From: Simon Trimmer <[email protected]>

The function can be more easily reused in HDA if the tracking of whether
a soft reset is being performed and whether the device is connected to a
SoundWire bus is moved out of the function.

Signed-off-by: Simon Trimmer <[email protected]>
Signed-off-by: Richard Fitzgerald <[email protected]>
Acked-by: Mark Brown <[email protected]>
---
sound/soc/codecs/cs35l56.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 4eb8e5b09bfd..7a83e388e869 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -802,10 +802,8 @@ static const struct reg_sequence cs35l56_system_reset_seq[] = {
REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
};

-static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
+static void cs35l56_system_reset(struct cs35l56_private *cs35l56, bool is_soundwire)
{
- cs35l56->soft_resetting = true;
-
/*
* Must enter cache-only first so there can't be any more register
* accesses other than the controlled system reset sequence below.
@@ -816,7 +814,7 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
ARRAY_SIZE(cs35l56_system_reset_seq));

/* On SoundWire the registers won't be accessible until it re-enumerates. */
- if (cs35l56->sdw_peripheral)
+ if (is_soundwire)
return;

usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
@@ -883,7 +881,8 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)

init_completion(&cs35l56->init_completion);

- cs35l56_system_reset(cs35l56);
+ cs35l56->soft_resetting = true;
+ cs35l56_system_reset(cs35l56, !!cs35l56->sdw_peripheral);

if (cs35l56->sdw_peripheral) {
/*
@@ -1547,7 +1546,8 @@ int cs35l56_init(struct cs35l56_private *cs35l56)

if (!cs35l56->base.reset_gpio) {
dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
- cs35l56_system_reset(cs35l56);
+ cs35l56->soft_resetting = true;
+ cs35l56_system_reset(cs35l56, !!cs35l56->sdw_peripheral);
if (cs35l56->sdw_peripheral) {
/* Keep alive while we wait for re-enumeration */
pm_runtime_get_noresume(cs35l56->base.dev);
--
2.30.2


2023-07-21 14:09:02

by Richard Fitzgerald

[permalink] [raw]
Subject: [PATCH v5 09/11] ASoC: cs35l56: Make a common function to shutdown the DSP

From: Simon Trimmer <[email protected]>

Move issuing of a CS35L56_MBOX_CMD_SHUTDOWN command and then waiting for
the DSP to reach CS35L56_HALO_STATE_SHUTDOWN in the register appropriate
for the hardware revision into a common function.

Signed-off-by: Simon Trimmer <[email protected]>
Signed-off-by: Richard Fitzgerald <[email protected]>
Acked-by: Mark Brown <[email protected]>
---
include/sound/cs35l56.h | 1 +
sound/soc/codecs/cs35l56-shared.c | 26 ++++++++++++++++++++++++++
sound/soc/codecs/cs35l56.c | 17 +----------------
3 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 79e117abee06..3950322bf3cb 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -274,6 +274,7 @@ extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];

int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
+int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);
void cs35l56_wait_control_port_ready(void);
void cs35l56_wait_min_reset_pulse(void);
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 4e3becb9581d..ae373f335ea8 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -213,6 +213,32 @@ int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);

+int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
+{
+ int ret;
+ unsigned int reg;
+ unsigned int val;
+
+ ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN);
+ if (ret)
+ return ret;
+
+ if (cs35l56_base->rev < CS35L56_REVID_B0)
+ reg = CS35L56_DSP1_PM_CUR_STATE_A1;
+ else
+ reg = CS35L56_DSP1_PM_CUR_STATE;
+
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
+ val, (val == CS35L56_HALO_STATE_SHUTDOWN),
+ CS35L56_HALO_STATE_POLL_US,
+ CS35L56_HALO_STATE_TIMEOUT_US);
+ if (ret < 0)
+ dev_err(cs35l56_base->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
+ val, ret);
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED);
+
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
{
unsigned int reg;
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index d06b83dfc462..19b6b4fbe5de 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -673,8 +673,6 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)

static void cs35l56_patch(struct cs35l56_private *cs35l56)
{
- unsigned int reg;
- unsigned int val;
int ret;

/*
@@ -691,23 +689,10 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
flush_work(&cs35l56->sdw_irq_work);
}

- ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_SHUTDOWN);
+ ret = cs35l56_firmware_shutdown(&cs35l56->base);
if (ret)
goto err;

- if (cs35l56->base.rev < CS35L56_REVID_B0)
- reg = CS35L56_DSP1_PM_CUR_STATE_A1;
- else
- reg = CS35L56_DSP1_PM_CUR_STATE;
-
- ret = regmap_read_poll_timeout(cs35l56->base.regmap, reg,
- val, (val == CS35L56_HALO_STATE_SHUTDOWN),
- CS35L56_HALO_STATE_POLL_US,
- CS35L56_HALO_STATE_TIMEOUT_US);
- if (ret < 0)
- dev_err(cs35l56->base.dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
- val, ret);
-
/* Use wm_adsp to load and apply the firmware patch and coefficient files */
ret = wm_adsp_power_up(&cs35l56->dsp);
if (ret) {
--
2.30.2


2023-07-21 15:09:15

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

On Fri, 21 Jul 2023 15:21:09 +0200,
Richard Fitzgerald wrote:
>
> This set of patches adds support for using the CS35L56 boosted smart
> amplifier on HDA systems. In these systems the CS35L56 audio is
> routed through a HDA-to-I2S bridge codec.
>
> This doesn't include the changes to the Realtek driver to actually hook
> up the CS35L56 driver, because we don't yet have the QUIRK IDs to
> associate it with. But we want to publish the driver now so that it is
> available for bringing up hardware with the CS35L56.
>
> The first 9 patches are moving code out of the ASoC driver and into the
> shared library so that it can be shared with the HDA driver.
>
> Patch #10 fixes missing #includes in the HDA headers so that the CS35L56
> driver doesn't have to #include headers that it doesn't use.
>
> CHANGES SINCE V5
> The series has been rebased onto commit df4167d658d4
> ("ASoC: cs35l56: Patch soft registers to defaults"), which removes
> cs35l56_reread_firmware_registers() and adds cs35l56_set_patch().
>
> Changes are trivial so I have carried forward Mark's and Takashi's acks.

Mark, I suppose it's fine to take all of those to my sound.git tree?


Takashi

2023-07-21 15:10:06

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

On Fri, Jul 21, 2023 at 04:50:35PM +0200, Takashi Iwai wrote:
> Richard Fitzgerald wrote:

> > Changes are trivial so I have carried forward Mark's and Takashi's acks.

> Mark, I suppose it's fine to take all of those to my sound.git tree?

Should be. Might be handy to have a branch to pull from in case of
conflicts I guess but probably not essential?


Attachments:
(No filename) (364.00 B)
signature.asc (499.00 B)
Download all attachments

2023-07-21 15:22:50

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

On Fri, 21 Jul 2023 16:52:52 +0200,
Mark Brown wrote:
>
> On Fri, Jul 21, 2023 at 04:50:35PM +0200, Takashi Iwai wrote:
> > Richard Fitzgerald wrote:
>
> > > Changes are trivial so I have carried forward Mark's and Takashi's acks.
>
> > Mark, I suppose it's fine to take all of those to my sound.git tree?
>
> Should be. Might be handy to have a branch to pull from in case of
> conflicts I guess but probably not essential?

That's fine, I'll put a signed tag.


thanks,

Takashi

2023-07-21 17:06:52

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

On Fri, 21 Jul 2023 17:04:33 +0200,
Takashi Iwai wrote:
>
> On Fri, 21 Jul 2023 16:52:52 +0200,
> Mark Brown wrote:
> >
> > On Fri, Jul 21, 2023 at 04:50:35PM +0200, Takashi Iwai wrote:
> > > Richard Fitzgerald wrote:
> >
> > > > Changes are trivial so I have carried forward Mark's and Takashi's acks.
> >
> > > Mark, I suppose it's fine to take all of those to my sound.git tree?
> >
> > Should be. Might be handy to have a branch to pull from in case of
> > conflicts I guess but probably not essential?
>
> That's fine, I'll put a signed tag.

... and it turned out that it's not cleanly applicable, presumably
it's based on some more stuff of the latest asoc.

So, Mark, feel free to apply through yours.


Takashi

2023-07-24 18:55:29

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

On Fri, 21 Jul 2023 14:21:09 +0100, Richard Fitzgerald wrote:
> This set of patches adds support for using the CS35L56 boosted smart
> amplifier on HDA systems. In these systems the CS35L56 audio is
> routed through a HDA-to-I2S bridge codec.
>
> This doesn't include the changes to the Realtek driver to actually hook
> up the CS35L56 driver, because we don't yet have the QUIRK IDs to
> associate it with. But we want to publish the driver now so that it is
> available for bringing up hardware with the CS35L56.
>
> [...]

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[01/11] ASoC: cs35l56: Move shared data into a common data structure
commit: 898673b905b9318489430663083f629bc38c7461
[02/11] ASoC: cs35l56: Make cs35l56_system_reset() code more generic
commit: cf6e7486de80b680fe178a6517dd7c4166a12dbc
[03/11] ASoC: cs35l56: Convert utility functions to use common data structure
commit: 0a2e49230f7f1796aa79c532426d56e8739ee4b1
[04/11] ASoC: cs35l56: Move utility functions to shared file
commit: 8a731fd37f8b33026e545f5ee5cdd7b9a837cbeb
[05/11] ASoC: cs35l56: Move runtime suspend/resume to shared library
commit: 9974d5b57697770cba2a99c6fe925d01152cd544
[06/11] ASoC: cs35l56: Move cs_dsp init into shared library
commit: 22e51dbb257a218e43de42764b5bdc5302f27cd1
[07/11] ASoC: cs35l56: Move part of cs35l56_init() to shared library
commit: 84851aa055c890f2ea731a128e8feb64520c2c8e
[08/11] ASoC: cs35l56: Make common function for control port wait
commit: f32a2bcbc092d60ba8a1b00a22607b220d53a25e
[09/11] ASoC: cs35l56: Make a common function to shutdown the DSP
commit: 444dfa0912639fb2431553e8e54d2b35fdf590c2
[10/11] ALSA: hda: Fix missing header dependencies
commit: 64e05321506261b737abdbfc7a82144f30d0a925
[11/11] ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier
commit: 73cfbfa9caea8eda54b4c6e49a9555533660aa1e

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark


2023-07-25 10:54:19

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] ALSA: hda: Adding support for CS35L56 on HDA systems

On Mon, 24 Jul 2023 20:28:08 +0200,
Mark Brown wrote:
>
> On Fri, 21 Jul 2023 14:21:09 +0100, Richard Fitzgerald wrote:
> > This set of patches adds support for using the CS35L56 boosted smart
> > amplifier on HDA systems. In these systems the CS35L56 audio is
> > routed through a HDA-to-I2S bridge codec.
> >
> > This doesn't include the changes to the Realtek driver to actually hook
> > up the CS35L56 driver, because we don't yet have the QUIRK IDs to
> > associate it with. But we want to publish the driver now so that it is
> > available for bringing up hardware with the CS35L56.
> >
> > [...]
>
> Applied to
>
> https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Mark, could you send an earlier PR including this?
Otherwise we'll be in a messy situation when applying further
conflicting patches like TAS HD-audio codec patches.


thanks,

Takashi