Browse Source

Merge "ASoC: wcd938x: Update soundwire slave clock rate on WCD938x"

qctecmdr 5 years ago
parent
commit
fe82be14e0
2 changed files with 58 additions and 0 deletions
  1. 2 0
      asoc/codecs/wcd938x/internal.h
  2. 56 0
      asoc/codecs/wcd938x/wcd938x.c

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

@@ -11,6 +11,8 @@
 #include <asoc/wcd-clsh.h>
 #include "wcd938x-mbhc.h"
 
+#define SWR_SCP_CONTROL    0x44
+#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0
 #define WCD938X_MAX_MICBIAS 4
 
 /* Convert from vout ctl to micbias voltage in mV */

+ 56 - 0
asoc/codecs/wcd938x/wcd938x.c

@@ -25,6 +25,7 @@
 #include "wcd938x-registers.h"
 #include "wcd938x.h"
 
+
 #define WCD938X_DRV_NAME "wcd938x_codec"
 #define NUM_SWRS_DT_PARAMS 5
 #define WCD938X_VARIANT_ENTRY_SIZE 32
@@ -126,6 +127,45 @@ static int wcd938x_handle_post_irq(void *data)
 	return IRQ_HANDLED;
 }
 
+static int wcd938x_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum)
+{
+	int ret = 0;
+	int bank = 0;
+
+	ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1);
+	if (ret)
+		return -EINVAL;
+
+	return ((bank & 0x40) ? 1: 0);
+}
+
+static int wcd938x_swr_slv_set_host_clk_div2(struct swr_device *dev,
+						u8 devnum, int bank)
+{
+	u8 val = (bank ? 1 : 0);
+
+	return (swr_write(dev, devnum,
+		(SWR_SCP_HOST_CLK_DIV2_CTL_BANK + (0x10 * bank)), &val));
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component,
+					int mode, int bank)
+{
+	u8 mask = (bank ? 0xF0 : 0x0F);
+	u8 val = 0;
+
+	if ((mode == ADC_MODE_ULP1) || (mode == ADC_MODE_ULP2))
+		val = (bank ? 0x60 : 0x06);
+	else
+		val = 0x00;
+
+	snd_soc_component_update_bits(component,
+				      WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+				      mask, val);
+
+	return 0;
+}
+
 static int wcd938x_init_reg(struct snd_soc_component *component)
 {
 	snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E, 0x0E);
@@ -1335,17 +1375,33 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
 					snd_soc_dapm_to_component(w->dapm);
 	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 	int ret = 0;
+	int bank = 0;
+	int mode = 0;
 
+	bank = wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev,
+						wcd938x->tx_swr_dev->dev_num);
+	wcd938x_swr_slv_set_host_clk_div2(wcd938x->tx_swr_dev,
+					  wcd938x->tx_swr_dev->dev_num, bank);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
 		    wcd938x->tx_swr_dev->dev_num,
 		    true);
+		if (test_bit(WCD_ADC1, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC1];
+		if (test_bit(WCD_ADC2, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC2];
+		if (test_bit(WCD_ADC3, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC3];
+		if (test_bit(WCD_ADC4, &wcd938x->status_mask))
+			mode |= wcd938x->tx_mode[WCD_ADC4];
+		wcd938x_set_swr_clk_rate(component, mode, bank);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
 		    wcd938x->tx_swr_dev->dev_num,
 		    false);
+		wcd938x_set_swr_clk_rate(component, ADC_MODE_INVALID, bank);
 		break;
 	};