Kaynağa Gözat

Merge 700bd78ede0ff56af47ae2788333dcb0545f11b3 on remote branch

Change-Id: Iff0d63a9984de909dceac115d82f13c25984950d
Linux Build Service Account 4 yıl önce
ebeveyn
işleme
e41f9eab53
71 değiştirilmiş dosya ile 4656 ekleme ve 1045 silme
  1. 15 1
      asoc/bengal-port-config.h
  2. 130 12
      asoc/bengal.c
  3. 22 6
      asoc/codecs/bolero/bolero-cdc.c
  4. 7 4
      asoc/codecs/bolero/bolero-cdc.h
  5. 20 10
      asoc/codecs/bolero/bolero-clk-rsc.c
  6. 59 45
      asoc/codecs/bolero/rx-macro.c
  7. 62 37
      asoc/codecs/bolero/tx-macro.c
  8. 102 30
      asoc/codecs/bolero/va-macro.c
  9. 54 49
      asoc/codecs/bolero/wsa-macro.c
  10. 20 1
      asoc/codecs/csra66x0/csra66x0.c
  11. 3 1
      asoc/codecs/csra66x0/csra66x0.h
  12. 48 2
      asoc/codecs/ep92/ep92.c
  13. 5 1
      asoc/codecs/ep92/ep92.h
  14. 35 1
      asoc/codecs/msm-cdc-pinctrl.c
  15. 68 2
      asoc/codecs/msm-cdc-supply.c
  16. 85 14
      asoc/codecs/msm_hdmi_codec_rx.c
  17. 5 0
      asoc/codecs/rouleur/internal.h
  18. 209 216
      asoc/codecs/rouleur/rouleur-mbhc.c
  19. 1 1
      asoc/codecs/rouleur/rouleur-registers.h
  20. 3 1
      asoc/codecs/rouleur/rouleur-regmap.c
  21. 3 1
      asoc/codecs/rouleur/rouleur-tables.c
  22. 180 67
      asoc/codecs/rouleur/rouleur.c
  23. 312 12
      asoc/codecs/rouleur/rouleur_slave.c
  24. 29 0
      asoc/codecs/swr-dmic.c
  25. 6 16
      asoc/codecs/swr-haptics.c
  26. 41 10
      asoc/codecs/wcd-mbhc-adc.c
  27. 6 2
      asoc/codecs/wcd-mbhc-v2.c
  28. 62 62
      asoc/codecs/wcd9335.c
  29. 54 54
      asoc/codecs/wcd934x/wcd934x.c
  30. 1 0
      asoc/codecs/wcd938x/internal.h
  31. 61 4
      asoc/codecs/wcd938x/wcd938x.c
  32. 1 0
      asoc/codecs/wsa883x/internal.h
  33. 87 2
      asoc/codecs/wsa883x/wsa883x.c
  34. 22 2
      asoc/kona.c
  35. 120 0
      asoc/lahaina.c
  36. 25 25
      asoc/msm-audio-effects-q6-v2.c
  37. 177 0
      asoc/msm-compress-q6-v2.c
  38. 31 3
      asoc/msm-dai-q6-hdmi-v2.c
  39. 294 15
      asoc/msm-dai-q6-v2.c
  40. 321 109
      asoc/msm-lsm-client.c
  41. 369 4
      asoc/msm-pcm-routing-v2.c
  42. 55 1
      asoc/msm-pcm-routing-v2.h
  43. 0 8
      asoc/msm-qti-pp-config.c
  44. 5 0
      asoc/msm_dailink.h
  45. 320 6
      asoc/qcs405.c
  46. 4 0
      dsp/Kbuild
  47. 48 3
      dsp/adsp-loader.c
  48. 100 0
      dsp/digital-cdc-rsc-mgr.c
  49. 1 2
      dsp/msm-dts-srs-tm-config.c
  50. 3 1
      dsp/q6_init.c
  51. 14 0
      dsp/q6_init.h
  52. 2 2
      dsp/q6adm.c
  53. 483 64
      dsp/q6afe.c
  54. 4 0
      dsp/q6audio-v2.c
  55. 163 73
      dsp/q6lsm.c
  56. 6 1
      include/asoc/msm-cdc-pinctrl.h
  57. 6 0
      include/asoc/msm-cdc-supply.h
  58. 12 0
      include/asoc/wcd-mbhc-v2.h
  59. 99 0
      include/dsp/apr_audio-v2.h
  60. 32 0
      include/dsp/digital-cdc-rsc-mgr.h
  61. 15 0
      include/dsp/q6afe-v2.h
  62. 19 4
      include/dsp/q6lsm.h
  63. 5 5
      include/uapi/audio/sound/audio_effects.h
  64. 7 3
      include/uapi/audio/sound/lsm_params.h
  65. 2 0
      include/uapi/audio/sound/msmcal-hwdep.h
  66. 0 1
      include/uapi/audio/sound/voice_params.h
  67. 5 3
      ipc/apr_vm.c
  68. 16 3
      soc/pinctrl-lpi.c
  69. 1 5
      soc/soundwire.c
  70. 70 38
      soc/swr-mstr-ctrl.c
  71. 4 0
      soc/swr-mstr-ctrl.h

+ 15 - 1
asoc/bengal-port-config.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _BENGAL_PORT_CONFIG
@@ -21,6 +21,15 @@ static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = {
 	{0,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0,    0},
 };
 
+static struct port_params rx_frame_params_rouleur[SWR_MSTR_PORT_LEN] = {
+	{3,  0,  0,  0xFF, 0xFF, 1,    0xFF, 0xFF, 1},
+	{31, 0,  0,  3,    6,    7,    0,    0xFF, 0},
+	{31, 1,  0,  0xFF, 0xFF, 4,    1,    0xFF, 0},
+	{7,  1,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},
+	{0,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0,    0},
+};
+
+
 static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = {
 	{3,  0,  0,  0xFF, 0xFF, 1,    0xFF, 0xFF, 1},
 	{31, 0,  0,  3,    6,    7,    0,    0xFF, 0},
@@ -42,4 +51,9 @@ static struct swr_mstr_port_map sm_port_map[] = {
 	{RX_MACRO, SWR_UC1, rx_frame_params_dsd},
 };
 
+static struct swr_mstr_port_map sm_port_map_rouleur[] = {
+	{VA_MACRO, SWR_UC0, tx_frame_params_default},
+	{RX_MACRO, SWR_UC0, rx_frame_params_rouleur},
+	{RX_MACRO, SWR_UC1, rx_frame_params_dsd},
+};
 #endif /* _BENGAL_PORT_CONFIG */

+ 130 - 12
asoc/bengal.c

@@ -59,10 +59,12 @@
 
 #define WCD9XXX_MBHC_DEF_RLOADS     5
 #define WCD9XXX_MBHC_DEF_BUTTONS    8
+#define ROULEUR_MBHC_DEF_BUTTONS    5
 #define CODEC_EXT_CLK_RATE          9600000
 #define ADSP_STATE_READY_TIMEOUT_MS 3000
 #define DEV_NAME_STR_LEN            32
 #define WCD_MBHC_HS_V_MAX           1600
+#define ROULEUR_MBHC_HS_V_MAX       1700
 
 #define TDM_CHANNEL_MAX		8
 #define DEV_NAME_STR_LEN	32
@@ -555,6 +557,7 @@ static int dmic_0_1_gpio_cnt;
 static int dmic_2_3_gpio_cnt;
 
 static void *def_wcd_mbhc_cal(void);
+static void *def_rouleur_mbhc_cal(void);
 
 /*
  * Need to report LINEIN
@@ -4259,6 +4262,9 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
 	struct snd_soc_dapm_context *dapm;
 	struct snd_card *card;
 	struct snd_info_entry *entry;
+	struct platform_device *pdev = NULL;
+	int i = 0;
+	char *data = NULL;
 	struct msm_asoc_mach_data *pdata =
 				snd_soc_card_get_drvdata(rtd->card);
 
@@ -4305,8 +4311,38 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
 
 	snd_soc_dapm_sync(dapm);
 
-		bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
-				    sm_port_map);
+	for (i = 0; i < rtd->card->num_aux_devs; i++)
+	{
+		if (msm_aux_dev[i].name != NULL ) {
+			if (strstr(msm_aux_dev[i].name, "wsa"))
+				continue;
+		}
+
+		if (msm_aux_dev[i].codec_of_node) {
+			pdev = of_find_device_by_node(
+					msm_aux_dev[i].codec_of_node);
+
+			if (pdev)
+				data = (char*) of_device_get_match_data(
+								&pdev->dev);
+			if (data != NULL) {
+				if (!strncmp(data, "wcd937x",
+						sizeof("wcd937x"))) {
+					bolero_set_port_map(component,
+						ARRAY_SIZE(sm_port_map),
+						sm_port_map);
+					break;
+				} else if (!strncmp( data, "rouleur",
+							sizeof("rouleur"))) {
+					bolero_set_port_map(component,
+						ARRAY_SIZE(sm_port_map_rouleur),
+						sm_port_map_rouleur);
+					break;
+				}
+			}
+		}
+	}
+
 	card = rtd->card->snd_card;
 	if (!pdata->codec_root) {
 		entry = snd_info_create_subdir(card->module, "codecs",
@@ -4356,6 +4392,34 @@ static void *def_wcd_mbhc_cal(void)
 	return wcd_mbhc_cal;
 }
 
+static void *def_rouleur_mbhc_cal(void)
+{
+	void *wcd_mbhc_cal;
+	struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_high;
+
+	wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(ROULEUR_MBHC_DEF_BUTTONS,
+				WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+	if (!wcd_mbhc_cal)
+		return NULL;
+
+	WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->v_hs_max =
+						ROULEUR_MBHC_HS_V_MAX;
+	WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->num_btn =
+						ROULEUR_MBHC_DEF_BUTTONS;
+	btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal);
+	btn_high = ((void *)&btn_cfg->_v_btn_low) +
+		(sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+	btn_high[0] = 75;
+	btn_high[1] = 150;
+	btn_high[2] = 237;
+	btn_high[3] = 500;
+	btn_high[4] = 500;
+
+	return wcd_mbhc_cal;
+}
+
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link msm_common_dai_links[] = {
 	/* FrontEnd DAI Links */
@@ -4985,6 +5049,22 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ops = &msm_cdc_dma_be_ops,
 	},
+	{/* hw:x,39 */
+		.name = MSM_DAILINK_NAME(Compress3),
+		.stream_name = "Compress3",
+		.cpu_dai_name = "MultiMedia10",
+		.platform_name = "msm-compress-dsp",
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			 SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		/* this dainlink has playback support */
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+	},
 };
 
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {
@@ -5075,6 +5155,33 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1,
 	},
+	/* Proxy Tx BACK END DAI Link */
+	{
+		.name = LPASS_BE_PROXY_TX,
+		.stream_name = "Proxy Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.8195",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_PROXY_TX,
+		.ignore_suspend = 1,
+	},
+	/* Proxy Rx BACK END DAI Link */
+	{
+		.name = LPASS_BE_PROXY_RX,
+		.stream_name = "Proxy Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.8194",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_PROXY_RX,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
 	{
 		.name = LPASS_BE_USB_AUDIO_RX,
 		.stream_name = "USB Audio Playback",
@@ -6115,16 +6222,21 @@ static int msm_aux_codec_init(struct snd_soc_component *component)
 	}
 
 mbhc_cfg_cal:
-	mbhc_calibration = def_wcd_mbhc_cal();
-	if (!mbhc_calibration)
-		return -ENOMEM;
-	wcd_mbhc_cfg.calibration = mbhc_calibration;
         if (data != NULL) {
-                if (!strncmp(data, "wcd937x", sizeof("wcd937x")))
-                        ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
-                else if (!strncmp( data, "rouleur", sizeof("rouleur")))
-                        ret = rouleur_mbhc_hs_detect(component, &wcd_mbhc_cfg);
-        }
+		if (!strncmp(data, "wcd937x", sizeof("wcd937x"))) {
+			mbhc_calibration = def_wcd_mbhc_cal();
+			if (!mbhc_calibration)
+				return -ENOMEM;
+			wcd_mbhc_cfg.calibration = mbhc_calibration;
+			ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
+		} else if (!strncmp( data, "rouleur", sizeof("rouleur"))) {
+			mbhc_calibration = def_rouleur_mbhc_cal();
+			if (!mbhc_calibration)
+				return -ENOMEM;
+			wcd_mbhc_cfg.calibration = mbhc_calibration;
+			ret = rouleur_mbhc_hs_detect(component, &wcd_mbhc_cfg);
+		}
+	}
 
 	if (ret) {
 		dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n",
@@ -6714,10 +6826,16 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
 	}
 	buf = nvmem_cell_read(cell, &len);
 	nvmem_cell_put(cell);
-	if (IS_ERR_OR_NULL(buf) || len <= 0 || len > sizeof(32)) {
+	if (IS_ERR_OR_NULL(buf)) {
 		dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__);
 		goto ret;
 	}
+	if (len <= 0 || len > sizeof(u32)) {
+		dev_dbg(&pdev->dev, "%s: nvmem cell length out of range: %d\n",
+			__func__, len);
+		kfree(buf);
+		goto ret;
+	}
 	memcpy(&adsp_var_idx, buf, len);
 	kfree(buf);
 	va_disable = adsp_var_idx;

+ 22 - 6
asoc/codecs/bolero/bolero-cdc.c

@@ -14,6 +14,7 @@
 #include <soc/snd_event.h>
 #include <linux/pm_runtime.h>
 #include <soc/swr-common.h>
+#include <dsp/digital-cdc-rsc-mgr.h>
 #include "bolero-cdc.h"
 #include "internal.h"
 #include "bolero-clk-rsc.h"
@@ -835,6 +836,18 @@ static int bolero_ssr_enable(struct device *dev, void *data)
 				BOLERO_MACRO_EVT_CLK_RESET, 0x0);
 	}
 	trace_printk("%s: clk count reset\n", __func__);
+
+	if (priv->rsc_clk_cb)
+		priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_GFMUX_UP);
+
+	for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) {
+		if (!priv->macro_params[macro_idx].event_handler)
+			continue;
+		priv->macro_params[macro_idx].event_handler(
+			priv->component,
+			BOLERO_MACRO_EVT_PRE_SSR_UP, 0x0);
+	}
+
 	regcache_cache_only(priv->regmap, false);
 	mutex_lock(&priv->clk_lock);
 	priv->dev_up = true;
@@ -1081,7 +1094,7 @@ EXPORT_SYMBOL(bolero_tx_mclk_enable);
  * Returns 0 on success or -EINVAL on error.
  */
 int bolero_register_event_listener(struct snd_soc_component *component,
-				   bool enable)
+				   bool enable, bool is_dmic_sva)
 {
 	struct bolero_priv *priv = NULL;
 	int ret = 0;
@@ -1100,7 +1113,8 @@ int bolero_register_event_listener(struct snd_soc_component *component,
 
 	if (priv->macro_params[TX_MACRO].reg_evt_listener)
 		ret = priv->macro_params[TX_MACRO].reg_evt_listener(component,
-								    enable);
+								    enable,
+								    is_dmic_sva);
 
 	return ret;
 }
@@ -1388,7 +1402,7 @@ int bolero_runtime_resume(struct device *dev)
 	}
 
 	if (priv->core_hw_vote_count == 0) {
-		ret = clk_prepare_enable(priv->lpass_core_hw_vote);
+		ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_core_hw_vote);
 		if (ret < 0) {
 			dev_err(dev, "%s:lpass core hw enable failed\n",
 				__func__);
@@ -1406,7 +1420,7 @@ audio_vote:
 	}
 
 	if (priv->core_audio_vote_count == 0) {
-		ret = clk_prepare_enable(priv->lpass_audio_hw_vote);
+		ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_audio_hw_vote);
 		if (ret < 0) {
 			dev_err(dev, "%s:lpass audio hw enable failed\n",
 				__func__);
@@ -1431,7 +1445,8 @@ int bolero_runtime_suspend(struct device *dev)
 	mutex_lock(&priv->vote_lock);
 	if (priv->lpass_core_hw_vote != NULL) {
 		if (--priv->core_hw_vote_count == 0)
-			clk_disable_unprepare(priv->lpass_core_hw_vote);
+			digital_cdc_rsc_mgr_hw_vote_disable(
+					priv->lpass_core_hw_vote);
 		if (priv->core_hw_vote_count < 0)
 			priv->core_hw_vote_count = 0;
 	} else {
@@ -1443,7 +1458,8 @@ int bolero_runtime_suspend(struct device *dev)
 
 	if (priv->lpass_audio_hw_vote != NULL) {
 		if (--priv->core_audio_vote_count == 0)
-			clk_disable_unprepare(priv->lpass_audio_hw_vote);
+			digital_cdc_rsc_mgr_hw_vote_disable(
+					priv->lpass_audio_hw_vote);
 		if (priv->core_audio_vote_count < 0)
 			priv->core_audio_vote_count = 0;
 	} else {

+ 7 - 4
asoc/codecs/bolero/bolero-cdc.h

@@ -52,7 +52,9 @@ enum {
 	BOLERO_MACRO_EVT_CLK_RESET,
 	BOLERO_MACRO_EVT_REG_WAKE_IRQ,
 	BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST,
-	BOLERO_MACRO_EVT_BCS_CLK_OFF
+	BOLERO_MACRO_EVT_BCS_CLK_OFF,
+	BOLERO_MACRO_EVT_SSR_GFMUX_UP,
+	BOLERO_MACRO_EVT_PRE_SSR_UP,
 };
 
 enum {
@@ -75,7 +77,8 @@ struct macro_ops {
 			    u32 size, void *data);
 	int (*clk_div_get)(struct snd_soc_component *component);
 	int (*clk_switch)(struct snd_soc_component *component, int clk_src);
-	int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
+	int (*reg_evt_listener)(struct snd_soc_component *component,
+			bool en, bool is_dmic_sva);
 	int (*clk_enable)(struct snd_soc_component *c, bool en);
 	char __iomem *io_base;
 	u16 clk_id_req;
@@ -102,7 +105,7 @@ int bolero_runtime_suspend(struct device *dev);
 int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data);
 int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src);
 int bolero_register_event_listener(struct snd_soc_component *component,
-				   bool enable);
+				   bool enable, bool is_dmic_sva);
 void bolero_wsa_pa_on(struct device *dev);
 bool bolero_check_core_votes(struct device *dev);
 int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable);
@@ -176,7 +179,7 @@ static inline int bolero_tx_clk_switch(struct snd_soc_component *component,
 
 static inline int bolero_register_event_listener(
 					struct snd_soc_component *component,
-					bool enable)
+					bool enable, bool is_dmic_sva)
 {
 	return 0;
 }

+ 20 - 10
asoc/codecs/bolero/bolero-clk-rsc.c

@@ -38,6 +38,7 @@ struct bolero_clk_rsc {
 	int reg_seq_en_cnt;
 	int va_tx_clk_cnt;
 	bool dev_up;
+	bool dev_up_gfmux;
 	u32 num_fs_reg;
 	u32 *fs_gen_seq;
 	int default_clk_id[MAX_CLK];
@@ -65,10 +66,14 @@ static int bolero_clk_rsc_cb(struct device *dev, u16 event)
 	}
 
 	mutex_lock(&priv->rsc_clk_lock);
-	if (event == BOLERO_MACRO_EVT_SSR_UP)
+	if (event == BOLERO_MACRO_EVT_SSR_UP) {
 		priv->dev_up = true;
-	else if (event == BOLERO_MACRO_EVT_SSR_DOWN)
+	} else if (event == BOLERO_MACRO_EVT_SSR_DOWN) {
 		priv->dev_up = false;
+		priv->dev_up_gfmux = false;
+	} else if (event == BOLERO_MACRO_EVT_SSR_GFMUX_UP) {
+		priv->dev_up_gfmux = true;
+	}
 	mutex_unlock(&priv->rsc_clk_lock);
 
 	return 0;
@@ -282,10 +287,12 @@ static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv,
 			 * care in DSP itself
 			 */
 			if (clk_id != VA_CORE_CLK) {
-				iowrite32(0x1, clk_muxsel);
-				muxsel = ioread32(clk_muxsel);
-				trace_printk("%s: muxsel value after enable: %d\n",
-						__func__, muxsel);
+				if (priv->dev_up_gfmux) {
+					iowrite32(0x1, clk_muxsel);
+					muxsel = ioread32(clk_muxsel);
+					trace_printk("%s: muxsel value after enable: %d\n",
+							__func__, muxsel);
+				}
 				bolero_clk_rsc_mux0_clk_request(priv,
 							default_clk_id,
 							false);
@@ -313,10 +320,12 @@ static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv,
 					 * This configuration would be taken
 					 * care in DSP itself.
 					 */
-					iowrite32(0x0, clk_muxsel);
-					muxsel = ioread32(clk_muxsel);
-					trace_printk("%s: muxsel value after disable: %d\n",
-							__func__, muxsel);
+					if (priv->dev_up_gfmux) {
+						iowrite32(0x0, clk_muxsel);
+						muxsel = ioread32(clk_muxsel);
+						trace_printk("%s: muxsel value after disable: %d\n",
+								__func__, muxsel);
+					}
 				}
 			}
 			if (priv->clk[clk_id + NPL_CLK_OFFSET])
@@ -706,6 +715,7 @@ static int bolero_clk_rsc_probe(struct platform_device *pdev)
 	}
 	priv->dev = &pdev->dev;
 	priv->dev_up = true;
+	priv->dev_up_gfmux = true;
 	mutex_init(&priv->rsc_clk_lock);
 	mutex_init(&priv->fs_gen_lock);
 	dev_set_drvdata(&pdev->dev, priv);

+ 59 - 45
asoc/codecs/bolero/rx-macro.c

@@ -378,6 +378,7 @@ struct rx_swr_ctrl_platform_data {
 							  void *data),
 			  void *swrm_handle,
 			  int action);
+	int (*pinctrl_setup)(void *handle, bool enable);
 };
 
 enum {
@@ -1410,11 +1411,7 @@ static int rx_macro_event_handler(struct snd_soc_component *component,
 			}
 		}
 		break;
-	case BOLERO_MACRO_EVT_SSR_UP:
-		trace_printk("%s, enter SSR up\n", __func__);
-		rx_priv->dev_up = true;
-		/* reset swr after ssr/pdr */
-		rx_priv->reset_swr = true;
+	case BOLERO_MACRO_EVT_PRE_SSR_UP:
 		/* enable&disable RX_CORE_CLK to reset GFMUX reg */
 		ret = bolero_clk_rsc_request_clock(rx_priv->dev,
 						rx_priv->default_clk_id,
@@ -1427,6 +1424,12 @@ static int rx_macro_event_handler(struct snd_soc_component *component,
 			bolero_clk_rsc_request_clock(rx_priv->dev,
 						rx_priv->default_clk_id,
 						RX_CORE_CLK, false);
+		break;
+	case BOLERO_MACRO_EVT_SSR_UP:
+		trace_printk("%s, enter SSR up\n", __func__);
+		rx_priv->dev_up = true;
+		/* reset swr after ssr/pdr */
+		rx_priv->reset_swr = true;
 
 		if (rx_priv->swr_ctrl_data)
 			swrm_wcd_notify(
@@ -1709,13 +1712,6 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 	dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n",
 		__func__, event, comp + 1, rx_priv->comp_enabled[comp]);
 
-	if (!rx_priv->comp_enabled[comp])
-		return 0;
-
-	comp_ctl0_reg = BOLERO_CDC_RX_COMPANDER0_CTL0 +
-					(comp * RX_MACRO_COMP_OFFSET);
-	rx_path_cfg0_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0 +
-					(comp * RX_MACRO_RX_PATH_OFFSET);
 	rx_path_cfg3_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG3 +
 					(comp * RX_MACRO_RX_PATH_OFFSET);
 	rx0_path_ctl_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL +
@@ -1731,6 +1727,19 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 	else
 		val = 0x00;
 
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_component_update_bits(component, rx_path_cfg3_reg,
+					0x03, val);
+	if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(component, rx_path_cfg3_reg,
+					0x03, 0x03);
+	if (!rx_priv->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = BOLERO_CDC_RX_COMPANDER0_CTL0 +
+					(comp * RX_MACRO_COMP_OFFSET);
+	rx_path_cfg0_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0 +
+					(comp * RX_MACRO_RX_PATH_OFFSET);
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		/* Enable Compander Clock */
 		snd_soc_component_update_bits(component, comp_ctl0_reg,
@@ -1741,8 +1750,6 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 					0x02, 0x00);
 		snd_soc_component_update_bits(component, rx_path_cfg0_reg,
 					0x02, 0x02);
-		snd_soc_component_update_bits(component, rx_path_cfg3_reg,
-					0x03, val);
 	}
 
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
@@ -1754,8 +1761,6 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
 					0x01, 0x00);
 		snd_soc_component_update_bits(component, comp_ctl0_reg,
 					0x04, 0x00);
-		snd_soc_component_update_bits(component, rx_path_cfg3_reg,
-					0x03, 0x03);
 	}
 
 	return 0;
@@ -1930,7 +1935,12 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
 				0x40, 0x40);
 		break;
 	case INTERP_HPHR:
-		snd_soc_component_update_bits(component,
+		if (rx_priv->is_ear_mode_on)
+			snd_soc_component_update_bits(component,
+				BOLERO_CDC_RX_CLSH_HPH_V_PA,
+				0x3F, 0x39);
+		else
+			snd_soc_component_update_bits(component,
 				BOLERO_CDC_RX_CLSH_HPH_V_PA,
 				0x3F, 0x1C);
 		snd_soc_component_update_bits(component,
@@ -2988,21 +2998,24 @@ static int rx_macro_set_iir_gain(struct snd_soc_dapm_widget *w,
 }
 
 static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
-	SOC_SINGLE_SX_TLV("RX_RX0 Digital Volume",
+	SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume",
 			  BOLERO_CDC_RX_RX0_RX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX_RX1 Digital Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume",
 			  BOLERO_CDC_RX_RX1_RX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX_RX2 Digital Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume",
 			  BOLERO_CDC_RX_RX2_RX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX_RX0 Mix Digital Volume",
-		BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX_RX1 Mix Digital Volume",
-		BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX_RX2 Mix Digital Volume",
-		BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume",
+			  BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume",
+			  BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL,
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume",
+			  BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL,
+			  -84, 40, digital_gain),
 
 	SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0,
 		rx_macro_get_compander, rx_macro_set_compander),
@@ -3031,29 +3044,29 @@ static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
 			rx_macro_aux_hpf_mode_get,
 			rx_macro_aux_hpf_mode_put),
 
-	SOC_SINGLE_SX_TLV("IIR0 INP0 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP0 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP1 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP1 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP2 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP2 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP3 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP3 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP0 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP0 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
-		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+		BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40,
 		digital_gain),
 
 	SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0,
@@ -4092,6 +4105,7 @@ static int rx_macro_probe(struct platform_device *pdev)
 	rx_priv->swr_plat_data.clk = rx_swrm_clock;
 	rx_priv->swr_plat_data.core_vote = rx_macro_core_vote;
 	rx_priv->swr_plat_data.handle_irq = NULL;
+	rx_priv->swr_plat_data.pinctrl_setup = NULL;
 
 	ret = of_property_read_u8_array(pdev->dev.of_node,
 				"qcom,rx-bcl-pmic-params", bcl_pmic_params,

+ 62 - 37
asoc/codecs/bolero/tx-macro.c

@@ -81,6 +81,7 @@ struct tx_macro_swr_ctrl_platform_data {
 							  void *data),
 			  void *swrm_handle,
 			  int action);
+	int (*pinctrl_setup)(void *handle, bool enable);
 };
 
 enum {
@@ -411,6 +412,9 @@ static int tx_macro_event_handler(struct snd_soc_component *component,
 		else
 			tx_priv->hs_slow_insert_complete = false;
 		break;
+	default:
+		pr_debug("%s Invalid Event\n", __func__);
+		break;
 	}
 	return 0;
 }
@@ -2362,18 +2366,18 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
 };
 
 static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = {
-	SOC_SINGLE_SX_TLV("TX_DEC0 Volume",
+	SOC_SINGLE_S8_TLV("TX_DEC0 Volume",
 			  BOLERO_CDC_TX0_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC1 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC1 Volume",
 			  BOLERO_CDC_TX1_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC2 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC2 Volume",
 			  BOLERO_CDC_TX2_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC3 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC3 Volume",
 			  BOLERO_CDC_TX3_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 
 	SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum,
 			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
@@ -2398,18 +2402,18 @@ static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = {
 };
 
 static const struct snd_kcontrol_new tx_macro_snd_controls_v3[] = {
-	SOC_SINGLE_SX_TLV("TX_DEC4 Volume",
+	SOC_SINGLE_S8_TLV("TX_DEC4 Volume",
 			  BOLERO_CDC_TX4_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC5 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC5 Volume",
 			  BOLERO_CDC_TX5_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC6 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC6 Volume",
 			  BOLERO_CDC_TX6_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC7 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC7 Volume",
 			  BOLERO_CDC_TX7_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 
 	SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum,
 			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
@@ -2425,30 +2429,30 @@ static const struct snd_kcontrol_new tx_macro_snd_controls_v3[] = {
 };
 
 static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
-	SOC_SINGLE_SX_TLV("TX_DEC0 Volume",
+	SOC_SINGLE_S8_TLV("TX_DEC0 Volume",
 			  BOLERO_CDC_TX0_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC1 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC1 Volume",
 			  BOLERO_CDC_TX1_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC2 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC2 Volume",
 			  BOLERO_CDC_TX2_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC3 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC3 Volume",
 			  BOLERO_CDC_TX3_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC4 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC4 Volume",
 			  BOLERO_CDC_TX4_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC5 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC5 Volume",
 			  BOLERO_CDC_TX5_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC6 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC6 Volume",
 			  BOLERO_CDC_TX6_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("TX_DEC7 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("TX_DEC7 Volume",
 			  BOLERO_CDC_TX7_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 
 	SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum,
 			tx_macro_dec_mode_get, tx_macro_dec_mode_put),
@@ -2493,12 +2497,30 @@ static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
 		       tx_macro_get_bcs, tx_macro_set_bcs),
 };
 
+static int tx_macro_pinctrl_setup(void *handle, bool enable)
+{
+	struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
+
+	if (tx_priv == NULL) {
+		pr_err("%s: tx priv data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (enable)
+		msm_cdc_pinctrl_set_wakeup_capable(
+			tx_priv->tx_swr_gpio_p, true);
+	else
+		msm_cdc_pinctrl_set_wakeup_capable(
+			tx_priv->tx_swr_gpio_p, false);
+	return 0;
+}
+
 static int tx_macro_register_event_listener(struct snd_soc_component *component,
-					    bool enable)
+					    bool enable, bool is_dmic_sva)
 {
 	struct device *tx_dev = NULL;
 	struct tx_macro_priv *tx_priv = NULL;
 	int ret = 0;
+	u32 dmic_sva = is_dmic_sva;
 
 	if (!component)
 		return -EINVAL;
@@ -2520,15 +2542,17 @@ static int tx_macro_register_event_listener(struct snd_soc_component *component,
 		if (enable) {
 			ret = swrm_wcd_notify(
 				tx_priv->swr_ctrl_data[0].tx_swr_pdev,
-				SWR_REGISTER_WAKEUP, NULL);
+				SWR_REGISTER_WAKEUP, &dmic_sva);
 			msm_cdc_pinctrl_set_wakeup_capable(
-					tx_priv->tx_swr_gpio_p, false);
+				tx_priv->tx_swr_gpio_p, false);
 		} else {
+			/* while teardown we can reset the flag */
+			dmic_sva = 0;
 			msm_cdc_pinctrl_set_wakeup_capable(
-					tx_priv->tx_swr_gpio_p, true);
+				tx_priv->tx_swr_gpio_p, true);
 			ret = swrm_wcd_notify(
 				tx_priv->swr_ctrl_data[0].tx_swr_pdev,
-				SWR_DEREGISTER_WAKEUP, NULL);
+				SWR_DEREGISTER_WAKEUP, &dmic_sva);
 		}
 	}
 
@@ -3319,6 +3343,7 @@ static int tx_macro_probe(struct platform_device *pdev)
 		tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
 		tx_priv->swr_plat_data.core_vote = tx_macro_core_vote;
 		tx_priv->swr_plat_data.handle_irq = NULL;
+		tx_priv->swr_plat_data.pinctrl_setup = tx_macro_pinctrl_setup;
 		mutex_init(&tx_priv->swr_clk_lock);
 	}
 	tx_priv->is_used_tx_swr_gpio = is_used_tx_swr_gpio;

+ 102 - 30
asoc/codecs/bolero/va-macro.c

@@ -16,6 +16,7 @@
 #include <asoc/msm-cdc-pinctrl.h>
 #include <soc/swr-common.h>
 #include <soc/swr-wcd.h>
+#include <dsp/digital-cdc-rsc-mgr.h>
 #include "bolero-cdc.h"
 #include "bolero-cdc-registers.h"
 #include "bolero-clk-rsc.h"
@@ -129,6 +130,7 @@ struct va_macro_swr_ctrl_platform_data {
 							  void *data),
 			  void *swrm_handle,
 			  int action);
+	int (*pinctrl_setup)(void *handle, bool enable);
 };
 
 struct va_macro_priv {
@@ -297,8 +299,7 @@ static int va_macro_event_handler(struct snd_soc_component *component,
 				"%s: va_mclk_users is non-zero still, audio SSR fail!!\n",
 				__func__);
 		break;
-	case BOLERO_MACRO_EVT_SSR_UP:
-		trace_printk("%s, enter SSR up\n", __func__);
+	case BOLERO_MACRO_EVT_PRE_SSR_UP:
 		/* enable&disable VA_CORE_CLK to reset GFMUX reg */
 		ret = bolero_clk_rsc_request_clock(va_priv->dev,
 						va_priv->default_clk_id,
@@ -311,6 +312,9 @@ static int va_macro_event_handler(struct snd_soc_component *component,
 			bolero_clk_rsc_request_clock(va_priv->dev,
 						va_priv->default_clk_id,
 						VA_CORE_CLK, false);
+		break;
+	case BOLERO_MACRO_EVT_SSR_UP:
+		trace_printk("%s, enter SSR up\n", __func__);
 		/* reset swr after ssr/pdr */
 		va_priv->reset_swr = true;
 		if (va_priv->swr_ctrl_data)
@@ -444,7 +448,8 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (va_priv->lpass_audio_hw_vote) {
-			ret = clk_prepare_enable(va_priv->lpass_audio_hw_vote);
+			ret = digital_cdc_rsc_mgr_hw_vote_enable(
+					va_priv->lpass_audio_hw_vote);
 			if (ret)
 				dev_err(va_dev,
 					"%s: lpass audio hw enable failed\n",
@@ -455,19 +460,59 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
 				dev_dbg(va_dev, "%s: clock switch failed\n",
 					__func__);
 		if (va_priv->lpi_enable) {
-			bolero_register_event_listener(component, true);
+			bolero_register_event_listener(component, true, false);
 			va_priv->register_event_listener = true;
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		if (va_priv->register_event_listener) {
 			va_priv->register_event_listener = false;
-			bolero_register_event_listener(component, false);
+			bolero_register_event_listener(component, false, false);
 		}
 		if (bolero_tx_clk_switch(component, CLK_SRC_TX_RCG))
 			dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
 		if (va_priv->lpass_audio_hw_vote)
-			clk_disable_unprepare(va_priv->lpass_audio_hw_vote);
+			digital_cdc_rsc_mgr_hw_vote_disable(
+				va_priv->lpass_audio_hw_vote);
+		break;
+	default:
+		dev_err(va_priv->dev,
+			"%s: invalid DAPM event %d\n", __func__, event);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int va_macro_swr_intr_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);
+	int ret = 0;
+	struct device *va_dev = NULL;
+	struct va_macro_priv *va_priv = NULL;
+
+	if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+		return -EINVAL;
+
+	dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n",
+		__func__, event, va_priv->lpi_enable);
+
+	if (!va_priv->lpi_enable)
+		return ret;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (va_priv->lpi_enable) {
+			bolero_register_event_listener(component, true, true);
+			va_priv->register_event_listener = true;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (va_priv->register_event_listener) {
+			va_priv->register_event_listener = false;
+			bolero_register_event_listener(component, false, true);
+		}
 		break;
 	default:
 		dev_err(va_priv->dev,
@@ -1984,6 +2029,10 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v3[] = {
 	SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", -1, SND_SOC_NOPM, 0, 0,
 			      va_macro_swr_pwr_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("VA_SWR_INTR", 0, SND_SOC_NOPM, 0, 0,
+			      va_macro_swr_intr_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
@@ -2128,6 +2177,10 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0,
 			      va_macro_mclk_event,
 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("VA_SWR_INTR", 0, SND_SOC_NOPM, 0, 0,
+			      va_macro_swr_intr_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_widget va_macro_wod_dapm_widgets[] = {
@@ -2274,6 +2327,15 @@ static const struct snd_soc_dapm_route va_audio_map_v3[] = {
 	{"VA SMIC MUX3", "SWR_MIC9", "VA SWR_INPUT"},
 	{"VA SMIC MUX3", "SWR_MIC10", "VA SWR_INPUT"},
 	{"VA SMIC MUX3", "SWR_MIC11", "VA SWR_INPUT"},
+
+	{"VA DMIC0", NULL, "VA_SWR_INTR"},
+	{"VA DMIC1", NULL, "VA_SWR_INTR"},
+	{"VA DMIC2", NULL, "VA_SWR_INTR"},
+	{"VA DMIC3", NULL, "VA_SWR_INTR"},
+	{"VA DMIC4", NULL, "VA_SWR_INTR"},
+	{"VA DMIC5", NULL, "VA_SWR_INTR"},
+	{"VA DMIC6", NULL, "VA_SWR_INTR"},
+	{"VA DMIC7", NULL, "VA_SWR_INTR"},
 };
 
 static const struct snd_soc_dapm_route va_audio_map_v2[] = {
@@ -2510,6 +2572,15 @@ static const struct snd_soc_dapm_route va_audio_map[] = {
 	{"VA SMIC MUX7", "SWR_DMIC6", "VA SWR_MIC6"},
 	{"VA SMIC MUX7", "SWR_DMIC7", "VA SWR_MIC7"},
 
+	{"VA DMIC0", NULL, "VA_SWR_INTR"},
+	{"VA DMIC1", NULL, "VA_SWR_INTR"},
+	{"VA DMIC2", NULL, "VA_SWR_INTR"},
+	{"VA DMIC3", NULL, "VA_SWR_INTR"},
+	{"VA DMIC4", NULL, "VA_SWR_INTR"},
+	{"VA DMIC5", NULL, "VA_SWR_INTR"},
+	{"VA DMIC6", NULL, "VA_SWR_INTR"},
+	{"VA DMIC7", NULL, "VA_SWR_INTR"},
+
 	{"VA SWR_ADC0", NULL, "VA_SWR_PWR"},
 	{"VA SWR_ADC1", NULL, "VA_SWR_PWR"},
 	{"VA SWR_ADC2", NULL, "VA_SWR_PWR"},
@@ -2533,30 +2604,30 @@ static const struct soc_enum dec_mode_mux_enum =
 			    dec_mode_mux_text);
 
 static const struct snd_kcontrol_new va_macro_snd_controls[] = {
-	SOC_SINGLE_SX_TLV("VA_DEC0 Volume",
+	SOC_SINGLE_S8_TLV("VA_DEC0 Volume",
 			  BOLERO_CDC_VA_TX0_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC1 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC1 Volume",
 			  BOLERO_CDC_VA_TX1_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC2 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC2 Volume",
 			  BOLERO_CDC_VA_TX2_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC3 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC3 Volume",
 			  BOLERO_CDC_VA_TX3_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC4 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC4 Volume",
 			  BOLERO_CDC_VA_TX4_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC5 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC5 Volume",
 			  BOLERO_CDC_VA_TX5_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC6 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC6 Volume",
 			  BOLERO_CDC_VA_TX6_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC7 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC7 Volume",
 			  BOLERO_CDC_VA_TX7_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 	SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0,
 		va_macro_lpi_get, va_macro_lpi_put),
 
@@ -2574,23 +2645,23 @@ static const struct snd_kcontrol_new va_macro_snd_controls[] = {
 };
 
 static const struct snd_kcontrol_new va_macro_snd_controls_common[] = {
-	SOC_SINGLE_SX_TLV("VA_DEC0 Volume",
+	SOC_SINGLE_S8_TLV("VA_DEC0 Volume",
 			  BOLERO_CDC_VA_TX0_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC1 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC1 Volume",
 			  BOLERO_CDC_VA_TX1_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 	SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0,
 		va_macro_lpi_get, va_macro_lpi_put),
 };
 
 static const struct snd_kcontrol_new va_macro_snd_controls_v3[] = {
-	SOC_SINGLE_SX_TLV("VA_DEC2 Volume",
+	SOC_SINGLE_S8_TLV("VA_DEC2 Volume",
 			  BOLERO_CDC_VA_TX2_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("VA_DEC3 Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("VA_DEC3 Volume",
 			  BOLERO_CDC_VA_TX3_TX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 };
 
 static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
@@ -3159,6 +3230,7 @@ static int va_macro_probe(struct platform_device *pdev)
 		va_priv->swr_plat_data.clk = va_macro_swrm_clock;
 		va_priv->swr_plat_data.core_vote = va_macro_core_vote;
 		va_priv->swr_plat_data.handle_irq = NULL;
+		va_priv->swr_plat_data.pinctrl_setup = NULL;
 		mutex_init(&va_priv->swr_clk_lock);
 	}
 	va_priv->is_used_va_swr_gpio = is_used_va_swr_gpio;

+ 54 - 49
asoc/codecs/bolero/wsa-macro.c

@@ -166,6 +166,7 @@ struct wsa_macro_swr_ctrl_platform_data {
 							  void *data),
 			  void *swrm_handle,
 			  int action);
+	int (*pinctrl_setup)(void *handle, bool enable);
 };
 
 struct wsa_macro_bcl_pmic_params {
@@ -1022,10 +1023,7 @@ static int wsa_macro_event_handler(struct snd_soc_component *component,
 			}
 		}
 		break;
-	case BOLERO_MACRO_EVT_SSR_UP:
-		trace_printk("%s, enter SSR up\n", __func__);
-		/* reset swr after ssr/pdr */
-		wsa_priv->reset_swr = true;
+	case BOLERO_MACRO_EVT_PRE_SSR_UP:
 		/* enable&disable WSA_CORE_CLK to reset GFMUX reg */
 		ret = bolero_clk_rsc_request_clock(wsa_priv->dev,
 						wsa_priv->default_clk_id,
@@ -1038,6 +1036,11 @@ static int wsa_macro_event_handler(struct snd_soc_component *component,
 			bolero_clk_rsc_request_clock(wsa_priv->dev,
 						wsa_priv->default_clk_id,
 						WSA_CORE_CLK, false);
+		break;
+	case BOLERO_MACRO_EVT_SSR_UP:
+		trace_printk("%s, enter SSR up\n", __func__);
+		/* reset swr after ssr/pdr */
+		wsa_priv->reset_swr = true;
 		if (wsa_priv->swr_ctrl_data)
 			swrm_wcd_notify(
 				wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
@@ -1178,45 +1181,6 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_component *component =
-				snd_soc_dapm_to_component(w->dapm);
-	u16 gain_reg;
-	int offset_val = 0;
-	int val = 0;
-
-	dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name);
-
-	switch (w->reg) {
-	case BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL:
-		gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL;
-		break;
-	case BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL:
-		gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL;
-		break;
-	default:
-		dev_err(component->dev, "%s: No gain register avail for %s\n",
-			__func__, w->name);
-		return 0;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		val = snd_soc_component_read32(component, gain_reg);
-		val += offset_val;
-		snd_soc_component_write(component, gain_reg, val);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_update_bits(component,
-					w->reg, 0x20, 0x00);
-		break;
-	}
-
-	return 0;
-}
-
 static void wsa_macro_hd2_control(struct snd_soc_component *component,
 				  u16 reg, int event)
 {
@@ -1303,6 +1267,44 @@ static int wsa_macro_enable_swr(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
+static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+				snd_soc_dapm_to_component(w->dapm);
+	u16 gain_reg;
+	int offset_val = 0;
+	int val = 0;
+
+	dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (!(strcmp(w->name, "WSA_RX0 MIX INP"))) {
+		gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL;
+	} else if (!(strcmp(w->name, "WSA_RX1 MIX INP"))) {
+		gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL;
+	} else {
+		dev_err(component->dev, "%s: No gain register avail for %s\n",
+			__func__, w->name);
+		return 0;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wsa_macro_enable_swr(w, kcontrol, event);
+		val = snd_soc_component_read32(component, gain_reg);
+		val += offset_val;
+		snd_soc_component_write(component, gain_reg, val);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+					w->reg, 0x20, 0x00);
+		wsa_macro_enable_swr(w, kcontrol, event);
+		break;
+	}
+
+	return 0;
+}
+
 static int wsa_macro_config_compander(struct snd_soc_component *component,
 				int comp, int event)
 {
@@ -2370,12 +2372,12 @@ static const struct snd_kcontrol_new wsa_macro_snd_controls[] = {
 			WSA_MACRO_SOFTCLIP1, 1, 0,
 			wsa_macro_soft_clip_enable_get,
 			wsa_macro_soft_clip_enable_put),
-	SOC_SINGLE_SX_TLV("WSA_RX0 Digital Volume",
+	SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume",
 			  BOLERO_CDC_WSA_RX0_RX_VOL_CTL,
-			  0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("WSA_RX1 Digital Volume",
+			  -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume",
 			  BOLERO_CDC_WSA_RX1_RX_VOL_CTL,
-			  0, -84, 40, digital_gain),
+			  -84, 40, digital_gain),
 	SOC_SINGLE_EXT("WSA_RX0 Digital Mute", SND_SOC_NOPM, WSA_MACRO_RX0, 1,
 			0, wsa_macro_get_rx_mute_status,
 			wsa_macro_set_rx_mute_status),
@@ -2550,7 +2552,7 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0,
 		&rx0_prim_inp2_mux, wsa_macro_enable_swr,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL,
+	SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM,
 		0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0,
@@ -2562,7 +2564,7 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0,
 		&rx1_prim_inp2_mux, wsa_macro_enable_swr,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL,
+	SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM,
 		0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM,
@@ -3175,6 +3177,8 @@ static int wsa_macro_probe(struct platform_device *pdev)
 			__func__);
 		return -EPROBE_DEFER;
 	}
+	msm_cdc_pinctrl_set_wakeup_capable(
+				wsa_priv->wsa_swr_gpio_p, false);
 
 	wsa_io_base = devm_ioremap(&pdev->dev,
 				   wsa_base_addr, WSA_MACRO_MAX_OFFSET);
@@ -3193,6 +3197,7 @@ static int wsa_macro_probe(struct platform_device *pdev)
 	wsa_priv->swr_plat_data.clk = wsa_swrm_clock;
 	wsa_priv->swr_plat_data.core_vote = wsa_macro_core_vote;
 	wsa_priv->swr_plat_data.handle_irq = NULL;
+	wsa_priv->swr_plat_data.pinctrl_setup = NULL;
 
 	ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
 				   &default_clk_id);

+ 20 - 1
asoc/codecs/csra66x0/csra66x0.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -602,6 +602,25 @@ static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = {
 	{"PGA", NULL, "DAC"},
 	{"SPKR", NULL, "PGA"},
 };
+/*
+ * csra66x0_hw_free_mute - Update csra66x0 mute register
+ *
+ * @component - csra66x0 component
+ *
+ */
+void csra66x0_hw_free_mute(struct snd_soc_component *component)
+{
+	int val = 0;
+
+	if (component == NULL)
+		return;
+
+	val = snd_soc_component_read32(component,
+			CSRA66X0_MISC_CONTROL_STATUS_1_FA);
+	snd_soc_component_write(component, CSRA66X0_MISC_CONTROL_STATUS_1_FA,
+			val | 0x04);
+}
+EXPORT_SYMBOL(csra66x0_hw_free_mute);
 
 static int csra66x0_wait_for_config_state(struct snd_soc_component *component)
 {

+ 3 - 1
asoc/codecs/csra66x0/csra66x0.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CSRA66X0_H
@@ -226,4 +226,6 @@
 #define FAULT_STATUS_TEMP           0x10
 #define FAULT_STATUS_PROTECT        0x20
 
+
+void csra66x0_hw_free_mute(struct snd_soc_component *component);
 #endif /* _CSRA66X0_H */

+ 48 - 2
asoc/codecs/ep92/ep92.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -40,6 +40,10 @@ static const unsigned int ep92_samp_freq_table[8] = {
 	32000, 44100, 48000, 88200, 96000, 176400, 192000, 768000
 };
 
+static const unsigned int ep92_dsd_freq_table[4] = {
+	64, 128, 256, 0
+};
+
 static bool ep92_volatile_register(struct device *dev, unsigned int reg)
 {
 	/* do not cache register state in regmap */
@@ -549,6 +553,23 @@ static void ep92_read_audio_info(struct snd_soc_component *component,
 		send_uevent = true;
 	}
 
+	old = ep92->ai.system_status_1;
+	ep92->ai.system_status_1 = snd_soc_read(codec,
+		EP92_AUDIO_INFO_SYSTEM_STATUS_1);
+	if (ep92->ai.system_status_1 == 0xff) {
+		dev_dbg(codec->dev,
+			"ep92 EP92_AUDIO_INFO_SYSTEM_STATUS_1 read 0xff\n");
+		ep92->ai.system_status_1 = old;
+	}
+	change = ep92->ai.system_status_1 ^ old;
+	if (change & EP92_AI_DSD_RATE_MASK) {
+		dev_dbg(codec->dev, "ep92 dsd rate changed to %d\n",
+			ep92_dsd_freq_table[(ep92->ai.system_status_1 &
+				EP92_AI_DSD_RATE_MASK)
+				>> EP92_AI_DSD_RATE_SHIFT]);
+		send_uevent = true;
+	}
+
 	old = ep92->ai.audio_status;
 	ep92->ai.audio_status = snd_soc_component_read32(component,
 		EP92_AUDIO_INFO_AUDIO_STATUS);
@@ -580,7 +601,9 @@ static void ep92_read_audio_info(struct snd_soc_component *component,
 	}
 
 	new_mode = ep92->old_mode;
-	if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) {
+	if (ep92->ai.audio_status & EP92_AI_DSD_ADO_MASK)
+		new_mode = 2; /* One bit audio */
+	else if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) {
 		if (ep92->ai.cs[0] & EP92_AI_NPCM_MASK)
 			new_mode = 1; /* Compr */
 		else
@@ -897,6 +920,27 @@ static ssize_t ep92_sysfs_rda_audio_format(struct device *dev,
 	return ret;
 }
 
+static ssize_t ep92_sysfs_rda_dsd_rate(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	int val;
+	struct ep92_pdata *ep92 = dev_get_drvdata(dev);
+
+	if (!ep92 || !ep92->codec) {
+		dev_err(dev, "%s: device error\n", __func__);
+		return -ENODEV;
+	}
+
+	val = ep92_dsd_freq_table[(ep92->ai.system_status_1 &
+			EP92_AI_DSD_RATE_MASK) >> EP92_AI_DSD_RATE_SHIFT];
+
+	ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
+	dev_dbg(dev, "%s: '%d'\n", __func__, val);
+
+	return ret;
+}
+
 static ssize_t ep92_sysfs_rda_audio_rate(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -1621,6 +1665,7 @@ static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume,
 static DEVICE_ATTR(runout, 0444, ep92_sysfs_rda_runout, NULL);
 static DEVICE_ATTR(force_inactive, 0644, ep92_sysfs_rda_force_inactive,
 	ep92_sysfs_wta_force_inactive);
+static DEVICE_ATTR(dsd_rate, 0444, ep92_sysfs_rda_dsd_rate, NULL);
 
 static struct attribute *ep92_fs_attrs[] = {
 	&dev_attr_chipid.attr,
@@ -1647,6 +1692,7 @@ static struct attribute *ep92_fs_attrs[] = {
 	&dev_attr_cec_volume.attr,
 	&dev_attr_runout.attr,
 	&dev_attr_force_inactive.attr,
+	&dev_attr_dsd_rate.attr,
 	NULL,
 };
 

+ 5 - 1
asoc/codecs/ep92/ep92.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __EP92_H__
@@ -175,6 +175,10 @@ static struct reg_default ep92_reg_defaults[] = {
 #define EP92_AI_PREEMPH_MASK     0x38
 #define EP92_AI_CH_COUNT_MASK    0x07
 #define EP92_AI_CH_ALLOC_MASK    0xff
+#define EP92_AI_DSD_ADO_SHIFT    4
+#define EP92_AI_DSD_ADO_MASK     0x10
+#define EP92_AI_DSD_RATE_SHIFT   4
+#define EP92_AI_DSD_RATE_MASK    0x30
 
 #define EP92_2CHOICE_MASK        1
 #define EP92_GC_CEC_VOLUME_MIN   0

+ 35 - 1
asoc/codecs/msm-cdc-pinctrl.c

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/kernel.h>
@@ -21,6 +21,7 @@ struct msm_cdc_pinctrl_info {
 	struct pinctrl *pinctrl;
 	struct pinctrl_state *pinctrl_active;
 	struct pinctrl_state *pinctrl_sleep;
+	struct pinctrl_state *pinctrl_alt_active;
 	int gpio;
 	bool state;
 	u32 tlmm_gpio[MAX_GPIOS];
@@ -104,6 +105,31 @@ int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
 }
 EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state);
 
+/*
+ * msm_cdc_pinctrl_select_alt_active_state: select pinctrl alt_active state
+ * @np: pointer to struct device_node
+ *
+ * Returns error code for failure
+ */
+int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np)
+{
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
+	if (!gpio_data)
+		return -EINVAL;
+
+	if (!gpio_data->pinctrl_alt_active) {
+		pr_err("%s: pinctrl alt_active state is null\n", __func__);
+		return -EINVAL;
+	}
+	gpio_data->state = true;
+
+	return pinctrl_select_state(gpio_data->pinctrl,
+				    gpio_data->pinctrl_alt_active);
+}
+EXPORT_SYMBOL(msm_cdc_pinctrl_select_alt_active_state);
+
 /*
  * msm_cdc_pinctrl_select_active_state: select pinctrl active state
  * @np: pointer to struct device_node
@@ -231,6 +257,14 @@ static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
 		ret = PTR_ERR(gpio_data->pinctrl_sleep);
 		goto err_lookup_state;
 	}
+
+	gpio_data->pinctrl_alt_active = pinctrl_lookup_state(
+					gpio_data->pinctrl, "aud_alt_active");
+	if (IS_ERR_OR_NULL(gpio_data->pinctrl_alt_active)) {
+		dev_dbg(&pdev->dev, "%s: Cannot get aud_alt_active pinctrl state:%ld\n",
+			__func__, PTR_ERR(gpio_data->pinctrl_alt_active));
+	}
+
 	/* skip setting to sleep state for LPI_TLMM GPIOs */
 	if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
 		/* Set pinctrl state to aud_sleep by default */

+ 68 - 2
asoc/codecs/msm-cdc-supply.c

@@ -60,9 +60,22 @@ static int msm_cdc_dt_parse_vreg_info(struct device *dev,
 	}
 	cdc_vreg->optimum_uA = prop_val;
 
-	dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n",
+	/* Parse supply - LPM or NOM mode(default NOM) */
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-lpm-supported", name);
+	rc = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (rc) {
+		dev_dbg(dev, "%s: Looking up %s property in node %s failed",
+			__func__, prop_name, dev->of_node->full_name);
+		cdc_vreg->lpm_supported = 0;
+		rc = 0;
+	} else {
+		cdc_vreg->lpm_supported = prop_val;
+	}
+
+	dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d lpm %d\n",
 		 __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV,
-		 cdc_vreg->optimum_uA, cdc_vreg->ondemand);
+		 cdc_vreg->optimum_uA, cdc_vreg->ondemand,
+		 cdc_vreg->lpm_supported);
 
 done:
 	return rc;
@@ -260,6 +273,59 @@ int msm_cdc_enable_ondemand_supply(struct device *dev,
 }
 EXPORT_SYMBOL(msm_cdc_enable_ondemand_supply);
 
+/*
+ * msm_cdc_set_supplies_lpm_mode:
+ *	Update load for given supply string
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ * @supply_name: supply name to be checked
+ * @min_max: Apply optimum or 0 current
+ *
+ * Return error code if set current fail
+ */
+int msm_cdc_set_supplies_lpm_mode(struct device *dev,
+				struct regulator_bulk_data *supplies,
+				struct cdc_regulator *cdc_vreg,
+				int num_supplies,
+				bool flag)
+{
+	int rc = 0, i;
+
+	if (!supplies) {
+		pr_err("%s: supplies is NULL\n",
+				__func__);
+		return -EINVAL;
+	}
+	/* input parameter validation */
+	rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < num_supplies; i++) {
+		if (cdc_vreg[i].lpm_supported) {
+			rc = regulator_set_load(
+				supplies[i].consumer,
+				flag ? 0 : cdc_vreg[i].optimum_uA);
+			if (rc)
+				dev_err(dev,
+					"%s: failed to set supply %s to %s, err:%d\n",
+					__func__, supplies[i].supply,
+					flag ? "LPM" : "NOM",
+					rc);
+			else
+				dev_dbg(dev, "%s: regulator %s load set to %s\n",
+					__func__, supplies[i].supply,
+					flag ? "LPM" : "NOM");
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_cdc_set_supplies_lpm_mode);
+
 /*
  * msm_cdc_disable_static_supplies:
  *	Disable codec static supplies

+ 85 - 14
asoc/codecs/msm_hdmi_codec_rx.c

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  */
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -25,8 +25,8 @@
 	static SOC_ENUM_SINGLE_DECL(ext_disp_audio_ack_state##index, \
 			    SND_SOC_NOPM, index, ext_disp_audio_ack_text)
 
-#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id) \
-	codec_info.type = EXT_DISPLAY_TYPE_DP; \
+#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type) \
+	codec_info.type = type; \
 	codec_info.ctrl_id = codec_data->ctl[dai_id]; \
 	codec_info.stream_id = codec_data->stream[dai_id]; \
 
@@ -38,6 +38,7 @@ enum {
 enum {
 	DP_STREAM0 = 0,
 	DP_STREAM1,
+	HDMI,
 	DP_STREAM_MAX,
 };
 
@@ -49,6 +50,7 @@ enum {
 	DP_DAI1 = 1,
 	DP_DAI2,
 	HDMI_DAI,
+	HDMI_MS_DAI,
 	DP_DAI_MAX,
 };
 
@@ -60,6 +62,8 @@ SOC_EXT_DISP_AUDIO_TYPE(1);
 SOC_EXT_DISP_AUDIO_ACK_STATE(1);
 SOC_EXT_DISP_AUDIO_TYPE(2);
 SOC_EXT_DISP_AUDIO_ACK_STATE(2);
+SOC_EXT_DISP_AUDIO_TYPE(3);
+SOC_EXT_DISP_AUDIO_ACK_STATE(3);
 
 struct msm_ext_disp_audio_codec_rx_data {
 	struct platform_device *ext_disp_core_pdev;
@@ -80,6 +84,7 @@ static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
 	int rc = 0;
 	struct msm_ext_disp_codec_id codec_info;
 	int dai_id = kcontrol->private_value;
+	int type;
 
 	codec_data = snd_soc_component_get_drvdata(component);
 	if (!codec_data) {
@@ -91,7 +96,11 @@ static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
 		codec_data->ctl[dai_id], codec_data->stream[dai_id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
+	if (dai_id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 	if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) {
@@ -126,6 +135,7 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
 	struct msm_ext_disp_codec_id codec_info;
 	int rc = 0;
 	int dai_id = kcontrol->private_value;
+	int type;
 
 	codec_data = snd_soc_component_get_drvdata(component);
 	if (!codec_data) {
@@ -138,7 +148,11 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
 		codec_data->ctl[dai_id], codec_data->stream[dai_id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
+	if (dai_id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 	if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) {
@@ -147,7 +161,6 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
 		mutex_unlock(&codec_data->dp_ops_lock);
 		return -EINVAL;
 	}
-
 	rc = codec_data->ext_disp_ops.get_audio_edid_blk(
 			codec_data->ext_disp_core_pdev, &edid_blk);
 	mutex_unlock(&codec_data->dp_ops_lock);
@@ -188,6 +201,7 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
 	struct msm_ext_disp_codec_id codec_info;
 	int rc = 0;
 	int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
+	int type;
 
 	codec_data = snd_soc_component_get_drvdata(component);
 	if (!codec_data) {
@@ -200,7 +214,11 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
 		codec_data->ctl[dai_id], codec_data->stream[dai_id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
+	if (dai_id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 
@@ -213,7 +231,7 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
 	}
 
 	cable_state = codec_data->ext_disp_ops.cable_status(
-				   codec_data->ext_disp_core_pdev, 1);
+				codec_data->ext_disp_core_pdev, 1);
 	if (cable_state < 0) {
 		dev_err(component->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n",
 			__func__, cable_state);
@@ -274,6 +292,7 @@ static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
 	struct msm_ext_disp_codec_id codec_info;
 	int rc = 0;
 	int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
+	int type;
 
 	codec_data = snd_soc_component_get_drvdata(component);
 	if (!codec_data) {
@@ -287,7 +306,11 @@ static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
 		codec_data->ctl[dai_id], codec_data->stream[dai_id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
+	if (dai_id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 
@@ -421,6 +444,15 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
 		.get    = msm_ext_disp_edid_get,
 		.private_value = HDMI_DAI,
 	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface  = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name   = "HDMI MS EDID",
+		.info   = msm_ext_disp_edid_ctl_info,
+		.get    = msm_ext_disp_edid_get,
+		.private_value = HDMI_MS_DAI,
+	},
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ |
 			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -445,12 +477,18 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
 	SOC_ENUM_EXT("External Display1 Type",
 		     ext_disp_audio_type2,
 		     msm_ext_disp_audio_type_get, NULL),
+	SOC_ENUM_EXT("External HDMI Type",
+		     ext_disp_audio_type3,
+		     msm_ext_disp_audio_type_get, NULL),
 	SOC_ENUM_EXT("External Display Audio Ack",
 		     ext_disp_audio_ack_state1,
 		     NULL, msm_ext_disp_audio_ack_set),
 	SOC_ENUM_EXT("External Display1 Audio Ack",
 		     ext_disp_audio_ack_state2,
 		     NULL, msm_ext_disp_audio_ack_set),
+	SOC_ENUM_EXT("External HDMI Audio Ack",
+		     ext_disp_audio_ack_state3,
+		     NULL, msm_ext_disp_audio_ack_set),
 
 	SOC_SINGLE_MULTI_EXT("External Display Audio Device",
 			SND_SOC_NOPM, DP_DAI1, DP_STREAM_MAX - 1, 0, 2,
@@ -460,6 +498,11 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
 			SND_SOC_NOPM, DP_DAI2, DP_STREAM_MAX - 1, 0, 2,
 			msm_ext_disp_audio_device_get,
 			msm_ext_disp_audio_device_set),
+	SOC_SINGLE_MULTI_EXT("External HDMI Device",
+			SND_SOC_NOPM, HDMI_MS_DAI, DP_STREAM_MAX - 1, 0, 2,
+			msm_ext_disp_audio_device_get,
+			msm_ext_disp_audio_device_set),
+
 };
 
 static int msm_ext_disp_audio_codec_rx_dai_startup(
@@ -470,6 +513,7 @@ static int msm_ext_disp_audio_codec_rx_dai_startup(
 	struct msm_ext_disp_codec_id codec_info;
 	struct msm_ext_disp_audio_codec_rx_data *codec_data =
 			dev_get_drvdata(dai->component->dev);
+	int type;
 
 	if (!codec_data) {
 		dev_err(dai->dev, "%s() codec_data is null\n",
@@ -482,7 +526,11 @@ static int msm_ext_disp_audio_codec_rx_dai_startup(
 		codec_data->ctl[dai->id], codec_data->stream[dai->id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+	if (dai->id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 
@@ -524,7 +572,7 @@ static int msm_ext_disp_audio_codec_rx_dai_hw_params(
 	struct msm_ext_disp_codec_id codec_info;
 	int rc = 0;
 	struct msm_ext_disp_audio_setup_params audio_setup_params = {0};
-
+	int type;
 	struct msm_ext_disp_audio_codec_rx_data *codec_data =
 			dev_get_drvdata(dai->component->dev);
 
@@ -539,7 +587,11 @@ static int msm_ext_disp_audio_codec_rx_dai_hw_params(
 		codec_data->ctl[dai->id], codec_data->stream[dai->id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+	if (dai->id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 
@@ -609,7 +661,7 @@ static int msm_ext_disp_audio_codec_rx_dai_hw_params(
 	audio_setup_params.down_mix = down_mix;
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+	SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 	if (rc)
@@ -636,6 +688,7 @@ static void msm_ext_disp_audio_codec_rx_dai_shutdown(
 
 	struct msm_ext_disp_audio_codec_rx_data *codec_data =
 			dev_get_drvdata(dai->component->dev);
+	int type;
 
 	if (!codec_data) {
 		dev_err(dai->dev, "%s() codec_data is null\n",
@@ -648,7 +701,11 @@ static void msm_ext_disp_audio_codec_rx_dai_shutdown(
 		codec_data->ctl[dai->id], codec_data->stream[dai->id]);
 
 	mutex_lock(&codec_data->dp_ops_lock);
-	SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+	if (dai->id == HDMI_MS_DAI)
+		type = EXT_DISPLAY_TYPE_HDMI;
+	else
+		type = EXT_DISPLAY_TYPE_DP;
+	SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
 	rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
 						 &codec_info);
 
@@ -754,6 +811,20 @@ static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = {
 		},
 		.ops = &msm_ext_disp_audio_codec_rx_dai_ops,
 	},
+	{
+		.name = "msm_hdmi_ms_audio_codec_rx_dai",
+		.id = HDMI_MS_DAI,
+		.playback = {
+			.stream_name = "HDMI MS Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min = 48000,
+			.rate_max = 48000,
+			.rates = MSM_EXT_DISP_PCM_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &msm_ext_disp_audio_codec_rx_dai_ops,
+	},
 	{
 		.name = "msm_dp_audio_codec_rx_dai",
 		.id = DP_DAI1,

+ 5 - 0
asoc/codecs/rouleur/internal.h

@@ -50,6 +50,7 @@ struct rouleur_priv {
 
 	bool comp1_enable;
 	bool comp2_enable;
+	bool dapm_bias_off;
 
 	struct irq_domain *virq;
 	struct wcd_irq_info irq_info;
@@ -82,6 +83,8 @@ struct rouleur_priv {
 	int mbias_cnt;
 	struct mutex rx_clk_lock;
 	struct mutex main_bias_lock;
+	bool dev_up;
+	bool usbc_hs_status;
 };
 
 struct rouleur_micbias_setting {
@@ -169,4 +172,6 @@ extern int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
 extern int rouleur_get_micb_vout_ctl_val(u32 micb_mv);
 extern int rouleur_micbias_control(struct snd_soc_component *component,
 			int micb_num, int req, bool is_dapm);
+extern int rouleur_global_mbias_enable(struct snd_soc_component *component);
+extern int rouleur_global_mbias_disable(struct snd_soc_component *component);
 #endif

+ 209 - 216
asoc/codecs/rouleur/rouleur-mbhc.c

@@ -22,20 +22,19 @@
 
 #define ROULEUR_ZDET_SUPPORTED          true
 /* Z value defined in milliohm */
-#define ROULEUR_ZDET_VAL_32             32000
-#define ROULEUR_ZDET_VAL_400            400000
-#define ROULEUR_ZDET_VAL_1200           1200000
 #define ROULEUR_ZDET_VAL_100K           100000000
 /* Z floating defined in ohms */
 #define ROULEUR_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
 
-#define ROULEUR_ZDET_NUM_MEASUREMENTS   900
-#define ROULEUR_MBHC_GET_C1(c)          ((c & 0xC000) >> 14)
-#define ROULEUR_MBHC_GET_X1(x)          (x & 0x3FFF)
-/* Z value compared in milliOhm */
-#define ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
-#define ROULEUR_MBHC_ZDET_CONST         (86 * 16384)
-#define ROULEUR_MBHC_MOISTURE_RREF      R_24_KOHM
+#define ROULEUR_ZDET_NUM_MEASUREMENTS   100
+#define ROULEUR_ZDET_RMAX               1280000
+#define ROULEUR_ZDET_C1                 7500000
+#define ROULEUR_ZDET_C2                 187
+#define ROULEUR_ZDET_C3                 4500
+
+/* Cross connection thresholds in mV */
+#define ROULEUR_HPHL_CROSS_CONN_THRESHOLD 200
+#define ROULEUR_HPHR_CROSS_CONN_THRESHOLD 200
 
 static struct wcd_mbhc_register
 	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
@@ -88,7 +87,7 @@ static struct wcd_mbhc_register
 	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
 			  ROULEUR_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
 	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
-			  ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x04, 2, 0),
+			  ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x06, 1, 0),
 	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
 			  SND_SOC_NOPM, 0x00, 0, 0),
 	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
@@ -153,9 +152,6 @@ struct rouleur_mbhc_zdet_param {
 	u16 ldo_ctl;
 	u16 noff;
 	u16 nshift;
-	u16 btn5;
-	u16 btn6;
-	u16 btn7;
 };
 
 static int rouleur_mbhc_request_irq(struct snd_soc_component *component,
@@ -320,11 +316,11 @@ static void rouleur_mbhc_micb_ramp_control(struct snd_soc_component *component,
 					0x1C, 0x0C);
 		snd_soc_component_update_bits(component,
 					ROULEUR_ANA_MBHC_MICB2_RAMP,
-					0xA0, 0x80);
+					0x80, 0x80);
 	} else {
 		snd_soc_component_update_bits(component,
 					ROULEUR_ANA_MBHC_MICB2_RAMP,
-					0xA0, 0x00);
+					0x80, 0x00);
 		snd_soc_component_update_bits(component,
 					ROULEUR_ANA_MBHC_MICB2_RAMP,
 					0x1C, 0x00);
@@ -376,174 +372,180 @@ static int rouleur_mbhc_micb_ctrl_threshold_mic(
 	return rc;
 }
 
-static inline void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur,
-						s16 *d1_a, u16 noff,
-						int32_t *zdet)
+static void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur,
+					   struct snd_soc_component *component,
+					   int32_t *zdet)
 {
 	int i;
-	int val = 0, val1 = 0;
-	s16 c1 = 0;
-	s32 x1 = 0, d1 = 0;
-	int32_t denom;
-	int minCode_param[] = {
-			3277, 1639, 820, 410, 205, 103, 52, 26
-	};
+	int zcode = 0, zcode1 = 0, zdet_cal_result = 0, zdet_est_range = 0;
+	int noff = 0, ndac = 14;
+	int zdet_cal_coeff = 0, div_ratio = 0;
+	int num = 0, denom = 0;
 
+	/* Charge enable and wait for zcode to be updated */
 	regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x20);
 	for (i = 0; i < ROULEUR_ZDET_NUM_MEASUREMENTS; i++) {
-		regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val);
-		if (val & 0x80)
+		regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &zcode);
+		if (zcode & 0x80)
 			break;
+		usleep_range(200, 210);
 	}
-	val = val << 0x8;
-	regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val1);
-	val |= val1;
-	regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00);
-	x1 = ROULEUR_MBHC_GET_X1(val);
-	c1 = ROULEUR_MBHC_GET_C1(val);
-	/* If ramp is not complete, give additional 5ms */
-	if ((c1 < 2) && x1)
-		usleep_range(5000, 5050);
 
-	if (!c1 || !x1) {
+	/* If zcode updation is not complete, give additional 10ms */
+	if (!(zcode & 0x80))
+		usleep_range(10000, 10100);
+
+	regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &zcode);
+	if (!(zcode & 0x80)) {
 		dev_dbg(rouleur->dev,
-			"%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
-			__func__, c1, x1);
-		goto ramp_down;
+			"%s: Impedance detect calculation error, zcode=0x%x\n",
+			__func__, zcode);
+		regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET,
+				   0x20, 0x00);
+		return;
+	}
+	zcode = zcode << 0x8;
+	zcode = zcode & 0x3FFF;
+	regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &zcode1);
+	zcode |= zcode1;
+
+	dev_dbg(rouleur->dev,
+		"%s: zcode: %d, zcode1: %d\n", __func__, zcode, zcode1);
+
+	/* Calculate calibration coefficient */
+	zdet_cal_result = (snd_soc_component_read32(component,
+				ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)) & 0x1F;
+	zdet_cal_coeff = ROULEUR_ZDET_C1 /
+			((ROULEUR_ZDET_C2 * zdet_cal_result) + ROULEUR_ZDET_C3);
+	/* Rload calculation */
+	zdet_est_range = (snd_soc_component_read32(component,
+			  ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT) & 0x60) >> 5;
+
+	dev_dbg(rouleur->dev,
+		"%s: zdet_cal_result: %d, zdet_cal_coeff: %d, zdet_est_range: %d\n",
+		__func__, zdet_cal_result, zdet_cal_coeff, zdet_est_range);
+	switch (zdet_est_range) {
+	case 0:
+	default:
+		noff = 0;
+		div_ratio = 320;
+		break;
+	case 1:
+		noff = 0;
+		div_ratio = 64;
+		break;
+	case 2:
+		noff = 4;
+		div_ratio = 64;
+		break;
+	case 3:
+		noff = 5;
+		div_ratio = 40;
+		break;
 	}
-	d1 = d1_a[c1];
-	denom = (x1 * d1) - (1 << (14 - noff));
+
+	num = zdet_cal_coeff * ROULEUR_ZDET_RMAX;
+	denom = ((zcode * div_ratio * 100) - (1 << (ndac - noff)) * 1000);
+	dev_dbg(rouleur->dev,
+		"%s: num: %d, denom: %d\n", __func__, num, denom);
 	if (denom > 0)
-		*zdet = (ROULEUR_MBHC_ZDET_CONST * 1000) / denom;
-	else if (x1 < minCode_param[noff])
+		*zdet = (int32_t) ((num / denom) * 1000);
+	else
 		*zdet = ROULEUR_ZDET_FLOATING_IMPEDANCE;
 
-	dev_dbg(rouleur->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
-		__func__, d1, c1, x1, *zdet);
-ramp_down:
-	i = 0;
-	while (x1) {
-		regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val);
-		regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val1);
-		val = val << 0x8;
-		val |= val1;
-		x1 = ROULEUR_MBHC_GET_X1(val);
-		i++;
-		if (i == ROULEUR_ZDET_NUM_MEASUREMENTS)
-			break;
-	}
+	dev_dbg(rouleur->dev, "%s: z_val=%d(milliOhm)\n",
+		__func__, *zdet);
+	/* Start discharge */
+	regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00);
 }
 
-#if 0
-static void rouleur_mbhc_zdet_ramp(struct snd_soc_component *component,
-				 struct rouleur_mbhc_zdet_param *zdet_param,
-				 int32_t *zl, int32_t *zr, s16 *d1_a)
+static void rouleur_mbhc_zdet_start(struct snd_soc_component *component,
+				 int32_t *zl, int32_t *zr)
 {
 	struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
 	int32_t zdet = 0;
 
-	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL,
-				0x70, zdet_param->ldo_ctl << 4);
-	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN5, 0xFC,
-				zdet_param->btn5);
-	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN6, 0xFC,
-				zdet_param->btn6);
-	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN7, 0xFC,
-				zdet_param->btn7);
-	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL,
-				0x0F, zdet_param->noff);
-	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_RAMP_CTL,
-				0x0F, zdet_param->nshift);
-
 	if (!zl)
 		goto z_right;
-	/* Start impedance measurement for HPH_L */
+
+	/* HPHL pull down switch to force OFF */
+	regmap_update_bits(rouleur->regmap,
+			  ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x30, 0x00);
+	/* Averaging enable for reliable results */
+	regmap_update_bits(rouleur->regmap,
+			   ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x80);
+	/* ZDET left measurement enable */
 	regmap_update_bits(rouleur->regmap,
 			   ROULEUR_ANA_MBHC_ZDET, 0x80, 0x80);
-	dev_dbg(rouleur->dev, "%s: ramp for HPH_L, noff = %d\n",
-		__func__, zdet_param->noff);
-	rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet);
+	/* Calculate the left Rload result */
+	rouleur_mbhc_get_result_params(rouleur, component, &zdet);
+
 	regmap_update_bits(rouleur->regmap,
 			   ROULEUR_ANA_MBHC_ZDET, 0x80, 0x00);
+	regmap_update_bits(rouleur->regmap,
+			   ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x00);
+	regmap_update_bits(rouleur->regmap,
+			  ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x30, 0x20);
 
 	*zl = zdet;
 
 z_right:
 	if (!zr)
 		return;
-	/* Start impedance measurement for HPH_R */
+	/* HPHR pull down switch to force OFF */
+	regmap_update_bits(rouleur->regmap,
+			  ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x0C, 0x00);
+	/* Averaging enable for reliable results */
+	regmap_update_bits(rouleur->regmap,
+			   ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x80);
+	/* ZDET right measurement enable */
 	regmap_update_bits(rouleur->regmap,
 			   ROULEUR_ANA_MBHC_ZDET, 0x40, 0x40);
-	dev_dbg(rouleur->dev, "%s: ramp for HPH_R, noff = %d\n",
-		__func__, zdet_param->noff);
-	rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet);
+
+	/* Calculate the right Rload result */
+	rouleur_mbhc_get_result_params(rouleur, component, &zdet);
+
 	regmap_update_bits(rouleur->regmap,
 			   ROULEUR_ANA_MBHC_ZDET, 0x40, 0x00);
+	regmap_update_bits(rouleur->regmap,
+			   ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x00);
+	regmap_update_bits(rouleur->regmap,
+			  ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x0C, 0x08);
 
 	*zr = zdet;
 }
 
-static inline void rouleur_wcd_mbhc_qfuse_cal(
-					struct snd_soc_component *component,
-					int32_t *z_val, int flag_l_r)
-{
-	s16 q1;
-	int q1_cal;
-
-	if (*z_val < (ROULEUR_ZDET_VAL_400/1000))
-		q1 = snd_soc_component_read32(component,
-			ROULEUR_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
-	else
-		q1 = snd_soc_component_read32(component,
-			ROULEUR_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
-	if (q1 & 0x80)
-		q1_cal = (10000 - ((q1 & 0x7F) * 25));
-	else
-		q1_cal = (10000 + (q1 * 25));
-	if (q1_cal > 0)
-		*z_val = ((*z_val) * 10000) / q1_cal;
-}
-
 static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
 					  uint32_t *zr)
 {
 	struct snd_soc_component *component = mbhc->component;
 	struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
-	s16 reg0, reg1, reg2, reg3, reg4;
+	s16 reg0;
 	int32_t z1L, z1R, z1Ls;
 	int zMono, z_diff1, z_diff2;
 	bool is_fsm_disable = false;
-	struct rouleur_mbhc_zdet_param zdet_param[] = {
-		{4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
-		{2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
-		{1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
-		{1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
-	};
-	struct rouleur_mbhc_zdet_param *zdet_param_ptr = NULL;
-	s16 d1_a[][4] = {
-		{0, 30, 90, 30},
-		{0, 30, 30, 5},
-		{0, 30, 30, 5},
-		{0, 30, 30, 5},
-	};
-	s16 *d1 = NULL;
 
 	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
 
-	reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN5);
-	reg1 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN6);
-	reg2 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN7);
-	reg3 = snd_soc_component_read32(component, ROULEUR_MBHC_CTL_CLK);
-	reg4 = snd_soc_component_read32(component,
-			ROULEUR_ANA_MBHC_ZDET_ANA_CTL);
+	reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT);
 
-	if (snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT) &
-			0x80) {
+	if (reg0 & 0x80) {
 		is_fsm_disable = true;
 		regmap_update_bits(rouleur->regmap,
 				   ROULEUR_ANA_MBHC_ELECT, 0x80, 0x00);
 	}
 
+	/* Enable electrical bias */
+	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT,
+				      0x01, 0x01);
+
+	/* Enable codec main bias */
+	rouleur_global_mbias_enable(component);
+
+	/* Enable RCO clock */
+	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1,
+				      0x80, 0x80);
+
 	/* For NO-jack, disable L_DET_EN before Z-det measurements */
 	if (mbhc->hphl_swh)
 		regmap_update_bits(rouleur->regmap,
@@ -553,79 +555,34 @@ static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
 	regmap_update_bits(rouleur->regmap,
 			   ROULEUR_ANA_MBHC_MECH, 0x01, 0x00);
 
-	/* Disable surge protection before impedance detection.
+	/*
+	 * Disable surge protection before impedance detection.
 	 * This is done to give correct value for high impedance.
 	 */
-	regmap_update_bits(rouleur->regmap,
-			   ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+	snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN,
+					0xC0, 0x00);
 	/* 1ms delay needed after disable surge protection */
 	usleep_range(1000, 1010);
 
-	/* First get impedance on Left */
-	d1 = d1_a[1];
-	zdet_param_ptr = &zdet_param[1];
-	rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
-
-	if (!ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
-		goto left_ch_impedance;
-
-	/* Second ramp for left ch */
-	if (z1L < ROULEUR_ZDET_VAL_32) {
-		zdet_param_ptr = &zdet_param[0];
-		d1 = d1_a[0];
-	} else if ((z1L > ROULEUR_ZDET_VAL_400) &&
-		  (z1L <= ROULEUR_ZDET_VAL_1200)) {
-		zdet_param_ptr = &zdet_param[2];
-		d1 = d1_a[2];
-	} else if (z1L > ROULEUR_ZDET_VAL_1200) {
-		zdet_param_ptr = &zdet_param[3];
-		d1 = d1_a[3];
-	}
-	rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
-
-left_ch_impedance:
+	/* Start of left ch impedance calculation */
+	rouleur_mbhc_zdet_start(component, &z1L, NULL);
 	if ((z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
-		(z1L > ROULEUR_ZDET_VAL_100K)) {
+		(z1L > ROULEUR_ZDET_VAL_100K))
 		*zl = ROULEUR_ZDET_FLOATING_IMPEDANCE;
-		zdet_param_ptr = &zdet_param[1];
-		d1 = d1_a[1];
-	} else {
+	else
 		*zl = z1L/1000;
-		rouleur_wcd_mbhc_qfuse_cal(component, zl, 0);
-	}
+
 	dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n",
 		__func__, *zl);
 
-	/* Start of right impedance ramp and calculation */
-	rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1);
-	if (ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
-		if (((z1R > ROULEUR_ZDET_VAL_1200) &&
-			(zdet_param_ptr->noff == 0x6)) ||
-			((*zl) != ROULEUR_ZDET_FLOATING_IMPEDANCE))
-			goto right_ch_impedance;
-		/* Second ramp for right ch */
-		if (z1R < ROULEUR_ZDET_VAL_32) {
-			zdet_param_ptr = &zdet_param[0];
-			d1 = d1_a[0];
-		} else if ((z1R > ROULEUR_ZDET_VAL_400) &&
-			(z1R <= ROULEUR_ZDET_VAL_1200)) {
-			zdet_param_ptr = &zdet_param[2];
-			d1 = d1_a[2];
-		} else if (z1R > ROULEUR_ZDET_VAL_1200) {
-			zdet_param_ptr = &zdet_param[3];
-			d1 = d1_a[3];
-		}
-		rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL,
-				&z1R, d1);
-	}
-right_ch_impedance:
+	/* Start of right ch impedance calculation */
+	rouleur_mbhc_zdet_start(component, NULL, &z1R);
 	if ((z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
-		(z1R > ROULEUR_ZDET_VAL_100K)) {
+		(z1R > ROULEUR_ZDET_VAL_100K))
 		*zr = ROULEUR_ZDET_FLOATING_IMPEDANCE;
-	} else {
+	else
 		*zr = z1R/1000;
-		rouleur_wcd_mbhc_qfuse_cal(component, zr, 1);
-	}
+
 	dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n",
 		__func__, *zr);
 
@@ -647,24 +604,10 @@ right_ch_impedance:
 		mbhc->hph_type = WCD_MBHC_HPH_MONO;
 		goto zdet_complete;
 	}
-	snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST,
-				0x02, 0x02);
-	snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2,
-				0x40, 0x01);
-	if (*zl < (ROULEUR_ZDET_VAL_32/1000))
-		rouleur_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls,
-				NULL, d1);
-	else
-		rouleur_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls,
-				NULL, d1);
-	snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2,
-				0x40, 0x00);
-	snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST,
-				0x02, 0x00);
-	z1Ls /= 1000;
-	rouleur_wcd_mbhc_qfuse_cal(component, &z1Ls, 0);
-	/* Parallel of left Z and 9 ohm pull down resistor */
-	zMono = ((*zl) * 9) / ((*zl) + 9);
+
+	z1Ls = z1L/1000;
+	/* Parallel of left Z and 20 ohm pull down resistor */
+	zMono = ((*zl) * 20) / ((*zl) + 20);
 	z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
 	z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
 	if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
@@ -677,13 +620,10 @@ right_ch_impedance:
 		mbhc->hph_type = WCD_MBHC_HPH_MONO;
 	}
 
+zdet_complete:
 	/* Enable surge protection again after impedance detection */
 	regmap_update_bits(rouleur->regmap,
-			   ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
-zdet_complete:
-	snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN5, reg0);
-	snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN6, reg1);
-	snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN7, reg2);
+			   ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0);
 	/* Turn on 100k pull down on HPHL */
 	regmap_update_bits(rouleur->regmap,
 			   ROULEUR_ANA_MBHC_MECH, 0x01, 0x01);
@@ -693,13 +633,14 @@ zdet_complete:
 		regmap_update_bits(rouleur->regmap,
 				   ROULEUR_ANA_MBHC_MECH, 0x80, 0x80);
 
-	snd_soc_component_write(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL, reg4);
-	snd_soc_component_write(component, ROULEUR_MBHC_CTL_CLK, reg3);
+	/* Restore electrical bias state */
+	snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, 0x01,
+				      reg0 >> 7);
 	if (is_fsm_disable)
 		regmap_update_bits(rouleur->regmap,
 				   ROULEUR_ANA_MBHC_ELECT, 0x80, 0x80);
+	rouleur_global_mbias_disable(component);
 }
-#endif
 
 static void rouleur_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
 			bool enable)
@@ -723,10 +664,10 @@ static void rouleur_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
 	if (enable) {
 		snd_soc_component_update_bits(component,
 				    ROULEUR_ANA_HPHPA_CNP_CTL_2,
-				    0x30, 0x10);
+				    0x30, 0x20);
 		snd_soc_component_update_bits(component,
 				    ROULEUR_ANA_HPHPA_CNP_CTL_2,
-				    0x0C, 0x04);
+				    0x0C, 0x08);
 	} else {
 		snd_soc_component_update_bits(component,
 				    ROULEUR_ANA_HPHPA_CNP_CTL_2,
@@ -820,6 +761,54 @@ static void rouleur_mbhc_bcs_enable(struct wcd_mbhc *mbhc,
 		rouleur_disable_bcs_before_slow_insert(mbhc->component, true);
 }
 
+static void rouleur_mbhc_get_micbias_val(struct wcd_mbhc *mbhc, int *mb)
+{
+	u8 vout_ctl = 0;
+
+	/* Read MBHC Micbias (Mic Bias2) voltage */
+	WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl);
+
+	/* Formula for getting micbias from vout
+	 * micbias = 1.6V + VOUT_CTL * 50mV
+	 */
+	*mb = 1600 + (vout_ctl * 50);
+	pr_debug("%s: vout_ctl: %d, micbias: %d\n", __func__, vout_ctl, *mb);
+}
+
+static void rouleur_mbhc_comp_autozero_control(struct wcd_mbhc *mbhc,
+						bool az_enable)
+{
+	if (az_enable)
+		snd_soc_component_update_bits(mbhc->component,
+				ROULEUR_ANA_MBHC_CTL_CLK, 0x08, 0x08);
+	else
+		snd_soc_component_update_bits(mbhc->component,
+				ROULEUR_ANA_MBHC_CTL_CLK, 0x08, 0x00);
+
+}
+
+static void rouleur_mbhc_surge_control(struct wcd_mbhc *mbhc,
+						bool surge_enable)
+{
+	if (surge_enable)
+		snd_soc_component_update_bits(mbhc->component,
+				ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0);
+	else
+		snd_soc_component_update_bits(mbhc->component,
+				ROULEUR_ANA_SURGE_EN, 0xC0, 0x00);
+
+}
+
+static void rouleur_mbhc_update_cross_conn_thr(struct wcd_mbhc *mbhc)
+{
+	mbhc->hphl_cross_conn_thr = ROULEUR_HPHL_CROSS_CONN_THRESHOLD;
+	mbhc->hphr_cross_conn_thr = ROULEUR_HPHR_CROSS_CONN_THRESHOLD;
+
+	pr_debug("%s: Cross connection threshold for hphl: %d, hphr: %d\n",
+			__func__, mbhc->hphl_cross_conn_thr,
+			mbhc->hphr_cross_conn_thr);
+}
+
 static const struct wcd_mbhc_cb mbhc_cb = {
 	.request_irq = rouleur_mbhc_request_irq,
 	.irq_control = rouleur_mbhc_irq_control,
@@ -837,13 +826,17 @@ static const struct wcd_mbhc_cb mbhc_cb = {
 	.mbhc_micb_ramp_control = rouleur_mbhc_micb_ramp_control,
 	.get_hwdep_fw_cal = rouleur_get_hwdep_fw_cal,
 	.mbhc_micb_ctrl_thr_mic = rouleur_mbhc_micb_ctrl_threshold_mic,
-	//.compute_impedance = rouleur_wcd_mbhc_calc_impedance,
+	.compute_impedance = rouleur_wcd_mbhc_calc_impedance,
 	.mbhc_gnd_det_ctrl = rouleur_mbhc_gnd_det_ctrl,
 	.hph_pull_down_ctrl = rouleur_mbhc_hph_pull_down_ctrl,
 	.mbhc_moisture_config = rouleur_mbhc_moisture_config,
 	.mbhc_get_moisture_status = rouleur_mbhc_get_moisture_status,
 	.mbhc_moisture_detect_en = rouleur_mbhc_moisture_detect_en,
 	.bcs_enable = rouleur_mbhc_bcs_enable,
+	.get_micbias_val = rouleur_mbhc_get_micbias_val,
+	.mbhc_comp_autozero_control = rouleur_mbhc_comp_autozero_control,
+	.mbhc_surge_ctl = rouleur_mbhc_surge_control,
+	.update_cross_conn_thr = rouleur_mbhc_update_cross_conn_thr,
 };
 
 static int rouleur_get_hph_type(struct snd_kcontrol *kcontrol,

+ 1 - 1
asoc/codecs/rouleur/rouleur-registers.h

@@ -45,7 +45,7 @@ enum {
 #define ROULEUR_ANA_MBHC_ZDET_RAMP_CTL        (ROULEUR_ANA_BASE_ADDR+0x06A)
 #define ROULEUR_ANA_MBHC_FSM_STATUS           (ROULEUR_ANA_BASE_ADDR+0x06B)
 #define ROULEUR_ANA_MBHC_ADC_RESULT           (ROULEUR_ANA_BASE_ADDR+0x06C)
-#define ROULEUR_ANA_MBHC_MCLK                 (ROULEUR_ANA_BASE_ADDR+0x06D)
+#define ROULEUR_ANA_MBHC_CTL_CLK              (ROULEUR_ANA_BASE_ADDR+0x06D)
 #define ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT    (ROULEUR_ANA_BASE_ADDR+0x072)
 #define ROULEUR_ANA_NCP_EN                    (ROULEUR_ANA_BASE_ADDR+0x077)
 #define ROULEUR_ANA_HPHPA_CNP_CTL_1           (ROULEUR_ANA_BASE_ADDR+0x083)

+ 3 - 1
asoc/codecs/rouleur/rouleur-regmap.c

@@ -38,13 +38,15 @@ static const struct reg_default rouleur_defaults[] = {
 	{ ROULEUR_ANA_MBHC_ZDET_RAMP_CTL,         0x00 },
 	{ ROULEUR_ANA_MBHC_FSM_STATUS,            0x00 },
 	{ ROULEUR_ANA_MBHC_ADC_RESULT,            0x00 },
-	{ ROULEUR_ANA_MBHC_MCLK,                  0x30 },
+	{ ROULEUR_ANA_MBHC_CTL_CLK,               0x30 },
 	{ ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT,     0x00 },
 	{ ROULEUR_ANA_NCP_EN,                     0x00 },
 	{ ROULEUR_ANA_HPHPA_CNP_CTL_1,            0x54 },
 	{ ROULEUR_ANA_HPHPA_CNP_CTL_2,            0x2B },
 	{ ROULEUR_ANA_HPHPA_PA_STATUS,            0x00 },
 	{ ROULEUR_ANA_HPHPA_FSM_CLK,              0x12 },
+	{ ROULEUR_ANA_HPHPA_L_GAIN,               0x00 },
+	{ ROULEUR_ANA_HPHPA_R_GAIN,               0x00 },
 	{ ROULEUR_SWR_HPHPA_HD2,                  0x1B },
 	{ ROULEUR_ANA_HPHPA_SPARE_CTL,            0x02 },
 	{ ROULEUR_ANA_SURGE_EN,                   0x38 },

+ 3 - 1
asoc/codecs/rouleur/rouleur-tables.c

@@ -33,13 +33,15 @@ const u8 rouleur_reg_access_analog[ROULEUR_REG(
 	[ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_RAMP_CTL)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_MBHC_FSM_STATUS)] = RD_REG,
 	[ROULEUR_REG(ROULEUR_ANA_MBHC_ADC_RESULT)] = RD_REG,
-	[ROULEUR_REG(ROULEUR_ANA_MBHC_MCLK)] = RD_WR_REG,
+	[ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_CLK)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)] = RD_REG,
 	[ROULEUR_REG(ROULEUR_ANA_NCP_EN)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_1)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_2)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_HPHPA_PA_STATUS)] = RD_REG,
 	[ROULEUR_REG(ROULEUR_ANA_HPHPA_FSM_CLK)] = RD_WR_REG,
+	[ROULEUR_REG(ROULEUR_ANA_HPHPA_L_GAIN)] = RD_WR_REG,
+	[ROULEUR_REG(ROULEUR_ANA_HPHPA_R_GAIN)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_HPHPA_SPARE_CTL)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_SWR_HPHPA_HD2)] = RD_WR_REG,
 	[ROULEUR_REG(ROULEUR_ANA_SURGE_EN)] = RD_WR_REG,

+ 180 - 67
asoc/codecs/rouleur/rouleur.c

@@ -46,6 +46,7 @@ enum {
 	HPH_COMP_DELAY,
 	HPH_PA_DELAY,
 	AMIC2_BCS_ENABLE,
+	WCD_SUPPLIES_LPM_MODE,
 };
 
 /* TODO: Check on the step values */
@@ -107,6 +108,9 @@ static int rouleur_handle_post_irq(void *data)
 
 static int rouleur_init_reg(struct snd_soc_component *component)
 {
+	/* Disable HPH OCP */
+	snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_CNP_CTL_2,
+					0x03, 0x00);
 	/* Enable surge protection */
 	snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN,
 					0xC0, 0xC0);
@@ -301,7 +305,7 @@ static int rouleur_rx_connect_port(struct snd_soc_component *component,
 	return ret;
 }
 
-static int rouleur_global_mbias_enable(struct snd_soc_component *component)
+int rouleur_global_mbias_enable(struct snd_soc_component *component)
 {
 	struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
 
@@ -319,7 +323,7 @@ static int rouleur_global_mbias_enable(struct snd_soc_component *component)
 	return 0;
 }
 
-static int rouleur_global_mbias_disable(struct snd_soc_component *component)
+int rouleur_global_mbias_disable(struct snd_soc_component *component)
 {
 	struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
 
@@ -354,7 +358,7 @@ static int rouleur_rx_clk_enable(struct snd_soc_component *component)
 		usleep_range(5000, 5100);
 		rouleur_global_mbias_enable(component);
 		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x11);
+				ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x11);
 		snd_soc_component_update_bits(component,
 				ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x80);
 		snd_soc_component_update_bits(component,
@@ -382,14 +386,14 @@ static int rouleur_rx_clk_disable(struct snd_soc_component *component)
 		snd_soc_component_update_bits(component,
 				ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x00);
 		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x00);
+				ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_ANA_NCP_EN, 0x01, 0x00);
-		rouleur_global_mbias_disable(component);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x00);
+		rouleur_global_mbias_disable(component);
 
 	}
 	mutex_unlock(&rouleur->rx_clk_lock);
@@ -469,23 +473,27 @@ static int rouleur_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
 		}
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX0_CTL,
-				0x7C, 0x7C);
+				0x80, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
 				0x04, 0x04);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x01);
-		snd_soc_component_update_bits(component,
-				ROULEUR_DIG_SWR_PDM_WD_CTL0,
-				0x03, 0x03);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_component_update_bits(component,
-			ROULEUR_DIG_SWR_PDM_WD_CTL0,
-			0x03, 0x00);
+				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+				0x01, 0x00);
 		snd_soc_component_update_bits(component,
-			ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
-			0x01, 0x00);
+				ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+				0x04, 0x00);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_CDC_RX0_CTL,
+				0x80, 0x80);
+		if (rouleur->comp1_enable)
+			snd_soc_component_update_bits(component,
+					ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+					0x02, 0x00);
 		break;
 	}
 
@@ -540,22 +548,26 @@ static int rouleur_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
 		}
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX1_CTL,
-				0x7C, 0x7C);
+				0x80, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
 				0x08, 0x08);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x02);
-		snd_soc_component_update_bits(component,
-				ROULEUR_DIG_SWR_PDM_WD_CTL1,
-				0x03, 0x03);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_update_bits(component,
-			ROULEUR_DIG_SWR_PDM_WD_CTL1,
-			0x03, 0x00);
 		snd_soc_component_update_bits(component,
 			ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x00);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+				0x08, 0x00);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_CDC_RX1_CTL,
+				0x80, 0x80);
+		if (rouleur->comp2_enable)
+			snd_soc_component_update_bits(component,
+					ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+					0x01, 0x00);
 		break;
 
 	}
@@ -578,25 +590,25 @@ static int rouleur_codec_ear_lo_dac_event(struct snd_soc_dapm_widget *w,
 		rouleur_rx_clk_enable(component);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX0_CTL,
-				0x7C, 0x7C);
-		snd_soc_component_update_bits(component,
-				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
-				0x01, 0x01);
-		snd_soc_component_update_bits(component,
-				ROULEUR_DIG_SWR_PDM_WD_CTL0,
-				0x03, 0x03);
+				0x80, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
 				0x04, 0x04);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+				0x01, 0x01);
 
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_update_bits(component,
-				ROULEUR_DIG_SWR_PDM_WD_CTL0,
-				0x03, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
 				0x01, 0x00);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+				0x04, 0x00);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_CDC_RX0_CTL,
+				0x80, 0x80);
 
 		break;
 	};
@@ -622,14 +634,11 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
 				    rouleur->rx_swr_dev->dev_num,
 				    true);
 
-		snd_soc_component_update_bits(component,
-					ROULEUR_ANA_HPHPA_CNP_CTL_2,
-					0x40, 0x40);
 		set_bit(HPH_PA_DELAY, &rouleur->status_mask);
-		/* TODO: WHY SECOND TIME */
-		ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
-					    rouleur->rx_swr_dev->dev_num,
-					    true);
+		usleep_range(5000, 5100);
+		snd_soc_component_update_bits(component,
+			ROULEUR_DIG_SWR_PDM_WD_CTL1,
+			0x03, 0x03);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		/*
@@ -676,8 +685,8 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
 					     WCD_EVENT_POST_HPHR_PA_OFF,
 					     &rouleur->mbhc->wcd_mbhc);
 		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_HPHPA_CNP_CTL_2,
-				0x40, 0x00);
+				ROULEUR_DIG_SWR_PDM_WD_CTL1,
+				0x03, 0x00);
 		break;
 	};
 	return ret;
@@ -700,10 +709,11 @@ static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
 		ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
 				    rouleur->rx_swr_dev->dev_num,
 				    true);
-		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_HPHPA_CNP_CTL_2,
-				0x80, 0x80);
 		set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+		usleep_range(5000, 5100);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_PDM_WD_CTL0,
+				0x03, 0x03);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		/*
@@ -748,8 +758,8 @@ static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
 					     WCD_EVENT_POST_HPHL_PA_OFF,
 					     &rouleur->mbhc->wcd_mbhc);
 		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_HPHPA_CNP_CTL_2,
-				0x80, 0x00);
+			ROULEUR_DIG_SWR_PDM_WD_CTL0,
+			0x03, 0x00);
 
 		break;
 	};
@@ -773,10 +783,10 @@ static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
 		ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
 			    rouleur->rx_swr_dev->dev_num,
 			    true);
-		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_COMBOPA_CTL,
-				0x80, 0x80);
 		usleep_range(5000, 5100);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_PDM_WD_CTL0,
+				0x03, 0x03);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		if (rouleur->update_wcd_event)
@@ -795,10 +805,10 @@ static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
 						(WCD_RX1 << 0x10 | 0x1));
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_COMBOPA_CTL,
-				0x80, 0x00);
 		usleep_range(5000, 5100);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_PDM_WD_CTL0,
+				0x03, 0x00);
 	};
 	return ret;
 }
@@ -823,10 +833,10 @@ static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
 		snd_soc_component_update_bits(component,
 				ROULEUR_ANA_COMBOPA_CTL,
 				0x40, 0x40);
-		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_COMBOPA_CTL,
-				0x80, 0x80);
 		usleep_range(5000, 5100);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_PDM_WD_CTL0,
+				0x03, 0x03);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		if (rouleur->update_wcd_event)
@@ -845,13 +855,13 @@ static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
 						(WCD_RX1 << 0x10 | 0x1));
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_component_update_bits(component,
-				ROULEUR_ANA_COMBOPA_CTL,
-				0x80, 0x00);
 		snd_soc_component_update_bits(component,
 				ROULEUR_ANA_COMBOPA_CTL,
 				0x40, 0x00);
 		usleep_range(5000, 5100);
+		snd_soc_component_update_bits(component,
+				ROULEUR_DIG_SWR_PDM_WD_CTL0,
+				0x03, 0x00);
 	};
 	return ret;
 }
@@ -1166,6 +1176,7 @@ int rouleur_micbias_control(struct snd_soc_component *component,
 	int post_on_event = 0, post_dapm_off = 0;
 	int post_dapm_on = 0;
 	u8 pullup_mask = 0, enable_mask = 0;
+	int ret = 0;
 
 	if ((micb_index < 0) || (micb_index > ROULEUR_MAX_MICBIAS - 1)) {
 		dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n",
@@ -1201,6 +1212,12 @@ int rouleur_micbias_control(struct snd_soc_component *component,
 
 	switch (req) {
 	case MICB_PULLUP_ENABLE:
+		if (!rouleur->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		rouleur->pullup_ref[micb_index]++;
 		if ((rouleur->pullup_ref[micb_index] == 1) &&
 		    (rouleur->micb_ref[micb_index] == 0))
@@ -1208,6 +1225,12 @@ int rouleur_micbias_control(struct snd_soc_component *component,
 				pullup_mask, pullup_mask);
 		break;
 	case MICB_PULLUP_DISABLE:
+		if (!rouleur->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		if (rouleur->pullup_ref[micb_index] > 0)
 			rouleur->pullup_ref[micb_index]--;
 		if ((rouleur->pullup_ref[micb_index] == 0) &&
@@ -1216,11 +1239,15 @@ int rouleur_micbias_control(struct snd_soc_component *component,
 				pullup_mask, 0x00);
 		break;
 	case MICB_ENABLE:
+		if (!rouleur->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		rouleur->micb_ref[micb_index]++;
 		if (rouleur->micb_ref[micb_index] == 1) {
 			rouleur_global_mbias_enable(component);
-			snd_soc_component_update_bits(component, micb_reg,
-				0x80, 0x80);
 			snd_soc_component_update_bits(component,
 				micb_reg, enable_mask, enable_mask);
 			if (post_on_event)
@@ -1236,16 +1263,27 @@ int rouleur_micbias_control(struct snd_soc_component *component,
 	case MICB_DISABLE:
 		if (rouleur->micb_ref[micb_index] > 0)
 			rouleur->micb_ref[micb_index]--;
+		if (!rouleur->dev_up) {
+			dev_dbg(component->dev, "%s: enable req %d wcd device down\n",
+				__func__, req);
+			ret = -ENODEV;
+			goto done;
+		}
 		if ((rouleur->micb_ref[micb_index] == 0) &&
-			 (rouleur->pullup_ref[micb_index] == 0)) {
+		    (rouleur->pullup_ref[micb_index] > 0)) {
+			snd_soc_component_update_bits(component, micb_reg,
+				pullup_mask, pullup_mask);
+                        snd_soc_component_update_bits(component, micb_reg,
+                                enable_mask, 0x00);
+			rouleur_global_mbias_disable(component);
+		} else if ((rouleur->micb_ref[micb_index] == 0) &&
+			   (rouleur->pullup_ref[micb_index] == 0)) {
 			if (pre_off_event && rouleur->mbhc)
 				blocking_notifier_call_chain(
 					&rouleur->mbhc->notifier, pre_off_event,
 					&rouleur->mbhc->wcd_mbhc);
                         snd_soc_component_update_bits(component, micb_reg,
                                 enable_mask, 0x00);
-			snd_soc_component_update_bits(component, micb_reg,
-				0x80, 0x00);
 			rouleur_global_mbias_disable(component);
 			if (post_off_event && rouleur->mbhc)
 				blocking_notifier_call_chain(
@@ -1263,8 +1301,8 @@ int rouleur_micbias_control(struct snd_soc_component *component,
 	dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
 		__func__, micb_num, rouleur->micb_ref[micb_index],
 		rouleur->pullup_ref[micb_index]);
+done:
 	mutex_unlock(&rouleur->micb_lock);
-
 	return 0;
 }
 EXPORT_SYMBOL(rouleur_micbias_control);
@@ -1304,6 +1342,17 @@ static int rouleur_get_logical_addr(struct swr_device *swr_dev)
 	return 0;
 }
 
+static bool get_usbc_hs_status(struct snd_soc_component *component,
+			       struct wcd_mbhc_config *mbhc_cfg)
+{
+	if (mbhc_cfg->enable_usbc_analog) {
+		if (!(snd_soc_component_read32(component, ROULEUR_ANA_MBHC_MECH)
+			& 0x20))
+			return true;
+	}
+	return false;
+}
+
 static int rouleur_event_notify(struct notifier_block *block,
 				unsigned long val,
 				void *data)
@@ -1333,8 +1382,11 @@ static int rouleur_event_notify(struct notifier_block *block,
 				0x80, 0x00);
 		break;
 	case BOLERO_WCD_EVT_SSR_DOWN:
+		rouleur->dev_up = false;
 		rouleur->mbhc->wcd_mbhc.deinit_in_progress = true;
 		mbhc = &rouleur->mbhc->wcd_mbhc;
+		rouleur->usbc_hs_status = get_usbc_hs_status(component,
+						mbhc->mbhc_cfg);
 		rouleur_mbhc_ssr_down(rouleur->mbhc, component);
 		rouleur_reset(rouleur->dev, 0x01);
 		break;
@@ -1356,8 +1408,11 @@ static int rouleur_event_notify(struct notifier_block *block,
 				__func__);
 		} else {
 			rouleur_mbhc_hs_detect(component, mbhc->mbhc_cfg);
+			if (rouleur->usbc_hs_status)
+				mdelay(500);
 		}
 		rouleur->mbhc->wcd_mbhc.deinit_in_progress = false;
+		rouleur->dev_up = true;
 		break;
 	default:
 		dev_err(component->dev, "%s: invalid event %d\n", __func__,
@@ -1552,6 +1607,9 @@ static int rouleur_codec_enable_pa_vpos(struct snd_soc_dapm_widget *w,
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		set_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+		ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+				rouleur->rx_swr_dev->dev_num,
+				false);
 		break;
 	}
 	return 0;
@@ -1822,7 +1880,7 @@ static ssize_t rouleur_version_read(struct snd_info_entry *entry,
 
 	switch (priv->version) {
 	case ROULEUR_VERSION_1_0:
-		len = snprintf(buffer, sizeof(buffer), "rouleur_1_0\n");
+		len = snprintf(buffer, sizeof(buffer), "ROULEUR_1_0\n");
 		break;
 	default:
 		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
@@ -1986,6 +2044,7 @@ static int rouleur_soc_codec_probe(struct snd_soc_component *component)
 			return ret;
 		}
 	}
+	rouleur->dev_up = true;
 done:
 	return ret;
 }
@@ -2003,6 +2062,26 @@ static void rouleur_soc_codec_remove(struct snd_soc_component *component)
 						false);
 }
 
+static int rouleur_soc_codec_suspend(struct snd_soc_component *component)
+{
+	struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+	if (!rouleur)
+		return 0;
+	rouleur->dapm_bias_off = true;
+	return 0;
+}
+
+static int rouleur_soc_codec_resume(struct snd_soc_component *component)
+{
+	struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+	if (!rouleur)
+		return 0;
+	rouleur->dapm_bias_off = false;
+	return 0;
+}
+
 static const struct snd_soc_component_driver soc_codec_dev_rouleur = {
 	.name = DRV_NAME,
 	.probe = rouleur_soc_codec_probe,
@@ -2013,6 +2092,8 @@ static const struct snd_soc_component_driver soc_codec_dev_rouleur = {
 	.num_dapm_widgets = ARRAY_SIZE(rouleur_dapm_widgets),
 	.dapm_routes = rouleur_audio_map,
 	.num_dapm_routes = ARRAY_SIZE(rouleur_audio_map),
+	.suspend = rouleur_soc_codec_suspend,
+	.resume = rouleur_soc_codec_resume,
 };
 
 #ifdef CONFIG_PM_SLEEP
@@ -2049,11 +2130,45 @@ static int rouleur_suspend(struct device *dev)
 		}
 		clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
 	}
+	if (rouleur->dapm_bias_off) {
+		 msm_cdc_set_supplies_lpm_mode(rouleur->dev,
+					      rouleur->supplies,
+					      pdata->regulator,
+					      pdata->num_supplies,
+					      true);
+		set_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask);
+	}
 	return 0;
 }
 
 static int rouleur_resume(struct device *dev)
 {
+	struct rouleur_priv *rouleur = NULL;
+	struct rouleur_pdata *pdata = NULL;
+
+	if (!dev)
+		return -ENODEV;
+
+	rouleur = dev_get_drvdata(dev);
+	if (!rouleur)
+		return -EINVAL;
+
+	pdata = dev_get_platdata(rouleur->dev);
+
+	if (!pdata) {
+		dev_err(dev, "%s: pdata is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (test_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask)) {
+		msm_cdc_set_supplies_lpm_mode(rouleur->dev,
+						rouleur->supplies,
+						pdata->regulator,
+						pdata->num_supplies,
+						false);
+		clear_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask);
+	}
+
 	return 0;
 }
 #endif
@@ -2484,10 +2599,8 @@ static int rouleur_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM_SLEEP
 static const struct dev_pm_ops rouleur_dev_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(
-		rouleur_suspend,
-		rouleur_resume
-	)
+	.suspend_late = rouleur_suspend,
+	.resume_early = rouleur_resume
 };
 #endif
 

+ 312 - 12
asoc/codecs/rouleur/rouleur_slave.c

@@ -11,15 +11,276 @@
 #include <linux/component.h>
 #include <soc/soundwire.h>
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_SLV_MAX_REG_ADDR    0x2009
+#define SWR_SLV_START_REG_ADDR  0x40
+#define SWR_SLV_MAX_BUF_LEN     20
+#define BYTES_PER_LINE          12
+#define SWR_SLV_RD_BUF_LEN      8
+#define SWR_SLV_WR_BUF_LEN      32
+#define SWR_SLV_MAX_DEVICES     2
+#endif /* CONFIG_DEBUG_FS */
+
 struct rouleur_slave_priv {
 	struct swr_device *swr_slave;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_rouleur_dent;
+	struct dentry *debugfs_peek;
+	struct dentry *debugfs_poke;
+	struct dentry *debugfs_reg_dump;
+	unsigned int read_data;
+#endif
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+	char *token = NULL;
+	int base = 0, cnt = 0;
+
+	token = strsep(&buf, " ");
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (kstrtou32(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else {
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static bool is_swr_slv_reg_readable(int reg)
+{
+	int ret = true;
+
+	if (((reg > 0x46) && (reg < 0x4A)) ||
+	    ((reg > 0x4A) && (reg < 0x50)) ||
+	    ((reg > 0x55) && (reg < 0xD0)) ||
+	    ((reg > 0xD0) && (reg < 0xE0)) ||
+	    ((reg > 0xE0) && (reg < 0xF0)) ||
+	    ((reg > 0xF0) && (reg < 0x100)) ||
+	    ((reg > 0x105) && (reg < 0x120)) ||
+	    ((reg > 0x205) && (reg < 0x220)) ||
+	    ((reg > 0x305) && (reg < 0x320)) ||
+	    ((reg > 0x405) && (reg < 0x420)) ||
+	    ((reg > 0x128) && (reg < 0x130)) ||
+	    ((reg > 0x228) && (reg < 0x230)) ||
+	    ((reg > 0x328) && (reg < 0x330)) ||
+	    ((reg > 0x428) && (reg < 0x430)) ||
+	    ((reg > 0x138) && (reg < 0x205)) ||
+	    ((reg > 0x238) && (reg < 0x305)) ||
+	    ((reg > 0x338) && (reg < 0x405)) ||
+	    ((reg > 0x405) && (reg < 0xF00)) ||
+	    ((reg > 0xF05) && (reg < 0xF20)) ||
+	    ((reg > 0xF25) && (reg < 0xF30)) ||
+	    ((reg > 0xF35) && (reg < 0x2000)))
+		ret = false;
+
+	return ret;
+}
+
+static ssize_t rouleur_swrslave_reg_show(struct swr_device *pdev,
+					char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	int i, reg_val, len;
+	ssize_t total = 0;
+	char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+	if (!ubuf || !ppos)
+		return 0;
+
+	for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+		i <= SWR_SLV_MAX_REG_ADDR; i++) {
+		if (!is_swr_slv_reg_readable(i))
+			continue;
+		swr_read(pdev, pdev->dev_num, i, &reg_val, 1);
+		len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i,
+			       (reg_val & 0xFF));
+		if (len < 0) {
+			pr_err("%s: fail to fill the buffer\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		if (((total + len) >= count - 1) || (len < 0))
+			break;
+		if (copy_to_user((ubuf + total), tmp_buf, len)) {
+			pr_err("%s: fail to copy reg dump\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		total += len;
+		*ppos += len;
+	}
+
+copy_err:
+	*ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
+	return total;
+}
+
+static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct swr_device *pdev;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	return rouleur_swrslave_reg_show(pdev, ubuf, count, ppos);
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_RD_BUF_LEN];
+	struct swr_device *pdev = NULL;
+	struct rouleur_slave_priv *rouleur_slave = NULL;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	rouleur_slave = swr_get_dev_data(pdev);
+	if (!rouleur_slave)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	snprintf(lbuf, sizeof(lbuf), "0x%x\n",
+			(rouleur_slave->read_data & 0xFF));
+
+	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+					       strnlen(lbuf, 7));
+}
+
+static ssize_t codec_debug_peek_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc = 0;
+	u32 param[5];
+	struct swr_device *pdev = NULL;
+	struct rouleur_slave_priv *rouleur_slave = NULL;
+
+	if (!cnt || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	rouleur_slave = swr_get_dev_data(pdev);
+	if (!rouleur_slave)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	rc = get_parameters(lbuf, param, 1);
+	if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
+		return -EINVAL;
+	swr_read(pdev, pdev->dev_num, param[0], &rouleur_slave->read_data, 1);
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static ssize_t codec_debug_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc = 0;
+	u32 param[5];
+	struct swr_device *pdev;
+
+	if (!file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	rc = get_parameters(lbuf, param, 2);
+	if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
+		(param[1] <= 0xFF) && (rc == 0)))
+		return -EINVAL;
+	swr_write(pdev, pdev->dev_num, param[0], &param[1]);
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_write_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
 };
 
+static const struct file_operations codec_debug_read_ops = {
+	.open = codec_debug_open,
+	.read = codec_debug_read,
+	.write = codec_debug_peek_write,
+};
+
+static const struct file_operations codec_debug_dump_ops = {
+	.open = codec_debug_open,
+	.read = codec_debug_dump,
+};
+#endif
+
 static int rouleur_slave_bind(struct device *dev,
 				struct device *master, void *data)
 {
 	int ret = 0;
-	struct rouleur_slave_priv *rouleur_slave = NULL;
 	uint8_t devnum = 0;
 	struct swr_device *pdev = to_swr_device(dev);
 
@@ -28,15 +289,6 @@ static int rouleur_slave_bind(struct device *dev,
 		return -EINVAL;
 	}
 
-	rouleur_slave = devm_kzalloc(&pdev->dev,
-				sizeof(struct rouleur_slave_priv), GFP_KERNEL);
-	if (!rouleur_slave)
-		return -ENOMEM;
-
-	swr_set_dev_data(pdev, rouleur_slave);
-
-	rouleur_slave->swr_slave = pdev;
-
 	ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
 	if (ret) {
 		dev_dbg(&pdev->dev,
@@ -67,7 +319,6 @@ static void rouleur_slave_unbind(struct device *dev,
 		return;
 	}
 
-	swr_set_dev_data(pdev, NULL);
 }
 
 static const struct swr_device_id rouleur_swr_id[] = {
@@ -104,12 +355,61 @@ static int rouleur_swr_reset(struct swr_device *pdev)
 
 static int rouleur_swr_probe(struct swr_device *pdev)
 {
+	struct rouleur_slave_priv *rouleur_slave = NULL;
+
+	rouleur_slave = devm_kzalloc(&pdev->dev,
+				sizeof(struct rouleur_slave_priv), GFP_KERNEL);
+	if (!rouleur_slave)
+		return -ENOMEM;
+
+	swr_set_dev_data(pdev, rouleur_slave);
+
+	rouleur_slave->swr_slave = pdev;
+#ifdef CONFIG_DEBUG_FS
+	if (!rouleur_slave->debugfs_rouleur_dent) {
+		rouleur_slave->debugfs_rouleur_dent = debugfs_create_dir(
+						dev_name(&pdev->dev), 0);
+		if (!IS_ERR(rouleur_slave->debugfs_rouleur_dent)) {
+			rouleur_slave->debugfs_peek =
+					debugfs_create_file("swrslave_peek",
+					S_IFREG | 0444,
+					rouleur_slave->debugfs_rouleur_dent,
+					(void *) pdev,
+					&codec_debug_read_ops);
+
+			rouleur_slave->debugfs_poke =
+					debugfs_create_file("swrslave_poke",
+					S_IFREG | 0444,
+					rouleur_slave->debugfs_rouleur_dent,
+					(void *) pdev,
+					&codec_debug_write_ops);
+
+			rouleur_slave->debugfs_reg_dump =
+					debugfs_create_file(
+					"swrslave_reg_dump",
+					S_IFREG | 0444,
+					rouleur_slave->debugfs_rouleur_dent,
+					(void *) pdev,
+					&codec_debug_dump_ops);
+                }
+        }
+#endif
 	return component_add(&pdev->dev, &rouleur_slave_comp_ops);
 }
 
 static int rouleur_swr_remove(struct swr_device *pdev)
 {
+#ifdef CONFIG_DEBUG_FS
+	struct rouleur_slave_priv *rouleur_slave = swr_get_dev_data(pdev);
+
+	if (rouleur_slave) {
+		debugfs_remove_recursive(rouleur_slave->debugfs_rouleur_dent);
+		rouleur_slave->debugfs_rouleur_dent = NULL;
+	}
+#endif
 	component_del(&pdev->dev, &rouleur_slave_comp_ops);
+	swr_set_dev_data(pdev, NULL);
+	swr_remove_device(pdev);
 	return 0;
 }
 
@@ -140,5 +440,5 @@ static void __exit rouleur_slave_exit(void)
 module_init(rouleur_slave_init);
 module_exit(rouleur_slave_exit);
 
-MODULE_DESCRIPTION("WCD937X Swr Slave driver");
+MODULE_DESCRIPTION("Rouleur Swr Slave driver");
 MODULE_LICENSE("GPL v2");

+ 29 - 0
asoc/codecs/swr-dmic.c

@@ -325,11 +325,38 @@ static int swr_dmic_codec_probe(struct snd_soc_component *component)
 {
 	struct swr_dmic_priv *swr_dmic =
 			snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+			snd_soc_component_get_dapm(component);
+	char w_name[100];
 
 	if (!swr_dmic)
 		return -EINVAL;
 
 	swr_dmic->component = component;
+	snd_soc_dapm_ignore_suspend(dapm,
+				swr_dmic->dai_driver->capture.stream_name);
+	memset(w_name, 0, 100);
+	strlcpy(w_name, component->name_prefix, 100);
+	strlcat(w_name, " SWR_DMIC", 100);
+	snd_soc_dapm_ignore_suspend(dapm, w_name);
+
+	memset(w_name, 0, 100);
+	strlcpy(w_name, component->name_prefix, 100);
+	strlcat(w_name, " SMIC_SUPPLY", 100);
+	snd_soc_dapm_ignore_suspend(dapm, w_name);
+
+	memset(w_name, 0, 100);
+	strlcpy(w_name, component->name_prefix, 100);
+	strlcat(w_name, " SMIC_PORT_EN", 100);
+	snd_soc_dapm_ignore_suspend(dapm, w_name);
+
+	memset(w_name, 0, 100);
+	strlcpy(w_name, component->name_prefix, 100);
+	strlcat(w_name, " SWR_DMIC_OUTPUT", 100);
+	snd_soc_dapm_ignore_suspend(dapm, w_name);
+
+	snd_soc_dapm_sync(dapm);
+
 	return 0;
 }
 
@@ -624,6 +651,8 @@ static int swr_dmic_down(struct swr_device *pdev)
 		return -EINVAL;
 	}
 
+	dev_dbg(&pdev->dev, "%s: is_en_supply: %d\n",
+		__func__, swr_dmic->is_en_supply);
 	--swr_dmic->is_en_supply;
 	if (swr_dmic->is_en_supply < 0) {
 		dev_warn(&pdev->dev, "%s: mismatch in supply count %d\n",

+ 6 - 16
asoc/codecs/swr-haptics.c

@@ -186,12 +186,6 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		swr_disconnect_port(swr_hap->swr_slave, &port_id, num_port,
-				&ch_mask, &port_type);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		swr_slvdev_datapath_control(swr_hap->swr_slave,
-				swr_hap->swr_slave->dev_num, false);
 		/* stop SWR play */
 		val = 0;
 		rc = regmap_write(swr_hap->regmap, SWR_PLAY_REG, val);
@@ -200,6 +194,12 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
 					__func__, rc);
 			return rc;
 		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		swr_disconnect_port(swr_hap->swr_slave, &port_id, num_port,
+				&ch_mask, &port_type);
+		swr_slvdev_datapath_control(swr_hap->swr_slave,
+				swr_hap->swr_slave->dev_num, false);
 		swr_device_wakeup_unvote(swr_hap->swr_slave);
 		break;
 	default:
@@ -431,22 +431,12 @@ static int swr_haptics_device_down(struct swr_device *sdev)
 {
 	struct swr_haptics_dev *swr_hap = swr_get_dev_data(sdev);
 	int rc;
-	unsigned int val;
 
 	if (!swr_hap) {
 		dev_err(&sdev->dev, "%s: no data for swr_hap\n", __func__);
 		return -ENODEV;
 	}
 
-	/* Stop SWR play in SSR */
-	val = 0;
-	rc = regmap_write(swr_hap->regmap, SWR_PLAY_REG, val);
-	if (rc) {
-		dev_err(swr_hap->dev, "%s: disable SWR_PLAY failed, rc=%d\n",
-				__func__, rc);
-		return rc;
-	}
-
 	/* Put SWR slave into reset */
 	rc = regulator_disable(swr_hap->vdd);
 	if (rc < 0) {

+ 41 - 10
asoc/codecs/wcd-mbhc-adc.c

@@ -33,16 +33,20 @@ static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
 	int micbias = 0;
 	u8 vout_ctl = 0;
 
-	/* Read MBHC Micbias (Mic Bias2) voltage */
-	WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl);
-
-	/* Formula for getting micbias from vout
-	 * micbias = 1.0V + VOUT_CTL * 50mV
-	 */
-	micbias = 1000 + (vout_ctl * 50);
-	pr_debug("%s: vout_ctl: %d, micbias: %d\n",
-		 __func__, vout_ctl, micbias);
+	if (mbhc->mbhc_cb->get_micbias_val) {
+		mbhc->mbhc_cb->get_micbias_val(mbhc, &micbias);
+		pr_debug("%s: micbias: %d\n",  __func__, micbias);
+	} else {
+		/* Read MBHC Micbias (Mic Bias2) voltage */
+		WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl);
 
+		/* Formula for getting micbias from vout
+		 * micbias = 1.0V + VOUT_CTL * 50mV
+		 */
+		micbias = 1000 + (vout_ctl * 50);
+		pr_debug("%s: vout_ctl: %d, micbias: %d\n",
+			 __func__, vout_ctl, micbias);
+	}
 	return micbias;
 }
 
@@ -76,8 +80,22 @@ static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
 	/* Set the MUX selection to IN2P */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
+
+	/*
+	 * Current source mode requires Auto zeroing to be enabled
+	 * automatically. If HW doesn't do it, SW has to take care of this
+	 * for button interrupts to work fine and to avoid
+	 * fake electrical removal interrupts by enabling autozero before FSM
+	 * enable and disable it after FSM enable
+	 */
+	if (mbhc->mbhc_cb->mbhc_comp_autozero_control)
+		mbhc->mbhc_cb->mbhc_comp_autozero_control(mbhc,
+							true);
 	/* Enable MBHC FSM */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	if (mbhc->mbhc_cb->mbhc_comp_autozero_control)
+		mbhc->mbhc_cb->mbhc_comp_autozero_control(mbhc,
+							false);
 	/* Enable ADC_ENABLE bit */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1);
 
@@ -290,6 +308,10 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
 	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
 
+	/* Disable surge detection before ADC measurement */
+	if (mbhc->mbhc_cb->mbhc_surge_ctl)
+		mbhc->mbhc_cb->mbhc_surge_ctl(mbhc, false);
+
 	/* Read and set ADC to single measurement */
 	WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode);
 	/* Read ADC Enable bit to restore after adc measurement */
@@ -313,7 +335,12 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
 		goto done;
 	}
 
-	if (hphl_adc_res > 100 || hphr_adc_res > 100) {
+	/* Update cross connection threshold voltages if needed */
+	if (mbhc->mbhc_cb->update_cross_conn_thr)
+		mbhc->mbhc_cb->update_cross_conn_thr(mbhc);
+
+	if (hphl_adc_res > mbhc->hphl_cross_conn_thr ||
+	    hphr_adc_res > mbhc->hphr_cross_conn_thr) {
 		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
 		pr_debug("%s: Cross connection identified\n", __func__);
 	} else {
@@ -335,6 +362,10 @@ done:
 	/* Restore FSM state */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en);
 
+	/* Restore surge detection */
+	if (mbhc->mbhc_cb->mbhc_surge_ctl)
+		mbhc->mbhc_cb->mbhc_surge_ctl(mbhc, true);
+
 	/* Restore electrical detection */
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
 

+ 6 - 2
asoc/codecs/wcd-mbhc-v2.c

@@ -80,10 +80,12 @@ static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
 	struct snd_soc_component *component = mbhc->component;
 	u32 reg_val;
 
-	plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+	plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR(
+				mbhc->mbhc_cfg->calibration);
 	reg_val = ((plug_type_cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
 
-	dev_dbg(component->dev, "%s: reg_val  = %x\n", __func__, reg_val);
+	dev_dbg(component->dev, "%s: reg_val  = %x\n",
+		__func__, reg_val);
 	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_VREF, reg_val);
 }
 
@@ -1838,6 +1840,8 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_component *component,
 	mbhc->hph_type = WCD_MBHC_HPH_NONE;
 	mbhc->wcd_mbhc_regs = wcd_mbhc_regs;
 	mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD;
+	mbhc->hphl_cross_conn_thr = HPHL_CROSS_CONN_THRESHOLD;
+	mbhc->hphr_cross_conn_thr = HPHR_CROSS_CONN_THRESHOLD;
 
 	if (mbhc->intr_ids == NULL) {
 		pr_err("%s: Interrupt mapping not provided\n", __func__);

+ 62 - 62
asoc/codecs/wcd9335.c

@@ -8608,95 +8608,95 @@ static const struct soc_enum amic_pwr_lvl_enum =
 			    amic_pwr_lvl_text);
 
 static const struct snd_kcontrol_new tasha_snd_controls[] = {
-	SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
-		0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-
-	SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
+	SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
+		-84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
+		-84, 40, digital_gain),
+
+	SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume",
 			  WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume",
 			  WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume",
 			  WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume",
 			  WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume",
 			  WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume",
 			  WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume",
 			  WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume",
 			  WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume",
 			  WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
-			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+			  -84, 40, digital_gain), /* -84dB min - 40dB max */
 
-	SOC_SINGLE_SX_TLV("DEC0 Volume", WCD9335_CDC_TX0_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC0 Volume", WCD9335_CDC_TX0_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC1 Volume", WCD9335_CDC_TX1_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC1 Volume", WCD9335_CDC_TX1_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC2 Volume", WCD9335_CDC_TX2_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC2 Volume", WCD9335_CDC_TX2_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC3 Volume", WCD9335_CDC_TX3_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC3 Volume", WCD9335_CDC_TX3_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC4 Volume", WCD9335_CDC_TX4_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC4 Volume", WCD9335_CDC_TX4_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC5 Volume", WCD9335_CDC_TX5_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC5 Volume", WCD9335_CDC_TX5_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC6 Volume", WCD9335_CDC_TX6_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC6 Volume", WCD9335_CDC_TX6_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC7 Volume", WCD9335_CDC_TX7_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC7 Volume", WCD9335_CDC_TX7_TX_VOL_CTL,
 					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC8 Volume", WCD9335_CDC_TX8_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC8 Volume", WCD9335_CDC_TX8_TX_VOL_CTL,
 					  -84, 40, digital_gain),
 
-	SOC_SINGLE_SX_TLV("IIR0 INP0 Volume",
-			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR0 INP0 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP1 Volume",
-			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR0 INP1 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP2 Volume",
-			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR0 INP2 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP3 Volume",
-			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR0 INP3 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP0 Volume",
-			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR1 INP0 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
-			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
-			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84,
 			  40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
-			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84,
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84,
 			  40, digital_gain),
 
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tasha_get_anc_slot,

+ 54 - 54
asoc/codecs/wcd934x/wcd934x.c

@@ -6548,77 +6548,77 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = {
 	SOC_SINGLE_TLV("ADC3 Volume", WCD934X_ANA_AMIC3, 0, 20, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC4 Volume", WCD934X_ANA_AMIC4, 0, 20, 0, analog_gain),
 
-	SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL,
-		0, -84, 40, digital_gain), /* -84dB min - 40dB max */
-	SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
-		WCD934X_CDC_RX0_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
-		WCD934X_CDC_RX1_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
-		WCD934X_CDC_RX2_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
-		WCD934X_CDC_RX3_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
-		WCD934X_CDC_RX4_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
-		WCD934X_CDC_RX7_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
-		WCD934X_CDC_RX8_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
-
-	SOC_SINGLE_SX_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL,
+		-84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume",
+		WCD934X_CDC_RX0_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume",
+		WCD934X_CDC_RX1_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume",
+		WCD934X_CDC_RX2_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume",
+		WCD934X_CDC_RX3_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume",
+		WCD934X_CDC_RX4_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume",
+		WCD934X_CDC_RX7_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume",
+		WCD934X_CDC_RX8_RX_VOL_MIX_CTL, -84, 40, digital_gain),
+
+	SOC_SINGLE_S8_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL, 0,
+	SOC_SINGLE_S8_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL,
 		-84, 40, digital_gain),
 
-	SOC_SINGLE_SX_TLV("IIR0 INP0 Volume",
-		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP0 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP1 Volume",
-		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP1 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP2 Volume",
-		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP2 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR0 INP3 Volume",
-		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR0 INP3 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP0 Volume",
-		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP0 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
-		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
-		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40,
 		digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
-		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40,
+	SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40,
 		digital_gain),
 
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tavil_get_anc_slot,

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

@@ -73,6 +73,7 @@ struct wcd938x_priv {
 	bool comp2_enable;
 	bool ldoh;
 	bool bcs_dis;
+	bool dapm_bias_off;
 	struct irq_domain *virq;
 	struct wcd_irq_info irq_info;
 	u32 rx_clk_cnt;

+ 61 - 4
asoc/codecs/wcd938x/wcd938x.c

@@ -72,6 +72,7 @@ enum {
 	HPH_COMP_DELAY,
 	HPH_PA_DELAY,
 	AMIC2_BCS_ENABLE,
+	WCD_SUPPLIES_LPM_MODE,
 };
 
 enum {
@@ -3634,6 +3635,8 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
 		goto err_hwdep;
 	}
 
+	snd_soc_dapm_ignore_suspend(dapm, "WCD938X_AIF Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "WCD938X_AIF Capture");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
 	snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
@@ -3713,6 +3716,26 @@ static void wcd938x_soc_codec_remove(struct snd_soc_component *component)
 						false);
 }
 
+static int wcd938x_soc_codec_suspend(struct snd_soc_component *component)
+{
+	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+	if (!wcd938x)
+		return 0;
+	wcd938x->dapm_bias_off = true;
+	return 0;
+}
+
+static int wcd938x_soc_codec_resume(struct snd_soc_component *component)
+{
+	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+	if (!wcd938x)
+		return 0;
+	wcd938x->dapm_bias_off = false;
+	return 0;
+}
+
 static struct snd_soc_component_driver soc_codec_dev_wcd938x = {
 	.name = WCD938X_DRV_NAME,
 	.probe = wcd938x_soc_codec_probe,
@@ -3723,6 +3746,8 @@ static struct snd_soc_component_driver soc_codec_dev_wcd938x = {
 	.num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets),
 	.dapm_routes = wcd938x_audio_map,
 	.num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map),
+	.suspend =  wcd938x_soc_codec_suspend,
+	.resume = wcd938x_soc_codec_resume,
 };
 
 static int wcd938x_reset(struct device *dev)
@@ -4242,19 +4267,51 @@ static int wcd938x_suspend(struct device *dev)
 		}
 		clear_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask);
 	}
+	if (wcd938x->dapm_bias_off) {
+		msm_cdc_set_supplies_lpm_mode(wcd938x->dev,
+					      wcd938x->supplies,
+					      pdata->regulator,
+					      pdata->num_supplies,
+					      true);
+		set_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask);
+	}
 	return 0;
 }
 
 static int wcd938x_resume(struct device *dev)
 {
+	struct wcd938x_priv *wcd938x = NULL;
+	struct wcd938x_pdata *pdata = NULL;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd938x = dev_get_drvdata(dev);
+	if (!wcd938x)
+		return -EINVAL;
+
+	pdata = dev_get_platdata(wcd938x->dev);
+
+	if (!pdata) {
+		dev_err(dev, "%s: pdata is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask)) {
+		msm_cdc_set_supplies_lpm_mode(wcd938x->dev,
+					      wcd938x->supplies,
+					      pdata->regulator,
+					      pdata->num_supplies,
+					      false);
+		clear_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask);
+	}
+
 	return 0;
 }
 
 static const struct dev_pm_ops wcd938x_dev_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(
-		wcd938x_suspend,
-		wcd938x_resume
-	)
+	.suspend_late = wcd938x_suspend,
+	.resume_early = wcd938x_resume,
 };
 #endif
 

+ 1 - 0
asoc/codecs/wsa883x/internal.h

@@ -97,6 +97,7 @@ struct wsa883x_priv {
 	bool comp_enable;
 	bool visense_enable;
 	bool ext_vdd_spk;
+	bool dapm_bias_off;
 	struct swr_port port[WSA883X_MAX_SWR_PORTS];
 	int global_pa_cnt;
 	int dev_mode;

+ 87 - 2
asoc/codecs/wsa883x/wsa883x.c

@@ -123,6 +123,7 @@ static const struct wsa_reg_mask_val reg_init[] = {
 	{WSA883X_GMAMP_SUP1, 0x60, 0x60},
 };
 
+static int wsa883x_handle_post_irq(void *data);
 static int wsa883x_get_temperature(struct snd_soc_component *component,
 				   int *temp);
 enum {
@@ -132,6 +133,7 @@ enum {
 
 enum {
 	SPKR_STATUS = 0,
+	WSA_SUPPLIES_LPM_MODE,
 };
 
 enum {
@@ -172,9 +174,24 @@ static struct regmap_irq_chip wsa883x_regmap_irq_chip = {
 	.ack_base = WSA883X_INTR_CLEAR0,
 	.use_ack = 1,
 	.runtime_pm = false,
+	.handle_post_irq = wsa883x_handle_post_irq,
 	.irq_drv_data = NULL,
 };
 
+static int wsa883x_handle_post_irq(void *data)
+{
+	struct wsa883x_priv *wsa883x = data;
+	u32 sts1 = 0, sts2 = 0;
+
+	regmap_read(wsa883x->regmap, WSA883X_INTR_STATUS0, &sts1);
+	regmap_read(wsa883x->regmap, WSA883X_INTR_STATUS1, &sts2);
+
+	wsa883x->swr_slave->slave_irq_pending =
+			((sts1 || sts2) ? true : false);
+
+	return IRQ_HANDLED;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int codec_debug_open(struct inode *inode, struct file *file)
 {
@@ -253,7 +270,12 @@ static ssize_t swr_slave_reg_show(struct swr_device *pdev, char __user *ubuf,
 		swr_read(pdev, pdev->dev_num, i, &reg_val, 1);
 		len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i,
 			       (reg_val & 0xFF));
-		if (((total + len) >= count - 1) || (len < 0))
+		if (len < 0) {
+			pr_err("%s: fail to fill the buffer\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		if ((total + len) >= count - 1)
 			break;
 		if (copy_to_user((ubuf + total), tmp_buf, len)) {
 			pr_err("%s: fail to copy reg dump\n", __func__);
@@ -989,6 +1011,7 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
 					    wsa883x->swr_slave->dev_num,
 					    true);
 		wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD);
+		wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO);
 		/* Force remove group */
 		swr_remove_from_group(wsa883x->swr_slave,
 				      wsa883x->swr_slave->dev_num);
@@ -998,6 +1021,7 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
 		snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL,
 				0x01, 0x00);
 		wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD);
+		wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO);
 		clear_bit(SPKR_STATUS, &wsa883x->status_mask);
 		break;
 	}
@@ -1186,6 +1210,8 @@ static int wsa883x_codec_probe(struct snd_soc_component *component)
 	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
 	struct swr_device *dev;
 	int variant = 0, version = 0;
+	struct snd_soc_dapm_context *dapm =
+			snd_soc_component_get_dapm(component);
 
 	if (!wsa883x)
 		return -EINVAL;
@@ -1205,6 +1231,10 @@ static int wsa883x_codec_probe(struct snd_soc_component *component)
 	wsa883x_codec_init(component);
 	wsa883x->global_pa_cnt = 0;
 
+	snd_soc_dapm_ignore_suspend(dapm,
+		wsa883x->dai_driver->playback.stream_name);
+	snd_soc_dapm_sync(dapm);
+
 	return 0;
 }
 
@@ -1220,6 +1250,28 @@ static void wsa883x_codec_remove(struct snd_soc_component *component)
 	return;
 }
 
+static int wsa883x_soc_codec_suspend(struct snd_soc_component *component)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	if (!wsa883x)
+		return 0;
+
+	wsa883x->dapm_bias_off = true;
+	return 0;
+}
+
+static int wsa883x_soc_codec_resume(struct snd_soc_component *component)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	if (!wsa883x)
+		return 0;
+
+	wsa883x->dapm_bias_off = false;
+	return 0;
+}
+
 static const struct snd_soc_component_driver soc_codec_dev_wsa883x_wsa = {
 	.name = "",
 	.probe = wsa883x_codec_probe,
@@ -1230,6 +1282,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wsa883x_wsa = {
 	.num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets),
 	.dapm_routes = wsa883x_audio_map,
 	.num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map),
+	.suspend =  wsa883x_soc_codec_suspend,
+	.resume = wsa883x_soc_codec_resume,
 };
 
 static int wsa883x_gpio_ctrl(struct wsa883x_priv *wsa883x, bool enable)
@@ -1454,12 +1508,18 @@ static int wsa883x_swr_probe(struct swr_device *pdev)
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR,
 			"WSA SAF2WAR", wsa883x_saf2war_handle_irq, NULL);
 
+	wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR);
+
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF,
 			"WSA WAR2SAF", wsa883x_war2saf_handle_irq, NULL);
 
+	wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF);
+
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE,
 			"WSA OTP", wsa883x_otp_handle_irq, NULL);
 
+	wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE);
+
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_OCP,
 			"WSA OCP", wsa883x_ocp_handle_irq, NULL);
 
@@ -1483,10 +1543,14 @@ static int wsa883x_swr_probe(struct swr_device *pdev)
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN,
 			"WSA EXT INT", wsa883x_ext_int_handle_irq, NULL);
 
+	wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN);
+
 	/* Under Voltage Lock out (UVLO) interrupt handle */
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO,
 			"WSA UVLO", wsa883x_uvlo_handle_irq, NULL);
 
+	wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO);
+
 	wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR,
 			"WSA PA ERR", wsa883x_pa_on_err_handle_irq, NULL);
 
@@ -1692,7 +1756,20 @@ static int wsa883x_swr_remove(struct swr_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int wsa883x_swr_suspend(struct device *dev)
 {
+	struct wsa883x_priv *wsa883x = swr_get_dev_data(to_swr_device(dev));
+
+	if (!wsa883x) {
+		dev_err(dev, "%s: wsa883x private data is NULL\n", __func__);
+		return -EINVAL;
+	}
 	dev_dbg(dev, "%s: system suspend\n", __func__);
+	if (wsa883x->dapm_bias_off) {
+		msm_cdc_set_supplies_lpm_mode(dev, wsa883x->supplies,
+					wsa883x->regulator,
+					wsa883x->num_supplies,
+					true);
+		set_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask);
+	}
 	return 0;
 }
 
@@ -1704,13 +1781,21 @@ static int wsa883x_swr_resume(struct device *dev)
 		dev_err(dev, "%s: wsa883x private data is NULL\n", __func__);
 		return -EINVAL;
 	}
+	if (test_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask)) {
+		msm_cdc_set_supplies_lpm_mode(dev, wsa883x->supplies,
+					wsa883x->regulator,
+					wsa883x->num_supplies,
+					false);
+		clear_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask);
+	}
 	dev_dbg(dev, "%s: system resume\n", __func__);
 	return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops wsa883x_swr_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(wsa883x_swr_suspend, wsa883x_swr_resume)
+	.suspend_late = wsa883x_swr_suspend,
+	.resume_early = wsa883x_swr_resume,
 };
 
 static const struct swr_device_id wsa883x_swr_id[] = {

+ 22 - 2
asoc/kona.c

@@ -81,8 +81,10 @@
 
 #define ADSP_STATE_READY_TIMEOUT_MS 3000
 
-#define WSA8810_NAME_1 "wsa881x.20170211"
-#define WSA8810_NAME_2 "wsa881x.20170212"
+#define WSA8810_NAME_1 "wsa881x.1020170211"
+#define WSA8810_NAME_2 "wsa881x.1020170212"
+#define WSA8815_NAME_1 "wsa881x.1021170213"
+#define WSA8815_NAME_2 "wsa881x.1021170214"
 #define WCN_CDC_SLIM_RX_CH_MAX 2
 #define WCN_CDC_SLIM_TX_CH_MAX 2
 #define WCN_CDC_SLIM_TX_CH_MAX_LITO 3
@@ -5517,6 +5519,11 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
 						WSA_MACRO_SPKR_MODE_1);
 				wsa_macro_set_spkr_gain_offset(component,
 						WSA_MACRO_GAIN_OFFSET_M1P5_DB);
+			} else if (aux_comp->name != NULL && (
+				!strcmp(aux_comp->name, WSA8815_NAME_1) ||
+		    		!strcmp(aux_comp->name, WSA8815_NAME_2))) {
+				wsa_macro_set_spkr_mode(component,
+						WSA_MACRO_SPKR_MODE_DEFAULT);
 			}
 		}
 	}
@@ -6139,6 +6146,19 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
 		.ops = &msm_cdc_dma_be_ops,
 		SND_SOC_DAILINK_REG(tx_cdcdma5_tx),
 	},
+	{/* hw:x,40 */
+		.name = MSM_DAILINK_NAME(Compress3),
+		.stream_name = "Compress3",
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			 SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		/* this dainlink has playback support */
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+		SND_SOC_DAILINK_REG(multimedia10),
+	},
 };
 
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {

+ 120 - 0
asoc/lahaina.c

@@ -2723,6 +2723,63 @@ static int msm_get_port_id(int be_id)
 	case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2:
 		afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_2;
 		break;
+	case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0:
+		afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_RX_0;
+		break;
+	case MSM_BACKEND_DAI_WSA_CDC_DMA_TX_0:
+		afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_TX_0;
+		break;
+	case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_1:
+		afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_RX_1;
+		break;
+	case MSM_BACKEND_DAI_WSA_CDC_DMA_TX_1:
+		afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_TX_1;
+		break;
+	case MSM_BACKEND_DAI_WSA_CDC_DMA_TX_2:
+		afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_TX_2;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_0;
+		break;
+	case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0:
+		afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_0;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_1;
+		break;
+	case MSM_BACKEND_DAI_TX_CDC_DMA_TX_1:
+		afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_1;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_2;
+		break;
+	case MSM_BACKEND_DAI_TX_CDC_DMA_TX_2:
+		afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_2;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_3;
+		break;
+	case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3:
+		afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_3;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_4:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_4;
+		break;
+	case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4:
+		afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_4;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_5:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_5;
+		break;
+	case MSM_BACKEND_DAI_TX_CDC_DMA_TX_5:
+		afe_port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_5;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_6:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_6;
+		break;
+	case MSM_BACKEND_DAI_RX_CDC_DMA_RX_7:
+		afe_port_id = AFE_PORT_ID_RX_CODEC_DMA_RX_7;
+		break;
 	default:
 		pr_err("%s: Invalid BE id: %d\n", __func__, be_id);
 		afe_port_id = -EINVAL;
@@ -4124,6 +4181,38 @@ static int lahaina_send_island_va_config(int32_t be_id)
 	return rc;
 }
 
+static int lahaina_send_power_mode(int32_t be_id)
+{
+	int rc = 0;
+	int port_id = 0xFFFF;
+
+	port_id = msm_get_port_id(be_id);
+	if (port_id < 0) {
+		pr_err("%s: Invalid power interface, be_id: %d\n",
+			__func__, be_id);
+		rc = -EINVAL;
+	} else {
+		/*
+		 * send island mode config
+		 * This should be the first configuration
+		 *
+		 */
+		rc = afe_send_port_island_mode(port_id);
+		if (rc)
+			pr_err("%s: afe send island mode failed %d\n",
+				__func__, rc);
+		/*
+		 * send power mode config
+		 * This should be set after island configuration
+		 */
+		rc = afe_send_port_power_mode(port_id);
+		if (rc)
+			pr_err("%s: afe send power mode failed %d\n",
+				__func__, rc);
+	}
+	return rc;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				struct snd_pcm_hw_params *params)
 {
@@ -4887,6 +4976,12 @@ static int msm_snd_cdc_dma_startup(struct snd_pcm_substream *substream)
 			pr_err("%s: send island va cfg failed, err: %d\n",
 			       __func__, ret);
 		break;
+	default:
+		ret = lahaina_send_power_mode(dai_link->id);
+		if (ret)
+			pr_err("%s: send power mode failed, err: %d\n",
+				__func__, ret);
+		break;
 	}
 
 	return ret;
@@ -6019,6 +6114,19 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
 		.ignore_suspend = 1,
 		SND_SOC_DAILINK_REG(afepcm_tx1),
 	},
+        {/* hw:x,43 */
+		.name = MSM_DAILINK_NAME(Compress3),
+		.stream_name = "Compress3",
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			 SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		/* this dainlink has playback support */
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+		SND_SOC_DAILINK_REG(multimedia10),
+	},
 };
 
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {
@@ -6694,6 +6802,17 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = {
 		.ops = &msm_cdc_dma_be_ops,
 		SND_SOC_DAILINK_REG(wsa_dma_tx1),
 	},
+	{
+		.name = LPASS_BE_WSA_CDC_DMA_TX_0_VI,
+		.stream_name = "WSA CDC DMA0 Capture",
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.id = MSM_BACKEND_DAI_WSA_CDC_DMA_TX_0,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_cdc_dma_be_ops,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(wsa_dma_tx0_vi),
+	},
 };
 
 static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
@@ -7831,6 +7950,7 @@ static struct platform_driver lahaina_asoc_machine_driver = {
 };
 module_platform_driver(lahaina_asoc_machine_driver);
 
+MODULE_SOFTDEP("pre: bt_fm_slim");
 MODULE_DESCRIPTION("ALSA SoC msm");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);

+ 25 - 25
asoc/msm-audio-effects-q6-v2.c

@@ -184,7 +184,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: VIRT STRENGTH val: %d\n",
 					__func__, virtualizer->strength);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -208,7 +208,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: VIRT OUT_TYPE val:%d\n",
 				__func__, virtualizer->out_type);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -232,7 +232,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: VIRT GAIN_ADJUST val:%d\n",
 				__func__, virtualizer->gain_adjust);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -362,7 +362,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_MODE val:%d\n",
 				__func__, reverb->mode);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -385,7 +385,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_PRESET val:%d\n",
 					__func__, reverb->preset);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -408,7 +408,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_WET_MIX val:%d\n",
 				__func__, reverb->wet_mix);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -431,7 +431,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_GAIN_ADJUST val:%d\n",
 					__func__, reverb->gain_adjust);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -455,7 +455,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_ROOM_LEVEL val:%d\n",
 				__func__, reverb->room_level);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -478,7 +478,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_ROOM_HF_LEVEL val%d\n",
 				__func__, reverb->room_hf_level);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -502,7 +502,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_DECAY_TIME val:%d\n",
 				__func__, reverb->decay_time);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -525,7 +525,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_DECAY_HF_RATIO val%d\n",
 				__func__, reverb->decay_hf_ratio);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -549,7 +549,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_REFLECTIONS_LEVEL val:%d\n",
 				__func__, reverb->reflections_level);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -574,7 +574,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_REFLECTIONS_DELAY val:%d\n",
 				__func__, reverb->reflections_delay);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -599,7 +599,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_LEVEL val:%d\n",
 				__func__, reverb->level);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -622,7 +622,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s:REVERB_DELAY val:%d\n",
 					__func__, reverb->delay);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -645,7 +645,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_DIFFUSION val:%d\n",
 				__func__, reverb->diffusion);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -668,7 +668,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: REVERB_DENSITY val:%d\n",
 				__func__, reverb->density);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -798,7 +798,7 @@ int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: BASS_BOOST_MODE val:%d\n",
 				__func__, bass_boost->mode);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -821,7 +821,7 @@ int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: BASS_BOOST_STRENGTH val:%d\n",
 				__func__, bass_boost->strength);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -1014,7 +1014,7 @@ int msm_audio_effects_pbe_handler(struct audio_client *ac,
 				*p_coeffs++ = GET_NEXT(values, param_max_offset, rc);
 			}
 
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 
 			max_params_length =
@@ -1184,7 +1184,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
 				eq->per_band_cfg[idx].quality_factor =
 					GET_NEXT(values, param_max_offset, rc);
 			}
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			config_param_length = EQ_CONFIG_PARAM_SZ +
 					      (EQ_CONFIG_PER_BAND_PARAM_SZ *
@@ -1245,7 +1245,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
 			eq->band_index = idx;
 			pr_debug("%s: EQ_BAND_INDEX val:%d\n",
 				__func__, eq->band_index);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -1272,7 +1272,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
 				GET_NEXT(values, param_max_offset, rc);
 			pr_debug("%s: EQ_SINGLE_BAND_FREQ idx:%d, val:%d\n",
 				__func__, eq->band_index, eq->freq_millihertz);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -1377,7 +1377,7 @@ static int __msm_audio_effects_volume_handler(struct audio_client *ac,
 			vol->right_gain =
 				GET_NEXT(values, param_max_offset, rc);
 			vol->master_gain = 0x2000;
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +
@@ -1398,7 +1398,7 @@ static int __msm_audio_effects_volume_handler(struct audio_client *ac,
 			vol->right_gain = 0x2000;
 			vol->master_gain =
 				GET_NEXT(values, param_max_offset, rc);
-			if (command_config_state != CONFIG_SET)
+			if (command_config_state != AUDIO_EFFECTS_CONFIG_SET)
 				break;
 			max_params_length = params_length +
 					    COMMAND_IID_PAYLOAD_SZ +

+ 177 - 0
asoc/msm-compress-q6-v2.c

@@ -137,6 +137,9 @@ struct msm_compr_audio {
 
 	int32_t first_buffer;
 	int32_t last_buffer;
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+	int32_t zero_buffer;
+#endif
 	int32_t partial_drain_delay;
 
 	uint16_t session_id;
@@ -168,6 +171,9 @@ struct msm_compr_audio {
 	atomic_t start;
 	atomic_t eos;
 	atomic_t drain;
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+	atomic_t partial_drain;
+#endif
 	atomic_t xrun;
 	atomic_t close;
 	atomic_t wait_on_close;
@@ -622,8 +628,10 @@ static void compr_event_handler(uint32_t opcode,
 			if (atomic_cmpxchg(&prtd->drain, 1, 0) &&
 			    prtd->last_buffer) {
 				pr_debug("%s: wake up on drain\n", __func__);
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 				prtd->drain_ready = 1;
 				wake_up(&prtd->drain_wait);
+#endif
 				prtd->last_buffer = 0;
 			} else {
 				atomic_set(&prtd->start, 0);
@@ -666,6 +674,103 @@ static void compr_event_handler(uint32_t opcode,
 			break;
 		}
 
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+		if (prtd->zero_buffer) {
+			pr_debug("write_done for zero buffer\n");
+			prtd->zero_buffer = 0;
+
+			/* move to next stream and reset vars */
+			pr_debug("%s: Moving to next stream in gapless\n",
+								__func__);
+			ac->stream_id = NEXT_STREAM_ID(ac->stream_id);
+			prtd->byte_offset = 0;
+			prtd->app_pointer  = 0;
+			prtd->first_buffer = 1;
+			prtd->last_buffer = 0;
+			/*
+			 * Set gapless transition flag only if EOS hasn't been
+			 * acknowledged already.
+			 */
+			if (atomic_read(&prtd->eos))
+				prtd->gapless_state.gapless_transition = 1;
+			prtd->marker_timestamp = 0;
+
+			/*
+			 * Don't reset these as these vars map to
+			 * total_bytes_transferred and total_bytes_available
+			 * directly, only total_bytes_transferred will be
+			 * updated in the next avail() ioctl
+			 *	prtd->copied_total = 0;
+			 *	prtd->bytes_received = 0;
+			 */
+			atomic_set(&prtd->drain, 0);
+			atomic_set(&prtd->xrun, 1);
+			pr_debug("%s: issue CMD_RUN", __func__);
+			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+			snd_compr_drain_notify(cstream);
+			spin_unlock_irqrestore(&prtd->lock, flags);
+			break;
+		}
+
+		bytes_available = prtd->bytes_received - prtd->copied_total;
+		if (bytes_available == 0) {
+			pr_debug("%s:bytes_available is 0\n", __func__);
+			if (prtd->last_buffer)
+				prtd->last_buffer = 0;
+
+			if (atomic_read(&prtd->partial_drain) &&
+				prtd->gapless_state.set_next_stream_id &&
+				!prtd->zero_buffer) {
+
+				pr_debug("%s:Partial Drain Case\n", __func__);
+				pr_debug("%s:Send EOS command\n", __func__);
+				/* send EOS */
+				prtd->eos_ack = 0;
+				atomic_set(&prtd->eos, 1);
+				atomic_set(&prtd->drain, 0);
+				q6asm_stream_cmd_nowait(ac, CMD_EOS, ac->stream_id);
+
+				/* send a zero length buffer in case of partial drain*/
+				atomic_set(&prtd->xrun, 0);
+				pr_debug("%s:Send zero size buffer\n", __func__);
+				msm_compr_send_buffer(prtd);
+				prtd->zero_buffer = 1;
+			} else {
+				/*
+				 * moving to next stream failed, so reset the gapless state
+				 * set next stream id for the same session so that the same
+				 * stream can be used for gapless playback
+				 */
+				pr_debug("%s:Drain Case\n", __func__);
+				pr_debug("%s:Reset Gapless params \n", __func__);
+
+				prtd->gapless_state.set_next_stream_id = false;
+				prtd->gapless_state.gapless_transition = 0;
+
+				pr_debug("%s:Send EOS command\n", __func__);
+				prtd->eos_ack = 0;
+				atomic_set(&prtd->eos, 1);
+				atomic_set(&prtd->drain, 0);
+				q6asm_stream_cmd_nowait(ac, CMD_EOS, ac->stream_id);
+
+				prtd->cmd_interrupt = 0;
+			}
+		} else if (bytes_available < cstream->runtime->fragment_size) {
+			pr_debug("%s:Partial Buffer Case \n", __func__);
+			atomic_set(&prtd->xrun, 1);
+
+			if (prtd->last_buffer)
+				prtd->last_buffer = 0;
+			if (atomic_read(&prtd->drain)) {
+				if (bytes_available > 0) {
+					pr_debug("%s: send %d partial bytes at the end",
+						   __func__, bytes_available);
+					atomic_set(&prtd->xrun, 0);
+					prtd->last_buffer = 1;
+					msm_compr_send_buffer(prtd);
+				}
+			}
+#else
 		bytes_available = prtd->bytes_received - prtd->copied_total;
 		if (bytes_available < cstream->runtime->fragment_size) {
 			pr_debug("WRITE_DONE Insufficient data to send. break out\n");
@@ -679,6 +784,7 @@ static void compr_event_handler(uint32_t opcode,
 				wake_up(&prtd->drain_wait);
 				atomic_set(&prtd->drain, 0);
 			}
+#endif
 		} else if ((bytes_available == cstream->runtime->fragment_size)
 			   && atomic_read(&prtd->drain)) {
 			prtd->last_buffer = 1;
@@ -740,7 +846,40 @@ static void compr_event_handler(uint32_t opcode,
 		    !prtd->gapless_state.set_next_stream_id) {
 			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
 			prtd->eos_ack = 1;
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 			wake_up(&prtd->eos_wait);
+#else
+			pr_debug("%s:issue CMD_PAUSE stream_id %d",
+					  __func__, ac->stream_id);
+			q6asm_stream_cmd_nowait(ac, CMD_PAUSE, ac->stream_id);
+			prtd->cmd_ack = 0;
+
+			pr_debug("%s:DRAIN,don't wait for EOS ack\n", __func__);
+			/*
+			 * Don't reset these as these vars map to
+			 * total_bytes_transferred and total_bytes_available.
+			 * Just total_bytes_transferred will be updated
+			 * in the next avail() ioctl.
+			 * prtd->copied_total = 0;
+			 * prtd->bytes_received = 0;
+			 * do not reset prtd->bytes_sent as well as the same
+			 * session is used for gapless playback
+			 */
+			prtd->byte_offset = 0;
+
+			prtd->app_pointer  = 0;
+			prtd->first_buffer = 1;
+			prtd->last_buffer = 0;
+			atomic_set(&prtd->drain, 0);
+			atomic_set(&prtd->xrun, 1);
+
+			pr_debug("%s:issue CMD_FLUSH ac->stream_id %d",
+						  __func__, ac->stream_id);
+
+			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+
+			snd_compr_drain_notify(cstream);
+#endif
 		}
 		atomic_set(&prtd->eos, 0);
 		stream_index = STREAM_ARRAY_INDEX(stream_id);
@@ -841,7 +980,9 @@ static void compr_event_handler(uint32_t opcode,
 						prtd->last_buffer = 0;
 
 					prtd->drain_ready = 1;
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 					wake_up(&prtd->drain_wait);
+#endif
 					atomic_set(&prtd->drain, 0);
 				} else if (atomic_read(&prtd->xrun)) {
 					pr_debug("%s: RUN ack, continue write cycle\n", __func__);
@@ -916,11 +1057,13 @@ static void compr_event_handler(uint32_t opcode,
 		prtd->copied_total = prtd->bytes_received;
 		snd_compr_fragment_elapsed(cstream);
 		atomic_set(&prtd->error, 1);
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 		wake_up(&prtd->drain_wait);
 		if (atomic_cmpxchg(&prtd->eos, 1, 0)) {
 			pr_debug("%s:unblock eos wait queues", __func__);
 			wake_up(&prtd->eos_wait);
 		}
+#endif
 		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
 	default:
@@ -1754,6 +1897,9 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream)
 	atomic_set(&prtd->eos, 0);
 	atomic_set(&prtd->start, 0);
 	atomic_set(&prtd->drain, 0);
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+	atomic_set(&prtd->partial_drain, 0);
+#endif
 	atomic_set(&prtd->xrun, 0);
 	atomic_set(&prtd->close, 0);
 	atomic_set(&prtd->wait_on_close, 0);
@@ -1849,6 +1995,9 @@ static int msm_compr_capture_open(struct snd_compr_stream *cstream)
 	atomic_set(&prtd->eos, 0);
 	atomic_set(&prtd->start, 0);
 	atomic_set(&prtd->drain, 0);
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+	atomic_set(&prtd->partial_drain, 0);
+#endif
 	atomic_set(&prtd->xrun, 0);
 	atomic_set(&prtd->close, 0);
 	atomic_set(&prtd->wait_on_close, 0);
@@ -1911,7 +2060,9 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream)
 		return 0;
 	}
 	prtd->cmd_interrupt = 1;
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 	wake_up(&prtd->drain_wait);
+#endif
 	pdata = snd_soc_component_get_drvdata(component);
 	ac = prtd->audio_client;
 	if (!pdata || !ac) {
@@ -2293,6 +2444,7 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream,
 	return ret;
 }
 
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 static int msm_compr_drain_buffer(struct msm_compr_audio *prtd,
 				  unsigned long *flags)
 {
@@ -2321,6 +2473,7 @@ static int msm_compr_drain_buffer(struct msm_compr_audio *prtd,
 	}
 	return rc;
 }
+#endif
 
 static int msm_compr_wait_for_stream_avail(struct msm_compr_audio *prtd,
 				    unsigned long *flags)
@@ -2373,7 +2526,9 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 	struct audio_client *ac = prtd->audio_client;
 	unsigned long fe_id = rtd->dai_link->id;
 	int rc = 0;
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 	int bytes_to_write;
+#endif
 	unsigned long flags;
 	int stream_id;
 	uint32_t stream_index;
@@ -2465,17 +2620,21 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 			 * cmd_int and do not wake up eos_wait during gapless
 			 * transition
 			 */
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 			if (!prtd->gapless_state.gapless_transition) {
 				prtd->cmd_interrupt = 1;
 				wake_up(&prtd->eos_wait);
 			}
+#endif
 			atomic_set(&prtd->eos, 0);
 		}
 		if (atomic_read(&prtd->drain)) {
 			pr_debug("%s: interrupt drain wait queues", __func__);
 			prtd->cmd_interrupt = 1;
 			prtd->drain_ready = 1;
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 			wake_up(&prtd->drain_wait);
+#endif
 			atomic_set(&prtd->drain, 0);
 		}
 		prtd->last_buffer = 0;
@@ -2521,10 +2680,20 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 		break;
 	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
 		pr_debug("%s: SND_COMPR_TRIGGER_PARTIAL_DRAIN\n", __func__);
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+		spin_lock_irqsave(&prtd->lock, flags);
+		atomic_set(&prtd->partial_drain, 1);
+#endif
 		if (!prtd->gapless_state.use_dsp_gapless_mode) {
 			pr_debug("%s: set partial drain as drain\n", __func__);
 			cmd = SND_COMPR_TRIGGER_DRAIN;
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+			atomic_set(&prtd->partial_drain, 0);
+#endif
 		}
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+		spin_unlock_irqrestore(&prtd->lock, flags);
+#endif
 	case SND_COMPR_TRIGGER_DRAIN:
 		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
 		/* Make sure all the data is sent to DSP before sending EOS */
@@ -2534,9 +2703,13 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 			pr_err("%s: stream is not in started state\n",
 				__func__);
 			rc = -EPERM;
+#if !IS_ENABLED(CONFIG_AUDIO_QGKI)
+			atomic_set(&prtd->partial_drain, 0);
+#endif
 			spin_unlock_irqrestore(&prtd->lock, flags);
 			break;
 		}
+#if IS_ENABLED(CONFIG_AUDIO_QGKI)
 		if (prtd->bytes_received > prtd->copied_total) {
 			pr_debug("%s: wait till all the data is sent to dsp\n",
 				__func__);
@@ -2743,6 +2916,10 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 
 			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 		}
+#else
+		atomic_set(&prtd->drain, 1);
+		spin_unlock_irqrestore(&prtd->lock, flags);
+#endif
 		prtd->cmd_interrupt = 0;
 		break;
 	case SND_COMPR_TRIGGER_NEXT_TRACK:

+ 31 - 3
asoc/msm-dai-q6-hdmi-v2.c

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -54,7 +54,7 @@ struct msm_dai_q6_hdmi_dai_data {
 static int get_port_id(int dai_id)
 {
 	/* Currently, display devices share a common AFE port */
-	if (dai_id != HDMI_RX)
+	if (dai_id != HDMI_RX || dai_id != HDMI_RX_MS)
 		return DISPLAY_PORT_RX;
 
 	return dai_id;
@@ -436,7 +436,7 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
 
 	msm_dai_q6_hdmi_set_dai_id(dai);
 
-	if (dai->driver->id == HDMI_RX) {
+	if (dai->driver->id == HDMI_RX || dai->driver->id == HDMI_RX_MS) {
 		kcontrol = &hdmi_config_controls[0];
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(kcontrol, dai_data));
@@ -563,6 +563,28 @@ static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
 	.remove = msm_dai_q6_hdmi_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_ms_rx_dai = {
+	.playback = {
+		.stream_name = "HDMI MS Playback",
+		.aif_name = "HDMI_MS",
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+			 SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S24_3LE,
+		.channels_min = 2,
+		.channels_max = 8,
+		.rate_max = 192000,
+		.rate_min = 48000,
+	},
+	.ops = &msm_dai_q6_hdmi_ops,
+	.id = HDMI_RX_MS,
+	.probe = msm_dai_q6_hdmi_dai_probe,
+	.remove = msm_dai_q6_hdmi_dai_remove,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = {
 	{
 		.playback = {
@@ -646,6 +668,12 @@ static int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev)
 			&msm_dai_hdmi_q6_component,
 			&msm_dai_q6_display_port_rx_dai[1], 1);
 		break;
+	case HDMI_RX_MS:
+		rc = snd_soc_register_component(&pdev->dev,
+			&msm_dai_hdmi_q6_component,
+			&msm_dai_q6_hdmi_hdmi_ms_rx_dai, 1);
+		break;
+
 	default:
 		dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id);
 		rc = -ENODEV;

+ 294 - 15
asoc/msm-dai-q6-v2.c

@@ -232,6 +232,7 @@ struct msm_dai_q6_dai_data {
 	u16 afe_tx_out_bitformat;
 	struct afe_enc_config enc_config;
 	struct afe_dec_config dec_config;
+	struct afe_ttp_config ttp_config;
 	union afe_port_config port_config;
 	u16 vi_feed_mono;
 	u32 xt_logging_disable;
@@ -1279,6 +1280,83 @@ static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
 	return 0;
 }
 
+static int msm_dai_q6_power_mode_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	int value = ucontrol->value.integer.value[0];
+	u16 port_id = (u16)kcontrol->private_value;
+
+	pr_debug("%s: power mode = %d\n", __func__, value);
+	trace_printk("%s: power mode = %d\n", __func__, value);
+
+	afe_set_power_mode_cfg(port_id, value);
+	return 0;
+}
+
+static int msm_dai_q6_power_mode_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	int value;
+	u16 port_id = (u16)kcontrol->private_value;
+
+	afe_get_power_mode_cfg(port_id, &value);
+	ucontrol->value.integer.value[0] = value;
+	return 0;
+}
+
+static void power_mode_mx_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+	struct snd_kcontrol_new *knew = snd_kcontrol_chip(kcontrol);
+	kfree(knew);
+}
+
+static int msm_dai_q6_add_power_mode_mx_ctls(struct snd_card *card,
+					 const char *dai_name,
+					 int dai_id, void *dai_data)
+{
+	const char *mx_ctl_name = "Power Mode";
+	char *mixer_str = NULL;
+	int dai_str_len = 0, ctl_len = 0;
+	int rc = 0;
+	struct snd_kcontrol_new *knew = NULL;
+	struct snd_kcontrol *kctl = NULL;
+
+	dai_str_len = strlen(dai_name) + 1;
+
+	ctl_len = dai_str_len + strlen(mx_ctl_name) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s %s", dai_name, mx_ctl_name);
+
+	knew = kzalloc(sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+	if (!knew) {
+		kfree(mixer_str);
+		return -ENOMEM;
+	}
+	knew->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	knew->info = snd_ctl_boolean_mono_info;
+	knew->get = msm_dai_q6_power_mode_get;
+	knew->put = msm_dai_q6_power_mode_put;
+	knew->name = mixer_str;
+	knew->private_value = dai_id;
+	kctl = snd_ctl_new1(knew, knew);
+	if (!kctl) {
+		kfree(knew);
+		kfree(mixer_str);
+		return -ENOMEM;
+	}
+	kctl->private_free = power_mode_mx_ctl_private_free;
+	rc = snd_ctl_add(card, kctl);
+	if (rc < 0)
+		pr_err("%s: err add config ctl, DAI = %s\n",
+			__func__, dai_name);
+	kfree(mixer_str);
+
+	return rc;
+}
+
 static int msm_dai_q6_island_mode_put(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
@@ -1358,6 +1436,54 @@ static int msm_dai_q6_add_island_mx_ctls(struct snd_card *card,
 	return rc;
 }
 
+static int msm_dai_q6_add_isconfig_config_mx_ctls(struct snd_card *card,
+						const char *dai_name,
+						int dai_id, void *dai_data)
+
+{
+	const char *mx_ctl_name = "Island Config";
+	char *mixer_str = NULL;
+	int dai_str_len = 0, ctl_len = 0;
+	int rc = 0;
+	struct snd_kcontrol_new *knew = NULL;
+	struct snd_kcontrol *kctl = NULL;
+
+	dai_str_len = strlen(dai_name) + 1;
+
+	ctl_len = dai_str_len + strlen(mx_ctl_name) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s %s", dai_name, mx_ctl_name);
+
+	knew = kzalloc(sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+	if (!knew) {
+		kfree(mixer_str);
+		return -ENOMEM;
+	}
+	knew->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	knew->info = snd_ctl_boolean_mono_info;
+	knew->get = msm_dai_q6_island_mode_get;
+	knew->put = msm_dai_q6_island_mode_put;
+	knew->name = mixer_str;
+	knew->private_value = dai_id;
+	kctl = snd_ctl_new1(knew, knew);
+	if (!kctl) {
+		kfree(knew);
+		kfree(mixer_str);
+		return -ENOMEM;
+	}
+	kctl->private_free = island_mx_ctl_private_free;
+	rc = snd_ctl_add(card, kctl);
+	if (rc < 0)
+		pr_err("%s: err add config ctl, DAI = %s\n",
+			__func__, dai_name);
+	kfree(mixer_str);
+
+	return rc;
+}
+
 /*
  * For single CPU DAI registration, the dai id needs to be
  * set explicitly in the dai probe as ASoC does not read
@@ -2230,6 +2356,7 @@ static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
 {
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	int rc = 0;
+	uint16_t ttp_gen_enable = dai_data->ttp_config.ttp_gen_enable.enable;
 
 	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		if (dai_data->enc_config.format != ENC_FMT_NONE) {
@@ -2279,13 +2406,27 @@ static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
 				bitwidth = 0;
 				break;
 			}
-			pr_debug("%s: calling AFE_PORT_START_V2 with dec format: %d\n",
-				 __func__, dai_data->dec_config.format);
-			rc = afe_port_start_v2(dai->id, &dai_data->port_config,
-					       dai_data->rate,
-					       dai_data->afe_tx_out_channels,
-					       bitwidth,
-					       NULL, &dai_data->dec_config);
+
+			if (ttp_gen_enable == true) {
+				pr_debug("%s: calling AFE_PORT_START_V3 with dec format: %d\n",
+					 __func__, dai_data->dec_config.format);
+				rc = afe_port_start_v3(dai->id,
+						&dai_data->port_config,
+						dai_data->rate,
+						dai_data->afe_tx_out_channels,
+						bitwidth,
+						NULL, &dai_data->dec_config,
+						&dai_data->ttp_config);
+			} else {
+				pr_debug("%s: calling AFE_PORT_START_V2 with dec format: %d\n",
+					 __func__, dai_data->dec_config.format);
+				rc = afe_port_start_v2(dai->id,
+						&dai_data->port_config,
+						dai_data->rate,
+						dai_data->afe_tx_out_channels,
+						bitwidth,
+						NULL, &dai_data->dec_config);
+			}
 			if (rc < 0) {
 				pr_err("%s: fail to open AFE port 0x%x\n",
 					__func__, dai->id);
@@ -2796,7 +2937,6 @@ static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
 	return rc;
 }
 
-/* all ports with excursion logging requirement can use this digital_mute api */
 static int msm_dai_q6_spk_digital_mute(struct snd_soc_dai *dai,
 				       int mute)
 {
@@ -3670,6 +3810,91 @@ static int msm_dai_q6_afe_dec_cfg_put(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
+static int  msm_dai_q6_afe_enable_ttp_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(struct afe_ttp_gen_enable_t);
+
+	return 0;
+}
+
+static int msm_dai_q6_afe_enable_ttp_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	pr_debug("%s:\n", __func__);
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(ucontrol->value.bytes.data,
+	       &dai_data->ttp_config.ttp_gen_enable,
+	       sizeof(struct afe_ttp_gen_enable_t));
+	return 0;
+}
+
+static int msm_dai_q6_afe_enable_ttp_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	pr_debug("%s:\n", __func__);
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(&dai_data->ttp_config.ttp_gen_enable,
+		ucontrol->value.bytes.data,
+		sizeof(struct afe_ttp_gen_enable_t));
+	return 0;
+}
+
+static int  msm_dai_q6_afe_ttp_cfg_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(struct afe_ttp_gen_cfg_t);
+
+	return 0;
+}
+
+static int msm_dai_q6_afe_ttp_cfg_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	pr_debug("%s:\n", __func__);
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(ucontrol->value.bytes.data,
+	       &dai_data->ttp_config.ttp_gen_cfg,
+	       sizeof(struct afe_ttp_gen_cfg_t));
+	return 0;
+}
+
+static int msm_dai_q6_afe_ttp_cfg_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+	pr_debug("%s: Received ttp config\n", __func__);
+	if (!dai_data) {
+		pr_err("%s: Invalid dai data\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(&dai_data->ttp_config.ttp_gen_cfg,
+		ucontrol->value.bytes.data, sizeof(struct afe_ttp_gen_cfg_t));
+	return 0;
+}
+
 static const struct snd_kcontrol_new afe_dec_config_controls[] = {
 	{
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -3697,6 +3922,27 @@ static const struct snd_kcontrol_new afe_dec_config_controls[] = {
 		     msm_dai_q6_afe_output_bit_format_put),
 };
 
+static const struct snd_kcontrol_new afe_ttp_config_controls[] = {
+	{
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			   SNDRV_CTL_ELEM_ACCESS_INACTIVE),
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "TTP Enable",
+		.info = msm_dai_q6_afe_enable_ttp_info,
+		.get = msm_dai_q6_afe_enable_ttp_get,
+		.put = msm_dai_q6_afe_enable_ttp_put,
+	},
+	{
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			   SNDRV_CTL_ELEM_ACCESS_INACTIVE),
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "AFE TTP config",
+		.info = msm_dai_q6_afe_ttp_cfg_info,
+		.get = msm_dai_q6_afe_ttp_cfg_get,
+		.put = msm_dai_q6_afe_ttp_cfg_put,
+	},
+};
+
 static int msm_dai_q6_slim_rx_drift_info(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_info *uinfo)
 {
@@ -3920,6 +4166,12 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(&afe_dec_config_controls[3],
 				 dai_data));
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				 snd_ctl_new1(&afe_ttp_config_controls[0],
+				 dai_data));
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				 snd_ctl_new1(&afe_ttp_config_controls[1],
+				 dai_data));
 		break;
 	case RT_PROXY_DAI_001_RX:
 		rc = snd_ctl_add(dai->component->card->snd_card,
@@ -12195,6 +12447,14 @@ static int msm_dai_q6_dai_cdc_dma_probe(struct snd_soc_dai *dai)
 						dai->component->card->snd_card,
 						dai->name, dai->id,
 						(void *)dai_data);
+	rc = msm_dai_q6_add_power_mode_mx_ctls(
+						dai->component->card->snd_card,
+						dai->name, dai->id,
+						(void *)dai_data);
+	rc= msm_dai_q6_add_isconfig_config_mx_ctls(
+						dai->component->card->snd_card,
+						dai->name, dai->id,
+						(void *)dai_data);
 
 	rc = msm_dai_q6_dai_add_route(dai);
 	return rc;
@@ -12342,12 +12602,13 @@ static int msm_dai_q6_cdc_dma_prepare(struct snd_pcm_substream *substream,
 			dai_data->port_config.cdc_dma.data_format =
 				AFE_LINEAR_PCM_DATA_PACKED_16BIT;
 
-		rc = afe_send_cdc_dma_data_align(dai->id,
+		if (dai_data->cdc_dma_data_align) {
+			rc = afe_send_cdc_dma_data_align(dai->id,
 				dai_data->cdc_dma_data_align);
-		if (rc)
-			pr_debug("%s: afe send data alignment failed %d\n",
-				__func__, rc);
-
+			if (rc)
+				pr_debug("%s: afe send data alignment failed %d\n",
+					__func__, rc);
+		}
 		rc = afe_port_start(dai->id, &dai_data->port_config,
 						dai_data->rate);
 		if (rc < 0)
@@ -12364,7 +12625,8 @@ static int msm_dai_q6_cdc_dma_prepare(struct snd_pcm_substream *substream,
 static void msm_dai_q6_cdc_dma_shutdown(struct snd_pcm_substream *substream,
 				     struct snd_soc_dai *dai)
 {
-	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_cdc_dma_dai_data *dai_data =
+					dev_get_drvdata(dai->dev);
 	int rc = 0;
 
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
@@ -12383,6 +12645,19 @@ static void msm_dai_q6_cdc_dma_shutdown(struct snd_pcm_substream *substream,
 		clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
 }
 
+static int msm_dai_q6_cdc_dma_digital_mute(struct snd_soc_dai *dai,
+				       int mute)
+{
+	int port_id = dai->id;
+	struct msm_dai_q6_cdc_dma_dai_data *dai_data =
+					dev_get_drvdata(dai->dev);
+
+	if (mute && !dai_data->xt_logging_disable)
+		afe_get_sp_xt_logging_data(port_id);
+
+	return 0;
+}
+
 static struct snd_soc_dai_ops msm_dai_q6_cdc_dma_ops = {
 	.prepare          = msm_dai_q6_cdc_dma_prepare,
 	.hw_params        = msm_dai_q6_cdc_dma_hw_params,
@@ -12395,7 +12670,7 @@ static struct snd_soc_dai_ops msm_dai_q6_cdc_wsa_dma_ops = {
 	.hw_params        = msm_dai_q6_cdc_dma_hw_params,
 	.shutdown         = msm_dai_q6_cdc_dma_shutdown,
 	.set_channel_map = msm_dai_q6_cdc_dma_set_channel_map,
-	.digital_mute = msm_dai_q6_spk_digital_mute,
+	.digital_mute = msm_dai_q6_cdc_dma_digital_mute,
 };
 
 static struct snd_soc_dai_driver msm_dai_q6_cdc_dma_dai[] = {
@@ -12624,6 +12899,7 @@ static struct snd_soc_dai_driver msm_dai_q6_cdc_dma_dai[] = {
 			.rate_min = 8000,
 			.rate_max = 384000,
 		},
+		.name = "RX_CDC_DMA_RX_0",
 		.ops = &msm_dai_q6_cdc_dma_ops,
 		.id = AFE_PORT_ID_RX_CODEC_DMA_RX_0,
 		.probe = msm_dai_q6_dai_cdc_dma_probe,
@@ -12674,6 +12950,7 @@ static struct snd_soc_dai_driver msm_dai_q6_cdc_dma_dai[] = {
 			.rate_min = 8000,
 			.rate_max = 384000,
 		},
+		.name = "RX_CDC_DMA_RX_1",
 		.ops = &msm_dai_q6_cdc_dma_ops,
 		.id = AFE_PORT_ID_RX_CODEC_DMA_RX_1,
 		.probe = msm_dai_q6_dai_cdc_dma_probe,
@@ -12798,6 +13075,7 @@ static struct snd_soc_dai_driver msm_dai_q6_cdc_dma_dai[] = {
 			.rate_min = 8000,
 			.rate_max = 384000,
 		},
+		.name = "TX_CDC_DMA_TX_3",
 		.ops = &msm_dai_q6_cdc_dma_ops,
 		.id = AFE_PORT_ID_TX_CODEC_DMA_TX_3,
 		.probe = msm_dai_q6_dai_cdc_dma_probe,
@@ -12848,6 +13126,7 @@ static struct snd_soc_dai_driver msm_dai_q6_cdc_dma_dai[] = {
 			.rate_min = 8000,
 			.rate_max = 384000,
 		},
+		.name = "TX_CDC_DMA_TX_4",
 		.ops = &msm_dai_q6_cdc_dma_ops,
 		.id = AFE_PORT_ID_TX_CODEC_DMA_TX_4,
 		.probe = msm_dai_q6_dai_cdc_dma_probe,

+ 321 - 109
asoc/msm-lsm-client.c

@@ -499,38 +499,71 @@ static int msm_lsm_get_conf_levels(struct lsm_client *client,
 {
 	int rc = 0;
 
-	if (client->num_confidence_levels == 0) {
-		pr_debug("%s: no confidence levels provided\n",
-			__func__);
-		client->confidence_levels = NULL;
-		goto done;
-	}
+	if (client->num_sound_models != 0) {
+		if (client->num_keywords == 0) {
+			pr_debug("%s: no number of confidence_values provided\n",
+				 __func__);
+			client->multi_snd_model_confidence_levels = NULL;
+			goto done;
+		}
+
+		client->multi_snd_model_confidence_levels =
+			kzalloc((sizeof(uint32_t) * client->num_keywords),
+				 GFP_KERNEL);
+		if (!client->multi_snd_model_confidence_levels) {
+			pr_err("%s: No memory for confidence\n"
+				"levels num of level from user = %d\n",
+				__func__, client->num_keywords);
+				rc = -ENOMEM;
+				goto done;
+		}
 
-	client->confidence_levels =
-		kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
-			 GFP_KERNEL);
-	if (!client->confidence_levels) {
-		pr_err("%s: No memory for confidence\n"
-			"levels num of level from user = %d\n",
-			__func__, client->num_confidence_levels);
-			rc = -ENOMEM;
+		if (copy_from_user((u8 *)client->multi_snd_model_confidence_levels,
+				   conf_levels_ptr,
+				   sizeof(uint32_t) * client->num_keywords)) {
+			pr_err("%s: copy from user failed, number of keywords = %d\n",
+			       __func__, client->num_keywords);
+			rc = -EFAULT;
+			goto copy_err;
+		}
+	} else {
+		if (client->num_confidence_levels == 0) {
+			pr_debug("%s: no confidence levels provided\n",
+				 __func__);
+			client->confidence_levels = NULL;
 			goto done;
-	}
+		}
 
-	if (copy_from_user(client->confidence_levels,
-			   conf_levels_ptr,
-			   client->num_confidence_levels)) {
-		pr_err("%s: copy from user failed, size = %d\n",
-		       __func__, client->num_confidence_levels);
-		rc = -EFAULT;
-		goto copy_err;
-	}
+		client->confidence_levels =
+			kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
+				 GFP_KERNEL);
+		if (!client->confidence_levels) {
+			pr_err("%s: No memory for confidence\n"
+				"levels num of level from user = %d\n",
+				__func__, client->num_confidence_levels);
+				rc = -ENOMEM;
+				goto done;
+		}
 
+		if (copy_from_user(client->confidence_levels,
+				   conf_levels_ptr,
+				   client->num_confidence_levels)) {
+			pr_err("%s: copy from user failed, size = %d\n",
+			       __func__, client->num_confidence_levels);
+			rc = -EFAULT;
+			goto copy_err;
+		}
+	}
 	return rc;
 
 copy_err:
-	kfree(client->confidence_levels);
-	client->confidence_levels = NULL;
+	if (client->num_sound_models != 0) {
+		kfree(client->multi_snd_model_confidence_levels);
+		client->multi_snd_model_confidence_levels = NULL;
+	} else {
+		kfree(client->confidence_levels);
+		client->confidence_levels = NULL;
+	}
 done:
 	return rc;
 
@@ -652,35 +685,67 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int rc = 0;
 
-	if (p_info->param_size > MAX_NUM_CONFIDENCE) {
-		dev_err(rtd->dev,
-			"%s: invalid confidence levels %d\n",
-			__func__, p_info->param_size);
-		return -EINVAL;
-	}
+	if (p_info->param_type == LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS) {
+		if (p_info->param_size > MAX_KEYWORDS_SUPPORTED) {
+			dev_err(rtd->dev,
+				"%s: invalid number of snd_model keywords %d, the max is %d\n",
+				__func__, p_info->param_size, MAX_KEYWORDS_SUPPORTED);
+			return -EINVAL;
+		}
 
-	prtd->lsm_client->num_confidence_levels =
-			p_info->param_size;
-	rc = msm_lsm_get_conf_levels(prtd->lsm_client,
-				     p_info->param_data);
-	if (rc) {
-		dev_err(rtd->dev,
-			"%s: get_conf_levels failed, err = %d\n",
-			__func__, rc);
-		return rc;
-	}
+		prtd->lsm_client->num_keywords = p_info->param_size;
+		rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+					     p_info->param_data);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: get_conf_levels failed for snd_model %d, err = %d\n",
+				__func__, p_info->model_id, rc);
+			return rc;
+		}
 
-	rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
-				 prtd->lsm_client->confidence_levels,
-				 LSM_MIN_CONFIDENCE_LEVELS);
-	if (rc)
-		dev_err(rtd->dev,
-			"%s: Failed to set min_conf_levels, err = %d\n",
-			__func__, rc);
+		rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+					 prtd->lsm_client->multi_snd_model_confidence_levels,
+					 LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS);
+		if (rc)
+			dev_err(rtd->dev,
+				"%s: Failed to set multi_snd_model_confidence_levels, err = %d\n",
+				__func__, rc);
 
-	if (prtd->lsm_client->confidence_levels) {
-		kfree(prtd->lsm_client->confidence_levels);
-		prtd->lsm_client->confidence_levels = NULL;
+		if (prtd->lsm_client->multi_snd_model_confidence_levels) {
+			kfree(prtd->lsm_client->multi_snd_model_confidence_levels);
+			prtd->lsm_client->multi_snd_model_confidence_levels = NULL;
+		}
+	} else {
+		if (p_info->param_size > MAX_NUM_CONFIDENCE) {
+			dev_err(rtd->dev,
+				"%s: invalid confidence levels %d\n",
+				__func__, p_info->param_size);
+			return -EINVAL;
+		}
+
+		prtd->lsm_client->num_confidence_levels =
+				p_info->param_size;
+		rc = msm_lsm_get_conf_levels(prtd->lsm_client,
+					     p_info->param_data);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: get_conf_levels failed, err = %d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
+					 prtd->lsm_client->confidence_levels,
+					 LSM_MIN_CONFIDENCE_LEVELS);
+		if (rc)
+			dev_err(rtd->dev,
+				"%s: Failed to set min_conf_levels, err = %d\n",
+				__func__, rc);
+
+		if (prtd->lsm_client->confidence_levels) {
+			kfree(prtd->lsm_client->confidence_levels);
+			prtd->lsm_client->confidence_levels = NULL;
+		}
 	}
 	return rc;
 }
@@ -691,66 +756,166 @@ static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int rc = 0;
+	int rc = 0, stage_idx = p_info->stage_idx;
 	struct lsm_sound_model *sm = NULL;
 	size_t offset = sizeof(union param_hdrs);
+	struct lsm_client *client = prtd->lsm_client;
 
-	rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
-				       p_info->param_size, p_info);
-	if (rc) {
-		dev_err(rtd->dev,
-			"%s: snd_model buf alloc failed, size = %d\n",
-			__func__, p_info->param_size);
-		return rc;
-	}
+	if (p_info->model_id != 0 &&
+	    p_info->param_type == LSM_REG_MULTI_SND_MODEL) {
+		sm = kzalloc(sizeof(*sm), GFP_KERNEL);
+		if (sm == NULL) {
+			dev_err(rtd->dev, "%s: snd_model kzalloc failed\n", __func__);
+			return -ENOMEM;
+		}
 
-	q6lsm_sm_set_param_data(prtd->lsm_client, p_info, &offset);
+		INIT_LIST_HEAD(&sm->list);
 
-	/*
-	 * For set_param, advance the sound model data with the
-	 * number of bytes required by param_data.
-	 */
+		rc = q6lsm_snd_model_buf_alloc(client, p_info->param_size, p_info, sm);
+		if (rc) {
+			dev_err(rtd->dev, "%s: snd_model buf alloc failed, size = %d\n",
+				__func__, p_info->param_size);
+			goto err_buf_alloc;
+		}
 
-	sm = &prtd->lsm_client->stage_cfg[p_info->stage_idx].sound_model;
-	if (copy_from_user((u8 *)sm->data + offset,
-			   p_info->param_data, p_info->param_size)) {
-		dev_err(rtd->dev,
-			"%s: copy_from_user for snd_model failed, size = %d\n",
-			__func__, p_info->param_size);
-		rc = -EFAULT;
-		goto err_copy;
-	}
-	rc = q6lsm_set_one_param(prtd->lsm_client, p_info, NULL,
-				 LSM_REG_SND_MODEL);
-	if (rc) {
+		q6lsm_sm_set_param_data(client, p_info, &offset, sm);
+
+		/*
+		 * For set_param, advance the sound model data with the
+		 * number of bytes required by param_data.
+		 */
+		if (copy_from_user((u8 *)sm->data + offset,
+			p_info->param_data, p_info->param_size)) {
+			dev_err(rtd->dev,
+				"%s: copy_from_user for snd_model %d failed, size = %d\n",
+				__func__, p_info->model_id, p_info->param_size);
+			rc = -EFAULT;
+			goto err_copy;
+		}
+		/* Add this sound model to the list of multi sound models */
+		list_add_tail(&sm->list, &client->stage_cfg[stage_idx].sound_models);
+
+		rc = q6lsm_set_one_param(client, p_info, NULL,
+					 LSM_REG_MULTI_SND_MODEL);
+		if (rc) {
+			dev_err(rtd->dev,
+				"%s: Failed to register snd_model %d, err = %d\n",
+				__func__, p_info->model_id, rc);
+			goto err_copy;
+		}
+
+		client->num_sound_models++;
+		dev_dbg(rtd->dev,
+			"%s: registered snd_model: %d, total num of snd_model: %d\n",
+			__func__, p_info->model_id, client->num_sound_models);
+	} else if (p_info->model_id == 0 &&
+		   p_info->param_type == LSM_REG_SND_MODEL) {
+		sm = &client->stage_cfg[stage_idx].sound_model;
+
+		rc = q6lsm_snd_model_buf_alloc(client, p_info->param_size, p_info, sm);
+		if (rc) {
+			dev_err(rtd->dev, "%s: snd_model buf alloc failed, size = %d\n",
+				__func__, p_info->param_size);
+			return rc;
+		}
+
+		q6lsm_sm_set_param_data(client, p_info, &offset, sm);
+
+		/*
+		 * For set_param, advance the sound model data with the
+		 * number of bytes required by param_data.
+		 */
+
+		if (copy_from_user((u8 *)sm->data + offset,
+		    p_info->param_data, p_info->param_size)) {
+			dev_err(rtd->dev,
+				"%s: copy_from_user for snd_model failed, size = %d\n",
+				__func__, p_info->param_size);
+			rc = -EFAULT;
+			goto err_copy;
+		}
+		rc = q6lsm_set_one_param(client, p_info, NULL, LSM_REG_SND_MODEL);
+		if (rc) {
+			dev_err(rtd->dev, "%s: Failed to register snd_model, err = %d\n",
+				__func__, rc);
+			goto err_copy;
+		}
+	} else {
 		dev_err(rtd->dev,
-			"%s: Failed to set sound_model, err = %d\n",
-			__func__, rc);
-		goto err_copy;
+			"%s: snd_model id %d is invalid for param type %d\n",
+			__func__, p_info->model_id, p_info->param_type);
 	}
 	return rc;
 
 err_copy:
-	q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
+	q6lsm_snd_model_buf_free(client, p_info, sm);
+err_buf_alloc:
+	if (p_info->model_id != 0) {
+		list_del(&sm->list);
+		kfree(sm);
+		sm = NULL;
+	}
 	return rc;
 }
 
 static int msm_lsm_dereg_model(struct snd_pcm_substream *substream,
-		struct lsm_params_info_v2 *p_info)
+			struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct lsm_sound_model *sm = NULL;
+	struct lsm_client *client = prtd->lsm_client;
 	int rc = 0;
 
-	rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
-				 NULL, LSM_DEREG_SND_MODEL);
-	if (rc)
-		dev_err(rtd->dev,
-			"%s: Failed to set det_mode param, err = %d\n",
-			__func__, rc);
+	if (p_info->model_id != 0 &&
+		p_info->param_type == LSM_DEREG_MULTI_SND_MODEL) {
+		list_for_each_entry(sm,
+				   &client->stage_cfg[p_info->stage_idx].sound_models,
+				   list) {
+			dev_dbg(rtd->dev,
+				"%s: current snd_model: %d, looking for snd_model %d\n",
+				 __func__, sm->model_id, p_info->model_id);
+			if (sm->model_id == p_info->model_id)
+				break;
+		}
 
-	q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
+		if (sm->model_id == p_info->model_id) {
+			rc = q6lsm_set_one_param(client, p_info, NULL,
+						 LSM_DEREG_MULTI_SND_MODEL);
+			if (rc)
+				dev_err(rtd->dev,
+					"%s: Failed to deregister snd_model %d, err = %d\n",
+					__func__, p_info->model_id, rc);
+
+			q6lsm_snd_model_buf_free(client, p_info, sm);
+			list_del(&sm->list);
+			kfree(sm);
+			sm = NULL;
+			client->num_sound_models--;
+		} else {
+			rc = -EINVAL;
+			dev_err(rtd->dev,
+				"%s: Failed to find snd_model, invalid model_id %d\n",
+				__func__, p_info->model_id);
+		}
+	} else if (p_info->model_id == 0 &&
+		   p_info->param_type == LSM_DEREG_SND_MODEL) {
+		rc = q6lsm_set_one_param(client, p_info, NULL,
+					 LSM_DEREG_SND_MODEL);
+		if (rc)
+			dev_err(rtd->dev,
+				"%s: Failed to deregister snd_model, err = %d\n",
+				__func__, rc);
+
+		sm = &client->stage_cfg[p_info->stage_idx].sound_model;
+		q6lsm_snd_model_buf_free(client, p_info, sm);
+	} else {
+		rc = -EINVAL;
+		dev_err(rtd->dev,
+			"%s: snd_model id %d is invalid for param type %d\n",
+			__func__, p_info->model_id, p_info->param_type);
+	}
 
 	return rc;
 }
@@ -992,6 +1157,22 @@ static int msm_lsm_process_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
+	if (p_info->param_type == LSM_REG_MULTI_SND_MODEL &&
+		prtd->lsm_client->num_sound_models == LSM_MAX_SOUND_MODELS_SUPPORTED) {
+		dev_err(rtd->dev,
+			"%s: maximum supported sound models(8) have already reached\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (p_info->param_type == LSM_DEREG_MULTI_SND_MODEL &&
+		prtd->lsm_client->num_sound_models == 0) {
+		dev_err(rtd->dev,
+			"%s: no available sound model to be deregistered\n",
+			__func__);
+		return -EINVAL;
+	}
+
 	switch (p_info->param_type) {
 	case LSM_ENDPOINT_DETECT_THRESHOLD:
 		rc = msm_lsm_set_epd(substream, p_info);
@@ -1003,12 +1184,15 @@ static int msm_lsm_process_params(struct snd_pcm_substream *substream,
 		rc = msm_lsm_set_gain(substream, p_info);
 		break;
 	case LSM_MIN_CONFIDENCE_LEVELS:
+	case LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS:
 		rc = msm_lsm_set_conf(substream, p_info);
 		break;
 	case LSM_REG_SND_MODEL:
+	case LSM_REG_MULTI_SND_MODEL:
 		rc = msm_lsm_reg_model(substream, p_info);
 		break;
 	case LSM_DEREG_SND_MODEL:
+	case LSM_DEREG_MULTI_SND_MODEL:
 		rc = msm_lsm_dereg_model(substream, p_info);
 		break;
 	case LSM_CUSTOM_PARAMS:
@@ -1176,7 +1360,10 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 		 * also set stage index to LSM_STAGE_INDEX_FIRST.
 		 */
 		struct lsm_params_info_v2 p_info = {0};
+		struct lsm_sound_model *sm = NULL;
 		p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+		p_info.param_type = LSM_DEREG_SND_MODEL;
+		sm = &prtd->lsm_client->stage_cfg[p_info.stage_idx].sound_model;
 
 		dev_dbg(rtd->dev, "%s: Registering sound model V2\n",
 			__func__);
@@ -1192,21 +1379,20 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			break;
 		}
 		rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
-					snd_model_v2.data_size, &p_info);
+					snd_model_v2.data_size, &p_info, sm);
 		if (rc) {
 			dev_err(rtd->dev,
 				"%s: q6lsm buffer alloc failed V2, size %d\n",
 			       __func__, snd_model_v2.data_size);
 			break;
 		}
-		if (copy_from_user(
-				prtd->lsm_client->stage_cfg[p_info.stage_idx].sound_model.data,
-				snd_model_v2.data, snd_model_v2.data_size)) {
+		if (copy_from_user(sm->data, snd_model_v2.data,
+						   snd_model_v2.data_size)) {
 			dev_err(rtd->dev,
 				"%s: copy from user data failed\n"
 			       "data %pK size %d\n", __func__,
 			       snd_model_v2.data, snd_model_v2.data_size);
-			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
+			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info, sm);
 			rc = -EFAULT;
 			break;
 		}
@@ -1234,7 +1420,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			dev_err(rtd->dev,
 				"%s: Register snd Model v2 failed =%d\n",
 			       __func__, rc);
-			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
+			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info, sm);
 		}
 		if (prtd->lsm_client->confidence_levels) {
 			kfree(prtd->lsm_client->confidence_levels);
@@ -1697,6 +1883,7 @@ struct lsm_params_info_v2_32 {
 	uint32_t param_type;
 	u16 instance_id;
 	u16 stage_idx;
+	u32 model_id;
 };
 
 struct snd_lsm_module_params_32 {
@@ -2033,9 +2220,9 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 
 		if (p_data.data_size != expected_size) {
 			dev_err(rtd->dev,
-				"%s: %s: Invalid size %d\n",
+				"%s: %s: Invalid size %d, expected_size %d\n",
 				__func__, "SET_MODULE_PARAMS(_V2)_32",
-				p_data.data_size);
+				p_data.data_size, expected_size);
 			err = -EINVAL;
 			goto done;
 		}
@@ -2071,6 +2258,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 
 				p_info.instance_id = INSTANCE_ID_0;
 				p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+				p_info.model_id = 0;
 
 				p_info_32++;
 			} else {
@@ -2082,6 +2270,14 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 
 				p_info.instance_id = p_info_v2_32->instance_id;
 				p_info.stage_idx = p_info_v2_32->stage_idx;
+				/* set sound model id to 0 for backward compatibility */
+				p_info.model_id = 0;
+
+				if (LSM_REG_MULTI_SND_MODEL == p_info_v2_32->param_type ||
+				    LSM_DEREG_MULTI_SND_MODEL == p_info_v2_32->param_type ||
+				    LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS ==
+								p_info_v2_32->param_type)
+					p_info.model_id = p_info_v2_32->model_id;
 
 				p_info_v2_32++;
 			}
@@ -2208,7 +2404,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 	case SNDRV_LSM_SET_MODULE_PARAMS_V2: {
 		struct snd_lsm_module_params p_data;
 		struct lsm_params_info *temp_ptr_info = NULL;
-		struct lsm_params_info_v2 info_v2;
 		struct lsm_params_info_v2 *ptr_info_v2 = NULL, *temp_ptr_info_v2 = NULL;
 		size_t p_size = 0, count;
 		u8 *params;
@@ -2277,26 +2472,37 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 		for (count = 0; count < p_data.num_params; count++) {
 			if (cmd == SNDRV_LSM_SET_MODULE_PARAMS) {
 				/* convert to V2 param info struct from legacy param info */
-				info_v2.module_id = temp_ptr_info->module_id;
-				info_v2.param_id = temp_ptr_info->param_id;
-				info_v2.param_size = temp_ptr_info->param_size;
-				info_v2.param_data = temp_ptr_info->param_data;
-				info_v2.param_type = temp_ptr_info->param_type;
+				ptr_info_v2->module_id = temp_ptr_info->module_id;
+				ptr_info_v2->param_id = temp_ptr_info->param_id;
+				ptr_info_v2->param_size = temp_ptr_info->param_size;
+				ptr_info_v2->param_data = temp_ptr_info->param_data;
+				ptr_info_v2->param_type = temp_ptr_info->param_type;
 
-				info_v2.instance_id = INSTANCE_ID_0;
-				info_v2.stage_idx = LSM_STAGE_INDEX_FIRST;
+				ptr_info_v2->instance_id = INSTANCE_ID_0;
+				ptr_info_v2->stage_idx = LSM_STAGE_INDEX_FIRST;
+				ptr_info_v2->model_id = 0;
 
-				ptr_info_v2 = &info_v2;
 				temp_ptr_info++;
 			} else {
-				/* Just copy the pointer as user already provided v2 params */
+				if (LSM_REG_MULTI_SND_MODEL != temp_ptr_info_v2->param_type ||
+				    LSM_DEREG_MULTI_SND_MODEL !=
+								temp_ptr_info_v2->param_type ||
+				    LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS !=
+								temp_ptr_info_v2->param_type) {
+					/* set sound model id to 0 for backward compatibility */
+					temp_ptr_info_v2->model_id = 0;
+				}
+				/*
+				 * Just copy the pointer as user
+				 * already provided sound model id
+				 */
 				ptr_info_v2 = temp_ptr_info_v2;
 				temp_ptr_info_v2++;
 			}
 			err = msm_lsm_process_params(substream, ptr_info_v2);
 			if (err)
 				dev_err(rtd->dev,
-					"%s: Failed to process param, type%d stage=%d err=%d\n",
+					"%s: Failed to process param, type=%d stage=%d err=%d\n",
 					__func__, ptr_info_v2->param_type,
 					ptr_info_v2->stage_idx, err);
 		}
@@ -2464,7 +2670,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int ret = 0;
+	int ret = 0, i;
 
 	pr_debug("%s\n", __func__);
 	prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
@@ -2530,6 +2736,12 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
 	prtd->lsm_client->event_type = LSM_DET_EVENT_TYPE_LEGACY;
 	prtd->lsm_client->fe_id = rtd->dai_link->id;
 	prtd->lsm_client->unprocessed_data = 0;
+	prtd->lsm_client->num_sound_models = 0;
+	prtd->lsm_client->num_keywords = 0;
+	prtd->lsm_client->multi_snd_model_confidence_levels = NULL;
+
+	for (i = 0; i < LSM_MAX_STAGES_PER_SESSION; i++)
+		INIT_LIST_HEAD(&prtd->lsm_client->stage_cfg[i].sound_models);
 
 	prtd->ws = wakeup_source_register(rtd->dev, "lsm-client");
 

+ 369 - 4
asoc/msm-pcm-routing-v2.c

@@ -18,7 +18,6 @@
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
-#include <sound/asound.h>
 #include <sound/pcm_params.h>
 #include <sound/hwdep.h>
 #include <audio/sound/audio_effects.h>
@@ -50,6 +49,9 @@
 #define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF
 #endif
 
+#define STRING_LENGTH_OF_INT 12
+#define MAX_USR_CTRL_CNT 128
+
 static struct mutex routing_lock;
 
 static struct cal_type_data *cal_data[MAX_ROUTING_CAL_TYPES];
@@ -147,6 +149,7 @@ struct msm_pcm_route_bdai_pp_params {
 static struct msm_pcm_route_bdai_pp_params
 	msm_bedais_pp_params[MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX] = {
 	{HDMI_RX, 0, 0, 0},
+	{HDMI_RX_MS, 0, 0, 0},
 	{DISPLAY_PORT_RX, 0, 0, 0},
 };
 
@@ -168,6 +171,187 @@ static int msm_routing_send_device_pp_params(int port_id,  int copp_idx,
 static void msm_routing_load_topology(size_t data_size, void *data);
 static void msm_routing_unload_topology(uint32_t topology_id);
 
+#ifndef SND_PCM_ADD_VOLUME_CTL
+static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x2000;
+	return 0;
+}
+
+static void pcm_volume_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+	struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol);
+
+	kfree(info);
+}
+
+/**
+ * snd_pcm_add_volume_ctls - create volume control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @max_length: the max length of the volume parameter of stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_volume instance if non-NULL
+ *
+ * Create volume control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
+			   const struct snd_pcm_volume_elem *volume,
+			   int max_length,
+			   unsigned long private_value,
+			   struct snd_pcm_volume **info_ret)
+{
+	int err = 0;
+	int size = 0;
+	struct snd_pcm_volume *info;
+	struct snd_kcontrol_new knew = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = pcm_volume_ctl_info,
+	};
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	info->pcm = pcm;
+	info->stream = stream;
+	info->volume = volume;
+	info->max_length = max_length;
+	size = sizeof("Playback ") + sizeof(" Volume") +
+		STRING_LENGTH_OF_INT*sizeof(char) + 1;
+	knew.name = kzalloc(size, GFP_KERNEL);
+	if (!knew.name) {
+		kfree(info);
+		return -ENOMEM;
+	}
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snprintf((char *)knew.name, size, "%s %d %s",
+			"Playback", pcm->device, "Volume");
+	else
+		snprintf((char *)knew.name, size, "%s %d %s",
+			"Capture", pcm->device, "Volume");
+	knew.device = pcm->device;
+	knew.count = pcm->streams[stream].substream_count;
+	knew.private_value = private_value;
+	info->kctl = snd_ctl_new1(&knew, info);
+	if (!info->kctl) {
+		kfree(info);
+		kfree(knew.name);
+		return -ENOMEM;
+	}
+	info->kctl->private_free = pcm_volume_ctl_private_free;
+	err = snd_ctl_add(pcm->card, info->kctl);
+	if (err < 0) {
+		kfree(info);
+		kfree(knew.name);
+		return -ENOMEM;
+	}
+	if (info_ret)
+		*info_ret = info;
+	kfree(knew.name);
+	return 0;
+}
+EXPORT_SYMBOL(snd_pcm_add_volume_ctls);
+#endif
+
+#ifndef SND_PCM_ADD_USR_CTL
+static int pcm_usr_ctl_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = MAX_USR_CTRL_CNT;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = INT_MAX;
+	return 0;
+}
+
+static void pcm_usr_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+	struct snd_pcm_usr *info = snd_kcontrol_chip(kcontrol);
+
+	kfree(info);
+}
+
+/**
+ * snd_pcm_add_usr_ctls - create user control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @max_length: the max length of the user parameter of stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_usr instance if non-NULL
+ *
+ * Create usr control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
+			 const struct snd_pcm_usr_elem *usr,
+			 int max_length, int max_kctrl_str_len,
+			 unsigned long private_value,
+			 struct snd_pcm_usr **info_ret)
+{
+	int err = 0;
+	char *buf = NULL;
+	struct snd_pcm_usr *info;
+	struct snd_kcontrol_new knew = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = pcm_usr_ctl_info,
+	};
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pcm = pcm;
+	info->stream = stream;
+	info->usr = usr;
+	info->max_length = max_length;
+	buf = kzalloc(max_kctrl_str_len, GFP_KERNEL);
+	if (!buf) {
+		pr_err("%s: buffer allocation failed\n", __func__);
+		kfree(info);
+		return -ENOMEM;
+	}
+	knew.name = buf;
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snprintf(buf, max_kctrl_str_len, "%s %d %s",
+			"Playback", pcm->device, "User kcontrol");
+	else
+		snprintf(buf, max_kctrl_str_len, "%s %d %s",
+			"Capture", pcm->device, "User kcontrol");
+	knew.device = pcm->device;
+	knew.count = pcm->streams[stream].substream_count;
+	knew.private_value = private_value;
+	info->kctl = snd_ctl_new1(&knew, info);
+	if (!info->kctl) {
+		kfree(info);
+		kfree(knew.name);
+		pr_err("%s: snd_ctl_new failed\n", __func__);
+		return -ENOMEM;
+	}
+	info->kctl->private_free = pcm_usr_ctl_private_free;
+	err = snd_ctl_add(pcm->card, info->kctl);
+	if (err < 0) {
+		kfree(info);
+		kfree(knew.name);
+		pr_err("%s: snd_ctl_add failed:%d\n", __func__,
+			err);
+		return -ENOMEM;
+	}
+	if (info_ret)
+		*info_ret = info;
+	kfree(knew.name);
+	return 0;
+}
+EXPORT_SYMBOL(snd_pcm_add_usr_ctls);
+#endif
+
 static int msm_routing_get_bit_width(unsigned int format)
 {
 	int bit_width;
@@ -699,6 +883,7 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
 	  LPASS_BE_SEC_META_MI2S_RX},
 	{ RT_PROXY_PORT_002_RX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_PROXY_RX},
 	{ RT_PROXY_PORT_002_TX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_PROXY_TX},
+	{ HDMI_RX_MS, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_HDMI_MS},
 };
 
 /* Track ASM playback & capture sessions of DAI
@@ -3534,7 +3719,7 @@ static const char *const be_name[] = {
 "RX_CDC_DMA_RX_6", "RX_CDC_DMA_RX_7",
 "PRI_SPDIF_TX", "SEC_SPDIF_RX", "SEC_SPDIF_TX",
 "SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX", "PRI_META_MI2S_RX",
-"SEC_META_MI2S_RX", "PROXY_RX", "PROXY_TX"
+"SEC_META_MI2S_RX", "PROXY_RX", "PROXY_TX", "HDMI_RX_MS"
 };
 
 static SOC_ENUM_SINGLE_DECL(mm1_channel_mux,
@@ -7549,6 +7734,101 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new hdmi_ms_mixer_controls[] = {
+	SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia30", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_FRONTEND_DAI_MULTIMEDIA30, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new display_port_mixer_controls[] = {
 	SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_DISPLAY_PORT_RX,
@@ -18458,6 +18738,13 @@ static const struct snd_kcontrol_new hdmi_rx_port_mixer_controls[] = {
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new hdmi_rx_ms_port_mixer_controls[] = {
+	SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
+	MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
+
 static const struct snd_kcontrol_new display_port_rx_port_mixer_controls[] = {
 	SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_DISPLAY_PORT_RX,
@@ -24225,6 +24512,7 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("HDMI_MS", "HDMI MS Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT", "Display Port Playback",
 			     0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT1", "Display Port1 Playback",
@@ -24673,6 +24961,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
 	slimbus_9_rx_mixer_controls, ARRAY_SIZE(slimbus_9_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
 	hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
+	SND_SOC_DAPM_MIXER("HDMI_MS Mixer", SND_SOC_NOPM, 0, 0,
+	hdmi_ms_mixer_controls, ARRAY_SIZE(hdmi_ms_mixer_controls)),
 	SND_SOC_DAPM_MIXER("DISPLAY_PORT Mixer", SND_SOC_NOPM, 0, 0,
 	display_port_mixer_controls, ARRAY_SIZE(display_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("DISPLAY_PORT1 Mixer", SND_SOC_NOPM, 0, 0,
@@ -25125,6 +25415,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
 	SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls,
 	ARRAY_SIZE(hdmi_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("HDMI_RX_MS Port Mixer",
+	SND_SOC_NOPM, 0, 0, hdmi_rx_ms_port_mixer_controls,
+	ARRAY_SIZE(hdmi_rx_ms_port_mixer_controls)),
 	SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, display_port_rx_port_mixer_controls,
 	ARRAY_SIZE(display_port_rx_port_mixer_controls)),
@@ -25666,6 +25959,25 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HDMI Mixer", "MultiMedia26", "MM_DL26"},
 	{"HDMI", NULL, "HDMI Mixer"},
 
+	{"HDMI_MS Mixer", "MultiMedia1", "MM_DL1"},
+	{"HDMI_MS Mixer", "MultiMedia2", "MM_DL2"},
+	{"HDMI_MS Mixer", "MultiMedia3", "MM_DL3"},
+	{"HDMI_MS Mixer", "MultiMedia4", "MM_DL4"},
+	{"HDMI_MS Mixer", "MultiMedia5", "MM_DL5"},
+	{"HDMI_MS Mixer", "MultiMedia6", "MM_DL6"},
+	{"HDMI_MS Mixer", "MultiMedia7", "MM_DL7"},
+	{"HDMI_MS Mixer", "MultiMedia8", "MM_DL8"},
+	{"HDMI_MS Mixer", "MultiMedia9", "MM_DL9"},
+	{"HDMI_MS Mixer", "MultiMedia10", "MM_DL10"},
+	{"HDMI_MS Mixer", "MultiMedia11", "MM_DL11"},
+	{"HDMI_MS Mixer", "MultiMedia12", "MM_DL12"},
+	{"HDMI_MS Mixer", "MultiMedia13", "MM_DL13"},
+	{"HDMI_MS Mixer", "MultiMedia14", "MM_DL14"},
+	{"HDMI_MS Mixer", "MultiMedia15", "MM_DL15"},
+	{"HDMI_MS Mixer", "MultiMedia16", "MM_DL16"},
+	{"HDMI_MS Mixer", "MultiMedia26", "MM_DL26"},
+	{"HDMI_MS", NULL, "HDMI_MS Mixer"},
+
 	{"DISPLAY_PORT Mixer", "MultiMedia1", "MM_DL1"},
 	{"DISPLAY_PORT Mixer", "MultiMedia2", "MM_DL2"},
 	{"DISPLAY_PORT Mixer", "MultiMedia3", "MM_DL3"},
@@ -29345,6 +29657,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
 	{"HDMI", NULL, "HDMI_RX Port Mixer"},
 
+	{"HDMI_RX_MS Port Mixer", "MI2S_TX", "MI2S_TX"},
+	{"HDMI_MS", NULL, "HDMI_RX_MS Port Mixer"},
+
 	{"DISPLAY_PORT_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
 	{"DISPLAY_PORT", NULL, "DISPLAY_PORT_RX Port Mixer"},
 
@@ -29440,6 +29755,7 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"BE_OUT", NULL, "SLIMBUS_9_RX"},
 	{"BE_OUT", NULL, "USB_AUDIO_RX"},
 	{"BE_OUT", NULL, "HDMI"},
+	{"BE_OUT", NULL, "HDMI_MS"},
 	{"BE_OUT", NULL, "DISPLAY_PORT"},
 	{"BE_OUT", NULL, "DISPLAY_PORT1"},
 	{"BE_OUT", NULL, "PRI_SPDIF_RX"},
@@ -29928,7 +30244,8 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
 
 	pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx);
 
-	if (port_id != HDMI_RX && port_id != DISPLAY_PORT_RX) {
+	if (port_id != HDMI_RX && port_id != DISPLAY_PORT_RX
+			&& port_id != HDMI_RX_MS) {
 		pr_err("%s: Device pp params on invalid port %d, copp_idx %d, fe_id %d\n",
 			__func__, port_id, copp_idx, fe_id);
 		return  -EINVAL;
@@ -30065,7 +30382,8 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol,
 
 	for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) {
 		port_id = msm_bedais[be_idx].port_id;
-		if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX)
+		if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX
+				|| port_id == HDMI_RX_MS)
 			break;
 	}
 
@@ -30180,6 +30498,50 @@ static const struct snd_kcontrol_new aptx_dec_license_controls[] = {
 	msm_aptx_dec_license_control_put),
 };
 
+static int msm_routing_get_pll_clk_drift(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int msm_routing_put_pll_clk_drift(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	u16 port_id = 0;
+	int32_t clk_drift = 0;
+	uint32_t clk_reset = 0;
+	int be_idx, ret = -EINVAL;
+
+	be_idx = ucontrol->value.integer.value[0];
+	clk_drift = ucontrol->value.integer.value[1];
+	clk_reset = ucontrol->value.integer.value[2];
+
+	if (be_idx < 0 && be_idx >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: Invalid be id %d\n", __func__, be_idx);
+		return -EINVAL;
+	}
+
+	if (!msm_bedais[be_idx].active && !clk_reset) {
+		pr_err("%s:BE is not active %d, cannot set clock drift\n",
+			__func__, be_idx);
+		return -EINVAL;
+	}
+
+	port_id = msm_bedais[be_idx].port_id;
+	pr_debug("%s: clk drift %d be idx %d clk reset %d port id 0x%x\n",
+		  __func__, clk_drift, be_idx, clk_reset, port_id);
+	ret = afe_set_pll_clk_drift(port_id, clk_drift, clk_reset);
+	if (ret < 0)
+		pr_err("%s: failed to set pll clk drift\n", __func__);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new pll_clk_drift_controls[] = {
+	SOC_SINGLE_MULTI_EXT("PLL config data", SND_SOC_NOPM, 0, 0xFFFFFFFF,
+	0, 128, msm_routing_get_pll_clk_drift, msm_routing_put_pll_clk_drift),
+};
+
 static int msm_routing_put_port_chmap_mixer(struct snd_kcontrol *kcontrol,
 					    struct snd_ctl_elem_value *ucontrol)
 {
@@ -30480,6 +30842,9 @@ static int msm_routing_probe(struct snd_soc_component *component)
 			port_multi_channel_map_mixer_controls,
 			ARRAY_SIZE(port_multi_channel_map_mixer_controls));
 
+	snd_soc_add_component_controls(component, pll_clk_drift_controls,
+				      ARRAY_SIZE(pll_clk_drift_controls));
+
 	return 0;
 }
 

+ 55 - 1
asoc/msm-pcm-routing-v2.h

@@ -17,6 +17,7 @@
 #define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
 #define LPASS_BE_SLIMBUS_0_TX "SLIMBUS_0_TX"
 #define LPASS_BE_HDMI "HDMI"
+#define LPASS_BE_HDMI_MS "HDMI_MS"
 #define LPASS_BE_DISPLAY_PORT "DISPLAY_PORT"
 #define LPASS_BE_DISPLAY_PORT1 "DISPLAY_PORT1"
 #define LPASS_BE_INT_BT_SCO_RX "INT_BT_SCO_RX"
@@ -211,6 +212,7 @@
 
 #define LPASS_BE_WSA_CDC_DMA_RX_0 "WSA_CDC_DMA_RX_0"
 #define LPASS_BE_WSA_CDC_DMA_TX_0 "WSA_CDC_DMA_TX_0"
+#define LPASS_BE_WSA_CDC_DMA_TX_0_VI "WSA_CDC_DMA_TX_0_VI"
 #define LPASS_BE_WSA_CDC_DMA_RX_1 "WSA_CDC_DMA_RX_1"
 #define LPASS_BE_WSA_CDC_DMA_TX_1 "WSA_CDC_DMA_TX_1"
 #define LPASS_BE_WSA_CDC_DMA_TX_2 "WSA_CDC_DMA_TX_2"
@@ -508,6 +510,7 @@ enum {
 	MSM_BACKEND_DAI_SEC_META_MI2S_RX,
 	MSM_BACKEND_DAI_PROXY_RX,
 	MSM_BACKEND_DAI_PROXY_TX,
+	MSM_BACKEND_DAI_HDMI_RX_MS,
 	MSM_BACKEND_DAI_MAX,
 };
 
@@ -539,7 +542,7 @@ enum {
 #define RELEASE_LOCK	0
 #define ACQUIRE_LOCK	1
 
-#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX	2
+#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX	3
 #define HDMI_RX_ID				0x8001
 #define ADM_PP_PARAM_MUTE_ID			0
 #define ADM_PP_PARAM_MUTE_BIT			1
@@ -653,4 +656,55 @@ int msm_pcm_routing_set_channel_mixer_runtime(
 	int be_id, int session_id,
 	int session_type,
 	struct msm_pcm_channel_mixer *params);
+
+#ifndef SND_PCM_ADD_VOLUME_CTL
+/* PCM Volume control API
+ */
+/* array element of volume */
+struct snd_pcm_volume_elem {
+      int volume;
+};
+ /* pp information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_volume {
+      struct snd_pcm *pcm;    /* assigned PCM instance */
+      int stream;             /* PLAYBACK or CAPTURE */
+      struct snd_kcontrol *kctl;
+      const struct snd_pcm_volume_elem *volume;
+      int max_length;
+      void *private_data;     /* optional: private data pointer */
+};
+
+int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
+		const struct snd_pcm_volume_elem *volume,
+		int max_length,
+		unsigned long private_value,
+		struct snd_pcm_volume **info_ret);
+
+#endif
+
+#ifndef SND_PCM_ADD_USR_CTL
+/*
+ * PCM User control API	1450
+ */
+/* array element of usr elem */
+struct snd_pcm_usr_elem {
+	   int val[128];
+};
+
+/* pp information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_usr {
+   struct snd_pcm *pcm;   /* assigned PCM instance */
+   int stream;      /* PLAYBACK or CAPTURE */
+   struct snd_kcontrol *kctl;
+   const struct snd_pcm_usr_elem *usr;
+   int max_length;
+   void *private_data;   /* optional: private data pointer */
+};
+
+int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
+    const struct snd_pcm_usr_elem *usr,
+    int max_length, int max_control_str_len,
+    unsigned long private_value,
+    struct snd_pcm_usr **info_ret);
+#endif
 #endif /*_MSM_PCM_H*/

+ 0 - 8
asoc/msm-qti-pp-config.c

@@ -7,7 +7,6 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 #include <sound/control.h>
-#include <sound/asound.h>
 #include <sound/tlv.h>
 #include <dsp/q6adm-v2.h>
 #include <dsp/q6asm-v2.h>
@@ -1238,13 +1237,6 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
 	}
 
 	event_data = (struct msm_adsp_event_data *)payload;
-	if (event_data->payload_len < sizeof(struct msm_adsp_event_data)) {
-		pr_err("%s: event_data size of %x is less than expected.\n",
-			__func__, event_data->payload_len);
-		ret = -EINVAL;
-		goto done;
-	}
-
 	kctl->info(kctl, &kctl_info);
 
 	if (event_data->payload_len >

+ 5 - 0
asoc/msm_dailink.h

@@ -323,6 +323,11 @@ SND_SOC_DAILINK_DEFS(sen_tdm_tx_0,
 	DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-tx")),
 	DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
 
+SND_SOC_DAILINK_DEFS(wsa_dma_tx0_vi,
+	DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-cdc-dma-dev.45057")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "wsa_macro_vifeedback")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing")));
+
 SND_SOC_DAILINK_DEFS(slimbus_7_rx,
 	DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-dev.16398")),
 	DAILINK_COMP_ARRAY(COMP_CODEC("btfmslim_slave",

+ 320 - 6
asoc/qcs405.c

@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -148,6 +148,11 @@ enum {
 	SPDIF_TX_MAX,
 };
 
+enum {
+	HDMI_RX_IDX = 0,
+	EXT_HDMI_RX_IDX_MAX,
+};
+
 struct mi2s_conf {
 	struct mutex lock;
 	u32 ref_cnt;
@@ -344,7 +349,9 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
 		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
 	}
 };
-
+static struct dev_config ext_hdmi_rx_cfg[] = {
+	[HDMI_RX_IDX] =   {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
 
 /* Default configuration of slimbus channels */
 static struct dev_config slim_rx_cfg[] = {
@@ -488,6 +495,12 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
 					"KHZ_32", "KHZ_44P1", "KHZ_48",
 					"KHZ_88P2", "KHZ_96", "KHZ_176P4",
 					"KHZ_192", "KHZ_352P8", "KHZ_384"};
+static char const *ext_hdmi_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+					"KHZ_192", "KHZ_32", "KHZ_44P1",
+					"KHZ_88P2", "KHZ_176P4"};
+static char const *ext_hdmi_bit_format_text[] = {"S16_LE", "S24_LE",
+					"S24_3LE"};
+
 static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
 				    "Five", "Six", "Seven", "Eight"};
 static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -539,6 +552,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_chs, ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text);
@@ -546,6 +560,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_format, ext_hdmi_bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
@@ -553,6 +568,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_sink, bt_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_sample_rate,
+				ext_hdmi_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
 static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
@@ -2110,6 +2127,191 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
 	return rc;
 }
 
+static int ext_hdmi_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+	int idx;
+
+	if (strnstr(kcontrol->id.name, "HDMI_RX",
+		    sizeof("HDMI_RX"))) {
+		idx = HDMI_RX_IDX;
+	} else {
+		pr_err("%s: unsupported BE: %s",
+			__func__, kcontrol->id.name);
+		idx = -EINVAL;
+	}
+
+	return idx;
+}
+
+static int ext_hdmi_rx_format_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_hdmi_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ext_hdmi_rx_cfg[idx].bit_format) {
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+	default:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	}
+
+	pr_debug("%s: ext_hdmi_rx[%d].format = %d, ucontrol value = %ld\n",
+		 __func__, idx, ext_hdmi_rx_cfg[idx].bit_format,
+		 ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int ext_hdmi_rx_format_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_hdmi_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		ext_hdmi_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 0:
+	default:
+		ext_hdmi_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	}
+	pr_debug("%s: ext_hdmi_rx[%d].format = %d, ucontrol value = %ld\n",
+		 __func__, idx, ext_hdmi_rx_cfg[idx].bit_format,
+		 ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int ext_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_hdmi_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.integer.value[0] =
+			ext_hdmi_rx_cfg[idx].channels - 2;
+
+	pr_debug("%s: ext_hdmi_rx[%d].ch = %d\n", __func__,
+		 idx, ext_hdmi_rx_cfg[idx].channels);
+
+	return 0;
+}
+
+static int ext_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_hdmi_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ext_hdmi_rx_cfg[idx].channels =
+			ucontrol->value.integer.value[0] + 2;
+
+	pr_debug("%s: ext_hdmi_rx[%d].ch = %d\n", __func__,
+		 idx, ext_hdmi_rx_cfg[idx].channels);
+	return 0;
+}
+
+static int ext_hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	int sample_rate_val;
+	int idx = ext_hdmi_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ext_hdmi_rx_cfg[idx].sample_rate) {
+	case SAMPLING_RATE_176P4KHZ:
+		sample_rate_val = 6;
+		break;
+
+	case SAMPLING_RATE_88P2KHZ:
+		sample_rate_val = 5;
+		break;
+
+	case SAMPLING_RATE_44P1KHZ:
+		sample_rate_val = 4;
+		break;
+
+	case SAMPLING_RATE_32KHZ:
+		sample_rate_val = 3;
+		break;
+
+	case SAMPLING_RATE_192KHZ:
+		sample_rate_val = 2;
+		break;
+
+	case SAMPLING_RATE_96KHZ:
+		sample_rate_val = 1;
+		break;
+
+	case SAMPLING_RATE_48KHZ:
+	default:
+		sample_rate_val = 0;
+		break;
+	}
+
+	ucontrol->value.integer.value[0] = sample_rate_val;
+	pr_debug("%s: ext_hdmi_rx[%d].sample_rate = %d\n", __func__,
+		 idx, ext_hdmi_rx_cfg[idx].sample_rate);
+
+	return 0;
+}
+
+
+static int ext_hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = ext_hdmi_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 6:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ;
+		break;
+	case 5:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ;
+		break;
+	case 4:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ;
+		break;
+	case 3:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ;
+		break;
+	case 2:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
+		break;
+	case 1:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ;
+		break;
+	case 0:
+	default:
+		ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ;
+		break;
+	}
+
+	pr_debug("%s: control value = %ld, ext_hdmi_rx[%d].sample_rate = %d\n",
+		 __func__, ucontrol->value.integer.value[0], idx,
+		 ext_hdmi_rx_cfg[idx].sample_rate);
+	return 0;
+}
+
 static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -3842,6 +4044,14 @@ static const struct snd_kcontrol_new msm_snd_sb_controls[] = {
 			slim_rx_bit_format_get, slim_rx_bit_format_put),
 	SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format,
 			slim_tx_bit_format_get, slim_tx_bit_format_put),
+	SOC_ENUM_EXT("HDMI_RX Bit Format", ext_hdmi_rx_format,
+			ext_hdmi_rx_format_get, ext_hdmi_rx_format_put),
+	SOC_ENUM_EXT("HDMI_RX SampleRate", ext_hdmi_rx_sample_rate,
+			ext_hdmi_rx_sample_rate_get,
+			ext_hdmi_rx_sample_rate_put),
+	SOC_ENUM_EXT("HDMI_RX Channels", ext_hdmi_rx_chs,
+			ext_hdmi_rx_ch_get,
+			ext_hdmi_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate,
 			slim_rx_sample_rate_get, slim_rx_sample_rate_put),
 	SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate,
@@ -4506,6 +4716,23 @@ static int msm_slim_get_ch_from_beid(int32_t be_id)
 	return ch_id;
 }
 
+static int msm_ext_hdmi_get_idx_from_beid(int32_t be_id)
+{
+	int idx;
+
+	switch (be_id) {
+	case MSM_BACKEND_DAI_HDMI_RX_MS:
+		idx = HDMI_RX_IDX;
+		break;
+	default:
+		pr_err("%s: Incorrect ext_hdmi BE id %d\n", __func__, be_id);
+		idx = -EINVAL;
+		break;
+	}
+
+	return idx;
+}
+
 static int msm_cdc_dma_get_idx_from_beid(int32_t be_id)
 {
 	int idx = 0;
@@ -5040,11 +5267,27 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 		channels->min = channels->max = afe_lb_tx_cfg.channels;
 		break;
 
+	case MSM_BACKEND_DAI_HDMI_RX_MS:
+		idx = msm_ext_hdmi_get_idx_from_beid(dai_link->id);
+
+		if (idx < 0) {
+			pr_err("%s: Incorrect ext hdmi idx %d\n",
+			       __func__, idx);
+			rc = idx;
+			goto done;
+		}
+
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				ext_hdmi_rx_cfg[idx].bit_format);
+		rate->min = rate->max = ext_hdmi_rx_cfg[idx].sample_rate;
+		channels->min = channels->max = ext_hdmi_rx_cfg[idx].channels;
+		break;
+
 	default:
 		rate->min = rate->max = SAMPLING_RATE_48KHZ;
 		break;
 	}
-
+done:
 	return rc;
 }
 
@@ -6104,7 +6347,6 @@ static struct snd_soc_ops msm_fe_qos_ops = {
 	.prepare = msm_fe_qos_prepare,
 };
 
-
 static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
@@ -6177,6 +6419,36 @@ err:
 	return ret;
 }
 
+static int msm_mi2s_snd_hw_free(struct snd_pcm_substream *substream)
+{
+	int i, data_format = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int index = rtd->cpu_dai->id;
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_component *component;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		data_format = mi2s_rx_cfg[index].data_format;
+	else
+		data_format = mi2s_tx_cfg[index].data_format;
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	/* Call csra mute function if data format is DSD, else return */
+	if (data_format != AFE_DSD_DATA)
+		return 0;
+
+	for (i = 0; i < card->num_aux_devs; i++) {
+		component =
+			soc_find_component(card->aux_dev[i].codec_of_node,
+					NULL);
+		csra66x0_hw_free_mute(component);
+	}
+
+	return 0;
+}
+
 static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
 {
 	int ret;
@@ -6279,6 +6551,7 @@ static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream)
 	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	u16 port_id = 0;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
@@ -6312,6 +6585,13 @@ static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream)
 		meta_mi2s_intf_conf[index].clk_enable[i] = true;
 
 		if (i == 0) {
+			port_id = msm_get_port_id(rtd->dai_link->id);
+			ret = afe_set_clk_id(port_id,
+					     mi2s_clk[member_port].clk_id);
+			if (ret < 0)
+				pr_err("%s: afe_set_clk_id fail %d\n",
+					 __func__, ret);
+
 			ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
 			if (ret < 0) {
 				pr_err("%s: set fmt cpu dai failed for META_MI2S (%d), err:%d\n",
@@ -6504,6 +6784,7 @@ static void msm_spdif_snd_shutdown(struct snd_pcm_substream *substream)
 
 static struct snd_soc_ops msm_mi2s_be_ops = {
 	.startup = msm_mi2s_snd_startup,
+	.hw_free = msm_mi2s_snd_hw_free,
 	.shutdown = msm_mi2s_snd_shutdown,
 };
 
@@ -7298,6 +7579,24 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
 	},
 };
 
+static struct snd_soc_dai_link ext_hdmi_be_dai_link[] = {
+	/* HDMI RX BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI_MS,
+		.stream_name = "HDMI MS Playback",
+		.cpu_dai_name = "msm-dai-q6-hdmi.24578",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-ext-disp-audio-codec-rx",
+		.codec_dai_name = "msm_hdmi_ms_audio_codec_rx_dai",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_HDMI_RX_MS,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 	/* Backend AFE DAI Links */
 	{
@@ -8305,7 +8604,8 @@ static struct snd_soc_dai_link msm_qcs405_dai_links[
 			 ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) +
 			 ARRAY_SIZE(msm_bolero_fe_dai_links) +
 			 ARRAY_SIZE(msm_spdif_be_dai_links) +
-			 ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)];
+			 ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) +
+			 ARRAY_SIZE(ext_hdmi_be_dai_link)];
 
 static int msm_snd_card_tasha_late_probe(struct snd_soc_card *card)
 {
@@ -8556,6 +8856,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 	uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0;
 	uint32_t spdif_audio_intf = 0, wcn_audio_intf = 0;
 	uint32_t afe_loopback_intf = 0, meta_mi2s_intf = 0;
+	uint32_t ext_disp_hdmi_rx = 0;
 	const struct of_device_id *match;
 	char __iomem *spdif_cfg, *spdif_pin_ctl;
 	int rc = 0;
@@ -8743,6 +9044,20 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 				ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link);
 			}
 		}
+		rc = of_property_read_u32(dev->of_node,
+				"qcom,ext-disp-audio-rx", &ext_disp_hdmi_rx);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match ext disp hdmi rx\n",
+				__func__);
+		} else {
+			if (ext_disp_hdmi_rx) {
+				memcpy(msm_qcs405_dai_links + total_links,
+					ext_hdmi_be_dai_link,
+					sizeof(ext_hdmi_be_dai_link));
+				total_links += ARRAY_SIZE(ext_hdmi_be_dai_link);
+			}
+		}
+
 		dailink = msm_qcs405_dai_links;
 	} else if (!strcmp(match->data, "stub_codec")) {
 		card = &snd_soc_card_stub_msm;
@@ -8756,7 +9071,6 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 		       msm_stub_be_dai_links,
 		       sizeof(msm_stub_be_dai_links));
 		total_links += ARRAY_SIZE(msm_stub_be_dai_links);
-
 		dailink = msm_stub_dai_links;
 	}
 

+ 4 - 0
dsp/Kbuild

@@ -186,6 +186,10 @@ ifdef CONFIG_VOICE_MHI
 	Q6_OBJS += voice_mhi.o
 endif
 
+ifdef CONFIG_DIGITAL_CDC_RSC_MGR
+	Q6_OBJS += digital-cdc-rsc-mgr.o
+endif
+
 LINUX_INC +=	-Iinclude/linux
 
 INCS +=		$(COMMON_INC) \

+ 48 - 3
dsp/adsp-loader.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2014, 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -333,6 +333,8 @@ static int adsp_loader_probe(struct platform_device *pdev)
 	int fw_name_size;
 	u32 adsp_var_idx = 0;
 	int ret = 0;
+	u32 adsp_fuse_not_supported = 0;
+	const char *adsp_fw_name;
 
 	ret = adsp_loader_init_sysfs(pdev);
 	if (ret != 0) {
@@ -344,15 +346,58 @@ static int adsp_loader_probe(struct platform_device *pdev)
 	/* get adsp variant idx */
 	cell = nvmem_cell_get(&pdev->dev, "adsp_variant");
 	if (IS_ERR_OR_NULL(cell)) {
-		dev_dbg(&pdev->dev, "%s: FAILED to get nvmem cell \n", __func__);
+		dev_dbg(&pdev->dev, "%s: FAILED to get nvmem cell \n",
+			__func__);
+
+		/*
+		 * When ADSP variant read from fuse register is not
+		 * supported, check if image with different fw image
+		 * name needs to be loaded
+		 */
+		ret = of_property_read_u32(pdev->dev.of_node,
+					  "adsp-fuse-not-supported",
+					  &adsp_fuse_not_supported);
+		if (ret) {
+			dev_dbg(&pdev->dev,
+				"%s: adsp_fuse_not_supported prop not found",
+				__func__, ret);
+			goto wqueue;
+		}
+
+		if (adsp_fuse_not_supported) {
+			/* Read ADSP firmware image name */
+			ret = of_property_read_string(pdev->dev.of_node,
+						"adsp-fw-name",
+						 &adsp_fw_name);
+			if (ret < 0) {
+				dev_dbg(&pdev->dev, "%s: unable to read fw-name\n",
+					__func__);
+				goto wqueue;
+			}
+
+			fw_name_size = strlen(adsp_fw_name) + 1;
+			priv->adsp_fw_name = devm_kzalloc(&pdev->dev,
+						fw_name_size,
+						GFP_KERNEL);
+			if (!priv->adsp_fw_name)
+				goto wqueue;
+			strlcpy(priv->adsp_fw_name, adsp_fw_name,
+				fw_name_size);
+		}
 		goto wqueue;
 	}
 	buf = nvmem_cell_read(cell, &len);
 	nvmem_cell_put(cell);
-	if (IS_ERR_OR_NULL(buf) || len <= 0 || len > sizeof(u32)) {
+	if (IS_ERR_OR_NULL(buf)) {
 		dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__);
 		goto wqueue;
 	}
+	if (len <= 0 || len > sizeof(u32)) {
+		dev_dbg(&pdev->dev, "%s: nvmem cell length out of range: %d\n",
+			__func__, len);
+		kfree(buf);
+		goto wqueue;
+	}
 	memcpy(&adsp_var_idx, buf, len);
 	kfree(buf);
 

+ 100 - 0
dsp/digital-cdc-rsc-mgr.c

@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/ratelimit.h>
+#include <dsp/digital-cdc-rsc-mgr.h>
+
+struct mutex hw_vote_lock;
+static bool is_init_done;
+
+/**
+ * digital_cdc_rsc_mgr_hw_vote_enable - Enables hw vote in DSP
+ *
+ * @vote_handle: vote handle for which voting needs to be done
+ *
+ * Returns 0 on success or -EINVAL/error code on failure
+ */
+int digital_cdc_rsc_mgr_hw_vote_enable(struct clk* vote_handle)
+{
+	int ret = 0;
+
+	if (!is_init_done || vote_handle == NULL) {
+		pr_err_ratelimited("%s: init failed or vote handle NULL\n",
+				   __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_vote_lock);
+	ret = clk_prepare_enable(vote_handle);
+	mutex_unlock(&hw_vote_lock);
+
+	pr_debug("%s: return %d\n", __func__, ret);
+	trace_printk("%s: return %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_enable);
+
+/**
+ * digital_cdc_rsc_mgr_hw_vote_disable - Disables hw vote in DSP
+ *
+ * @vote_handle: vote handle for which voting needs to be disabled
+ *
+ */
+void digital_cdc_rsc_mgr_hw_vote_disable(struct clk* vote_handle)
+{
+	if (!is_init_done || vote_handle == NULL) {
+		pr_err_ratelimited("%s: init failed or vote handle NULL\n",
+				   __func__);
+		return;
+	}
+
+	mutex_lock(&hw_vote_lock);
+	clk_disable_unprepare(vote_handle);
+	mutex_unlock(&hw_vote_lock);
+	trace_printk("%s\n", __func__);
+}
+EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_disable);
+
+/**
+ * digital_cdc_rsc_mgr_hw_vote_reset - Resets hw vote count
+ *
+ */
+void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle)
+{
+	int count = 0;
+
+	if (!is_init_done || vote_handle == NULL) {
+		pr_err_ratelimited("%s: init failed or vote handle NULL\n",
+				   __func__);
+		return;
+	}
+
+	mutex_lock(&hw_vote_lock);
+	while (__clk_is_enabled(vote_handle)) {
+		clk_disable_unprepare(vote_handle);
+		count++;
+	}
+	pr_debug("%s: Vote count after SSR: %d\n", __func__, count);
+	trace_printk("%s: Vote count after SSR: %d\n", __func__, count);
+
+	while (count--)
+		clk_prepare_enable(vote_handle);
+	mutex_unlock(&hw_vote_lock);
+}
+EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_reset);
+
+void digital_cdc_rsc_mgr_init()
+{
+	mutex_init(&hw_vote_lock);
+	is_init_done = true;
+}
+
+void digital_cdc_rsc_mgr_exit()
+{
+	mutex_destroy(&hw_vote_lock);
+	is_init_done = false;
+}

+ 1 - 2
dsp/msm-dts-srs-tm-config.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2014, 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2018, 2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/err.h>
@@ -8,7 +8,6 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 #include <linux/atomic.h>
-#include <sound/asound.h>
 #include <sound/control.h>
 #include <dsp/msm_audio_ion.h>
 #include <dsp/q6adm-v2.h>

+ 3 - 1
dsp/q6_init.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019-2020 The Linux Foundation. All rights reserved.
  */
 
 #include <linux/kernel.h>
@@ -24,11 +24,13 @@ static int __init audio_q6_init(void)
 	avtimer_init();
 	msm_mdf_init();
 	voice_mhi_init();
+	digital_cdc_rsc_mgr_init();
 	return 0;
 }
 
 static void __exit audio_q6_exit(void)
 {
+	digital_cdc_rsc_mgr_exit();
 	msm_mdf_exit();
 	avtimer_exit();
 	audio_slimslave_exit();

+ 14 - 0
dsp/q6_init.h

@@ -94,5 +94,19 @@ static inline void voice_mhi_exit(void)
 	return;
 }
 #endif
+
+#ifdef CONFIG_DIGITAL_CDC_RSC_MGR
+void digital_cdc_rsc_mgr_init(void);
+void digital_cdc_rsc_mgr_exit(void);
+#else
+static inline void digital_cdc_rsc_mgr_init(void)
+{
+}
+
+static inline void digital_cdc_rsc_mgr_exit(void)
+{
+}
+#endif /* CONFIG_DIGITAL_CDC_RSC_MGR */
+
 #endif
 

+ 2 - 2
dsp/q6adm.c

@@ -9,7 +9,6 @@
 #include <linux/jiffies.h>
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
-#include <sound/asound.h>
 #include <dsp/msm-dts-srs-tm-config.h>
 #include <dsp/apr_audio-v2.h>
 #include <dsp/q6adm-v2.h>
@@ -3082,7 +3081,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
 				this_adm.ffecns_port_id);
 	}
 
-	if (topology == VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY)
+	if (topology == VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY ||
+	    topology == VPM_TX_VOICE_FLUENCE_SM_COPP_TOPOLOGY)
 		channel_mode = 1;
 
 	/*

+ 483 - 64
dsp/q6afe.c

@@ -126,7 +126,7 @@ struct afe_ctl {
 	void (*rx_cb)(uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv);
 	void *tx_private_data;
-	void *rx_private_data;
+	void *rx_private_data[NUM_RX_PROXY_PORTS];
 	uint32_t mmap_handle;
 
 	void (*pri_spdif_tx_cb)(uint32_t opcode,
@@ -176,12 +176,51 @@ struct afe_ctl {
 	/* cal info for AFE */
 	struct afe_fw_info *fw_data;
 	u32 island_mode[AFE_MAX_PORTS];
+	u32 power_mode[AFE_MAX_PORTS];
 	struct vad_config vad_cfg[AFE_MAX_PORTS];
 	struct work_struct afe_dc_work;
 	struct notifier_block event_notifier;
 	/* FTM spk params */
 	uint32_t initial_cal;
 	uint32_t v_vali_flag;
+	uint32_t num_spkrs;
+};
+
+struct afe_clkinfo_per_port {
+	u16 port_id; /* AFE port ID */
+	uint32_t clk_id; /* Clock ID */
+};
+
+struct afe_clkinfo_per_port clkinfo_per_port[] = {
+	{ AFE_PORT_ID_PRIMARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT},
+	{ AFE_PORT_ID_SECONDARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT},
+	{ AFE_PORT_ID_TERTIARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT},
+	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT},
+	{ AFE_PORT_ID_QUINARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT},
+	{ AFE_PORT_ID_SENARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT},
+	{ AFE_PORT_ID_PRIMARY_PCM_RX, Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT},
+	{ AFE_PORT_ID_SECONDARY_PCM_RX, Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT},
+	{ AFE_PORT_ID_TERTIARY_PCM_RX, Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT},
+	{ AFE_PORT_ID_QUATERNARY_PCM_RX, Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT},
+	{ AFE_PORT_ID_QUINARY_PCM_RX, Q6AFE_LPASS_CLK_ID_QUIN_PCM_IBIT},
+	{ AFE_PORT_ID_SENARY_PCM_RX, Q6AFE_LPASS_CLK_ID_SEN_PCM_IBIT},
+	{ AFE_PORT_ID_PRIMARY_TDM_RX, Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT},
+	{ AFE_PORT_ID_SECONDARY_TDM_RX, Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT},
+	{ AFE_PORT_ID_TERTIARY_TDM_RX, Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT},
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX, Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT},
+	{ AFE_PORT_ID_QUINARY_TDM_RX, Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT},
+	{ AFE_PORT_ID_PRIMARY_SPDIF_RX,
+		AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_CORE},
+	{ AFE_PORT_ID_PRIMARY_SPDIF_TX,
+		AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_INPUT_CORE},
+	{ AFE_PORT_ID_SECONDARY_SPDIF_RX,
+		AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_CORE},
+	{ AFE_PORT_ID_SECONDARY_SPDIF_TX,
+		AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_INPUT_CORE},
+	{ AFE_PORT_ID_PRIMARY_META_MI2S_RX,
+		Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT},
+	{ AFE_PORT_ID_SECONDARY_META_MI2S_RX,
+		Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT},
 };
 
 static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -699,12 +738,14 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
 					this_afe.tx_private_data);
 			this_afe.tx_cb = NULL;
 		}
-		if (this_afe.rx_cb) {
-			this_afe.rx_cb(data->opcode, data->token,
-					data->payload,
-					this_afe.rx_private_data);
-			this_afe.rx_cb = NULL;
+		for (i = 0; i < NUM_RX_PROXY_PORTS; i++) {
+			if (this_afe.rx_cb && this_afe.rx_private_data[i]) {
+				this_afe.rx_cb(data->opcode, data->token,
+						data->payload,
+						this_afe.rx_private_data[i]);
+			}
 		}
+		this_afe.rx_cb = NULL;
 
 		return 0;
 	}
@@ -825,7 +866,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
 				port_id = RT_PROXY_PORT_001_TX;
 				break;
 			case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
-				port_id = RT_PROXY_PORT_001_RX;
+				port_id = data->src_port;
 				break;
 			case AFE_CMD_ADD_TOPOLOGIES:
 				atomic_set(&this_afe.state, 0);
@@ -973,7 +1014,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
 			if (this_afe.rx_cb) {
 				this_afe.rx_cb(data->opcode, data->token,
 					data->payload,
-					this_afe.rx_private_data);
+					this_afe.rx_private_data[PORTID_TO_IDX(port_id)]);
 			}
 			break;
 		}
@@ -1045,6 +1086,7 @@ int afe_sizeof_cfg_cmd(u16 port_id)
 		ret_size = SIZEOF_CFG_CMD(afe_param_id_meta_i2s_cfg);
 		break;
 	case HDMI_RX:
+	case HDMI_RX_MS:
 	case DISPLAY_PORT_RX:
 		ret_size =
 		SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg);
@@ -2121,6 +2163,7 @@ static void afe_send_cal_spv4_tx(int port_id)
 	struct afe_sp_v4_channel_v_vali_cfg *ch_v_vali_cfg = NULL;
 	struct afe_sp_v4_param_ex_vi_ftm_cfg *ex_vi_ftm_cfg = NULL;
 	struct afe_sp_v4_channel_ex_vi_ftm *ch_ex_vi_ftm_cfg = NULL;
+	uint32_t i = 0;
 
 	pr_debug("%s: Entry.. port_id %d\n", __func__, port_id);
 
@@ -2181,7 +2224,7 @@ static void afe_send_cal_spv4_tx(int port_id)
 			v4_vi_op_mode->th_r0t0_selection_flag[SP_V2_SPKR_2] =
 							    USE_SAFE_R0TO;
 		}
-		afe_spk_config.v4_vi_op_mode.num_speakers = SP_V2_NUM_MAX_SPKRS;
+		afe_spk_config.v4_vi_op_mode.num_speakers = this_afe.num_spkrs;
 		if (afe_spk_prot_prepare(port_id, 0,
 			AFE_PARAM_ID_SP_V4_VI_OP_MODE_CFG,
 			&afe_spk_config,
@@ -2190,7 +2233,7 @@ static void afe_send_cal_spv4_tx(int port_id)
 				__func__);
 
 		size = sizeof(struct afe_sp_v4_param_th_vi_r0t0_cfg) +
-		(SP_V2_NUM_MAX_SPKRS * sizeof(struct afe_sp_v4_channel_r0t0));
+		(this_afe.num_spkrs * sizeof(struct afe_sp_v4_channel_r0t0));
 		tmp_ptr = kzalloc(size, GFP_KERNEL);
 		if (!tmp_ptr) {
 			mutex_unlock(
@@ -2204,15 +2247,13 @@ static void afe_send_cal_spv4_tx(int port_id)
 		ch_r0t0_cfg =
 			(struct afe_sp_v4_channel_r0t0 *)(th_vi_r0t0_cfg + 1);
 
-		th_vi_r0t0_cfg->num_speakers = SP_V2_NUM_MAX_SPKRS;
-		ch_r0t0_cfg[SP_V2_SPKR_1].r0_cali_q24 =
-			(uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_1];
-		ch_r0t0_cfg[SP_V2_SPKR_2].r0_cali_q24 =
-			(uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_2];
-		ch_r0t0_cfg[SP_V2_SPKR_1].t0_cali_q6 =
-			(uint32_t) this_afe.prot_cfg.t0[SP_V2_SPKR_1];
-		ch_r0t0_cfg[SP_V2_SPKR_2].t0_cali_q6 =
-			(uint32_t) this_afe.prot_cfg.t0[SP_V2_SPKR_2];
+		th_vi_r0t0_cfg->num_speakers = this_afe.num_spkrs;
+		for (i = 0; i < this_afe.num_spkrs; i++) {
+			ch_r0t0_cfg[i].r0_cali_q24 =
+				(uint32_t) this_afe.prot_cfg.r0[i];
+			ch_r0t0_cfg[i].t0_cali_q6 =
+				(uint32_t) this_afe.prot_cfg.t0[i];
+		}
 		if (afe_spk_prot_prepare(port_id, 0,
 			AFE_PARAM_ID_SP_V4_VI_R0T0_CFG,
 			(union afe_spkr_prot_config *)tmp_ptr, size))
@@ -2227,7 +2268,7 @@ static void afe_send_cal_spv4_tx(int port_id)
 	    (this_afe.vi_tx_port == port_id) &&
 	    (this_afe.prot_cfg.sp_version >= AFE_API_VERSION_V9)) {
 		size = sizeof(struct afe_sp_v4_param_th_vi_ftm_cfg) +
-		(SP_V2_NUM_MAX_SPKRS*sizeof(struct afe_sp_v4_channel_ftm_cfg));
+		(this_afe.num_spkrs * sizeof(struct afe_sp_v4_channel_ftm_cfg));
 		tmp_ptr = kzalloc(size, GFP_KERNEL);
 		if (!tmp_ptr) {
 			mutex_unlock(
@@ -2240,16 +2281,13 @@ static void afe_send_cal_spv4_tx(int port_id)
 		ch_ftm_cfg =
 			 (struct afe_sp_v4_channel_ftm_cfg *)(th_vi_ftm_cfg+1);
 
-		th_vi_ftm_cfg->num_ch = SP_V2_NUM_MAX_SPKRS;
-		ch_ftm_cfg[SP_V2_SPKR_1].wait_time_ms =
-			this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_1];
-		ch_ftm_cfg[SP_V2_SPKR_2].wait_time_ms =
-			this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_2];
-		ch_ftm_cfg[SP_V2_SPKR_1].ftm_time_ms =
-			this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_1];
-		ch_ftm_cfg[SP_V2_SPKR_2].ftm_time_ms =
-			this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_2];
-
+		th_vi_ftm_cfg->num_ch = this_afe.num_spkrs;
+		for (i = 0; i < this_afe.num_spkrs; i++) {
+			ch_ftm_cfg[i].wait_time_ms =
+				this_afe.th_ftm_cfg.wait_time[i];
+			ch_ftm_cfg[i].ftm_time_ms =
+				this_afe.th_ftm_cfg.ftm_time[i];
+		}
 		if (afe_spk_prot_prepare(port_id, 0,
 				AFE_PARAM_ID_SP_V4_TH_VI_FTM_CFG,
 				(union afe_spkr_prot_config *)tmp_ptr, size))
@@ -2261,8 +2299,8 @@ static void afe_send_cal_spv4_tx(int port_id)
 			MSM_SPKR_PROT_IN_V_VALI_MODE) &&
 		   (this_afe.vi_tx_port == port_id)) {
 		size = sizeof(struct afe_sp_v4_param_th_vi_v_vali_cfg) +
-			(SP_V2_NUM_MAX_SPKRS *
-			 sizeof(struct afe_sp_v4_channel_v_vali_cfg));
+			(this_afe.num_spkrs *
+			sizeof(struct afe_sp_v4_channel_v_vali_cfg));
 		tmp_ptr = kzalloc(size, GFP_KERNEL);
 		if (!tmp_ptr) {
 			mutex_unlock(
@@ -2276,16 +2314,13 @@ static void afe_send_cal_spv4_tx(int port_id)
 		ch_v_vali_cfg =
 		 (struct afe_sp_v4_channel_v_vali_cfg *)(th_vi_v_vali_cfg + 1);
 
-		th_vi_v_vali_cfg->num_ch = SP_V2_NUM_MAX_SPKRS;
-		ch_v_vali_cfg[SP_V2_SPKR_1].wait_time_ms =
-			this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_1];
-		ch_v_vali_cfg[SP_V2_SPKR_2].wait_time_ms =
-			this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_2];
-		ch_v_vali_cfg[SP_V2_SPKR_1].vali_time_ms =
-			this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_1];
-		ch_v_vali_cfg[SP_V2_SPKR_2].vali_time_ms =
-			this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_2];
-
+		th_vi_v_vali_cfg->num_ch = this_afe.num_spkrs;
+		for (i = 0; i < this_afe.num_spkrs; i++) {
+			ch_v_vali_cfg[i].wait_time_ms =
+				this_afe.v_vali_cfg.wait_time[i];
+			ch_v_vali_cfg[i].vali_time_ms =
+				this_afe.v_vali_cfg.vali_time[i];
+		}
 		if (afe_spk_prot_prepare(port_id, 0,
 				AFE_PARAM_ID_SP_V4_TH_VI_V_VALI_CFG,
 				(union afe_spkr_prot_config *)tmp_ptr, size))
@@ -2301,7 +2336,7 @@ static void afe_send_cal_spv4_tx(int port_id)
 	    (this_afe.vi_tx_port == port_id) &&
 	    (this_afe.prot_cfg.sp_version >= AFE_API_VERSION_V9)) {
 		size = sizeof(struct afe_sp_v4_param_ex_vi_ftm_cfg) +
-		(SP_V2_NUM_MAX_SPKRS *
+		(this_afe.num_spkrs *
 		 sizeof(struct afe_sp_v4_channel_ex_vi_ftm));
 		tmp_ptr = kzalloc(size, GFP_KERNEL);
 		if (!tmp_ptr) {
@@ -2323,17 +2358,14 @@ static void afe_send_cal_spv4_tx(int port_id)
 				 sizeof(struct afe_sp_v4_param_ex_vi_mode_cfg)))
 			pr_info("%s: ex vi mode cfg failed\n", __func__);
 
-		ex_vi_ftm_cfg->num_ch = SP_V2_NUM_MAX_SPKRS;
-
-		ch_ex_vi_ftm_cfg[SP_V2_SPKR_1].wait_time_ms =
-			this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_1];
-		ch_ex_vi_ftm_cfg[SP_V2_SPKR_2].wait_time_ms =
-			this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_2];
-		ch_ex_vi_ftm_cfg[SP_V2_SPKR_1].ftm_time_ms =
-			this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_1];
-		ch_ex_vi_ftm_cfg[SP_V2_SPKR_2].ftm_time_ms =
-			this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_2];
+		ex_vi_ftm_cfg->num_ch = this_afe.num_spkrs;
 
+		for (i = 0; i < this_afe.num_spkrs; i++) {
+			ch_ex_vi_ftm_cfg[i].wait_time_ms =
+				this_afe.ex_ftm_cfg.wait_time[i];
+			ch_ex_vi_ftm_cfg[i].ftm_time_ms =
+				this_afe.ex_ftm_cfg.ftm_time[i];
+		}
 		if (afe_spk_prot_prepare(port_id, 0,
 				 AFE_PARAM_ID_SP_V4_EX_VI_FTM_CFG,
 				 (union afe_spkr_prot_config *)tmp_ptr, size))
@@ -2843,6 +2875,81 @@ done:
 
 }
 
+static int afe_get_power_mode(u16 port_id, u32 *power_mode)
+{
+	int ret = 0;
+	int index = 0;
+	*power_mode = 0;
+
+	index = q6audio_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: AFE port index[%d] invalid!\n",
+			 __func__, index);
+		return -EINVAL;
+	}
+	*power_mode = this_afe.power_mode[index];
+	return ret;
+}
+
+/**
+ * afe_send_port_power_mode -
+ *          for sending power mode to AFE
+ *
+ * @port_id: AFE port id number
+ * Returns 0 on success or error on failure.
+ */
+int afe_send_port_power_mode(u16 port_id)
+{
+	struct afe_param_id_power_mode_cfg_t power_mode_cfg;
+	struct param_hdr_v3 param_info;
+	u32 power_mode = 0;
+	int ret = 0;
+
+	if (!(q6core_get_avcs_api_version_per_service(
+		APRV2_IDS_SERVICE_ID_ADSP_AFE_V) >= AFE_API_VERSION_V4)) {
+		pr_debug("%s: AFE port[%d] API version is invalid!\n",
+			__func__, port_id);
+		return 0;
+	}
+
+	memset(&power_mode_cfg, 0, sizeof(power_mode_cfg));
+	memset(&param_info, 0, sizeof(param_info));
+
+	ret = afe_get_power_mode(port_id, &power_mode);
+	if (ret) {
+		pr_err("%s: AFE port[%d] get power mode is invalid!\n",
+			__func__, port_id);
+		return ret;
+	}
+	if (power_mode == 0) {
+		pr_debug("%s: AFE port[%d] power mode is not enabled\n",
+			__func__, port_id);
+		return ret;
+	}
+	param_info.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	param_info.instance_id = INSTANCE_ID_0;
+	param_info.param_id = AFE_PARAM_ID_POWER_MODE_CONFIG;
+	param_info.param_size = sizeof(power_mode_cfg);
+
+	power_mode_cfg.power_mode_cfg_minor_version =
+					AFE_API_VERSION_POWER_MODE_CONFIG;
+	power_mode_cfg.power_mode_enable = power_mode;
+
+	ret = q6afe_pack_and_set_param_in_band(port_id,
+						q6audio_get_port_index(port_id),
+						param_info, (u8 *) &power_mode_cfg);
+	if (ret) {
+		pr_err("%s: AFE set power mode enable for port 0x%x failed %d\n",
+			__func__, port_id, ret);
+		return ret;
+	}
+	pr_debug("%s: AFE set power mode 0x%x  enable for port 0x%x ret %d\n",
+			__func__, power_mode, port_id, ret);
+	trace_printk("%s: AFE set power mode 0x%x  enable for port 0x%x ret %d\n",
+			__func__, power_mode, port_id, ret);
+	return ret;
+}
+EXPORT_SYMBOL(afe_send_port_power_mode);
 
 static int afe_get_island_mode(u16 port_id, u32 *island_mode)
 {
@@ -2892,6 +2999,11 @@ int afe_send_port_island_mode(u16 port_id)
 				__func__, port_id);
 		return ret;
 	}
+	if (island_mode == 0) {
+		pr_debug("%s: AFE port[%d] island mode is not enabled\n",
+			__func__, port_id);
+		return ret;
+	}
 	param_info.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
 	param_info.instance_id = INSTANCE_ID_0;
 	param_info.param_id = AFE_PARAM_ID_ISLAND_CONFIG;
@@ -4239,6 +4351,55 @@ void afe_set_island_mode_cfg(u16 port_id, u32 enable_flag)
 }
 EXPORT_SYMBOL(afe_set_island_mode_cfg);
 
+/**
+ * afe_get_power_mode_cfg -
+ *         get power mode configuration
+ * @port_id: AFE port id number
+ * @enable_flag: Enable or Disable
+ */
+int afe_get_power_mode_cfg(u16 port_id, u32 *enable_flag)
+{
+	uint16_t port_index;
+	int ret = 0;
+
+	if (enable_flag) {
+		port_index = afe_get_port_index(port_id);
+		if (port_index < 0 || port_index >= AFE_MAX_PORTS) {
+			pr_err("%s: AFE port index[%d] invalid!\n",
+				__func__, port_index);
+			return -EINVAL;
+		}
+		*enable_flag = this_afe.power_mode[port_index];
+	}
+	return ret;
+}
+EXPORT_SYMBOL(afe_get_power_mode_cfg);
+
+/**
+ * afe_set_power_mode_cfg -
+ *         set power mode configuration
+ * @port_id: AFE port id number
+ * @enable_flag: Enable or Disable
+ */
+int afe_set_power_mode_cfg(u16 port_id, u32 enable_flag)
+{
+	uint16_t port_index;
+	int  ret= 0;
+
+	port_index = afe_get_port_index(port_id);
+	if (port_index < 0 || port_index >= AFE_MAX_PORTS) {
+		pr_err("%s: AFE port index[%d] invalid!\n",
+			__func__, port_index);
+		return -EINVAL;
+	}
+	this_afe.power_mode[port_index] = enable_flag;
+
+	trace_printk("%s: set power mode cfg 0x%x for port 0x%x\n",
+			__func__, this_afe.power_mode[port_index], port_id);
+	return ret;
+}
+EXPORT_SYMBOL(afe_set_power_mode_cfg);
+
 /**
  * afe_set_routing_callback -
  *         Update callback function for routing
@@ -4329,6 +4490,51 @@ exit:
 	return ret;
 }
 
+static int q6afe_send_ttp_config(u16 port_id,
+			union afe_port_config afe_config,
+			struct afe_ttp_config *ttp_cfg)
+{
+	struct afe_ttp_gen_enable_t ttp_gen_enable;
+	struct afe_ttp_gen_cfg_t ttp_gen_cfg;
+	struct param_hdr_v3 param_hdr;
+	int ret;
+
+	memset(&ttp_gen_enable, 0, sizeof(ttp_gen_enable));
+	memset(&ttp_gen_cfg, 0, sizeof(ttp_gen_cfg));
+	memset(&param_hdr, 0, sizeof(param_hdr));
+
+	param_hdr.module_id = AFE_MODULE_ID_DECODER;
+	param_hdr.instance_id = INSTANCE_ID_0;
+
+	pr_debug("%s: Enable TTP generator\n", __func__);
+	ttp_gen_enable = ttp_cfg->ttp_gen_enable;
+	param_hdr.param_id = AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_STATE;
+	param_hdr.param_size = sizeof(struct afe_ttp_gen_enable_t);
+	ret = q6afe_pack_and_set_param_in_band(port_id,
+					       q6audio_get_port_index(port_id),
+					       param_hdr,
+					       (u8 *) &ttp_gen_enable);
+	if (ret) {
+		pr_err("%s: AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_STATE for port 0x%x failed %d\n",
+			__func__, port_id, ret);
+		goto exit;
+	}
+
+	pr_debug("%s: sending TTP generator config\n", __func__);
+	ttp_gen_cfg = ttp_cfg->ttp_gen_cfg;
+	param_hdr.param_id = AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_CFG;
+	param_hdr.param_size = sizeof(struct afe_ttp_gen_cfg_t);
+	ret = q6afe_pack_and_set_param_in_band(port_id,
+					       q6audio_get_port_index(port_id),
+					       param_hdr,
+					       (u8 *) &ttp_gen_cfg);
+	if (ret)
+		pr_err("%s: AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_CFG for port 0x%x failed %d\n",
+			__func__, port_id, ret);
+exit:
+	return ret;
+}
+
 static int q6afe_send_dec_config(u16 port_id,
 			union afe_port_config afe_config,
 			struct afe_dec_config *cfg,
@@ -4999,7 +5205,8 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
 			    u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
 			    union afe_enc_config_data *enc_cfg,
 			    u32 codec_format, u32 scrambler_mode, u32 mono_mode,
-			    struct afe_dec_config *dec_cfg)
+			    struct afe_dec_config *dec_cfg,
+			    struct afe_ttp_config *ttp_cfg)
 {
 	union afe_port_config port_cfg;
 	struct param_hdr_v3 param_hdr;
@@ -5204,6 +5411,7 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
 		cfg_type = AFE_PARAM_ID_META_I2S_CONFIG;
 		break;
 	case HDMI_RX:
+	case HDMI_RX_MS:
 	case DISPLAY_PORT_RX:
 		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
 		break;
@@ -5332,6 +5540,15 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
 				goto fail_cmd;
 			}
 		}
+		if (ttp_cfg != NULL) {
+			ret = q6afe_send_ttp_config(port_id, *afe_config,
+						    ttp_cfg);
+			if (ret) {
+				pr_err("%s: AFE TTP config for port 0x%x failed %d\n",
+					 __func__, port_id, ret);
+				goto fail_cmd;
+			}
+		}
 	}
 
 	port_index = afe_get_port_index(port_id);
@@ -5378,8 +5595,8 @@ fail_cmd:
 int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 		   u32 rate)
 {
-	return __afe_port_start(port_id, afe_config, rate,
-				0, 0, NULL, ASM_MEDIA_FMT_NONE, 0, 0, NULL);
+	return __afe_port_start(port_id, afe_config, rate, 0, 0, NULL,
+				ASM_MEDIA_FMT_NONE, 0, 0, NULL, NULL);
 }
 EXPORT_SYMBOL(afe_port_start);
 
@@ -5409,16 +5626,50 @@ int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
 					afe_in_channels, afe_in_bit_width,
 					&enc_cfg->data, enc_cfg->format,
 					enc_cfg->scrambler_mode,
-					enc_cfg->mono_mode, dec_cfg);
+					enc_cfg->mono_mode, dec_cfg, NULL);
 	else if (dec_cfg != NULL)
 		ret = __afe_port_start(port_id, afe_config, rate,
 					afe_in_channels, afe_in_bit_width,
-					NULL, dec_cfg->format, 0, 0, dec_cfg);
+					NULL, dec_cfg->format, 0, 0,
+					dec_cfg, NULL);
 
 	return ret;
 }
 EXPORT_SYMBOL(afe_port_start_v2);
 
+/**
+ * afe_port_start_v3 - to configure AFE session with
+ * specified port configuration and encoder /decoder params
+ *
+ * @port_id: AFE port id number
+ * @afe_config: port configuration
+ * @rate: sampling rate of port
+ * @enc_cfg: AFE enc configuration information to setup encoder
+ * @afe_in_channels: AFE input channel configuration, this needs
+ *  update only if input channel is differ from AFE output
+ * @dec_cfg: AFE dec configuration information to set up decoder
+ * @ttp_cfg: TTP generator configuration to enable TTP in AFE
+ *
+ * Returns 0 on success or error value on port start failure.
+ */
+int afe_port_start_v3(u16 port_id, union afe_port_config *afe_config,
+		      u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
+		      struct afe_enc_config *enc_cfg,
+		      struct afe_dec_config *dec_cfg,
+		      struct afe_ttp_config *ttp_cfg)
+{
+	int ret = 0;
+
+	if (dec_cfg != NULL && ttp_cfg != NULL)
+		ret = __afe_port_start(port_id, afe_config, rate,
+				       afe_in_channels, afe_in_bit_width,
+				       NULL, dec_cfg->format, 0, 0,
+				       dec_cfg, ttp_cfg);
+
+	return ret;
+}
+EXPORT_SYMBOL(afe_port_start_v3);
+
 int afe_get_port_index(u16 port_id)
 {
 	switch (port_id) {
@@ -5453,6 +5704,7 @@ int afe_get_port_index(u16 port_id)
 	case MI2S_RX: return IDX_MI2S_RX;
 	case MI2S_TX: return IDX_MI2S_TX;
 	case HDMI_RX: return IDX_HDMI_RX;
+	case HDMI_RX_MS: return IDX_HDMI_RX_MS;
 	case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX;
 	case AFE_PORT_ID_PRIMARY_SPDIF_RX: return IDX_PRIMARY_SPDIF_RX;
 	case AFE_PORT_ID_PRIMARY_SPDIF_TX: return IDX_PRIMARY_SPDIF_TX;
@@ -5916,6 +6168,7 @@ int afe_open(u16 port_id,
 		cfg_type = AFE_PARAM_ID_META_I2S_CONFIG;
 		break;
 	case HDMI_RX:
+	case HDMI_RX_MS:
 	case DISPLAY_PORT_RX:
 		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
 		break;
@@ -6978,7 +7231,7 @@ int afe_register_get_events(u16 port_id,
 	} else if (port_id == RT_PROXY_PORT_001_RX ||
 			port_id == RT_PROXY_PORT_002_RX) {
 		this_afe.rx_cb = cb;
-		this_afe.rx_private_data = private_data;
+		this_afe.rx_private_data[PORTID_TO_IDX(port_id)] = private_data;
 	}
 
 	rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -7011,6 +7264,7 @@ int afe_unregister_get_events(u16 port_id)
 	int ret = 0;
 	struct afe_service_cmd_unregister_rt_port_driver rtproxy;
 	int index = 0;
+	uint16_t i = 0;
 
 	pr_debug("%s:\n", __func__);
 
@@ -7064,8 +7318,13 @@ int afe_unregister_get_events(u16 port_id)
 		this_afe.tx_private_data = NULL;
 	} else if (port_id == RT_PROXY_PORT_001_RX ||
 			port_id == RT_PROXY_PORT_002_RX) {
-		this_afe.rx_cb = NULL;
-		this_afe.rx_private_data = NULL;
+		this_afe.rx_private_data[PORTID_TO_IDX(port_id)] = NULL;
+		for (i = 0; i < NUM_RX_PROXY_PORTS; i++) {
+			if (this_afe.rx_private_data[i] != NULL)
+				break;
+		}
+		if (i == NUM_RX_PROXY_PORTS)
+			this_afe.rx_cb = NULL;
 	}
 
 	ret = afe_apr_send_pkt(&rtproxy, &this_afe.wait[index]);
@@ -7164,7 +7423,7 @@ int afe_rt_proxy_port_read(phys_addr_t buf_addr_p,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 	afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
 	afecmd_rd.hdr.src_port = 0;
-	afecmd_rd.hdr.dest_port = 0;
+	afecmd_rd.hdr.dest_port = port_id;
 	afecmd_rd.hdr.token = 0;
 	afecmd_rd.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2;
 	afecmd_rd.port_id = port_id;
@@ -7812,6 +8071,7 @@ int afe_validate_port(u16 port_id)
 	case MI2S_RX:
 	case MI2S_TX:
 	case HDMI_RX:
+	case HDMI_RX_MS:
 	case DISPLAY_PORT_RX:
 	case AFE_PORT_ID_PRIMARY_SPDIF_RX:
 	case AFE_PORT_ID_PRIMARY_SPDIF_TX:
@@ -8182,8 +8442,11 @@ int afe_close(int port_id)
 	 * even if ramp down configuration failed it is not serious enough to
 	 * warrant bailaing out.
 	 */
-	if (afe_spk_ramp_dn_cfg(port_id) < 0)
-		pr_err("%s: ramp down configuration failed\n", __func__);
+	if (q6core_get_avcs_api_version_per_service(
+		APRV2_IDS_SERVICE_ID_ADSP_AFE_V) < AFE_API_VERSION_V9) {
+		if (afe_spk_ramp_dn_cfg(port_id) < 0)
+			pr_err("%s: ramp down config failed\n", __func__);
+	}
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -8307,6 +8570,156 @@ int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg)
 }
 EXPORT_SYMBOL(afe_set_lpass_clock);
 
+static int afe_get_port_idx(u16 port_id)
+{
+	u16 afe_port = 0;
+	int i = -EINVAL;
+
+	pr_debug("%s: port id 0x%x\n", __func__, port_id);
+
+	if ((port_id >= AFE_PORT_ID_TDM_PORT_RANGE_START) &&
+		(port_id <= AFE_PORT_ID_TDM_PORT_RANGE_END))
+		afe_port = port_id & 0xFFF0;
+	else if ((port_id == AFE_PORT_ID_PRIMARY_SPDIF_RX) ||
+		 (port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) ||
+		 (port_id == AFE_PORT_ID_SECONDARY_SPDIF_RX) ||
+		 (port_id == AFE_PORT_ID_SECONDARY_SPDIF_TX))
+		afe_port = port_id;
+	else
+		afe_port = port_id & 0xFFFE;
+
+	for (i = 0; i < ARRAY_SIZE(clkinfo_per_port); i++) {
+		if (afe_port == clkinfo_per_port[i].port_id) {
+			pr_debug("%s: idx 0x%x port id 0x%x\n", __func__,
+				  i, afe_port);
+			return i;
+		}
+	}
+
+	pr_debug("%s: cannot get idx for port id 0x%x\n", __func__,
+		afe_port);
+
+	return -EINVAL;
+}
+
+static int afe_get_clk_id(u16 port_id)
+{
+	u16 afe_port = 0;
+	uint32_t clk_id = -EINVAL;
+	int idx = 0;
+
+	idx = afe_get_port_idx(port_id);
+	if (idx < 0) {
+		pr_err("%s: cannot get clock id for port id 0x%x\n", __func__,
+			afe_port);
+		return -EINVAL;
+	}
+
+	clk_id = clkinfo_per_port[idx].clk_id;
+	pr_debug("%s: clk id 0x%x port id 0x%x\n", __func__, clk_id,
+		  afe_port);
+
+	return clk_id;
+}
+
+/**
+ * afe_set_clk_id - Update clock id for AFE port
+ *
+ * @port_id: AFE port id
+ * @clk_id: CLock ID
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
+int afe_set_clk_id(u16 port_id, uint32_t clk_id)
+{
+	u16 afe_port = 0;
+	int idx = 0;
+
+	idx = afe_get_port_idx(port_id);
+	if (idx < 0) {
+		pr_debug("%s: cannot set clock id for port id 0x%x\n", __func__,
+			afe_port);
+		return -EINVAL;
+	}
+
+	clkinfo_per_port[idx].clk_id = clk_id;
+	pr_debug("%s: updated clk id 0x%x port id 0x%x\n", __func__,
+		  clkinfo_per_port[idx].clk_id, afe_port);
+
+	return 0;
+}
+EXPORT_SYMBOL(afe_set_clk_id);
+
+/**
+ * afe_set_pll_clk_drift - Set audio interface PLL clock drift
+ *
+ * @port_id: AFE port id
+ * @set_clk_drift: clk drift to adjust PLL
+ * @clk_reset: reset Interface clock to original value
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
+int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
+			  uint32_t clk_reset)
+{
+	struct afe_set_clk_drift clk_drift;
+	struct param_hdr_v3 param_hdr;
+	uint32_t clk_id;
+	int index = 0, ret = 0;
+
+	memset(&param_hdr, 0, sizeof(param_hdr));
+	memset(&clk_drift, 0, sizeof(clk_drift));
+
+	index = q6audio_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: index[%d] invalid!\n", __func__, index);
+		return -EINVAL;
+	}
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0) {
+		pr_err_ratelimited("%s: Q6 interface prepare failed %d\n",
+				    __func__, ret);
+		return ret;
+	}
+
+	clk_id = afe_get_clk_id(port_id);
+	if (clk_id < 0) {
+		pr_err("%s: cannot get clk id for port id 0x%x\n",
+			__func__, port_id);
+		return -EINVAL;
+	}
+
+	if (clk_id & 0x01) {
+		pr_err("%s: cannot adjust clock drift for external clock id 0x%x\n",
+			__func__, clk_id);
+		return -EINVAL;
+	}
+
+	clk_drift.clk_drift = set_clk_drift;
+	clk_drift.clk_reset = clk_reset;
+	clk_drift.clk_id = clk_id;
+	pr_debug("%s: clk id = 0x%x clk drift  = %d clk reset = %d port id 0x%x\n",
+		  __func__, clk_drift.clk_id, clk_drift.clk_drift,
+		 clk_drift.clk_reset, port_id);
+
+	mutex_lock(&this_afe.afe_clk_lock);
+	param_hdr.module_id = AFE_MODULE_CLOCK_SET;
+	param_hdr.instance_id = INSTANCE_ID_0;
+	param_hdr.param_id = AFE_PARAM_ID_CLOCK_ADJUST;
+	param_hdr.param_size = sizeof(struct afe_set_clk_drift);
+
+	ret = q6afe_svc_pack_and_set_param_in_band(index, param_hdr,
+						   (u8 *) &clk_drift);
+	if (ret < 0)
+		pr_err_ratelimited("%s: AFE PLL clk drift failed with ret %d\n",
+				    __func__, ret);
+
+	mutex_unlock(&this_afe.afe_clk_lock);
+	return ret;
+}
+EXPORT_SYMBOL(afe_set_pll_clk_drift);
+
 /**
  * afe_set_lpass_clk_cfg - Set AFE clk config
  *
@@ -8393,6 +8806,10 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
 		return -EINVAL;
 	}
 
+	ret = afe_set_clk_id(port_id, cfg->clk_id);
+	if (ret < 0)
+		pr_debug("%s: afe_set_clk_id fail %d\n", __func__, ret);
+
 	ret = afe_set_lpass_clk_cfg(index, cfg);
 	if (ret)
 		pr_err("%s: afe_set_lpass_clk_cfg_v2 failed %d\n",
@@ -9171,6 +9588,7 @@ int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
 			this_afe.v4_ch_map_cfg.chan_info[index++] = 4;
 		}
 		this_afe.v4_ch_map_cfg.num_channels = index;
+		this_afe.num_spkrs = index / 2;
 		pr_debug("%s no of channels: %d\n", __func__, index);
 		this_afe.vi_tx_port = src_port;
 		this_afe.vi_rx_port = dst_port;
@@ -10199,6 +10617,7 @@ int __init afe_init(void)
 		this_afe.afe_sample_rates[i] = 0;
 		this_afe.dev_acdb_id[i] = 0;
 		this_afe.island_mode[i] = 0;
+		this_afe.power_mode[i] = 0;
 		this_afe.vad_cfg[i].is_enable = 0;
 		this_afe.vad_cfg[i].pre_roll = 0;
 		init_waitqueue_head(&this_afe.wait[i]);

+ 4 - 0
dsp/q6audio-v2.c

@@ -46,6 +46,7 @@ int q6audio_get_port_index(u16 port_id)
 	case MI2S_RX: return IDX_MI2S_RX;
 	case MI2S_TX: return IDX_MI2S_TX;
 	case HDMI_RX: return IDX_HDMI_RX;
+	case HDMI_RX_MS: return IDX_HDMI_RX_MS;
 	case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX;
 	case AFE_PORT_ID_PRIMARY_SPDIF_RX: return IDX_PRIMARY_SPDIF_RX;
 	case AFE_PORT_ID_PRIMARY_SPDIF_TX: return IDX_PRIMARY_SPDIF_TX;
@@ -427,6 +428,8 @@ int q6audio_get_port_id(u16 port_id)
 	case MI2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
 	case MI2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
 	case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX;
+	case HDMI_RX_MS:
+		return AFE_PORT_ID_HDMI_MS;
 	case DISPLAY_PORT_RX:
 			return AFE_PORT_ID_HDMI_OVER_DP_RX;
 	case AFE_PORT_ID_PRIMARY_SPDIF_RX:
@@ -1017,6 +1020,7 @@ int q6audio_validate_port(u16 port_id)
 	case MI2S_RX:
 	case MI2S_TX:
 	case HDMI_RX:
+	case HDMI_RX_MS:
 	case DISPLAY_PORT_RX:
 	case RSVD_2:
 	case RSVD_3:

+ 163 - 73
dsp/q6lsm.c

@@ -908,17 +908,15 @@ done:
  * @client: LSM client handle
  * @p_info: param info
  * @offset: pointer to retrieve size
- *
+ * @sm: pointer to sound model
  */
 void q6lsm_sm_set_param_data(struct lsm_client *client,
-		struct lsm_params_info_v2 *p_info,
-		size_t *offset)
+			     struct lsm_params_info_v2 *p_info,
+			     size_t *offset, struct lsm_sound_model *sm)
 {
 	struct param_hdr_v3 param_hdr;
 	int ret;
-	struct lsm_sound_model *sm;
 
-	sm = &client->stage_cfg[p_info->stage_idx].sound_model;
 	memset(&param_hdr, 0, sizeof(param_hdr));
 
 	param_hdr.module_id = p_info->module_id;
@@ -926,6 +924,8 @@ void q6lsm_sm_set_param_data(struct lsm_client *client,
 	param_hdr.param_id = p_info->param_id;
 	param_hdr.param_size = p_info->param_size;
 
+	sm->model_id = p_info->model_id;
+
 	ret = q6lsm_pack_params(sm->data, &param_hdr,
 				NULL, offset, LSM_SESSION_CMD_SET_PARAMS_V2);
 	if (ret)
@@ -1010,42 +1010,78 @@ EXPORT_SYMBOL(q6lsm_open);
 
 static int q6lsm_send_confidence_levels(struct lsm_client *client,
 					struct param_hdr_v3 *param_info,
-					uint32_t set_param_opcode)
+					uint32_t set_param_opcode, uint32_t model_id)
 {
 	struct lsm_param_confidence_levels *conf_levels = NULL;
 	uint32_t num_conf_levels = client->num_confidence_levels;
+	struct lsm_param_multi_snd_model_conf_levels *multi_sm_conf_levels = NULL;
+	uint32_t num_keywords = client->num_keywords;
 	uint8_t i = 0;
 	uint8_t padd_size = 0;
 	uint32_t param_size = 0;
 	int rc = 0;
 
-	/* Data must be 4 byte aligned so add any necessary padding. */
-	padd_size = (4 - (num_conf_levels % 4)) - 1;
-	param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
-		     sizeof(uint8_t);
-	param_info->param_size = param_size;
-	pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
+	if (model_id != 0) {
+		/* No padding is need since the structure is always 4 byte aligend.
+		 * The number "2" below represents the first two u32 variables in
+		 * struct lsm_param_multi_snd_model_conf_levels.
+		 */
+		param_size = (2 + num_keywords) * sizeof(uint32_t);
+		param_info->param_size = param_size;
+		pr_debug("%s: Set Conf Levels PARAM SIZE: %d\n", __func__, param_size);
 
-	conf_levels = kzalloc(param_size, GFP_KERNEL);
-	if (!conf_levels)
-		return -ENOMEM;
+		multi_sm_conf_levels = kzalloc(param_size, GFP_KERNEL);
+		if (!multi_sm_conf_levels)
+			return -ENOMEM;
 
-	conf_levels->num_confidence_levels = num_conf_levels;
-	pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
+		multi_sm_conf_levels->model_id = model_id;
+		multi_sm_conf_levels->num_keywords = num_keywords;
+		pr_debug("%s: snd_model id: %d, num_keywords: %d\n",
+			 __func__, model_id, num_keywords);
+
+		memcpy(multi_sm_conf_levels->confidence_levels,
+		       client->multi_snd_model_confidence_levels,
+		       sizeof(uint32_t) * num_keywords);
+		for (i = 0; i < num_keywords; i++)
+			pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
+				 multi_sm_conf_levels->confidence_levels[i]);
+
+		rc = q6lsm_pack_and_set_params(client, param_info,
+					       (uint8_t *) multi_sm_conf_levels,
+					       set_param_opcode);
+		if (rc)
+			pr_err("%s: Send multi_snd_model_conf_levels cmd failed, err %d\n",
+			       __func__, rc);
+		kfree(multi_sm_conf_levels);
+	} else {
+		/* Data must be 4 byte aligned so add any necessary padding. */
+		padd_size = (4 - (num_conf_levels % 4)) - 1;
+		param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
+			      sizeof(uint8_t);
+		param_info->param_size = param_size;
+		pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
+
+		conf_levels = kzalloc(param_size, GFP_KERNEL);
+		if (!conf_levels)
+			return -ENOMEM;
 
-	memcpy(conf_levels->confidence_levels, client->confidence_levels,
-	       num_conf_levels);
-	for (i = 0; i < num_conf_levels; i++)
-		pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
-			 conf_levels->confidence_levels[i]);
+		conf_levels->num_confidence_levels = num_conf_levels;
+		pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
 
-	rc = q6lsm_pack_and_set_params(client, param_info,
-				       (uint8_t *) conf_levels,
-				       set_param_opcode);
-	if (rc)
-		pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
-		       __func__, rc);
-	kfree(conf_levels);
+		memcpy(conf_levels->confidence_levels, client->confidence_levels,
+		       num_conf_levels);
+		for (i = 0; i < num_conf_levels; i++)
+			pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
+				 conf_levels->confidence_levels[i]);
+
+		rc = q6lsm_pack_and_set_params(client, param_info,
+					       (uint8_t *) conf_levels,
+					       set_param_opcode);
+		if (rc)
+			pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
+			       __func__, rc);
+		kfree(conf_levels);
+	}
 	return rc;
 }
 
@@ -1459,7 +1495,7 @@ int q6lsm_set_data(struct lsm_client *client,
 
 	param_hdr.param_id = LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
 	rc = q6lsm_send_confidence_levels(client, &param_hdr,
-					  LSM_SESSION_CMD_SET_PARAMS);
+					  LSM_SESSION_CMD_SET_PARAMS, 0);
 	if (rc) {
 		pr_err("%s: Failed to send conf_levels, err = %d\n",
 			__func__, rc);
@@ -1537,8 +1573,9 @@ EXPORT_SYMBOL(q6lsm_register_sound_model);
  */
 int q6lsm_deregister_sound_model(struct lsm_client *client)
 {
-	int rc;
+	int rc = 0;
 	struct lsm_cmd_reg_snd_model cmd;
+	struct lsm_sound_model *sm = NULL, *next = NULL;
 	/*
 	 * With multi-stage support sm buff allocation/free usage param info
 	 * to check stage index for which this sound model is being set, and
@@ -1564,19 +1601,39 @@ int q6lsm_deregister_sound_model(struct lsm_client *client)
 		return -EINVAL;
 	}
 
-	memset(&cmd, 0, sizeof(cmd));
-	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
-	cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
-
-	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
-	if (rc) {
-		pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
-		       cmd.hdr.opcode, rc);
+	if (client->num_sound_models > 0) {
+		p_info.param_type = LSM_DEREG_MULTI_SND_MODEL;
+		list_for_each_entry_safe(sm, next,
+				&client->stage_cfg[p_info.stage_idx].sound_models,
+				list) {
+			pr_debug("%s: current snd_model: %d, num of sound models left %d\n",
+				 __func__, sm->model_id, client->num_sound_models);
+			q6lsm_snd_model_buf_free(client, &p_info, sm);
+			list_del(&sm->list);
+			kfree(sm);
+			sm = NULL;
+			client->num_sound_models--;
+
+			if (0 == client->num_sound_models)
+				break;
+		}
 	} else {
-		pr_debug("%s: Deregister sound model succeeded\n", __func__);
-	}
+		memset(&cmd, 0, sizeof(cmd));
+		q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+		cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+		rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+		if (rc) {
+			pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+			       cmd.hdr.opcode, rc);
+		} else {
+			pr_debug("%s: Deregister sound model succeeded\n", __func__);
+		}
 
-	q6lsm_snd_model_buf_free(client, &p_info);
+		p_info.param_type = LSM_DEREG_SND_MODEL;
+		sm = &client->stage_cfg[p_info.stage_idx].sound_model;
+		q6lsm_snd_model_buf_free(client, &p_info, sm);
+	}
 
 	return rc;
 }
@@ -1825,14 +1882,15 @@ fail:
  *
  * @client: LSM client handle
  * @p_info: sound model param info
+ * @sm: pointer to sound model
  *
  * Returns 0 on success or error on failure
  */
 int q6lsm_snd_model_buf_free(struct lsm_client *client,
-			struct lsm_params_info_v2 *p_info)
+			     struct lsm_params_info_v2 *p_info,
+			     struct lsm_sound_model *sm)
 {
 	int rc = 0, stage_idx = p_info->stage_idx;
-	struct lsm_sound_model *sm = NULL;
 
 	pr_debug("%s: Session id %d\n", __func__, client->session);
 	if (CHECK_SESSION(client->session)) {
@@ -1840,11 +1898,11 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client,
 		return -EINVAL;
 	}
 
-	if (!client->stage_cfg[stage_idx].sound_model.data)
+	if (p_info->param_type == LSM_DEREG_SND_MODEL &&
+	    !client->stage_cfg[stage_idx].sound_model.data)
 		return 0;
 
 	mutex_lock(&client->cmd_lock);
-	sm = &client->stage_cfg[stage_idx].sound_model;
 	if (sm->mem_map_handle != 0) {
 		rc = q6lsm_memory_unmap_regions(client, sm->mem_map_handle);
 		if (rc)
@@ -1858,7 +1916,10 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client,
 	sm->phys = 0;
 	mutex_unlock(&client->cmd_lock);
 
-	rc = q6lsm_snd_cal_free(client, p_info);
+	if ((p_info->param_type == LSM_DEREG_MULTI_SND_MODEL &&
+	    client->num_sound_models == 1) ||
+	    p_info->param_type == LSM_DEREG_SND_MODEL)
+		rc = q6lsm_snd_cal_free(client, p_info);
 	return rc;
 }
 EXPORT_SYMBOL(q6lsm_snd_model_buf_free);
@@ -1980,20 +2041,20 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
  * Returns 0 on success or error on failure
  */
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
-			      struct lsm_params_info_v2 *p_info)
+			      struct lsm_params_info_v2 *p_info,
+			      struct lsm_sound_model *sm)
 {
 	int rc = -EINVAL, stage_idx = p_info->stage_idx;
+	int model_id = p_info->model_id;
 	size_t total_mem = 0;
-	struct lsm_sound_model *sm = NULL;
 
 	if (!client)
 		return rc;
 
-	pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
-			__func__, len, stage_idx);
+	pr_debug("%s:Snd Model len %zd, stage_idx %d, model_id %d\n",
+		 __func__, len, stage_idx, model_id);
 
 	mutex_lock(&client->cmd_lock);
-	sm = &client->stage_cfg[stage_idx].sound_model;
 	if (!sm->data) {
 		/*
 		 * If sound model is sent as set_param, i.e. param_id != 0,
@@ -2008,7 +2069,7 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
 		pr_debug("%s: sm param size %zd Total mem %zd, stage_idx %d\n",
 				 __func__, len, total_mem, stage_idx);
 		rc = msm_audio_ion_alloc(&sm->dma_buf, total_mem,
-								&sm->phys, &len, &sm->data);
+					 &sm->phys, &len, &sm->data);
 		if (rc) {
 			pr_err("%s: Audio ION alloc is failed, rc = %d, stage_idx = %d\n",
 				__func__, rc, stage_idx);
@@ -2040,7 +2101,7 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
 fail:
 	mutex_unlock(&client->cmd_lock);
 fail_1:
-	q6lsm_snd_model_buf_free(client, p_info);
+	q6lsm_snd_model_buf_free(client, p_info, sm);
 	return rc;
 }
 EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc);
@@ -2126,8 +2187,8 @@ static int q6lsm_send_param_gain(struct lsm_client *client, u16 gain,
  * Returns 0 on success or error on failure
  */
 int q6lsm_set_one_param(struct lsm_client *client,
-	struct lsm_params_info_v2 *p_info, void *data,
-	uint32_t param_type)
+			struct lsm_params_info_v2 *p_info,
+			void *data, uint32_t param_type)
 {
 	struct param_hdr_v3 param_info;
 	int rc = 0;
@@ -2186,14 +2247,19 @@ int q6lsm_set_one_param(struct lsm_client *client,
 	}
 
 	case LSM_MIN_CONFIDENCE_LEVELS:
+	case LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS:
 		param_info.module_id = p_info->module_id;
 		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		rc = q6lsm_send_confidence_levels(
-			client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2);
+			client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2,
+			p_info->model_id);
 		if (rc)
-			pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
-				 __func__, rc);
+			pr_err("%s: %s cmd failed, rc %d\n",
+				 __func__,
+				 param_type == LSM_MIN_CONFIDENCE_LEVELS ?
+				 "LSM_MIN_CONFIDENCE_LEVELS" :
+				 "LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS", rc);
 		break;
 	case LSM_POLLING_ENABLE: {
 		struct snd_lsm_poll_enable *lsm_poll_enable =
@@ -2210,7 +2276,8 @@ int q6lsm_set_one_param(struct lsm_client *client,
 		break;
 	}
 
-	case LSM_REG_SND_MODEL: {
+	case LSM_REG_SND_MODEL:
+	case LSM_REG_MULTI_SND_MODEL: {
 		struct mem_mapping_hdr mem_hdr;
 		u32 payload_size;
 		struct lsm_sound_model *sm = NULL;
@@ -2224,8 +2291,18 @@ int q6lsm_set_one_param(struct lsm_client *client,
 			payload_size = p_info->param_size +
 				       sizeof(struct param_hdr_v2);
 
-		sm = &client->stage_cfg[p_info->stage_idx].sound_model;
-
+		if (param_type == LSM_REG_MULTI_SND_MODEL) {
+			list_for_each_entry(sm,
+					    &client->stage_cfg[p_info->stage_idx].sound_models,
+					    list) {
+				pr_debug("%s: current snd_model: %d, looking for snd_model %d\n",
+					__func__, sm->model_id, p_info->model_id);
+				if (sm->model_id == p_info->model_id)
+					break;
+			}
+		} else {
+			sm = &client->stage_cfg[p_info->stage_idx].sound_model;
+		}
 		mem_hdr.data_payload_addr_lsw =
 			lower_32_bits(sm->phys);
 		mem_hdr.data_payload_addr_msw =
@@ -2236,28 +2313,41 @@ int q6lsm_set_one_param(struct lsm_client *client,
 		rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size,
 				      LSM_SESSION_CMD_SET_PARAMS_V2);
 		if (rc) {
-			pr_err("%s: REG_SND_MODEL failed, rc %d\n",
-				__func__, rc);
+			pr_err("%s: %s failed, rc %d\n",
+				__func__, param_type == LSM_REG_SND_MODEL ?
+				"LSM_REG_SND_MODEL" : "LSM_REG_MULTI_SND_MODEL", rc);
 			return rc;
 		}
 
-		rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
-		if (rc)
-			pr_err("%s: Failed to send lsm cal, err = %d\n",
-				__func__, rc);
+		if (client->num_sound_models == 0) {
+			rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
+			if (rc)
+				pr_err("%s: Failed to send lsm cal, err = %d\n",
+					__func__, rc);
+		}
 		break;
 	}
 
-	case LSM_DEREG_SND_MODEL: {
+	case LSM_DEREG_SND_MODEL:
+	case LSM_DEREG_MULTI_SND_MODEL: {
 		param_info.module_id = p_info->module_id;
 		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		param_info.param_size = 0;
-		rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
-					       LSM_SESSION_CMD_SET_PARAMS_V2);
+
+		if (param_type == LSM_DEREG_MULTI_SND_MODEL) {
+			param_info.param_size = p_info->param_size;
+			rc = q6lsm_pack_and_set_params(client, &param_info,
+							(uint8_t *)&p_info->model_id,
+							LSM_SESSION_CMD_SET_PARAMS_V2);
+		} else {
+			rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
+							LSM_SESSION_CMD_SET_PARAMS_V2);
+		}
 		if (rc)
-			pr_err("%s: DEREG_SND_MODEL failed, rc %d\n",
-				__func__, rc);
+			pr_err("%s: %s failed, rc %d\n",
+				__func__,  param_type == LSM_DEREG_SND_MODEL ?
+				"LSM_DEREG_SND_MODEL" : "LSM_DEREG_MULTI_SND_MODEL", rc);
 		break;
 	}
 

+ 6 - 1
include/asoc/msm-cdc-pinctrl.h

@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __MFD_CDC_PINCTRL_H_
@@ -11,6 +11,7 @@
 #if IS_ENABLED(CONFIG_MSM_CDC_PINCTRL)
 extern int msm_cdc_pinctrl_select_sleep_state(struct device_node *np);
 extern int msm_cdc_pinctrl_select_active_state(struct device_node *np);
+extern int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np);
 extern int msm_cdc_pinctrl_get_state(struct device_node *np);
 extern int msm_cdc_get_gpio_state(struct device_node *np);
 extern int msm_cdc_pinctrl_set_wakeup_capable(struct device_node *np,
@@ -27,6 +28,10 @@ int msm_cdc_pinctrl_select_active_state(struct device_node *np)
 {
 	return 0;
 }
+int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np)
+{
+	return 0;
+}
 int msm_cdc_get_gpio_state(struct device_node *np)
 {
 	return 0;

+ 6 - 0
include/asoc/msm-cdc-supply.h

@@ -15,6 +15,7 @@ struct cdc_regulator {
 	int max_uV;
 	int optimum_uA;
 	bool ondemand;
+	bool lpm_supported;
 	struct regulator *regulator;
 };
 
@@ -51,6 +52,11 @@ extern int msm_cdc_enable_static_supplies(struct device *dev,
 					  struct regulator_bulk_data *supplies,
 					  struct cdc_regulator *cdc_vreg,
 					  int num_supplies);
+extern int msm_cdc_set_supplies_lpm_mode(struct device *dev,
+					 struct regulator_bulk_data *supplies,
+					 struct cdc_regulator *cdc_vreg,
+					 int num_supplies,
+					 bool flag);
 extern int msm_cdc_init_supplies(struct device *dev,
 				 struct regulator_bulk_data **supplies,
 				 struct cdc_regulator *cdc_vreg,

+ 12 - 0
include/asoc/wcd-mbhc-v2.h

@@ -145,6 +145,8 @@ do {                                                    \
 #define FW_READ_ATTEMPTS 15
 #define FW_READ_TIMEOUT 4000000
 #define FAKE_REM_RETRY_ATTEMPTS 3
+#define HPHL_CROSS_CONN_THRESHOLD 100
+#define HPHR_CROSS_CONN_THRESHOLD 100
 
 #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS  50
 #define ANC_DETECT_RETRY_CNT 7
@@ -456,6 +458,14 @@ struct wcd_mbhc_register {
 };
 
 struct wcd_mbhc_cb {
+	void (*update_cross_conn_thr)
+		(struct wcd_mbhc *mbhc);
+	void (*mbhc_surge_ctl)
+		(struct wcd_mbhc *mbhc, bool surge_en);
+	void (*mbhc_comp_autozero_control)
+		(struct wcd_mbhc *mbhc, bool az_enable);
+	void (*get_micbias_val)
+		(struct wcd_mbhc *mbhc, int *mb);
 	void (*bcs_enable)
 		(struct wcd_mbhc *mbhc, bool bcs_enable);
 	int (*enable_mb_source)(struct wcd_mbhc *mbhc, bool turn_on);
@@ -551,6 +561,8 @@ struct wcd_mbhc {
 	u32 moist_vref;
 	u32 moist_iref;
 	u32 moist_rref;
+	u32 hphl_cross_conn_thr;
+	u32 hphr_cross_conn_thr;
 	u8 micbias1_cap_mode; /* track ext cap setting */
 	u8 micbias2_cap_mode; /* track ext cap setting */
 	bool hs_detect_work_stop;

+ 99 - 0
include/dsp/apr_audio-v2.h

@@ -1356,6 +1356,7 @@ struct adm_cmd_connect_afe_port_v5 {
 #define RT_PROXY_PORT_001_RX	0x2000
 #define RT_PROXY_PORT_001_TX	0x2001
 #define AFE_LOOPBACK_TX	0x6001
+#define HDMI_RX_MS			0x6002
 #define DISPLAY_PORT_RX	0x6020
 
 #define AFE_LANE_MASK_INVALID 0
@@ -1562,6 +1563,8 @@ struct adm_cmd_connect_afe_port_v5 {
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_9_RX      0x4012
 /* SLIMbus Tx port on channel 9. */
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_9_TX      0x4013
+/*AFE Rx port for audio over hdmi*/
+#define AFE_PORT_ID_HDMI_MS					0x6002
 /* AFE Rx port for audio over Display port */
 #define AFE_PORT_ID_HDMI_OVER_DP_RX              0x6020
 /*USB AFE port */
@@ -4734,6 +4737,56 @@ struct afe_enc_config {
 	union afe_enc_config_data data;
 };
 
+/*
+ * Enable TTP generator in AFE.
+ */
+#define AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_STATE         0x000132EF
+/*
+ * Configure TTP generator params in AFE.
+ */
+#define AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_CFG           0x000132F0
+#define MAX_TTP_OFFSET_PAIRS  4
+struct afe_ttp_gen_enable_t {
+	uint16_t enable;
+	uint16_t reserved;
+} __packed;
+
+struct afe_ttp_ssrc_offset_pair_t {
+	uint32_t ssrc;
+	uint32_t offset;
+} __packed;
+
+struct afe_ttp_gen_cfg_t {
+	uint32_t ttp_offset_default;
+	/*
+	 * TTP offset uses for all other cases
+	 * where no valid SSRC is received.
+	 */
+	uint32_t settling_time;
+	/*
+	 * If settling_mode==0x00: time in [us]
+	 * after first received packet until
+	 * packets are no longer dropped.
+	 */
+	uint16_t settling_mode;
+	/*
+	 * 0x00(Drop), 0x01(Settle)
+	 */
+	uint16_t num_ssrc_offsets;
+	/*
+	 * Number of SSRC/TTPOFFSET pairs to follow
+	 */
+	struct afe_ttp_ssrc_offset_pair_t ssrc_ttp_offset[MAX_TTP_OFFSET_PAIRS];
+	/*
+	 * Array of ssrc/offset pairs
+	 */
+} __packed;
+
+struct afe_ttp_config {
+	struct afe_ttp_gen_enable_t ttp_gen_enable;
+	struct afe_ttp_gen_cfg_t ttp_gen_cfg;
+};
+
 union afe_dec_config_data {
 	struct asm_sbc_dec_cfg_t sbc_config;
 	struct asm_aac_dec_cfg_v2_t aac_config;
@@ -4876,6 +4929,9 @@ struct avs_dec_congestion_buffer_param_t {
 /* Payload of the AFE_PARAM_ID_ISLAND_CONFIG parameter used by
  * AFE_MODULE_AUDIO_DEV_INTERFACE.
  */
+
+#define AFE_PARAM_ID_POWER_MODE_CONFIG		0x0002002c
+#define AFE_API_VERSION_POWER_MODE_CONFIG		0x1
 struct afe_param_id_island_cfg_t {
 	uint32_t	island_cfg_minor_version;
 	/* Tracks the configuration of this parameter.
@@ -4889,6 +4945,19 @@ struct afe_param_id_island_cfg_t {
 	 */
 } __packed;
 
+struct afe_param_id_power_mode_cfg_t {
+	uint32_t	power_mode_cfg_minor_version;
+	/* Tracks the configuration of this parameter
+         * Supported values: #AFE_API_VERSION_POWER_MODE_CONFIG
+	 */
+
+	uint32_t	power_mode_enable;
+	/* Specifies whether island mode should be enabled or disabled for the
+	 * use-case being setup.
+	 * Supported values: 0 - Disable, 1 - Enable
+	 */
+} __packed;
+
 /* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to configure
  * the Codec DMA interface.
  */
@@ -5380,6 +5449,7 @@ struct afe_param_id_lpass_core_shared_clk_cfg {
 #define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY            0x00010774
 #define VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY			0x00010F89
 #define VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY		0x10000003
+#define VPM_TX_VOICE_FLUENCE_SM_COPP_TOPOLOGY		0x10000004
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
 #define VPM_TX_DM_RFECNS_COPP_TOPOLOGY			0x00010F86
@@ -12102,6 +12172,35 @@ struct afe_clk_cfg {
 #define AFE_MODULE_CLOCK_SET		0x0001028F
 #define AFE_PARAM_ID_CLOCK_SET		0x00010290
 
+struct afe_set_clk_drift {
+	/*
+	 * Clock ID
+	 *	@values
+	 *	- 0x100 to 0x10E
+	 *	- 0x200 to 0x20C
+	 *	- 0x500 to 0x505
+	 */
+	uint32_t clk_id;
+
+	/*
+	 * Clock drift  (in PPB) to be set.
+	 *	@values
+	 *	- need to get values from DSP team
+	 */
+	int32_t clk_drift;
+
+	/*
+	 * Clock rest.
+	 *	@values
+	 *	- 1 -- Reset PLL with the original frequency
+	 *	- 0 -- Adjust the clock with the clk drift value
+	 */
+	uint32_t clk_reset;
+} __packed;
+
+/* This param id is used to adjust audio interface PLL*/
+#define AFE_PARAM_ID_CLOCK_ADJUST       0x000102C6
+
 enum afe_lpass_digital_clk_src {
 	Q6AFE_LPASS_DIGITAL_ROOT_INVALID,
 	Q6AFE_LPASS_DIGITAL_ROOT_PRI_MI2S_OSR,

+ 32 - 0
include/dsp/digital-cdc-rsc-mgr.h

@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef DIGITAL_CDC_RSC_MGR_H
+#define DIGITAL_CDC_RSC_MGR_H
+
+#ifdef CONFIG_DIGITAL_CDC_RSC_MGR
+
+int digital_cdc_rsc_mgr_hw_vote_enable(struct clk* vote_handle);
+void digital_cdc_rsc_mgr_hw_vote_disable(struct clk* vote_handle);
+void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle);
+
+#else
+
+static inline int digital_cdc_rsc_mgr_hw_vote_enable(struct clk* vote_handle)
+{
+	return 0;
+}
+
+static inline void digital_cdc_rsc_mgr_hw_vote_disable(struct clk* vote_handle)
+{
+}
+
+static inline void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle)
+{
+}
+
+#endif /* CONFIG_DIGITAL_CDC_RSC_MGR */
+
+#endif /* DIGITAL_CDC_RSC_MGR_H */

+ 15 - 0
include/dsp/q6afe-v2.h

@@ -36,6 +36,8 @@
 #define RT_PROXY_DAI_002_TX	0xE1
 #define RT_PROXY_DAI_003_TX	0xF2
 #define VIRTUAL_ID_TO_PORTID(val) ((val & 0xF) | 0x2000)
+#define PORTID_TO_IDX(val)	((val & 0xF) >> 1)
+#define NUM_RX_PROXY_PORTS	2
 
 #define AFE_CLK_VERSION_V1    1
 #define AFE_CLK_VERSION_V2    2
@@ -289,6 +291,8 @@ enum {
 	/* IDX 210-> 211 */
 	IDX_RT_PROXY_PORT_002_RX,
 	IDX_RT_PROXY_PORT_002_TX,
+	/* IDX 212 */
+	IDX_HDMI_RX_MS,
 	AFE_MAX_PORTS
 };
 
@@ -396,6 +400,8 @@ void afe_set_vad_cfg(u32 vad_enable, u32 preroll_config,
 void afe_set_island_mode_cfg(u16 port_id, u32 enable_flag);
 void afe_get_island_mode_cfg(u16 port_id, u32 *enable_flag);
 int afe_send_cdc_dma_data_align(u16 port_id, u32 cdc_dma_data_align);
+int afe_set_power_mode_cfg(u16 port_id, u32 enable_flag);
+int afe_get_power_mode_cfg(u16 port_id, u32 *enable_flag);
 int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	u32 rate);
 int afe_set_tws_channel_mode(u32 foramt, u16 port_id, u32 channel_mode);
@@ -403,6 +409,11 @@ int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
 		      u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
 		      struct afe_enc_config *enc_config,
 		      struct afe_dec_config *dec_config);
+int afe_port_start_v3(u16 port_id, union afe_port_config *afe_config,
+		      u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
+		      struct afe_enc_config *enc_config,
+		      struct afe_dec_config *dec_config,
+		      struct afe_ttp_config *ttp_config);
 int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
 	int l_ch, int r_ch, u32 enable);
 int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib);
@@ -482,12 +493,16 @@ int afe_get_sp_rx_tmax_xmax_logging_data(
 		u16 port_id);
 int afe_cal_init_hwdep(void *card);
 int afe_send_port_island_mode(u16 port_id);
+int afe_send_port_power_mode(u16 port_id);
 int afe_send_port_vad_cfg_params(u16 port_id);
 int afe_send_cmd_wakeup_register(void *handle, bool enable);
 void afe_register_wakeup_irq_callback(
 	void (*afe_cb_wakeup_irq)(void *handle));
 int afe_get_doa_tracking_mon(u16 port_id,
 	struct doa_tracking_mon_param *doa_tracking_data);
+int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
+			  uint32_t clk_reset);
+int afe_set_clk_id(u16 port_id, uint32_t clk_id);
 
 enum {
 	AFE_LPASS_CORE_HW_BLOCK_ID_NONE,

+ 19 - 4
include/dsp/q6lsm.h

@@ -22,6 +22,10 @@
 
 #define MAX_LSM_SESSIONS 8
 
+#define MAX_KEYWORDS_SUPPORTED 8
+
+#define LSM_MAX_SOUND_MODELS_SUPPORTED 8
+
 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
 		       uint32_t *payload, uint16_t client_size, void *priv);
 
@@ -32,6 +36,8 @@ struct lsm_sound_model {
 	uint32_t	actual_size; /* actual number of bytes read by DSP */
 	struct dma_buf	*dma_buf;
 	uint32_t	mem_map_handle;
+	uint32_t	model_id;
+	struct list_head	list;
 };
 
 struct snd_lsm_event_status_v2 {
@@ -71,6 +77,7 @@ struct lsm_stage_config {
 	bool	lab_enable;
 	struct lsm_sound_model	sound_model;
 	struct lsm_cal_data_info	cal_info;
+	struct list_head	sound_models;
 };
 
 
@@ -106,6 +113,9 @@ struct lsm_client {
 	struct lsm_stage_config	stage_cfg[LSM_MAX_STAGES_PER_SESSION];
 	uint64_t	fe_id;
 	uint16_t	unprocessed_data;
+	uint32_t	num_sound_models;
+	uint32_t	num_keywords;
+	uint32_t	*multi_snd_model_confidence_levels;
 };
 
 struct lsm_stream_cmd_open_tx {
@@ -193,6 +203,11 @@ struct lsm_param_media_fmt_v2 {
 	uint8_t		channel_mapping[0];
 } __packed;
 
+struct lsm_param_multi_snd_model_conf_levels {
+	uint32_t model_id;
+	uint32_t num_keywords;
+	uint32_t confidence_levels[0];
+} __packed;
 
 struct lsm_param_confidence_levels {
 	uint8_t num_confidence_levels;
@@ -268,9 +283,9 @@ int q6lsm_open(struct lsm_client *client, uint16_t app_id);
 int q6lsm_start(struct lsm_client *client, bool wait);
 int q6lsm_stop(struct lsm_client *client, bool wait);
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
-			struct lsm_params_info_v2 *p_info);
+			struct lsm_params_info_v2 *p_info, struct lsm_sound_model *sm);
 int q6lsm_snd_model_buf_free(struct lsm_client *client,
-			struct lsm_params_info_v2 *p_info);
+			struct lsm_params_info_v2 *p_info, struct lsm_sound_model *sm);
 int q6lsm_close(struct lsm_client *client);
 int q6lsm_register_sound_model(struct lsm_client *client,
 			       enum lsm_detection_mode mode,
@@ -290,8 +305,8 @@ int q6lsm_set_one_param(struct lsm_client *client,
 			struct lsm_params_info_v2 *p_info, void *data,
 			uint32_t param_type);
 void q6lsm_sm_set_param_data(struct lsm_client *client,
-		struct lsm_params_info_v2 *p_info,
-		size_t *offset);
+		struct lsm_params_info_v2 *p_info, size_t *offset,
+		struct lsm_sound_model *sm);
 int q6lsm_set_port_connected(struct lsm_client *client);
 int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
 int q6lsm_set_media_fmt_params(struct lsm_client *client);

+ 5 - 5
include/uapi/audio/sound/audio_effects.h

@@ -7,9 +7,9 @@
 
 
 /* CONFIG GET/SET */
-#define CONFIG_CACHE			0
-#define CONFIG_SET			1
-#define CONFIG_GET			2
+#define AUDIO_EFFECTS_CONFIG_CACHE			0
+#define AUDIO_EFFECTS_CONFIG_SET			1
+#define AUDIO_EFFECTS_CONFIG_GET			2
 
 /* CONFIG HEADER */
 /*
@@ -17,14 +17,14 @@
  * DEVICE,
  * NUM_COMMANDS,
  * COMMAND_ID_1,
- * CONFIG_CACHE/SET/GET,
+ * AUDIO_EFFECTS_CONFIG_CACHE/SET/GET,
  * OFFSET_1,
  * LENGTH_1,
  * VALUES_1,
  * ...,
  * ...,
  * COMMAND_ID_2,
- * CONFIG_CACHE/SET/GET,
+ * AUDIO_EFFECTS_CONFIG_CACHE/SET/GET,
  * OFFSET_2,
  * LENGTH_2,
  * VALUES_2,

+ 7 - 3
include/uapi/audio/sound/lsm_params.h

@@ -5,9 +5,8 @@
 #define LSM_EVENT_TIMESTAMP_MODE_SUPPORT
 
 #include <linux/types.h>
-#include <sound/asound.h>
 
-#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 1)
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 2)
 
 #define LSM_MAX_STAGES_PER_SESSION 2
 #define LSM_STAGE_INDEX_FIRST 0
@@ -34,7 +33,10 @@
 #define LSM_POLLING_ENABLE (7)
 #define LSM_DET_EVENT_TYPE (8)
 #define LSM_LAB_CONTROL (9)
-#define LSM_PARAMS_MAX (LSM_LAB_CONTROL + 1)
+#define LSM_REG_MULTI_SND_MODEL (10)
+#define LSM_DEREG_MULTI_SND_MODEL (11)
+#define LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS (12)
+#define LSM_PARAMS_MAX (LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS + 1)
 
 #define LSM_EVENT_NON_TIME_STAMP_MODE (0)
 #define LSM_EVENT_TIME_STAMP_MODE (1)
@@ -227,6 +229,7 @@ struct lsm_params_info {
  * Member variables applicable only to V2:
  * @instance_id: instance id of the param to which parameter is to be set
  * @stage_idx: detection stage for which the param is applicable
+ * @model_id: an unique number to identify sound models in DSP
  */
 struct lsm_params_info_v2 {
 	__u32 module_id;
@@ -236,6 +239,7 @@ struct lsm_params_info_v2 {
 	__u32 param_type;
 	__u16 instance_id;
 	__u16 stage_idx;
+	__u32 model_id;
 };
 
 /*

+ 2 - 0
include/uapi/audio/sound/msmcal-hwdep.h

@@ -1,6 +1,8 @@
 #ifndef _CALIB_HWDEP_H
 #define _CALIB_HWDEP_H
 
+#include <linux/types.h>
+
 #define WCD9XXX_CODEC_HWDEP_NODE    1000
 #define AQT1000_CODEC_HWDEP_NODE    1001
 #define Q6AFE_HWDEP_NODE    1002

+ 0 - 1
include/uapi/audio/sound/voice_params.h

@@ -2,7 +2,6 @@
 #define __VOICE_PARAMS_H__
 
 #include <linux/types.h>
-#include <sound/asound.h>
 
 enum voice_lch_mode {
 	VOICE_LCH_START = 1,

+ 5 - 3
ipc/apr_vm.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2010-2014, 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, 2016-2020 The Linux Foundation. All rights reserved.
  */
 
 #include <linux/kernel.h>
@@ -1308,9 +1308,9 @@ static int __init apr_debug_init(void)
 }
 #else
 static int __init apr_debug_init(void)
-(
+{
 	return 0;
-)
+}
 #endif
 
 static void apr_cleanup(void)
@@ -1331,7 +1331,9 @@ static void apr_cleanup(void)
 				mutex_destroy(&client[i][j].svc[k].m_lock);
 		}
 	}
+#ifdef CONFIG_DEBUG_FS
 	debugfs_remove(debugfs_apr_debug);
+#endif
 }
 
 static int apr_probe(struct platform_device *pdev)

+ 16 - 3
soc/pinctrl-lpi.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/gpio.h>
@@ -16,6 +16,7 @@
 #include <linux/clk.h>
 #include <linux/bitops.h>
 #include <soc/snd_event.h>
+#include <dsp/digital-cdc-rsc-mgr.h>
 #include <linux/pm_runtime.h>
 #include <dsp/audio_notifier.h>
 
@@ -469,6 +470,7 @@ static int lpi_notifier_service_cb(struct notifier_block *this,
 				   unsigned long opcode, void *ptr)
 {
 	static bool initial_boot = true;
+	struct lpi_gpio_state *state = dev_get_drvdata(lpi_dev);
 
 	pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
 
@@ -484,6 +486,17 @@ static int lpi_notifier_service_cb(struct notifier_block *this,
 	case AUDIO_NOTIFIER_SERVICE_UP:
 		if (initial_boot)
 			initial_boot = false;
+
+		/* Reset HW votes after SSR */
+		if (!lpi_dev_up) {
+			if (state->lpass_core_hw_vote)
+				digital_cdc_rsc_mgr_hw_vote_reset(
+					state->lpass_core_hw_vote);
+			if (state->lpass_audio_hw_vote)
+				digital_cdc_rsc_mgr_hw_vote_reset(
+					state->lpass_audio_hw_vote);
+		}
+
 		lpi_dev_up = true;
 		snd_event_notify(lpi_dev, SND_EVENT_UP);
 		break;
@@ -870,7 +883,7 @@ int lpi_pinctrl_runtime_resume(struct device *dev)
 	}
 
 	mutex_lock(&state->core_hw_vote_lock);
-	ret = clk_prepare_enable(hw_vote);
+	ret = digital_cdc_rsc_mgr_hw_vote_enable(hw_vote);
 	if (ret < 0) {
 		pm_runtime_set_autosuspend_delay(dev,
 						 LPI_AUTO_SUSPEND_DELAY_ERROR);
@@ -906,7 +919,7 @@ int lpi_pinctrl_runtime_suspend(struct device *dev)
 
 	mutex_lock(&state->core_hw_vote_lock);
 	if (state->core_hw_vote_status) {
-		clk_disable_unprepare(hw_vote);
+		digital_cdc_rsc_mgr_hw_vote_disable(hw_vote);
 		state->core_hw_vote_status = false;
 	}
 	mutex_unlock(&state->core_hw_vote_lock);

+ 1 - 5
soc/soundwire.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/kernel.h>
@@ -473,10 +473,6 @@ int swr_get_logical_dev_num(struct swr_device *dev, u64 dev_id,
 	}
 	mutex_lock(&master->mlock);
 	ret = master->get_logical_dev_num(master, dev_id, dev_num);
-	if (ret) {
-		pr_err("%s: Error %d to get logical addr for device %llx\n",
-			__func__, ret, dev_id);
-	}
 	mutex_unlock(&master->mlock);
 	return ret;
 }

+ 70 - 38
soc/swr-mstr-ctrl.c

@@ -24,6 +24,7 @@
 #include <dsp/msm-audio-event-notify.h>
 #include "swr-mstr-registers.h"
 #include "swr-slave-registers.h"
+#include <dsp/digital-cdc-rsc-mgr.h>
 #include "swr-mstr-ctrl.h"
 
 #define SWR_NUM_PORTS    4 /* TODO - Get this info from DT */
@@ -403,8 +404,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
 				}
 				if (++swrm->hw_core_clk_en == 1) {
 					ret =
-					   clk_prepare_enable(
-						swrm->lpass_core_hw_vote);
+					   digital_cdc_rsc_mgr_hw_vote_enable(
+							swrm->lpass_core_hw_vote);
 					if (ret < 0) {
 						dev_err(swrm->dev,
 							"%s:lpass core hw enable failed\n",
@@ -417,8 +418,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
 				if (swrm->hw_core_clk_en < 0)
 					swrm->hw_core_clk_en = 0;
 				else if (swrm->hw_core_clk_en == 0)
-					clk_disable_unprepare(
-						swrm->lpass_core_hw_vote);
+					digital_cdc_rsc_mgr_hw_vote_disable(
+							swrm->lpass_core_hw_vote);
 			}
 		}
 	}
@@ -435,8 +436,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
 				}
 				if (++swrm->aud_core_clk_en == 1) {
 					ret =
-					   clk_prepare_enable(
-						swrm->lpass_core_audio);
+					   digital_cdc_rsc_mgr_hw_vote_enable(
+							swrm->lpass_core_audio);
 					if (ret < 0) {
 						dev_err(swrm->dev,
 							"%s:lpass audio hw enable failed\n",
@@ -449,8 +450,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
 				if (swrm->aud_core_clk_en < 0)
 					swrm->aud_core_clk_en = 0;
 				else if (swrm->aud_core_clk_en == 0)
-					clk_disable_unprepare(
-						swrm->lpass_core_audio);
+					digital_cdc_rsc_mgr_hw_vote_disable(
+							swrm->lpass_core_audio);
 			}
 		}
 	}
@@ -1104,6 +1105,8 @@ int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq)
 			bus_clk_freq = SWR_CLK_RATE_4P8MHZ;
 		else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ)
 			bus_clk_freq = SWR_CLK_RATE_9P6MHZ;
+		else
+			bus_clk_freq = SWR_CLK_RATE_9P6MHZ;
 	} else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ)
 		bus_clk_freq = SWR_CLK_RATE_11P2896MHZ;
 
@@ -1870,7 +1873,7 @@ handle_irq:
 			swrm_enable_slave_irq(swrm);
 			if (status == swrm->slave_status) {
 				dev_dbg(swrm->dev,
-					"%s: No change in slave status: %d\n",
+					"%s: No change in slave status: 0x%x\n",
 					__func__, status);
 				break;
 			}
@@ -2174,17 +2177,19 @@ static int swrm_get_logical_dev_num(struct swr_master *mstr, u64 dev_id,
 					if ((id & SWR_DEV_ID_MASK) == dev_id) {
 						*dev_num = i;
 						ret = 0;
+						dev_info(swrm->dev,
+							"%s: devnum %d assigned for dev %llx\n",
+							__func__, i,
+							swr_dev->addr);
 					}
-					dev_dbg(swrm->dev,
-						"%s: devnum %d is assigned for dev addr %lx\n",
-						__func__, i, swr_dev->addr);
 				}
 			}
 		}
 	}
 	if (ret)
-		dev_err(swrm->dev, "%s: device 0x%llx is not ready\n",
-			__func__, dev_id);
+		dev_err_ratelimited(swrm->dev,
+				"%s: device 0x%llx is not ready\n",
+				__func__, dev_id);
 
 	pm_runtime_mark_last_busy(swrm->dev);
 	pm_runtime_put_autosuspend(swrm->dev);
@@ -2234,7 +2239,7 @@ static void swrm_device_wakeup_unvote(struct swr_master *mstr)
 
 static int swrm_master_init(struct swr_mstr_ctrl *swrm)
 {
-	int ret = 0;
+	int ret = 0, i = 0;
 	u32 val;
 	u8 row_ctrl = SWR_ROW_50;
 	u8 col_ctrl = SWR_MIN_COL;
@@ -2245,6 +2250,18 @@ static int swrm_master_init(struct swr_mstr_ctrl *swrm)
 	u32 temp = 0;
 	int len = 0;
 
+	/* SW workaround to gate hw_ctl for SWR version >=1.6 */
+	if (swrm->version >= SWRM_VERSION_1_6) {
+		if (swrm->swrm_hctl_reg) {
+			temp = ioread32(swrm->swrm_hctl_reg);
+			temp &= 0xFFFFFFFD;
+			iowrite32(temp, swrm->swrm_hctl_reg);
+			usleep_range(500, 505);
+			temp = ioread32(swrm->swrm_hctl_reg);
+			dev_dbg(swrm->dev, "%s: hctl_reg val: 0x%x\n",
+				__func__, temp);
+		}
+	}
 	ssp_period = swrm_get_ssp_period(swrm, SWRM_ROW_50,
 					SWRM_COL_02, SWRM_FRAME_SYNC_SEL);
 	dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
@@ -2300,6 +2317,13 @@ static int swrm_master_init(struct swr_mstr_ctrl *swrm)
 		dev_err(swrm->dev,
 			"%s: swr link failed to connect\n",
 			__func__);
+		for (i = 0; i < len; i++) {
+			usleep_range(50, 55);
+			dev_err(swrm->dev,
+				"%s:reg:0x%x val:0x%x\n",
+				__func__,
+				reg[i], swr_master_read(swrm, reg[i]));
+		}
 		return -EINVAL;
 	}
 
@@ -2309,14 +2333,6 @@ static int swrm_master_init(struct swr_mstr_ctrl *swrm)
 				(swr_master_read(swrm,
 					SWRM_CMD_FIFO_CFG) | 0x80000000));
 
-	/* SW workaround to gate hw_ctl for SWR version >=1.6 */
-	if (swrm->version >= SWRM_VERSION_1_6) {
-		if (swrm->swrm_hctl_reg) {
-			temp = ioread32(swrm->swrm_hctl_reg);
-			temp &= 0xFFFFFFFD;
-			iowrite32(temp, swrm->swrm_hctl_reg);
-		}
-	}
 	return ret;
 }
 
@@ -2455,6 +2471,8 @@ static int swrm_probe(struct platform_device *pdev)
 		ret = -EINVAL;
 		goto err_pdata_fail;
 	}
+	swrm->pinctrl_setup = pdata->pinctrl_setup;
+
 	if (of_property_read_u32(pdev->dev.of_node,
 			"qcom,swr-clock-stop-mode0",
 			&swrm->clk_stop_mode0_supp)) {
@@ -2656,6 +2674,7 @@ static int swrm_probe(struct platform_device *pdev)
 			"%s: Error in master Initialization , err %d\n",
 			__func__, ret);
 		mutex_unlock(&swrm->mlock);
+		ret = -EPROBE_DEFER;
 		goto err_mstr_init_fail;
 	}
 
@@ -2704,11 +2723,17 @@ err_irq_wakeup_fail:
 err_mstr_init_fail:
 	swr_unregister_master(&swrm->master);
 err_mstr_fail:
-	if (swrm->reg_irq)
+	if (swrm->reg_irq) {
 		swrm->reg_irq(swrm->handle, swr_mstr_interrupt,
 				swrm, SWR_IRQ_FREE);
-	else if (swrm->irq)
+	} else if (swrm->irq) {
 		free_irq(swrm->irq, swrm);
+		irqd_set_trigger_type(
+			irq_get_irq_data(swrm->irq),
+			IRQ_TYPE_NONE);
+	}
+	if (swrm->swr_irq_wakeup_capable)
+		irq_set_irq_wake(swrm->irq, 0);
 err_irq_fail:
 	mutex_destroy(&swrm->irq_lock);
 	mutex_destroy(&swrm->mlock);
@@ -2728,13 +2753,17 @@ static int swrm_remove(struct platform_device *pdev)
 {
 	struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
 
-	if (swrm->reg_irq)
+	if (swrm->reg_irq) {
 		swrm->reg_irq(swrm->handle, swr_mstr_interrupt,
 				swrm, SWR_IRQ_FREE);
-	else if (swrm->irq)
+	} else if (swrm->irq) {
 		free_irq(swrm->irq, swrm);
-	else if (swrm->wake_irq > 0)
+		irqd_set_trigger_type(
+			irq_get_irq_data(swrm->irq),
+			IRQ_TYPE_NONE);
+	} else if (swrm->wake_irq > 0) {
 		free_irq(swrm->wake_irq, swrm);
+	}
 	if (swrm->swr_irq_wakeup_capable)
 		irq_set_irq_wake(swrm->irq, 0);
 	cancel_work_sync(&swrm->wakeup_work);
@@ -2776,7 +2805,6 @@ static int swrm_runtime_resume(struct device *dev)
 	int ret = 0;
 	bool swrm_clk_req_err = false;
 	bool hw_core_err = false;
-	bool aud_core_err = false;
 	struct swr_master *mstr = &swrm->master;
 	struct swr_device *swr_dev;
 	u32 temp = 0;
@@ -2795,7 +2823,7 @@ static int swrm_runtime_resume(struct device *dev)
 	if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) {
 		dev_err(dev, "%s:lpass audio hw enable failed\n",
 			__func__);
-		aud_core_err = true;
+		swrm->aud_core_err = true;
 	}
 
 	if ((swrm->state == SWR_MSTR_DOWN) ||
@@ -2814,6 +2842,9 @@ static int swrm_runtime_resume(struct device *dev)
 				    irq_get_irq_data(swrm->wake_irq)))
 					disable_irq_nosync(swrm->wake_irq);
 				mutex_unlock(&swrm->irq_lock);
+				if (swrm->dmic_sva && swrm->pinctrl_setup)
+					swrm->pinctrl_setup(swrm->handle,
+							    false);
 			}
 			if (swrm->ipc_wakeup)
 				msm_aud_evt_blocking_notifier_call_chain(
@@ -2887,7 +2918,7 @@ static int swrm_runtime_resume(struct device *dev)
 		swrm->state = SWR_MSTR_UP;
 	}
 exit:
-	if (!aud_core_err)
+	if (ret && !swrm->aud_core_err)
 		swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
 	if (!hw_core_err)
 		swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
@@ -2910,7 +2941,6 @@ static int swrm_runtime_suspend(struct device *dev)
 	struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
 	int ret = 0;
 	bool hw_core_err = false;
-	bool aud_core_err = false;
 	struct swr_master *mstr = &swrm->master;
 	struct swr_device *swr_dev;
 	int current_state = 0;
@@ -2929,11 +2959,6 @@ static int swrm_runtime_suspend(struct device *dev)
 			__func__);
 		hw_core_err = true;
 	}
-	if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) {
-		dev_err(dev, "%s:lpass audio hw enable failed\n",
-			__func__);
-		aud_core_err = true;
-	}
 
 	if ((current_state == SWR_MSTR_UP) ||
 	    (current_state == SWR_MSTR_SSR)) {
@@ -3002,6 +3027,8 @@ static int swrm_runtime_suspend(struct device *dev)
 
 		if (swrm->clk_stop_mode0_supp) {
 			if (swrm->wake_irq > 0) {
+				if (swrm->dmic_sva && swrm->pinctrl_setup)
+					swrm->pinctrl_setup(swrm->handle, true);
 				enable_irq(swrm->wake_irq);
 			} else if (swrm->ipc_wakeup) {
 				msm_aud_evt_blocking_notifier_call_chain(
@@ -3015,10 +3042,11 @@ static int swrm_runtime_suspend(struct device *dev)
 	if (current_state != SWR_MSTR_SSR)
 		swrm->state = SWR_MSTR_DOWN;
 exit:
-	if (!aud_core_err)
+	if (!swrm->aud_core_err)
 		swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
 	if (!hw_core_err)
 		swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
+	swrm->aud_core_err = false;
 	mutex_unlock(&swrm->reslock);
 	trace_printk("%s: pm_runtime: suspend done state: %d\n",
 		__func__, swrm->state);
@@ -3235,6 +3263,8 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 			swrm_device_down(&pdev->dev);
 		mutex_lock(&swrm->devlock);
 		swrm->dev_up = false;
+		swrm->hw_core_clk_en = 0;
+		swrm->aud_core_clk_en = 0;
 		mutex_unlock(&swrm->devlock);
 		mutex_lock(&swrm->reslock);
 		swrm->state = SWR_MSTR_SSR;
@@ -3348,10 +3378,12 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 	case SWR_REGISTER_WAKEUP:
 		msm_aud_evt_blocking_notifier_call_chain(
 					SWR_WAKE_IRQ_REGISTER, (void *)swrm);
+		swrm->dmic_sva = *(u32 *)data;
 		break;
 	case SWR_DEREGISTER_WAKEUP:
 		msm_aud_evt_blocking_notifier_call_chain(
 					SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
+		swrm->dmic_sva = 0;
 		break;
 	case SWR_SET_PORT_MAP:
 		if (!data) {

+ 4 - 0
soc/swr-mstr-ctrl.h

@@ -115,6 +115,7 @@ struct swr_ctrl_platform_data {
 	int (*core_vote)(void *handle, bool enable);
 	int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
 			void *data), void *swr_handle, int type);
+	int (*pinctrl_setup)(void *handle, bool enable);
 };
 
 struct swr_mstr_ctrl {
@@ -148,6 +149,7 @@ struct swr_mstr_ctrl {
 	int (*core_vote)(void *handle, bool enable);
 	int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
 			void *data), void *swr_handle, int type);
+	int (*pinctrl_setup)(void *handle, bool enable);
 	int irq;
 	int wake_irq;
 	int version;
@@ -173,8 +175,10 @@ struct swr_mstr_ctrl {
 	u32 clk_stop_mode0_supp;
 	struct work_struct wakeup_work;
 	u32 ipc_wakeup;
+	u32 dmic_sva;
 	bool dev_up;
 	bool ipc_wakeup_triggered;
+	bool aud_core_err;
 	struct pm_qos_request pm_qos_req;
 	enum swrm_pm_state pm_state;
 	wait_queue_head_t pm_wq;