[PATCH v1 0/3] rtq9128: Fix user reported issues
From: ChiYuan Huang cy_huang@richtek.com
Refersh the patch series based on the below previous one https://lore.kernel.org/lkml/1697795435-5858-1-git-send-email-cy_huang@richt...
RTQ9128 fixes for pm_runtime/tdm_usage/E1 Sample amp on sequence
ChiYuan Huang (3): ASoC: codecs: rtq9128: Fix PM_RUNTIME usage ASoC: codecs: rtq9128: Fix TDM enable and DAI format control flow ASoC: codecs: rtq9128: Fix E1 eng version amp on sequence
sound/soc/codecs/rtq9128.c | 130 +++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 35 deletions(-)
base-commit: a60a609b7f548050d1e84c7aa1c0a57d5d7e22d5
From: ChiYuan Huang cy_huang@richtek.com
If 'pm_runtime_resume_and_get' is used, must check the return value to prevent the active count not matched problem.
Signed-off-by: ChiYuan Huang cy_huang@richtek.com --- sound/soc/codecs/rtq9128.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c index c22b047115cc..bda64f9eeb62 100644 --- a/sound/soc/codecs/rtq9128.c +++ b/sound/soc/codecs/rtq9128.c @@ -391,7 +391,11 @@ static int rtq9128_component_probe(struct snd_soc_component *comp) unsigned int val; int i, ret;
- pm_runtime_resume_and_get(comp->dev); + ret = pm_runtime_resume_and_get(comp->dev); + if (ret < 0) { + dev_err(comp->dev, "Failed to resume device (%d)\n", ret); + return ret; + }
val = snd_soc_component_read(comp, RTQ9128_REG_EFUSE_DATA);
From: ChiYuan Huang cy_huang@richtek.com
To enable TDM mode, the current control flow limits the function calling order should be 'set_tdm_slot->set_dai_fmt'. But not all platform sound card like as simeple card to follow this design. To bypass this limit, adjust the DAI format setting in runtime 'hw_param' callback.
Signed-off-by: ChiYuan Huang cy_huang@richtek.com --- sound/soc/codecs/rtq9128.c | 67 ++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 31 deletions(-)
diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c index bda64f9eeb62..aa3eadecd974 100644 --- a/sound/soc/codecs/rtq9128.c +++ b/sound/soc/codecs/rtq9128.c @@ -59,6 +59,7 @@
struct rtq9128_data { struct gpio_desc *enable; + unsigned int daifmt; int tdm_slots; int tdm_slot_width; bool tdm_input_data2_select; @@ -441,10 +442,7 @@ static const struct snd_soc_component_driver rtq9128_comp_driver = { static int rtq9128_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai); - struct snd_soc_component *comp = dai->component; struct device *dev = dai->dev; - unsigned int audfmt, fmtval; - int ret;
dev_dbg(dev, "%s: fmt 0x%8x\n", __func__, fmt);
@@ -454,35 +452,10 @@ static int rtq9128_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; }
- fmtval = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - if (data->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && fmtval != SND_SOC_DAIFMT_DSP_B) { - dev_err(dev, "TDM is used, format only support DSP_A or DSP_B\n"); - return -EINVAL; - } + /* Store here and will be used in runtime hw_params for DAI format setting */ + data->daifmt = fmt;
- switch (fmtval) { - case SND_SOC_DAIFMT_I2S: - audfmt = 8; - break; - case SND_SOC_DAIFMT_LEFT_J: - audfmt = 9; - break; - case SND_SOC_DAIFMT_RIGHT_J: - audfmt = 10; - break; - case SND_SOC_DAIFMT_DSP_A: - audfmt = data->tdm_slots ? 12 : 11; - break; - case SND_SOC_DAIFMT_DSP_B: - audfmt = data->tdm_slots ? 4 : 3; - break; - default: - dev_err(dev, "Unsupported format 0x%8x\n", fmt); - return -EINVAL; - } - - ret = snd_soc_component_write_field(comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDFMT_MASK, audfmt); - return ret < 0 ? ret : 0; + return 0; }
static int rtq9128_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, @@ -558,10 +531,38 @@ static int rtq9128_dai_hw_params(struct snd_pcm_substream *stream, struct snd_pc unsigned int width, slot_width, bitrate, audbit, dolen; struct snd_soc_component *comp = dai->component; struct device *dev = dai->dev; + unsigned int fmtval, audfmt; int ret;
dev_dbg(dev, "%s: width %d\n", __func__, params_width(param));
+ fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, data->daifmt); + if (data->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && fmtval != SND_SOC_DAIFMT_DSP_B) { + dev_err(dev, "TDM is used, format only support DSP_A or DSP_B\n"); + return -EINVAL; + } + + switch (fmtval) { + case SND_SOC_DAIFMT_I2S: + audfmt = 8; + break; + case SND_SOC_DAIFMT_LEFT_J: + audfmt = 9; + break; + case SND_SOC_DAIFMT_RIGHT_J: + audfmt = 10; + break; + case SND_SOC_DAIFMT_DSP_A: + audfmt = data->tdm_slots ? 12 : 11; + break; + case SND_SOC_DAIFMT_DSP_B: + audfmt = data->tdm_slots ? 4 : 3; + break; + default: + dev_err(dev, "Unsupported format 0x%8x\n", fmtval); + return -EINVAL; + } + switch (width = params_width(param)) { case 16: audbit = 0; @@ -615,6 +616,10 @@ static int rtq9128_dai_hw_params(struct snd_pcm_substream *stream, struct snd_pc return -EINVAL; }
+ ret = snd_soc_component_write_field(comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDFMT_MASK, audfmt); + if (ret < 0) + return ret; + ret = snd_soc_component_write_field(comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDBIT_MASK, audbit); if (ret < 0) return ret;
From: ChiYuan Huang cy_huang@richtek.com
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@richtek.com --- 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;
participants (1)
-
cy_huang@richtek.com