From: ChiYuan Huang <cy_huang@xxxxxxxxxxx> For E1 eng sample, there's the current bias issue. Some undocumented RGs should be runtime controlled during the DAPM flow to prevent the abnormal false alarm protection latchup. Signed-off-by: ChiYuan Huang <cy_huang@xxxxxxxxxxx> --- sound/soc/codecs/rtq9128.c | 57 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c index aa3eadecd974..b1b889cbbc6f 100644 --- a/sound/soc/codecs/rtq9128.c +++ b/sound/soc/codecs/rtq9128.c @@ -63,6 +63,7 @@ struct rtq9128_data { int tdm_slots; int tdm_slot_width; bool tdm_input_data2_select; + bool tka470b_e1_ver; }; struct rtq9128_init_reg { @@ -171,7 +172,7 @@ static bool rtq9128_is_writeable_reg(struct device *dev, unsigned int reg) case 0x80 ... 0x8B: case 0xA0 ... 0xAD: case 0xB0 ... 0xBA: - case 0xC0: + case 0xC0 ... 0xC1: case 0xD0 ... 0xDE: case 0xE0 ... 0xE5: case 0xF0 ... 0xF3: @@ -283,6 +284,33 @@ static const struct snd_kcontrol_new rtq9128_snd_ctrls[] = { SOC_ENUM("DVDD UV Threshold Select", rtq9128_dvdduv_select_enum), }; +static int rtq9128_int_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct rtq9128_data *data = snd_soc_component_get_drvdata(comp); + int ret; + + dev_dbg(comp->dev, "%s: event %d, ver %d\n", __func__, event, data->tka470b_e1_ver); + + if (!data->tka470b_e1_ver) + return 0; + + if (event == SND_SOC_DAPM_POST_PMU) { + ret = snd_soc_component_write(comp, 0xB9, 0x03); + if (ret) + return ret; + + return snd_soc_component_write(comp, 0xC1, 0); + } + + ret = snd_soc_component_write(comp, 0xA1, 0x02); + if (ret) + return ret; + + return snd_soc_component_write(comp, 0xA8, 0x01); +} + static int rtq9128_dac_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -320,6 +348,8 @@ static int rtq9128_dac_power_event(struct snd_soc_dapm_widget *w, struct snd_kco } static const struct snd_soc_dapm_widget rtq9128_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PWR", SND_SOC_NOPM, 0, 0, rtq9128_int_power_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_DAC_E("DAC1", NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_DAC_E("DAC2", NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event, @@ -339,6 +369,10 @@ static const struct snd_soc_dapm_route rtq9128_dapm_routes[] = { { "DAC2", NULL, "Playback" }, { "DAC3", NULL, "Playback" }, { "DAC4", NULL, "Playback" }, + { "DAC1", NULL, "PWR" }, + { "DAC2", NULL, "PWR" }, + { "DAC3", NULL, "PWR" }, + { "DAC4", NULL, "PWR" }, { "OUT1", NULL, "DAC1" }, { "OUT2", NULL, "DAC2" }, { "OUT3", NULL, "DAC3" }, @@ -358,9 +392,7 @@ static const struct rtq9128_init_reg rtq9128_tka470b_tables[] = { { 0x70, 0x11 }, { 0x75, 0x1F }, { 0xB6, 0x03 }, - { 0xB9, 0x03 }, { 0xB8, 0x03 }, - { 0xC1, 0xFF }, { 0xF8, 0x72 }, { 0x30, 0x180 }, }; @@ -387,6 +419,7 @@ static const struct rtq9128_init_reg rtq9128_dl_tables[] = { static int rtq9128_component_probe(struct snd_soc_component *comp) { + struct rtq9128_data *data = snd_soc_component_get_drvdata(comp); const struct rtq9128_init_reg *table, *curr; size_t table_size; unsigned int val; @@ -402,6 +435,7 @@ static int rtq9128_component_probe(struct snd_soc_component *comp) switch (FIELD_GET(RTQ9128_DIE_CHECK_MASK, val)) { case RTQ9128_TKA470B_VAL: + data->tka470b_e1_ver = true; table = rtq9128_tka470b_tables; table_size = ARRAY_SIZE(rtq9128_tka470b_tables); break; @@ -630,12 +664,29 @@ static int rtq9128_dai_hw_params(struct snd_pcm_substream *stream, struct snd_pc static int rtq9128_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { + struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai); struct snd_soc_component *comp = dai->component; struct device *dev = dai->dev; int ret; dev_dbg(dev, "%s: mute (%d), stream (%d)\n", __func__, mute, stream); + if (data->tka470b_e1_ver && !mute) { + ret = snd_soc_component_write(comp, 0xB9, 0x02); + if (ret) + return ret; + + usleep_range(10000, 11000); + + ret = snd_soc_component_write(comp, 0xA1, 0xF2); + if (ret) + return ret; + + ret = snd_soc_component_write(comp, 0xA8, 0x00); + if (ret) + return ret; + } + ret = snd_soc_component_write_field(comp, RTQ9128_REG_DSP_EN, RTQ9128_MSMUTE_MASK, mute ? 1 : 0); return ret < 0 ? ret : 0; -- 2.34.1