diff mbox series

[2/2] ASoC: rt1015: Fix the failure to flush DAC data before playback

Message ID 1600073839-6762-2-git-send-email-derek.fang@realtek.com
State Accepted
Commit 8d9a14fc7371a18d54226bf2542f77b11e5a7101
Headers show
Series [1/2] ASoC: rt1015: Fix DC calibration on bypass boost mode | expand

Commit Message

Derek [方德義] Sept. 14, 2020, 8:57 a.m. UTC
From: "derek.fang" <derek.fang@realtek.com>

Fix the failure to flush DAC data before playback.

Signed-off-by: derek.fang <derek.fang@realtek.com>
---
 sound/soc/codecs/rt1015.c | 63 +++++++++++++++++++++++++++++++++++++++++------
 sound/soc/codecs/rt1015.h |  7 ++++++
 2 files changed, 63 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index ba1b6b3..25fe2dd 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 4d11f58..d3fdd30 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__ */