Skip to content

Commit dfd2ffb

Browse files
rfvirgilbroonie
authored andcommitted
ASoC: cs35l56: Prevent overwriting firmware ASP config
Only populate the ASP1 config registers in the regmap cache if the ASP DAI is used. This prevents regcache_sync() from overwriting these registers with their defaults when the firmware owns control of these registers. On a SoundWire system the ASP could be owned by the firmware to share reference audio with the firmware on other cs35l56. Or it can be used as a normal codec-codec interface owned by the driver. The driver must not overwrite the registers if the firmware has control of them. The original implementation for this in commit 07f7d6e ("ASoC: cs35l56: Fix for initializing ASP1 mixer registers") was to still provide defaults for these registers, assuming that if they were never reconfigured from defaults then regcache_sync() would not write them out because they are not dirty. Unfortunately regcache_sync() is not that smart. If the chip has not reset (so the driver has not called regcache_mark_dirty()) a regcache_sync() could write out registers that are not dirty. To avoid accidental overwriting of the ASP registers, they are removed from the table of defaults and instead are populated with defaults only if one of the ASP DAI configuration functions is called. So if the DAI has never been configured, the firmware is assumed to have ownership of these registers, and the regmap cache will not contain any entries for them. Signed-off-by: Richard Fitzgerald <[email protected]> Fixes: 07f7d6e ("ASoC: cs35l56: Fix for initializing ASP1 mixer registers") Link: https://msgid.link/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent d4884fd commit dfd2ffb

File tree

3 files changed

+67
-22
lines changed

3 files changed

+67
-22
lines changed

include/sound/cs35l56.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ struct cs35l56_base {
267267
bool fw_patched;
268268
bool secured;
269269
bool can_hibernate;
270+
bool fw_owns_asp1;
270271
bool cal_data_valid;
271272
s8 cal_index;
272273
struct cirrus_amp_cal_data cal_data;
@@ -283,6 +284,7 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
283284
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
284285

285286
int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
287+
int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base);
286288
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base);
287289
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
288290
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);

sound/soc/codecs/cs35l56-shared.c

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,11 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
4040
static const struct reg_default cs35l56_reg_defaults[] = {
4141
/* no defaults for OTP_MEM - first read populates cache */
4242

43-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
44-
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
45-
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
46-
{ CS35L56_ASP1_CONTROL3, 0x00000002 },
47-
{ CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
48-
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
49-
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
50-
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
51-
52-
/* no defaults for ASP1TX mixer */
43+
/*
44+
* No defaults for ASP1 control or ASP1TX mixer. See
45+
* cs35l56_populate_asp1_register_defaults() and
46+
* cs35l56_sync_asp1_mixer_widgets_with_firmware().
47+
*/
5348

5449
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
5550
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
@@ -210,26 +205,52 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
210205
}
211206
}
212207

208+
static const struct reg_sequence cs35l56_asp1_defaults[] = {
209+
REG_SEQ0(CS35L56_ASP1_ENABLES1, 0x00000000),
210+
REG_SEQ0(CS35L56_ASP1_CONTROL1, 0x00000028),
211+
REG_SEQ0(CS35L56_ASP1_CONTROL2, 0x18180200),
212+
REG_SEQ0(CS35L56_ASP1_CONTROL3, 0x00000002),
213+
REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1, 0x03020100),
214+
REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100),
215+
REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018),
216+
REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018),
217+
};
218+
219+
/*
220+
* The firmware can have control of the ASP so we don't provide regmap
221+
* with defaults for these registers, to prevent a regcache_sync() from
222+
* overwriting the firmware settings. But if the machine driver hooks up
223+
* the ASP it means the driver is taking control of the ASP, so then the
224+
* registers are populated with the defaults.
225+
*/
226+
int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base)
227+
{
228+
if (!cs35l56_base->fw_owns_asp1)
229+
return 0;
230+
231+
cs35l56_base->fw_owns_asp1 = false;
232+
233+
return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults,
234+
ARRAY_SIZE(cs35l56_asp1_defaults));
235+
}
236+
EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED);
237+
213238
/*
214239
* The firmware boot sequence can overwrite the ASP1 config registers so that
215240
* they don't match regmap's view of their values. Rewrite the values from the
216241
* regmap cache into the hardware registers.
217242
*/
218243
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
219244
{
220-
struct reg_sequence asp1_regs[] = {
221-
{ .reg = CS35L56_ASP1_ENABLES1 },
222-
{ .reg = CS35L56_ASP1_CONTROL1 },
223-
{ .reg = CS35L56_ASP1_CONTROL2 },
224-
{ .reg = CS35L56_ASP1_CONTROL3 },
225-
{ .reg = CS35L56_ASP1_FRAME_CONTROL1 },
226-
{ .reg = CS35L56_ASP1_FRAME_CONTROL5 },
227-
{ .reg = CS35L56_ASP1_DATA_CONTROL1 },
228-
{ .reg = CS35L56_ASP1_DATA_CONTROL5 },
229-
};
245+
struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)];
230246
int i, ret;
231247

232-
/* Read values from regmap cache into a write sequence */
248+
if (cs35l56_base->fw_owns_asp1)
249+
return 0;
250+
251+
memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs));
252+
253+
/* Read current values from regmap cache into the write sequence */
233254
for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) {
234255
ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def);
235256
if (ret)

sound/soc/codecs/cs35l56.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,14 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
454454
{
455455
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
456456
unsigned int val;
457+
int ret;
457458

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

461+
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
462+
if (ret)
463+
return ret;
464+
460465
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
461466
case SND_SOC_DAIFMT_CBC_CFC:
462467
break;
@@ -530,6 +535,11 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
530535
unsigned int rx_mask, int slots, int slot_width)
531536
{
532537
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
538+
int ret;
539+
540+
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
541+
if (ret)
542+
return ret;
533543

534544
if ((slots == 0) || (slot_width == 0)) {
535545
dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
@@ -578,6 +588,11 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
578588
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
579589
unsigned int rate = params_rate(params);
580590
u8 asp_width, asp_wl;
591+
int ret;
592+
593+
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
594+
if (ret)
595+
return ret;
581596

582597
asp_wl = params_width(params);
583598
if (cs35l56->asp_slot_width)
@@ -634,7 +649,11 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
634649
int clk_id, unsigned int freq, int dir)
635650
{
636651
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
637-
int freq_id;
652+
int freq_id, ret;
653+
654+
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
655+
if (ret)
656+
return ret;
638657

639658
if (freq == 0) {
640659
cs35l56->sysclk_set = false;
@@ -1403,6 +1422,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
14031422
cs35l56->base.cal_index = -1;
14041423
cs35l56->speaker_id = -ENOENT;
14051424

1425+
/* Assume that the firmware owns ASP1 until we know different */
1426+
cs35l56->base.fw_owns_asp1 = true;
1427+
14061428
dev_set_drvdata(cs35l56->base.dev, cs35l56);
14071429

14081430
cs35l56_fill_supply_names(cs35l56->supplies);

0 commit comments

Comments
 (0)