* [PATCH 1/2] ASoC: cs35l56: Only write ASP1TXn registers when widget is powered-up
2026-11-13 11:29 [PATCH 0/2] ASoC: cs35l56: Series to stop writing ASP registers the driver doesn't own Richard Fitzgerald
@ 2026-11-13 11:29 ` Richard Fitzgerald
2026-11-13 11:29 ` [PATCH 2/2] ASoC: cs35l56: Fix unwanted writes to ASP config registers Richard Fitzgerald
1 sibling, 0 replies; 3+ messages in thread
From: Richard Fitzgerald @ 2026-11-13 11:29 UTC (permalink / raw)
To: broonie; +Cc: linux-sound, linux-kernel, patches
Cache the value written to the "ASP1 TXn Source" controls and write them
to registers only when the widget is powered-up. Remove them from the
regmap defaults table so regmap won't write them during a regcache_sync().
The ASP registers have multiple ownership, depending on the hardware
design. They can be owned by the firmware, or by a MCU on a secondary
control interface, or by the driver. If the driver doesn't own control
of the ASP it must not overwrite the registers.
ALSA control read/write now goes to cached values in struct
cs35l56_private. The values are written out if the widget powers up,
which can only happen if the machine driver has connected the ASP DAI in
a DAIlink. If the control value is changed while the widget is powered
the change will be deferred until the next widget power-up. Changing
the hardware mux on-the-fly while active is not supported.
Fixes: 9351cf3fd92dc ("ASoC: cs35l56: Only patch ASP registers if the DAI is part of a DAIlink")
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
---
sound/soc/codecs/cs35l56-shared.c | 12 ----
sound/soc/codecs/cs35l56.c | 104 ++++++++++++++++++++++++------
sound/soc/codecs/cs35l56.h | 1 +
3 files changed, 86 insertions(+), 31 deletions(-)
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index b37f65cd4d33..c44bf8bc4e0c 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -39,10 +39,6 @@ static const struct reg_sequence cs35l56_asp_patch[] = {
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
- { CS35L56_ASP1TX1_INPUT, 0x00000000 },
- { CS35L56_ASP1TX2_INPUT, 0x00000000 },
- { CS35L56_ASP1TX3_INPUT, 0x00000000 },
- { CS35L56_ASP1TX4_INPUT, 0x00000000 },
};
int cs35l56_set_asp_patch(struct cs35l56_base *cs35l56_base)
@@ -117,10 +113,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
- { CS35L56_ASP1TX1_INPUT, 0x00000000 },
- { CS35L56_ASP1TX2_INPUT, 0x00000000 },
- { CS35L56_ASP1TX3_INPUT, 0x00000000 },
- { CS35L56_ASP1TX4_INPUT, 0x00000000 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
@@ -145,10 +137,6 @@ static const struct reg_default cs35l63_reg_defaults[] = {
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
- { CS35L56_ASP1TX1_INPUT, 0x00000000 },
- { CS35L56_ASP1TX2_INPUT, 0x00000000 },
- { CS35L56_ASP1TX3_INPUT, 0x00000000 },
- { CS35L56_ASP1TX4_INPUT, 0x00000000 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index a4d25c287941..852491f8340b 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -178,41 +178,91 @@ static const struct snd_kcontrol_new cs35l63_controls[] = {
SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
};
+static int cs35l56_asp_tx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ucontrol->value.enumerated.item[0] =
+ snd_soc_enum_val_to_item(e, cs35l56->asp_tx_input[e->shift_l]);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return 0;
+}
+
+static int cs35l56_asp_tx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int item = ucontrol->value.enumerated.item[0];
+ unsigned int val;
+ bool change = false;
+
+ if (item >= e->items)
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ if (cs35l56->asp_tx_input[e->shift_l] != val)
+ change = true;
+
+ cs35l56->asp_tx_input[e->shift_l] = val;
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ if (change)
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
+
+ return change;
+}
+
+/* The shift field of each virtual enum holds the ASP TX channel index. */
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
- CS35L56_ASP1TX1_INPUT,
+ SND_SOC_NOPM,
0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx1_mux =
- SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum);
+ SOC_DAPM_ENUM_EXT("ASP1TX1 SRC", cs35l56_asp1tx1_enum,
+ cs35l56_asp_tx_get, cs35l56_asp_tx_put);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum,
- CS35L56_ASP1TX2_INPUT,
- 0, CS35L56_ASP_TXn_SRC_MASK,
+ SND_SOC_NOPM,
+ 1, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx2_mux =
- SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum);
+ SOC_DAPM_ENUM_EXT("ASP1TX2 SRC", cs35l56_asp1tx2_enum,
+ cs35l56_asp_tx_get, cs35l56_asp_tx_put);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum,
- CS35L56_ASP1TX3_INPUT,
- 0, CS35L56_ASP_TXn_SRC_MASK,
+ SND_SOC_NOPM,
+ 2, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx3_mux =
- SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum);
+ SOC_DAPM_ENUM_EXT("ASP1TX3 SRC", cs35l56_asp1tx3_enum,
+ cs35l56_asp_tx_get, cs35l56_asp_tx_put);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum,
- CS35L56_ASP1TX4_INPUT,
- 0, CS35L56_ASP_TXn_SRC_MASK,
+ SND_SOC_NOPM,
+ 3, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx4_mux =
- SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum);
+ SOC_DAPM_ENUM_EXT("ASP1TX4 SRC", cs35l56_asp1tx4_enum,
+ cs35l56_asp_tx_get, cs35l56_asp_tx_put);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum,
CS35L56_SWIRE_DP3_CH1_INPUT,
@@ -282,6 +332,16 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
}
}
+static int cs35l56_asp_tx_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+ return regmap_write(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT + (4 * w->shift),
+ cs35l56->asp_tx_input[w->shift]);
+}
+
static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0),
@@ -299,14 +359,18 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
CS35L56_ASP_RX1_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASP1RX2", NULL, 1, CS35L56_ASP1_ENABLES1,
CS35L56_ASP_RX2_EN_SHIFT, 0),
- SND_SOC_DAPM_AIF_OUT("ASP1TX1", NULL, 0, CS35L56_ASP1_ENABLES1,
- CS35L56_ASP_TX1_EN_SHIFT, 0),
- SND_SOC_DAPM_AIF_OUT("ASP1TX2", NULL, 1, CS35L56_ASP1_ENABLES1,
- CS35L56_ASP_TX2_EN_SHIFT, 0),
- SND_SOC_DAPM_AIF_OUT("ASP1TX3", NULL, 2, CS35L56_ASP1_ENABLES1,
- CS35L56_ASP_TX3_EN_SHIFT, 0),
- SND_SOC_DAPM_AIF_OUT("ASP1TX4", NULL, 3, CS35L56_ASP1_ENABLES1,
- CS35L56_ASP_TX4_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX1", NULL, 0, CS35L56_ASP1_ENABLES1,
+ CS35L56_ASP_TX1_EN_SHIFT, 0,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX2", NULL, 1, CS35L56_ASP1_ENABLES1,
+ CS35L56_ASP_TX2_EN_SHIFT, 0,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX3", NULL, 2, CS35L56_ASP1_ENABLES1,
+ CS35L56_ASP_TX3_EN_SHIFT, 0,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX4", NULL, 3, CS35L56_ASP1_ENABLES1,
+ CS35L56_ASP_TX4_EN_SHIFT, 0,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("ASP1 TX1 Source", SND_SOC_NOPM, 0, 0, &asp1_tx1_mux),
SND_SOC_DAPM_MUX("ASP1 TX2 Source", SND_SOC_NOPM, 0, 0, &asp1_tx2_mux),
@@ -1438,6 +1502,8 @@ static int _cs35l56_component_probe(struct snd_soc_component *component)
BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values));
+ memset(&cs35l56->asp_tx_input, 0, sizeof(cs35l56->asp_tx_input));
+
cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type);
if (!cs35l56->dsp.part)
return -ENOMEM;
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index b46f410f0e09..020bee21c806 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -49,6 +49,7 @@ struct cs35l56_private {
int speaker_id;
u32 rx_mask;
u32 tx_mask;
+ u8 asp_tx_input[4];
u8 asp_slot_width;
u8 asp_slot_count;
bool tdm_mode;
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] ASoC: cs35l56: Fix unwanted writes to ASP config registers
2026-11-13 11:29 [PATCH 0/2] ASoC: cs35l56: Series to stop writing ASP registers the driver doesn't own Richard Fitzgerald
2026-11-13 11:29 ` [PATCH 1/2] ASoC: cs35l56: Only write ASP1TXn registers when widget is powered-up Richard Fitzgerald
@ 2026-11-13 11:29 ` Richard Fitzgerald
1 sibling, 0 replies; 3+ messages in thread
From: Richard Fitzgerald @ 2026-11-13 11:29 UTC (permalink / raw)
To: broonie; +Cc: linux-sound, linux-kernel, patches
Remove the ASP config registers from the regmap defaults table and use
regmap_multi_reg_write() instead of regmap_register_patch() to write
default values. Use custom event handlers for the ASP1 widgets so
ASP1_ENABLES1 is only written if the ASP is used. Move the HIZ mode
write to ASP1_CONTROL3 into the register sequence instead of writing
it on every driver probe.
This is to prevent accidentally writing to these registers when the driver
does not own them.
The ASP config registers have multiple ownership. They can be owned and
written by the firmware on SKUs that use the ASP as a chip-to-chip audio
interface managed by the firmware. They can be owned and written by an MCU
through one of the other control ports. Or they can be owned by the ASoC
codec driver if they are used for the CPU->amp audio. Because of this
multiple ownership the codec driver must not write the registers if it
doesn't own control of the ASP.
Commit 9351cf3fd92dc ("ASoC: cs35l56: Only patch ASP registers if the DAI
is part of a DAIlink") attempted to deal with this by only writing default
values into the cache if the dai probe() callback was called (which only
happens when the DAI is part of a dailink). The intention was that the
cache values would only be populated if the driver owns the DAI. But this
commit was flawed in three ways:
1. A regcache_sync() without a regcache_mark_dirty() would write the
registers.
The cs35l56/57/62/63 amps are designed to preserve state across suspend
states, so the registers have not necessarily reset when the driver
resumes. For this reason the driver may call regcache_sync() without
regcache_mark_dirty() to sync any changes made while in cache-only.
Regmap pre-populates the cache from the values in the defaults table. So
the cache always contained values for these registers. The regmap cache
doesn't have a per-register dirty flag, only a global dirty. It will write
out everything in the cache if it is dirty. Filtering of cache values that
are at default only happens if regcache_mark_dirty() has been called. So
the ASP config registers were being written for every non-default cache
sync.
2. regmap_register_patch() writes to hardware
The intent was to populate the cache. But regmap_register_patch() disables
cache-only and tries to write the patch to hardware. The DAI probe() can
be called while in runtime-suspend with the hardware not accessible, so
this could fail. There is no need to write the registers to hardware at
this time, the only need is to populate the cache so that the register
settings can be accumulated in the cache as the DAI is configured.
3. ASP1_ENABLES1 was read into the cache during widget initialization
The ASP1 RX and TX widgets provided the address of ASP1_ENABLES1 for ASoC
to manage. But during widget initialization ASoC reads the initial value
of the registers. This meant that the cache was populated with a value
for ASP1_ENABLES1, so that would be written out by regcache_sync().
Fixes: 9351cf3fd92dc ("ASoC: cs35l56: Only patch ASP registers if the DAI is part of a DAIlink")
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
---
include/sound/cs35l56.h | 2 +-
sound/soc/codecs/cs35l56-shared.c | 26 +++----------
sound/soc/codecs/cs35l56.c | 63 ++++++++++++++++++++-----------
3 files changed, 48 insertions(+), 43 deletions(-)
diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index e1b098d1d146..362dfa2761bc 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -412,7 +412,7 @@ extern const char * const cs35l56_cal_set_status_text[3];
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_asp_patch(struct cs35l56_base *cs35l56_base);
+int cs35l56_set_asp_defaults(struct cs35l56_base *cs35l56_base);
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);
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index c44bf8bc4e0c..4d76f1777927 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -34,19 +34,19 @@ static const struct reg_sequence cs35l56_asp_patch[] = {
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
- { CS35L56_ASP1_CONTROL3, 0x00000002 },
+ { CS35L56_ASP1_CONTROL3, 0x00000003 },
{ CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
};
-int cs35l56_set_asp_patch(struct cs35l56_base *cs35l56_base)
+int cs35l56_set_asp_defaults(struct cs35l56_base *cs35l56_base)
{
- return regmap_register_patch(cs35l56_base->regmap, cs35l56_asp_patch,
- ARRAY_SIZE(cs35l56_asp_patch));
+ return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp_patch,
+ ARRAY_SIZE(cs35l56_asp_patch));
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_set_asp_patch, "SND_SOC_CS35L56_SHARED");
+EXPORT_SYMBOL_NS_GPL(cs35l56_set_asp_defaults, "SND_SOC_CS35L56_SHARED");
static const struct reg_sequence cs35l56_patch[] = {
/*
@@ -105,14 +105,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED");
static const struct reg_default cs35l56_reg_defaults[] = {
- { CS35L56_ASP1_ENABLES1, 0x00000000 },
- { CS35L56_ASP1_CONTROL1, 0x00000028 },
- { CS35L56_ASP1_CONTROL2, 0x18180200 },
- { CS35L56_ASP1_CONTROL3, 0x00000002 },
- { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
- { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
- { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
- { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
@@ -129,14 +121,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
};
static const struct reg_default cs35l63_reg_defaults[] = {
- { CS35L56_ASP1_ENABLES1, 0x00000000 },
- { CS35L56_ASP1_CONTROL1, 0x00000028 },
- { CS35L56_ASP1_CONTROL2, 0x18180200 },
- { CS35L56_ASP1_CONTROL3, 0x00000002 },
- { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
- { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
- { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
- { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 852491f8340b..ded8d1cdfd24 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -332,14 +332,38 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
}
}
+static int cs35l56_asp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+ return regmap_assign_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+ BIT(w->shift),
+ SND_SOC_DAPM_EVENT_ON(event));
+}
+
static int cs35l56_asp_tx_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ int ret;
- return regmap_write(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT + (4 * w->shift),
- cs35l56->asp_tx_input[w->shift]);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regmap_write(cs35l56->base.regmap,
+ CS35L56_ASP1TX1_INPUT + (4 * w->shift),
+ cs35l56->asp_tx_input[w->shift]);
+ if (ret)
+ return ret;
+
+ break;
+ default:
+ break;
+ }
+
+ return cs35l56_asp_event(w, kcontrol, event);
}
static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
@@ -355,22 +379,25 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
SND_SOC_DAPM_PGA_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, cs35l56_dsp_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_AIF_IN("ASP1RX1", NULL, 0, CS35L56_ASP1_ENABLES1,
- CS35L56_ASP_RX1_EN_SHIFT, 0),
- SND_SOC_DAPM_AIF_IN("ASP1RX2", NULL, 1, CS35L56_ASP1_ENABLES1,
- CS35L56_ASP_RX2_EN_SHIFT, 0),
- SND_SOC_DAPM_AIF_OUT_E("ASP1TX1", NULL, 0, CS35L56_ASP1_ENABLES1,
+ /* Avoid reading ASP1_ENABLES1 when DAPM initializes the widgets. */
+ SND_SOC_DAPM_AIF_IN_E("ASP1RX1", NULL, 0, SND_SOC_NOPM,
+ CS35L56_ASP_RX1_EN_SHIFT, 0,
+ cs35l56_asp_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("ASP1RX2", NULL, 1, SND_SOC_NOPM,
+ CS35L56_ASP_RX2_EN_SHIFT, 0,
+ cs35l56_asp_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX1", NULL, 0, SND_SOC_NOPM,
CS35L56_ASP_TX1_EN_SHIFT, 0,
- cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_AIF_OUT_E("ASP1TX2", NULL, 1, CS35L56_ASP1_ENABLES1,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX2", NULL, 1, SND_SOC_NOPM,
CS35L56_ASP_TX2_EN_SHIFT, 0,
- cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_AIF_OUT_E("ASP1TX3", NULL, 2, CS35L56_ASP1_ENABLES1,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX3", NULL, 2, SND_SOC_NOPM,
CS35L56_ASP_TX3_EN_SHIFT, 0,
- cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_AIF_OUT_E("ASP1TX4", NULL, 3, CS35L56_ASP1_ENABLES1,
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("ASP1TX4", NULL, 3, SND_SOC_NOPM,
CS35L56_ASP_TX4_EN_SHIFT, 0,
- cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU),
+ cs35l56_asp_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("ASP1 TX1 Source", SND_SOC_NOPM, 0, 0, &asp1_tx1_mux),
SND_SOC_DAPM_MUX("ASP1 TX2 Source", SND_SOC_NOPM, 0, 0, &asp1_tx2_mux),
@@ -473,7 +500,7 @@ static int cs35l56_asp_dai_probe(struct snd_soc_dai *codec_dai)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
- return cs35l56_set_asp_patch(&cs35l56->base);
+ return cs35l56_set_asp_defaults(&cs35l56->base);
}
static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
@@ -2315,12 +2342,6 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
/* Registers could be dirty after soft reset or SoundWire enumeration */
regcache_sync(cs35l56->base.regmap);
- /* Set ASP1 DOUT to high-impedance when it is not transmitting audio data. */
- ret = regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
- CS35L56_ASP1_DOUT_HIZ_CTRL_MASK);
- if (ret)
- return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
-
cs35l56->needs_wait_for_fw_idle =
cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base);
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread