Skip to content

Commit 72a77d7

Browse files
rfvirgilbroonie
authored andcommitted
ASoC: cs35l56: Fix to ensure ASP1 registers match cache
Add a dummy SUPPLY widget connected to the ASP that forces the chip registers to match the regmap cache when the ASP is powered-up. On a SoundWire system the ASP is free for use as a chip-to-chip interconnect. This can be either for the firmware on multiple CS35L56 to share reference audio; or as a bridge to another device. If it is a firmware interconnect it is owned by the firmware and the Linux driver should avoid writing the registers. However. If it is a bridge then Linux may take over and handle it as a normal codec-to-codec link. CS35L56 is designed for SDCA and a generic SDCA driver would know nothing about these chip-specific registers. So if the ASP is being used on a SoundWire system the firmware sets up the ASP registers. This means that we can't assume the default state of the ASP registers. But we don't know the initial state that the firmware set them to until after the firmware has been downloaded and booted, which can take several seconds when downloading multiple amps. To avoid blocking probe() for several seconds waiting for the firmware, the silicon defaults are assumed. This allows the machine driver to setup the ASP configuration during probe() without being blocked. If the ASP is hooked up and used, the SUPPLY widget ensures that the chip registers match what was configured in the regmap cache. If the machine driver does not hook up the ASP, it is assumed that it won't call any functions to configure the ASP DAI. Therefore the regmap cache will be clean for these registers so a regcache_sync() will not overwrite the chip registers. If the DAI is not hooked up, the dummy SUPPLY widget will not be invoked so it will never force-overwrite the chip registers. Backport note: This won't apply cleanly to kernels older than v6.6. Signed-off-by: Richard Fitzgerald <[email protected]> Fixes: e496112 ("ASoC: cs35l56: Add driver for Cirrus Logic CS35L56") Link: https://msgid.link/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 3739cc0 commit 72a77d7

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

include/sound/cs35l56.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
272272
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
273273

274274
int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
275+
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base);
275276
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
276277
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
277278
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);

sound/soc/codecs/cs35l56-shared.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,47 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
195195
}
196196
}
197197

198+
/*
199+
* The firmware boot sequence can overwrite the ASP1 config registers so that
200+
* they don't match regmap's view of their values. Rewrite the values from the
201+
* regmap cache into the hardware registers.
202+
*/
203+
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
204+
{
205+
struct reg_sequence asp1_regs[] = {
206+
{ .reg = CS35L56_ASP1_ENABLES1 },
207+
{ .reg = CS35L56_ASP1_CONTROL1 },
208+
{ .reg = CS35L56_ASP1_CONTROL2 },
209+
{ .reg = CS35L56_ASP1_CONTROL3 },
210+
{ .reg = CS35L56_ASP1_FRAME_CONTROL1 },
211+
{ .reg = CS35L56_ASP1_FRAME_CONTROL5 },
212+
{ .reg = CS35L56_ASP1_DATA_CONTROL1 },
213+
{ .reg = CS35L56_ASP1_DATA_CONTROL5 },
214+
};
215+
int i, ret;
216+
217+
/* Read values from regmap cache into a write sequence */
218+
for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) {
219+
ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def);
220+
if (ret)
221+
goto err;
222+
}
223+
224+
/* Write the values cache-bypassed so that they will be written to silicon */
225+
ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs,
226+
ARRAY_SIZE(asp1_regs));
227+
if (ret)
228+
goto err;
229+
230+
return 0;
231+
232+
err:
233+
dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret);
234+
235+
return ret;
236+
}
237+
EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED);
238+
198239
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
199240
{
200241
unsigned int val;

sound/soc/codecs/cs35l56.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,21 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum,
148148
static const struct snd_kcontrol_new sdw1_tx4_mux =
149149
SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum);
150150

151+
static int cs35l56_asp1_cfg_event(struct snd_soc_dapm_widget *w,
152+
struct snd_kcontrol *kcontrol, int event)
153+
{
154+
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
155+
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
156+
157+
switch (event) {
158+
case SND_SOC_DAPM_PRE_PMU:
159+
/* Override register values set by firmware boot */
160+
return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
161+
default:
162+
return 0;
163+
}
164+
}
165+
151166
static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
152167
struct snd_kcontrol *kcontrol, int event)
153168
{
@@ -184,6 +199,9 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
184199
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0),
185200
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0),
186201

202+
SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event,
203+
SND_SOC_DAPM_PRE_PMU),
204+
187205
SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event,
188206
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
189207

@@ -251,6 +269,9 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = {
251269
{ "AMP", NULL, "VDD_B" },
252270
{ "AMP", NULL, "VDD_AMP" },
253271

272+
{ "ASP1 Playback", NULL, "ASP1 CFG" },
273+
{ "ASP1 Capture", NULL, "ASP1 CFG" },
274+
254275
{ "ASP1 Playback", NULL, "PLAY" },
255276
{ "SDW1 Playback", NULL, "PLAY" },
256277

0 commit comments

Comments
 (0)