Browse Source

ASoC: wcd937x: Fix playback stop issue after SSR/PDR on special hs

If we start playback on special hs after record is done and perform
SSR/PDR then playback gets paused. This happens because ANA_TX_DIV2_CLK
which needs to be enabled for special hs gets disabled after record
is stopped. Maintain a count for ANA_DIV2_CLK to enable/disable it
as required.

Change-Id: Ic73475c83cb16e3c014f35b8d46ee22d2e7a2efd
Signed-off-by: Vatsal Bucha <[email protected]>
Vatsal Bucha 6 years ago
parent
commit
13faf538b3
2 changed files with 33 additions and 1 deletions
  1. 2 0
      asoc/codecs/wcd937x/internal.h
  2. 31 1
      asoc/codecs/wcd937x/wcd937x.c

+ 2 - 0
asoc/codecs/wcd937x/internal.h

@@ -83,6 +83,8 @@ struct wcd937x_priv {
 	struct snd_info_entry *entry;
 	struct snd_info_entry *version_entry;
 	int ear_rx_path;
+	int ana_clk_count;
+	struct mutex ana_tx_clk_lock;
 };
 
 struct wcd937x_micbias_setting {

+ 31 - 1
asoc/codecs/wcd937x/wcd937x.c

@@ -1267,12 +1267,17 @@ static int wcd937x_codec_enable_adc(struct snd_soc_dapm_widget *w,
 
 	struct snd_soc_component *component =
 			snd_soc_dapm_to_component(w->dapm);
+	struct wcd937x_priv *wcd937x =
+			snd_soc_component_get_drvdata(component);
 
 	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
 		w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		mutex_lock(&wcd937x->ana_tx_clk_lock);
+		wcd937x->ana_clk_count++;
+		mutex_unlock(&wcd937x->ana_tx_clk_lock);
 		snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80);
 		snd_soc_component_update_bits(component,
@@ -1296,6 +1301,8 @@ static int wcd937x_enable_req(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_component *component =
 			snd_soc_dapm_to_component(w->dapm);
+	struct wcd937x_priv *wcd937x =
+			snd_soc_component_get_drvdata(component);
 
 	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
 		w->name, event);
@@ -1324,8 +1331,15 @@ static int wcd937x_enable_req(struct snd_soc_dapm_widget *w,
 				WCD937X_ANA_TX_CH2, 0x80, 0x00);
 		snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00);
-		snd_soc_component_update_bits(component,
+		mutex_lock(&wcd937x->ana_tx_clk_lock);
+		wcd937x->ana_clk_count--;
+		if (wcd937x->ana_clk_count <= 0) {
+			snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+			wcd937x->ana_clk_count = 0;
+		}
+
+		mutex_unlock(&wcd937x->ana_tx_clk_lock);
 		snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00);
 		break;
@@ -1389,6 +1403,9 @@ int wcd937x_micbias_control(struct snd_soc_component *component,
 		break;
 	case MICB_ENABLE:
 		wcd937x->micb_ref[micb_index]++;
+		mutex_lock(&wcd937x->ana_tx_clk_lock);
+		wcd937x->ana_clk_count++;
+		mutex_unlock(&wcd937x->ana_tx_clk_lock);
 		if (wcd937x->micb_ref[micb_index] == 1) {
 			snd_soc_component_update_bits(component,
 				WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0xE0, 0xE0);
@@ -1413,6 +1430,9 @@ int wcd937x_micbias_control(struct snd_soc_component *component,
 				&wcd937x->mbhc->wcd_mbhc);
 		break;
 	case MICB_DISABLE:
+		mutex_lock(&wcd937x->ana_tx_clk_lock);
+		wcd937x->ana_clk_count--;
+		mutex_unlock(&wcd937x->ana_tx_clk_lock);
 		if (wcd937x->micb_ref[micb_index] > 0)
 			wcd937x->micb_ref[micb_index]--;
 		if ((wcd937x->micb_ref[micb_index] == 0) &&
@@ -1433,6 +1453,14 @@ int wcd937x_micbias_control(struct snd_soc_component *component,
 					post_off_event,
 					&wcd937x->mbhc->wcd_mbhc);
 		}
+		mutex_lock(&wcd937x->ana_tx_clk_lock);
+		if (wcd937x->ana_clk_count <= 0) {
+			snd_soc_component_update_bits(component,
+					    WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+					    0x10, 0x00);
+			wcd937x->ana_clk_count = 0;
+		}
+		mutex_unlock(&wcd937x->ana_tx_clk_lock);
 		if (is_dapm && post_dapm_off && wcd937x->mbhc)
 			blocking_notifier_call_chain(
 				&wcd937x->mbhc->notifier, post_dapm_off,
@@ -2757,6 +2785,7 @@ static int wcd937x_bind(struct device *dev)
 	}
 
 	mutex_init(&wcd937x->micb_lock);
+	mutex_init(&wcd937x->ana_tx_clk_lock);
 	/* Request for watchdog interrupt */
 	wcd_request_irq(&wcd937x->irq_info, WCD937X_IRQ_HPHR_PDM_WD_INT,
 			"HPHR PDM WD INT", wcd937x_wd_handle_irq, NULL);
@@ -2793,6 +2822,7 @@ static void wcd937x_unbind(struct device *dev)
 	snd_soc_unregister_component(dev);
 	component_unbind_all(dev, wcd937x);
 	mutex_destroy(&wcd937x->micb_lock);
+	mutex_destroy(&wcd937x->ana_tx_clk_lock);
 }
 
 static const struct of_device_id wcd937x_dt_match[] = {