diff options
author | derek.fang <derek.fang@realtek.com> | 2020-09-14 16:57:19 +0800 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-09-14 13:53:57 +0100 |
commit | 8d9a14fc7371a18d54226bf2542f77b11e5a7101 (patch) | |
tree | 6119c9fd1656a18e3775ed4efe6b36a0ded3aefc | |
parent | da145172b236b1ac322fa81f6250aa59074eba68 (diff) |
ASoC: rt1015: Fix the failure to flush DAC data before playback
Fix the failure to flush DAC data before playback.
Signed-off-by: derek.fang <derek.fang@realtek.com>
Link: https://lore.kernel.org/r/1600073839-6762-2-git-send-email-derek.fang@realtek.com
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/rt1015.c | 63 | ||||
-rw-r--r-- | sound/soc/codecs/rt1015.h | 7 |
2 files changed, 63 insertions, 7 deletions
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index ba1b6b3822a5..25fe2ddedd54 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -534,6 +534,32 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol, return 0; } +static void rt1015_flush_work(struct work_struct *work) +{ + struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv, + flush_work.work); + struct snd_soc_component *component = rt1015->component; + unsigned int val, i = 0, count = 20; + + while (i < count) { + usleep_range(1000, 1500); + dev_dbg(component->dev, "Flush DAC (retry:%u)\n", i); + regmap_read(rt1015->regmap, RT1015_CLK_DET, &val); + if (val & 0x800) + break; + i++; + } + + regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597); + regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x05f7); + regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x0028); + + if (val & 0x800) + dev_dbg(component->dev, "Flush DAC completed.\n"); + else + dev_warn(component->dev, "Fail to flush DAC data.\n"); +} + static const struct snd_kcontrol_new rt1015_snd_controls[] = { SOC_SINGLE_TLV("DAC Playback Volume", RT1015_DAC1, RT1015_DAC_VOL_SFT, 127, 0, dac_vol_tlv), @@ -587,12 +613,7 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: - if (rt1015->bypass_boost == RT1015_Bypass_Boost) { - regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x00a8); - regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597); - regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x05f7); - regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x0028); - } + regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x00a8); break; case SND_SOC_DAPM_POST_PMD: @@ -608,6 +629,8 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, RT1015_SYS_RST1, 0x05f5); } rt1015->dac_is_used = 0; + + cancel_delayed_work_sync(&rt1015->flush_work); break; default: @@ -616,6 +639,24 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt1015_amp_drv_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 rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (rt1015->hw_config == RT1015_HW_28) + schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10)); + break; + default: + break; + } + return 0; +} + static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0, NULL, 0), @@ -649,6 +690,8 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_OUTPUT("SPO"), }; @@ -667,7 +710,8 @@ static const struct snd_soc_dapm_route rt1015_dapm_routes[] = { { "DAC", NULL, "MIXERV" }, { "DAC", NULL, "SUMV" }, { "DAC", NULL, "VREFLV" }, - { "SPO", NULL, "DAC" }, + { "Amp Drv", NULL, "DAC" }, + { "SPO", NULL, "Amp Drv" }, }; static int rt1015_hw_params(struct snd_pcm_substream *substream, @@ -910,6 +954,8 @@ static int rt1015_probe(struct snd_soc_component *component) rt1015->cali_done = 0; snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c); + INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work); + return 0; } @@ -917,6 +963,7 @@ static void rt1015_remove(struct snd_soc_component *component) { struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component); + cancel_delayed_work_sync(&rt1015->flush_work); regmap_write(rt1015->regmap, RT1015_RESET, 0); } @@ -1042,6 +1089,8 @@ static int rt1015_i2c_probe(struct i2c_client *i2c, return ret; } + rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28; + regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val); if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) { dev_err(&i2c->dev, diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h index 4d11f5865725..d3fdd30aca6d 100644 --- a/sound/soc/codecs/rt1015.h +++ b/sound/soc/codecs/rt1015.h @@ -373,6 +373,11 @@ enum { RT1015_Bypass_Boost, }; +enum { + RT1015_HW_28 = 0, + RT1015_HW_29, +}; + struct rt1015_priv { struct snd_soc_component *component; struct regmap *regmap; @@ -390,6 +395,8 @@ struct rt1015_priv { int amp_ver; int dac_is_used; int cali_done; + int hw_config; + struct delayed_work flush_work; }; #endif /* __RT1015_H__ */ |