Bladeren bron

Merge commit '33ea77356f47c6c596c8505ca90307fc1245ef3f' into audio-kernel-5-4.lnx.1.0

Change-Id: Iacb389506a643a1ac70a3d51c2dfc1eeb47f690c
Phani Kumar Uppalapati 4 jaren geleden
bovenliggende
commit
726d5ea145
60 gewijzigde bestanden met toevoegingen van 2851 en 1075 verwijderingen
  1. 15 1
      asoc/bengal-port-config.h
  2. 130 12
      asoc/bengal.c
  3. 35 37
      asoc/codecs/bolero/bolero-cdc.c
  4. 9 14
      asoc/codecs/bolero/bolero-cdc.h
  5. 20 10
      asoc/codecs/bolero/bolero-clk-rsc.c
  6. 89 45
      asoc/codecs/bolero/rx-macro.c
  7. 71 63
      asoc/codecs/bolero/tx-macro.c
  8. 30 71
      asoc/codecs/bolero/va-macro.c
  9. 66 51
      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. 76 48
      asoc/codecs/swr-dmic.c
  25. 12 7
      asoc/codecs/swr-haptics.c
  26. 41 10
      asoc/codecs/wcd-mbhc-adc.c
  27. 25 2
      asoc/codecs/wcd-mbhc-v2.c
  28. 62 62
      asoc/codecs/wcd9335.c
  29. 54 54
      asoc/codecs/wcd934x/wcd934x.c
  30. 2 0
      asoc/codecs/wcd937x/internal.h
  31. 56 1
      asoc/codecs/wcd937x/wcd937x.c
  32. 4 0
      asoc/codecs/wcd938x/internal.h
  33. 11 2
      asoc/codecs/wcd938x/wcd938x-slave.c
  34. 212 75
      asoc/codecs/wcd938x/wcd938x.c
  35. 9 0
      asoc/codecs/wcd938x/wcd938x.h
  36. 3 2
      asoc/codecs/wsa881x.c
  37. 1 0
      asoc/codecs/wsa883x/internal.h
  38. 93 3
      asoc/codecs/wsa883x/wsa883x.c
  39. 4 2
      asoc/kona.c
  40. 57 95
      asoc/lahaina.c
  41. 4 0
      asoc/msm-compress-q6-v2.h
  42. 6 2
      asoc/msm_dailink.h
  43. 320 6
      asoc/qcs405.c
  44. 4 0
      dsp/Kbuild
  45. 108 24
      dsp/adsp-loader.c
  46. 12 0
      dsp/audio_notifier.c
  47. 2 2
      dsp/digital-cdc-rsc-mgr.c
  48. 6 1
      include/asoc/msm-cdc-pinctrl.h
  49. 6 0
      include/asoc/msm-cdc-supply.h
  50. 13 0
      include/asoc/wcd-mbhc-v2.h
  51. 127 1
      include/dsp/apr_audio-v2.h
  52. 10 1
      include/ipc/apr.h
  53. 5 5
      include/uapi/audio/sound/audio_effects.h
  54. 7 3
      include/uapi/audio/sound/lsm_params.h
  55. 2 0
      include/uapi/audio/sound/msmcal-hwdep.h
  56. 0 1
      include/uapi/audio/sound/voice_params.h
  57. 4 1
      soc/pinctrl-lpi.c
  58. 1 5
      soc/soundwire.c
  59. 49 36
      soc/swr-mstr-ctrl.c
  60. 1 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;

+ 35 - 37
asoc/codecs/bolero/bolero-cdc.c

@@ -600,6 +600,28 @@ int bolero_dmic_clk_enable(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL(bolero_dmic_clk_enable);
 
+bool bolero_is_va_macro_registered(struct device *dev)
+{
+	struct bolero_priv *priv;
+
+	if (!dev) {
+		pr_err("%s: dev is null\n", __func__);
+		return false;
+	}
+	if (!bolero_is_valid_child_dev(dev)) {
+		dev_err(dev, "%s: child device calling is not added yet\n",
+			__func__);
+		return false;
+	}
+	priv = dev_get_drvdata(dev->parent);
+	if (!priv) {
+		dev_err(dev, "%s: priv is null\n", __func__);
+		return false;
+	}
+	return priv->macros_supported[VA_MACRO];
+}
+EXPORT_SYMBOL(bolero_is_va_macro_registered);
+
 /**
  * bolero_register_macro - Registers macro to bolero
  *
@@ -644,7 +666,6 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
 				bolero_mclk_mux_tbl[macro_id][MCLK_MUX0];
 	if (macro_id == TX_MACRO) {
 		priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq;
-		priv->macro_params[macro_id].clk_switch = ops->clk_switch;
 		priv->macro_params[macro_id].reg_evt_listener =
 							ops->reg_evt_listener;
 		priv->macro_params[macro_id].clk_enable = ops->clk_enable;
@@ -661,7 +682,7 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
 	priv->num_macros_registered++;
 	priv->macros_supported[macro_id] = true;
 
-	dev_dbg(dev, "%s: register macro successful:%d\n", macro_id);
+	dev_info(dev, "%s: register macro successful:%d\n", __func__, macro_id);
 
 	if (priv->num_macros_registered == priv->num_macros) {
 		ret = bolero_copy_dais_from_macro(priv);
@@ -719,7 +740,6 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id)
 	priv->macro_params[macro_id].dev = NULL;
 	if (macro_id == TX_MACRO) {
 		priv->macro_params[macro_id].reg_wake_irq = NULL;
-		priv->macro_params[macro_id].clk_switch = NULL;
 		priv->macro_params[macro_id].reg_evt_listener = NULL;
 		priv->macro_params[macro_id].clk_enable = NULL;
 	}
@@ -836,6 +856,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;
@@ -1004,40 +1036,6 @@ int bolero_register_wake_irq(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL(bolero_register_wake_irq);
 
-/**
- * bolero_tx_clk_switch - Switch tx macro clock
- *
- * @component: pointer to codec component instance.
- *
- * @clk_src: 0 for TX_RCG and 1 for VA_RCG
- *
- * Returns 0 on success or -EINVAL on error.
- */
-int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src)
-{
-	struct bolero_priv *priv = NULL;
-	int ret = 0;
-
-	if (!component)
-		return -EINVAL;
-
-	priv = snd_soc_component_get_drvdata(component);
-	if (!priv)
-		return -EINVAL;
-
-	if (!bolero_is_valid_codec_dev(priv->dev)) {
-		dev_err(component->dev, "%s: invalid codec\n", __func__);
-		return -EINVAL;
-	}
-
-	if (priv->macro_params[TX_MACRO].clk_switch)
-		ret = priv->macro_params[TX_MACRO].clk_switch(component,
-							      clk_src);
-
-	return ret;
-}
-EXPORT_SYMBOL(bolero_tx_clk_switch);
-
 /**
  * bolero_tx_mclk_enable - Enable/Disable TX Macro mclk
  *

+ 9 - 14
asoc/codecs/bolero/bolero-cdc.h

@@ -37,11 +37,6 @@ enum {
 	BOLERO_ADC_MAX
 };
 
-enum {
-	CLK_SRC_TX_RCG = 0,
-	CLK_SRC_VA_RCG,
-};
-
 enum {
 	BOLERO_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
 	BOLERO_MACRO_EVT_IMPED_TRUE, /* for imped true */
@@ -52,7 +47,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 {
@@ -74,7 +71,6 @@ struct macro_ops {
 	int (*set_port_map)(struct snd_soc_component *component, u32 uc,
 			    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 (*clk_enable)(struct snd_soc_component *c, bool en);
 	char __iomem *io_base;
@@ -87,6 +83,7 @@ typedef int (*rsc_clk_cb_t)(struct device *dev, u16 event);
 #if IS_ENABLED(CONFIG_SND_SOC_BOLERO)
 int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb);
 void bolero_unregister_res_clk(struct device *dev);
+bool bolero_is_va_macro_registered(struct device *dev);
 int bolero_register_macro(struct device *dev, u16 macro_id,
 			  struct macro_ops *ops);
 void bolero_unregister_macro(struct device *dev, u16 macro_id);
@@ -100,7 +97,6 @@ void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n);
 int bolero_runtime_resume(struct device *dev);
 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);
 void bolero_wsa_pa_on(struct device *dev);
@@ -118,6 +114,11 @@ static inline void bolero_unregister_res_clk(struct device *dev)
 {
 }
 
+static bool bolero_is_va_macro_registered(struct device *dev)
+{
+	return false;
+}
+
 static inline int bolero_register_macro(struct device *dev,
 					u16 macro_id,
 					struct macro_ops *ops)
@@ -168,12 +169,6 @@ static inline int bolero_set_port_map(struct snd_soc_component *component,
 	return 0;
 }
 
-static inline int bolero_tx_clk_switch(struct snd_soc_component *component,
-					int clk_src)
-{
-	return 0;
-}
-
 static inline int bolero_register_event_listener(
 					struct snd_soc_component *component,
 					bool enable)

+ 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);

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

@@ -387,6 +387,7 @@ enum {
 	RX_MACRO_AIF3_PB,
 	RX_MACRO_AIF4_PB,
 	RX_MACRO_AIF_ECHO,
+	RX_MACRO_AIF5_PB,
 	RX_MACRO_AIF6_PB,
 	RX_MACRO_MAX_DAIS,
 };
@@ -719,6 +720,20 @@ static struct snd_soc_dai_driver rx_macro_dai[] = {
 		},
 		.ops = &rx_macro_dai_ops,
 	},
+	{
+		.name = "rx_macro_rx5",
+		.id = RX_MACRO_AIF5_PB,
+		.playback = {
+			.stream_name = "RX_MACRO_AIF5 Playback",
+			.rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES,
+			.formats = RX_MACRO_FORMATS,
+			.rate_max = 384000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &rx_macro_dai_ops,
+	},
 	{
 		.name = "rx_macro_rx6",
 		.id = RX_MACRO_AIF6_PB,
@@ -1138,6 +1153,13 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
 			"%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%x\n",
 			__func__, dai->id, *rx_slot, *rx_num, rx_priv->active_ch_mask[dai->id]);
 		break;
+	case RX_MACRO_AIF5_PB:
+		*rx_slot = 0x1;
+		*rx_num = 0x01;
+		dev_dbg(rx_priv->dev,
+			"%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d\n",
+			__func__, dai->id, *rx_slot, *rx_num);
+		break;
 	case RX_MACRO_AIF6_PB:
 		*rx_slot = 0x1;
 		*rx_num = 0x01;
@@ -1410,11 +1432,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 +1445,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 +1733,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 +1748,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 +1771,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 +1782,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 +1956,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 +3019,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 +3065,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,
@@ -3179,6 +3213,9 @@ static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_OUT("RX AIF_ECHO", "RX_AIF_ECHO Capture", 0,
 		SND_SOC_NOPM, 0, 0),
 
+	SND_SOC_DAPM_AIF_IN("RX AIF5 PB", "RX_MACRO_AIF5 Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
 	SND_SOC_DAPM_AIF_IN("RX AIF6 PB", "RX_MACRO_AIF6 Playback", 0,
 		SND_SOC_NOPM, 0, 0),
 
@@ -3849,6 +3886,7 @@ static int rx_macro_init(struct snd_soc_component *component)
 	snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF2 Playback");
 	snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF3 Playback");
 	snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF4 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF5 Playback");
 	snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF6 Playback");
 	snd_soc_dapm_ignore_suspend(dapm, "HPHL_OUT");
 	snd_soc_dapm_ignore_suspend(dapm, "HPHR_OUT");
@@ -4016,6 +4054,12 @@ static int rx_macro_probe(struct platform_device *pdev)
 	u32 is_used_rx_swr_gpio = 1;
 	const char *is_used_rx_swr_gpio_dt = "qcom,is-used-swr-gpio";
 
+	if (!bolero_is_va_macro_registered(&pdev->dev)) {
+		dev_err(&pdev->dev,
+			"%s: va-macro not registered yet, defer\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
 	rx_priv = devm_kzalloc(&pdev->dev, sizeof(struct rx_macro_priv),
 			    GFP_KERNEL);
 	if (!rx_priv)

+ 71 - 63
asoc/codecs/bolero/tx-macro.c

@@ -176,6 +176,7 @@ struct tx_macro_priv {
 	int bcs_ch;
 	bool bcs_clk_en;
 	bool hs_slow_insert_complete;
+	int amic_sample_rate;
 };
 
 static bool tx_macro_get_data(struct snd_soc_component *component,
@@ -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;
 }
@@ -497,6 +501,29 @@ static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
 				hpf_cut_off_freq << 5);
 		snd_soc_component_update_bits(component, hpf_gate_reg,
 						0x03, 0x02);
+		/* Add delay between toggle hpf gate based on sample rate */
+		switch(tx_priv->amic_sample_rate) {
+		case 8000:
+			usleep_range(125, 130);
+			break;
+		case 16000:
+			usleep_range(62, 65);
+			break;
+		case 32000:
+			usleep_range(31, 32);
+			break;
+		case 48000:
+			usleep_range(20, 21);
+			break;
+		case 96000:
+			usleep_range(10, 11);
+			break;
+		case 192000:
+			usleep_range(5, 6);
+			break;
+		default:
+			usleep_range(125, 130);
+		}
 		snd_soc_component_update_bits(component, hpf_gate_reg,
 						0x03, 0x01);
 	} else {
@@ -932,6 +959,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 	u16 dec_cfg_reg = 0;
 	u16 hpf_gate_reg = 0;
 	u16 tx_gain_ctl_reg = 0;
+	u16 tx_fs_reg = 0;
 	u8 hpf_cut_off_freq = 0;
 	u16 adc_mux_reg = 0;
 	int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS;
@@ -957,6 +985,11 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 				TX_MACRO_TX_PATH_OFFSET * decimator;
 	adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
 			TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+	tx_fs_reg = BOLERO_CDC_TX0_TX_PATH_CTL +
+				TX_MACRO_TX_PATH_OFFSET * decimator;
+
+	tx_priv->amic_sample_rate = (snd_soc_component_read32(component,
+				     tx_fs_reg) & 0x0F);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -2362,18 +2395,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 +2431,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 +2458,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),
@@ -2722,36 +2755,6 @@ static int tx_macro_clk_div_get(struct snd_soc_component *component)
 	return tx_priv->dmic_clk_div;
 }
 
-static int tx_macro_clk_switch(struct snd_soc_component *component, int clk_src)
-{
-	struct device *tx_dev = NULL;
-	struct tx_macro_priv *tx_priv = NULL;
-	int ret = 0;
-
-	if (!component)
-		return -EINVAL;
-
-	tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO);
-	if (!tx_dev) {
-		dev_err(component->dev,
-			"%s: null device for macro!\n", __func__);
-		return -EINVAL;
-	}
-	tx_priv = dev_get_drvdata(tx_dev);
-	if (!tx_priv) {
-		dev_err(component->dev,
-			"%s: priv is null for macro!\n", __func__);
-		return -EINVAL;
-	}
-	if (tx_priv->swr_ctrl_data) {
-		ret = swrm_wcd_notify(
-			tx_priv->swr_ctrl_data[0].tx_swr_pdev,
-			SWR_REQ_CLK_SWITCH, &clk_src);
-	}
-
-	return ret;
-}
-
 static int tx_macro_core_vote(void *handle, bool enable)
 {
 	struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
@@ -3233,7 +3236,6 @@ static void tx_macro_init_ops(struct macro_ops *ops,
 	ops->reg_wake_irq = tx_macro_reg_wake_irq;
 	ops->set_port_map = tx_macro_set_port_map;
 	ops->clk_div_get = tx_macro_clk_div_get;
-	ops->clk_switch = tx_macro_clk_switch;
 	ops->reg_evt_listener = tx_macro_register_event_listener;
 	ops->clk_enable = __tx_macro_mclk_enable;
 }
@@ -3249,6 +3251,12 @@ static int tx_macro_probe(struct platform_device *pdev)
 	u32 is_used_tx_swr_gpio = 1;
 	const char *is_used_tx_swr_gpio_dt = "qcom,is-used-swr-gpio";
 
+	if (!bolero_is_va_macro_registered(&pdev->dev)) {
+		dev_err(&pdev->dev,
+			"%s: va-macro not registered yet, defer\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
 	tx_priv = devm_kzalloc(&pdev->dev, sizeof(struct tx_macro_priv),
 			    GFP_KERNEL);
 	if (!tx_priv)

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

@@ -298,8 +298,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,
@@ -312,6 +311,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)
@@ -378,7 +380,6 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w,
 	int ret = 0;
 	struct device *va_dev = NULL;
 	struct va_macro_priv *va_priv = NULL;
-	int clk_src = 0;
 
 	if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
 		return -EINVAL;
@@ -391,30 +392,12 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		if (va_priv->swr_ctrl_data) {
-			clk_src = CLK_SRC_VA_RCG;
-			ret = swrm_wcd_notify(
-				va_priv->swr_ctrl_data[0].va_swr_pdev,
-				SWR_REQ_CLK_SWITCH, &clk_src);
-			if (ret)
-				dev_dbg(va_dev, "%s: clock switch failed\n",
-					__func__);
-		}
 		msm_cdc_pinctrl_set_wakeup_capable(
 				va_priv->va_swr_gpio_p, false);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		msm_cdc_pinctrl_set_wakeup_capable(
 				va_priv->va_swr_gpio_p, true);
-		if (va_priv->swr_ctrl_data) {
-			clk_src = CLK_SRC_TX_RCG;
-			ret = swrm_wcd_notify(
-				va_priv->swr_ctrl_data[0].va_swr_pdev,
-				SWR_REQ_CLK_SWITCH, &clk_src);
-			if (ret)
-				dev_dbg(va_dev, "%s: clock switch failed\n",
-					__func__);
-		}
 		break;
 	default:
 		dev_err(va_priv->dev,
@@ -452,10 +435,6 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
 					"%s: lpass audio hw enable failed\n",
 					__func__);
 		}
-		if (!ret)
-			if (bolero_tx_clk_switch(component, CLK_SRC_VA_RCG))
-				dev_dbg(va_dev, "%s: clock switch failed\n",
-					__func__);
 		if (va_priv->lpi_enable) {
 			bolero_register_event_listener(component, true);
 			va_priv->register_event_listener = true;
@@ -466,8 +445,6 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
 			va_priv->register_event_listener = false;
 			bolero_register_event_listener(component, 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)
 			digital_cdc_rsc_mgr_hw_vote_disable(
 				va_priv->lpass_audio_hw_vote);
@@ -507,7 +484,6 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
 	int ret = 0;
 	struct device *va_dev = NULL;
 	struct va_macro_priv *va_priv = NULL;
-	int clk_src = 0;
 
 	if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
 		return -EINVAL;
@@ -528,27 +504,10 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
 			ret = bolero_tx_mclk_enable(component, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (va_priv->lpi_enable) {
-			if (va_priv->version == BOLERO_VERSION_2_1) {
-				if (va_priv->swr_ctrl_data) {
-					clk_src = CLK_SRC_TX_RCG;
-					ret = swrm_wcd_notify(
-					va_priv->swr_ctrl_data[0].va_swr_pdev,
-					SWR_REQ_CLK_SWITCH, &clk_src);
-					if (ret)
-						dev_dbg(va_dev,
-					"%s: clock switch failed\n",
-						__func__);
-				}
-			} else if (bolero_tx_clk_switch(component,
-					CLK_SRC_TX_RCG)) {
-				dev_dbg(va_dev, "%s: clock switch failed\n",
-					__func__);
-			}
+		if (va_priv->lpi_enable)
 			va_macro_mclk_enable(va_priv, 0, true);
-		} else {
+		else
 			bolero_tx_mclk_enable(component, 0);
-		}
 
 		if (va_priv->tx_clk_status > 0) {
 			bolero_clk_rsc_request_clock(va_priv->dev,
@@ -2536,30 +2495,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),
 
@@ -2577,23 +2536,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,

+ 66 - 51
asoc/codecs/bolero/wsa-macro.c

@@ -1022,10 +1022,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 +1035,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 +1180,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 +1266,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)
 {
@@ -2007,10 +2008,12 @@ static int wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol,
 	int value = ucontrol->value.integer.value[0];
 	int wsa_rx_shift = ((struct soc_multi_mixer_control *)
 			kcontrol->private_value)->shift;
+	int ret = 0;
 
 	if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
 		return -EINVAL;
 
+	pm_runtime_get_sync(wsa_priv->dev);
 	switch (wsa_rx_shift) {
 	case 0:
 		snd_soc_component_update_bits(component,
@@ -2035,13 +2038,16 @@ static int wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol,
 	default:
 		pr_err("%s: invalid argument rx_shift = %d\n", __func__,
 			wsa_rx_shift);
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+	pm_runtime_mark_last_busy(wsa_priv->dev);
+	pm_runtime_put_autosuspend(wsa_priv->dev);
 
 	dev_dbg(component->dev, "%s: WSA Digital Mute RX %d Enable %d\n",
 		__func__, wsa_rx_shift, value);
 	wsa_priv->wsa_digital_mute_status[wsa_rx_shift] = value;
-	return 0;
+
+	return ret;
 }
 
 static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
@@ -2370,12 +2376,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 +2556,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 +2568,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,
@@ -3138,6 +3144,12 @@ static int wsa_macro_probe(struct platform_device *pdev)
 	u32 is_used_wsa_swr_gpio = 1;
 	const char *is_used_wsa_swr_gpio_dt = "qcom,is-used-swr-gpio";
 
+	if (!bolero_is_va_macro_registered(&pdev->dev)) {
+		dev_err(&pdev->dev,
+			"%s: va-macro not registered yet, defer\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
 	wsa_priv = devm_kzalloc(&pdev->dev, sizeof(struct wsa_macro_priv),
 				GFP_KERNEL);
 	if (!wsa_priv)
@@ -3175,6 +3187,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);
@@ -3221,6 +3235,7 @@ static int wsa_macro_probe(struct platform_device *pdev)
 	wsa_macro_init_ops(&ops, wsa_io_base);
 	ops.clk_id_req = wsa_priv->default_clk_id;
 	ops.default_clk_id = wsa_priv->default_clk_id;
+
 	ret = bolero_register_macro(&pdev->dev, WSA_MACRO, &ops);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "%s: register macro failed\n", __func__);

+ 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 350
+#define ROULEUR_HPHR_CROSS_CONN_THRESHOLD 350
 
 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");

+ 76 - 48
asoc/codecs/swr-dmic.c

@@ -30,6 +30,9 @@
 #include "wcd938x/wcd938x.h"
 #include "swr-dmic.h"
 
+#define NUM_ATTEMPTS 5
+#define SWRS_SCP_CONTROL    0x44
+
 static int swr_master_channel_map[] = {
 	ZERO,
 	SWRM_TX1_CH1,
@@ -64,6 +67,7 @@ struct swr_dmic_priv {
 	int is_en_supply;
 	int port_type;
 	u8 tx_master_port_map[SWR_DMIC_MAX_PORTS];
+	struct notifier_block nblock;
 };
 
 const char *codec_name_list[] = {
@@ -243,38 +247,6 @@ static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w,
 	return ret;
 }
 
-static int swr_dmic_enable_supply(struct snd_soc_dapm_widget *w,
-			       struct snd_kcontrol *kcontrol,
-			       int event)
-{
-	struct snd_soc_component *component =
-			snd_soc_dapm_to_component(w->dapm);
-	struct swr_dmic_priv *swr_dmic =
-			snd_soc_component_get_drvdata(component);
-	int ret = 0;
-
-	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
-		w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		ret = swr_dmic_up(swr_dmic->swr_slave);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		ret = swr_dmic_reset(swr_dmic->swr_slave);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = swr_dmic_down(swr_dmic->swr_slave);
-		break;
-	}
-
-	if (ret)
-		dev_dbg(component->dev, "%s wname: %s event: %d ret : %d\n",
-			__func__, w->name, event, ret);
-
-	return ret;
-}
-
 static const char * const tx_master_port_text[] = {
 	"ZERO", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4",
 	"SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", "SWRM_TX2_CH4",
@@ -304,10 +276,6 @@ static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = {
 
 	SND_SOC_DAPM_INPUT("SWR_DMIC"),
 
-	SND_SOC_DAPM_SUPPLY_S("SMIC_SUPPLY", 1, SND_SOC_NOPM, 0, 0,
-				swr_dmic_enable_supply,
-				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-				SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_OUT_DRV_E("SMIC_PORT_EN", SND_SOC_NOPM, 0, 0, NULL, 0,
 				swr_dmic_port_enable,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -315,7 +283,6 @@ static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route swr_dmic_audio_map[] = {
-	{"SWR_DMIC", NULL, "SMIC_SUPPLY"},
 	{"SWR_DMIC_MIXER", "Switch", "SWR_DMIC"},
 	{"SMIC_PORT_EN", NULL, "SWR_DMIC_MIXER"},
 	{"SWR_DMIC_OUTPUT", NULL, "SMIC_PORT_EN"},
@@ -325,11 +292,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;
 }
 
@@ -364,6 +358,8 @@ static int enable_wcd_codec_supply(struct swr_dmic_priv *swr_dmic, bool enable)
 		pr_err("%s: component is NULL\n", __func__);
 		return -EINVAL;
 	}
+	dev_dbg(component->dev, "%s: supply %d micbias: %d enable: %d\n",
+		__func__, swr_dmic->is_en_supply, micb_num, enable);
 
 	if (enable)
 		rc = wcd938x_codec_force_enable_micbias_v2(component,
@@ -412,6 +408,29 @@ static struct snd_soc_dai_driver swr_dmic_dai[] = {
 	},
 };
 
+static int swr_dmic_event_notify(struct notifier_block *block,
+				unsigned long val,
+				void *data)
+{
+	u16 event = (val & 0xffff);
+	int ret = 0;
+	struct swr_dmic_priv *swr_dmic = container_of(block,
+					struct swr_dmic_priv,
+					nblock);
+	switch (event) {
+	case WCD938X_EVT_SSR_DOWN:
+		ret = swr_dmic_down(swr_dmic->swr_slave);
+		break;
+	case WCD938X_EVT_SSR_UP:
+		ret = swr_dmic_up(swr_dmic->swr_slave);
+		if (!ret)
+			ret = swr_dmic_reset(swr_dmic->swr_slave);
+		break;
+	}
+
+	return ret;
+}
+
 static int swr_dmic_probe(struct swr_device *pdev)
 {
 	int ret = 0;
@@ -423,6 +442,7 @@ static int swr_dmic_probe(struct swr_device *pdev)
 	const char *swr_dmic_name_prefix_of = NULL;
 	const char *swr_dmic_codec_name_of = NULL;
 	struct snd_soc_component *component = NULL;
+	int num_retry = NUM_ATTEMPTS;
 
 	swr_dmic = devm_kzalloc(&pdev->dev, sizeof(struct swr_dmic_priv),
 			    GFP_KERNEL);
@@ -485,13 +505,18 @@ static int swr_dmic_probe(struct swr_device *pdev)
 	 * as per HW requirement.
 	 */
 	usleep_range(5000, 5010);
-	ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum);
+	do {
+		/* Add delay for soundwire enumeration */
+		usleep_range(100, 110);
+		ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum);
+	} while (ret && --num_retry);
+
 	if (ret) {
-		dev_dbg(&pdev->dev,
-			"%s get devnum %d for dev addr %lx failed\n",
+		dev_info(&pdev->dev,
+			"%s get devnum %d for dev addr %llx failed\n",
 			__func__, swr_devnum, pdev->addr);
 		ret = -EPROBE_DEFER;
-		goto err;
+		goto dev_err;
 	}
 	pdev->dev_num = swr_devnum;
 
@@ -561,10 +586,9 @@ static int swr_dmic_probe(struct swr_device *pdev)
 			strlen(swr_dmic_name_prefix_of) + 1);
 	component->name_prefix = prefix_name;
 
-	if (swr_dmic->is_en_supply == 1) {
-		enable_wcd_codec_supply(swr_dmic, false);
-		--swr_dmic->is_en_supply;
-	}
+	swr_dmic->nblock.notifier_call = swr_dmic_event_notify;
+	wcd938x_swr_dmic_register_notifier(swr_dmic->supply_component,
+					&swr_dmic->nblock, true);
 
 	return 0;
 
@@ -589,7 +613,10 @@ static int swr_dmic_remove(struct swr_device *pdev)
 		dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__);
 		return -EINVAL;
 	}
-
+	if (swr_dmic->is_en_supply == 1) {
+		enable_wcd_codec_supply(swr_dmic, false);
+		--swr_dmic->is_en_supply;
+	}
 	snd_soc_unregister_component(&pdev->dev);
 	swr_set_dev_data(pdev, NULL);
 	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",
@@ -641,7 +670,7 @@ done:
 static int swr_dmic_reset(struct swr_device *pdev)
 {
 	struct swr_dmic_priv *swr_dmic;
-	u8 retry = 5;
+	u8 retry = NUM_ATTEMPTS;
 	u8 devnum = 0;
 
 	swr_dmic = swr_get_dev_data(pdev);
@@ -706,7 +735,6 @@ static struct swr_driver swr_dmic_driver = {
 	.probe = swr_dmic_probe,
 	.remove = swr_dmic_remove,
 	.id_table = swr_dmic_id,
-	.device_down = swr_dmic_down,
 };
 
 static int __init swr_dmic_init(void)

+ 12 - 7
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:
@@ -314,6 +314,7 @@ static int swr_haptics_probe(struct swr_device *sdev)
 	struct swr_haptics_dev *swr_hap;
 	int rc;
 	u8 devnum;
+	int retry = 5;
 
 	swr_hap = devm_kzalloc(&sdev->dev,
 			sizeof(struct swr_haptics_dev), GFP_KERNEL);
@@ -346,8 +347,12 @@ static int swr_haptics_probe(struct swr_device *sdev)
 				__func__, rc);
 		goto clean;
 	}
+	do {
+		/* Add delay for soundwire enumeration */
+		usleep_range(500, 510);
+		rc = swr_get_logical_dev_num(sdev, sdev->addr, &devnum);
+	} while (rc && --retry);
 
-	rc = swr_get_logical_dev_num(sdev, sdev->addr, &devnum);
 	if (rc) {
 		dev_err(swr_hap->dev, "%s: failed to get devnum for swr-haptics, rc=%d\n",
 				__func__, rc);

+ 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);
 

+ 25 - 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);
 }
 
@@ -1619,6 +1621,8 @@ static int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc)
 static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb,
 					   unsigned long mode, void *ptr)
 {
+	unsigned int l_det_en = 0;
+	unsigned int detection_type = 0;
 	struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, fsa_nb);
 
 	if (!mbhc)
@@ -1631,6 +1635,23 @@ static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb,
 			mbhc->mbhc_cb->clk_setup(mbhc->component, true);
 		/* insertion detected, enable L_DET_EN */
 		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
+	} else {
+		WCD_MBHC_REG_READ(WCD_MBHC_MECH_DETECTION_TYPE, detection_type);
+		WCD_MBHC_REG_READ(WCD_MBHC_L_DET_EN, l_det_en);
+		/* If both l_det_en and detection type are set, it means device was
+		 * unplugged during SSR and detection interrupt was not handled.
+		 * So trigger device disconnect */
+		if (detection_type && l_det_en) {
+			/* Set the detection type appropriately */
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE,
+						 !detection_type);
+			/* Set current plug type to the state before SSR */
+			mbhc->current_plug = mbhc->plug_before_ssr;
+
+			wcd_mbhc_swch_irq_handler(mbhc);
+			mbhc->mbhc_cb->lock_sleep(mbhc, false);
+			mbhc->plug_before_ssr = MBHC_PLUG_TYPE_NONE;
+		}
 	}
 	return 0;
 }
@@ -1838,6 +1859,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,

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

@@ -17,6 +17,7 @@
 #define  WCD_VOUT_CTL_TO_MICB(v)  (1000 + v * 50)
 #define MAX_PORT 8
 #define MAX_CH_PER_PORT 8
+#define MAX_TX_PWR_CH 2
 
 #define WCD937X_MAX_SLAVE_PORT_TYPES 10
 extern struct regmap_config wcd937x_regmap_config;
@@ -91,6 +92,7 @@ struct wcd937x_priv {
 	struct mutex ana_tx_clk_lock;
 	u8 tx_master_ch_map[WCD937X_MAX_SLAVE_CH_TYPES];
 	bool usbc_hs_status;
+	u32 tx_ch_pwr[MAX_TX_PWR_CH];
 };
 
 struct wcd937x_micbias_setting {

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

@@ -1777,6 +1777,48 @@ static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int wcd937x_tx_ch_pwr_level_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+	if (strnstr(kcontrol->id.name, "CH1", sizeof(kcontrol->id.name)))
+		ucontrol->value.integer.value[0] = wcd937x->tx_ch_pwr[0];
+	else if (strnstr(kcontrol->id.name, "CH3", sizeof(kcontrol->id.name)))
+		ucontrol->value.integer.value[0] = wcd937x->tx_ch_pwr[1];
+
+	return 0;
+}
+
+static int wcd937x_tx_ch_pwr_level_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+	u32 pwr_level = ucontrol->value.enumerated.item[0];
+
+	dev_dbg(component->dev, "%s: tx ch pwr_level: %d\n",
+		__func__, pwr_level);
+
+	if (strnstr(kcontrol->id.name, "CH1",
+				sizeof(kcontrol->id.name))) {
+		snd_soc_component_update_bits(component,
+				WCD937X_ANA_TX_CH1, 0x60,
+				pwr_level << 0x5);
+		wcd937x->tx_ch_pwr[0] = pwr_level;
+	} else if (strnstr(kcontrol->id.name, "CH3",
+			sizeof(kcontrol->id.name))) {
+		snd_soc_component_update_bits(component,
+				WCD937X_ANA_TX_CH3, 0x60,
+				pwr_level << 0x5);
+		wcd937x->tx_ch_pwr[1] = pwr_level;
+	}
+	return 0;
+}
+
 static int wcd937x_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -2001,6 +2043,10 @@ static int wcd937x_tx_master_ch_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static const char * const wcd937x_tx_ch_pwr_level_text[] = {
+	"L0", "L1", "L2", "L3",
+};
+
 static const char * const wcd937x_ear_pa_gain_text[] = {
 	"G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", "G_0_DB",
 	"G_M1P5_DB", "G_M3_DB", "G_M4P5_DB",
@@ -2016,6 +2062,9 @@ static const struct soc_enum rx_hph_mode_mux_enum =
 static SOC_ENUM_SINGLE_EXT_DECL(wcd937x_ear_pa_gain_enum,
 				wcd937x_ear_pa_gain_text);
 
+static SOC_ENUM_SINGLE_EXT_DECL(wcd937x_tx_ch_pwr_level_enum,
+				wcd937x_tx_ch_pwr_level_text);
+
 static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
 	SOC_ENUM_EXT("EAR PA GAIN", wcd937x_ear_pa_gain_enum,
 		wcd937x_ear_pa_gain_get, wcd937x_ear_pa_gain_put),
@@ -2054,6 +2103,10 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
 			wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put),
 	SOC_ENUM_EXT("DMIC5 ChMap", tx_master_ch_enum,
 			wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put),
+	SOC_ENUM_EXT("TX CH1 PWR", wcd937x_tx_ch_pwr_level_enum,
+		wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put),
+	SOC_ENUM_EXT("TX CH3 PWR", wcd937x_tx_ch_pwr_level_enum,
+		wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put),
 };
 
 static const struct snd_kcontrol_new adc1_switch[] = {
@@ -3114,7 +3167,9 @@ static int wcd937x_bind(struct device *dev)
 		dev_err(dev, "%s: bad micbias pdata\n", __func__);
 		goto err_irq;
 	}
-
+	/* default L1 power setting */
+	wcd937x->tx_ch_pwr[0] = 1;
+	wcd937x->tx_ch_pwr[1] = 1;
 	mutex_init(&wcd937x->micb_lock);
 	mutex_init(&wcd937x->ana_tx_clk_lock);
 	/* Request for watchdog interrupt */

+ 4 - 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;
@@ -105,6 +106,9 @@ struct wcd938x_priv {
 	bool dev_up;
 	u8 tx_master_ch_map[WCD938X_MAX_SLAVE_CH_TYPES];
 	bool usbc_hs_status;
+	/* wcd to swr dmic notification */
+	bool notify_swr_dmic;
+	struct blocking_notifier_head notifier;
 };
 
 struct wcd938x_micbias_setting {

+ 11 - 2
asoc/codecs/wcd938x/wcd938x-slave.c

@@ -24,6 +24,8 @@
 #define SWR_SLV_MAX_DEVICES     2
 #endif /* CONFIG_DEBUG_FS */
 
+#define SWR_MAX_RETRY    5
+
 struct wcd938x_slave_priv {
 	struct swr_device *swr_slave;
 #ifdef CONFIG_DEBUG_FS
@@ -278,17 +280,24 @@ static int wcd938x_slave_bind(struct device *dev,
 	int ret = 0;
 	uint8_t devnum = 0;
 	struct swr_device *pdev = to_swr_device(dev);
+	int retry = SWR_MAX_RETRY;
 
 	if (!pdev) {
 		pr_err("%s: invalid swr device handle\n", __func__);
 		return -EINVAL;
 	}
 
-	ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+	do {
+		/* Add delay for soundwire enumeration */
+		usleep_range(100, 110);
+		ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+	} while (ret && --retry);
+
 	if (ret) {
 		dev_dbg(&pdev->dev,
-			"%s get devnum %d for dev addr %lx failed\n",
+			"%s get devnum %d for dev addr %llx failed\n",
 			__func__, devnum, pdev->addr);
+		ret = -EPROBE_DEFER;
 		return ret;
 	}
 	pdev->dev_num = devnum;

+ 212 - 75
asoc/codecs/wcd938x/wcd938x.c

@@ -72,6 +72,11 @@ enum {
 	HPH_COMP_DELAY,
 	HPH_PA_DELAY,
 	AMIC2_BCS_ENABLE,
+	WCD_SUPPLIES_LPM_MODE,
+	WCD_ADC1_MODE,
+	WCD_ADC2_MODE,
+	WCD_ADC3_MODE,
+	WCD_ADC4_MODE,
 };
 
 enum {
@@ -1540,13 +1545,17 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (strnstr(w->name, "ADC", sizeof("ADC"))) {
-			if (test_bit(WCD_ADC1, &wcd938x->status_mask))
+			if (test_bit(WCD_ADC1, &wcd938x->status_mask) ||
+				test_bit(WCD_ADC1_MODE, &wcd938x->status_mask))
 				mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]];
-			if (test_bit(WCD_ADC2, &wcd938x->status_mask))
+			if (test_bit(WCD_ADC2, &wcd938x->status_mask) ||
+				test_bit(WCD_ADC2_MODE, &wcd938x->status_mask))
 				mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]];
-			if (test_bit(WCD_ADC3, &wcd938x->status_mask))
+			if (test_bit(WCD_ADC3, &wcd938x->status_mask) ||
+				test_bit(WCD_ADC3_MODE, &wcd938x->status_mask))
 				mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]];
-			if (test_bit(WCD_ADC4, &wcd938x->status_mask))
+			if (test_bit(WCD_ADC4, &wcd938x->status_mask) ||
+				test_bit(WCD_ADC4_MODE, &wcd938x->status_mask))
 				mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]];
 
 			if (mode != 0) {
@@ -1593,6 +1602,14 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
 
 		if (strnstr(w->name, "ADC", sizeof("ADC")))
 			wcd938x_set_swr_clk_rate(component, rate, bank);
+		if (strnstr(w->name, "ADC1", sizeof("ADC1")))
+			clear_bit(WCD_ADC1_MODE, &wcd938x->status_mask);
+		else if (strnstr(w->name, "ADC2", sizeof("ADC2")))
+			clear_bit(WCD_ADC2_MODE, &wcd938x->status_mask);
+		else if (strnstr(w->name, "ADC3", sizeof("ADC3")))
+			clear_bit(WCD_ADC3_MODE, &wcd938x->status_mask);
+		else if (strnstr(w->name, "ADC4", sizeof("ADC4")))
+			clear_bit(WCD_ADC4_MODE, &wcd938x->status_mask);
 		break;
 	};
 
@@ -1633,57 +1650,6 @@ static int wcd938x_get_adc_mode(int val)
 	return ret;
 }
 
-static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w,
-				    struct snd_kcontrol *kcontrol,
-				    int event){
-	struct snd_soc_component *component =
-					snd_soc_dapm_to_component(w->dapm);
-	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-	int clk_rate = 0, ret = 0;
-
-	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
-		w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_component_update_bits(component,
-				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08);
-		snd_soc_component_update_bits(component,
-				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
-		set_bit(w->shift, &wcd938x->status_mask);
-		clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]);
-		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
-				 wcd938x->tx_swr_dev->dev_num,
-				 true);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
-				wcd938x->tx_swr_dev->dev_num,
-				false);
-		snd_soc_component_update_bits(component,
-				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00);
-		clear_bit(w->shift, &wcd938x->status_mask);
-		break;
-	};
-
-	return ret;
-}
-
-void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component,
-					    bool bcs_disable)
-{
-	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
-	if (wcd938x->update_wcd_event) {
-		if (bcs_disable)
-			wcd938x->update_wcd_event(wcd938x->handle,
-						WCD_BOLERO_EVT_BCS_CLK_OFF, 0);
-		else
-			wcd938x->update_wcd_event(wcd938x->handle,
-						WCD_BOLERO_EVT_BCS_CLK_OFF, 1);
-	}
-}
-
 int wcd938x_tx_channel_config(struct snd_soc_component *component,
 			      int channel, int mode)
 {
@@ -1724,14 +1690,14 @@ int wcd938x_tx_channel_config(struct snd_soc_component *component,
 	return ret;
 }
 
-static int wcd938x_enable_req(struct snd_soc_dapm_widget *w,
-			      struct snd_kcontrol *kcontrol, int event)
-{
+static int wcd938x_codec_enable_adc(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 mode;
-	int ret = 0;
 	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+	int clk_rate = 0, ret = 0;
+	int mode;
 
 	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
 		w->name, event);
@@ -1739,9 +1705,14 @@ static int wcd938x_enable_req(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		snd_soc_component_update_bits(component,
-				WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02);
+				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08);
 		snd_soc_component_update_bits(component,
-				WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00);
+				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+		set_bit(w->shift, &wcd938x->status_mask);
+		clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]);
+		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
+				 wcd938x->tx_swr_dev->dev_num,
+				 true);
 		ret = wcd938x_tx_channel_config(component, w->shift, 1);
 		mode = wcd938x_get_adc_mode(wcd938x->tx_mode[w->shift]);
 		if (mode < 0) {
@@ -1817,6 +1788,51 @@ static int wcd938x_enable_req(struct snd_soc_dapm_widget *w,
 		default:
 			break;
 		}
+		ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
+				wcd938x->tx_swr_dev->dev_num,
+				false);
+		snd_soc_component_update_bits(component,
+				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00);
+		clear_bit(w->shift, &wcd938x->status_mask);
+		break;
+	};
+
+	return ret;
+}
+
+void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component,
+					    bool bcs_disable)
+{
+	struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+	if (wcd938x->update_wcd_event) {
+		if (bcs_disable)
+			wcd938x->update_wcd_event(wcd938x->handle,
+						WCD_BOLERO_EVT_BCS_CLK_OFF, 0);
+		else
+			wcd938x->update_wcd_event(wcd938x->handle,
+						WCD_BOLERO_EVT_BCS_CLK_OFF, 1);
+	}
+}
+
+static int wcd938x_enable_req(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;
+
+	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+				WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02);
+		snd_soc_component_update_bits(component,
+				WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_component_update_bits(component,
 				WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
 		break;
@@ -1991,15 +2007,16 @@ static int wcd938x_get_logical_addr(struct swr_device *swr_dev)
 	int num_retry = NUM_ATTEMPTS;
 
 	do {
+		/* retry after 1ms */
+		usleep_range(1000, 1010);
 		ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
-		if (ret) {
-			dev_err(&swr_dev->dev,
-				"%s get devnum %d for dev addr %lx failed\n",
-				__func__, devnum, swr_dev->addr);
-			/* retry after 1ms */
-			usleep_range(1000, 1010);
-		}
 	} while (ret && --num_retry);
+
+	if (ret)
+		dev_err(&swr_dev->dev,
+			"%s get devnum %d for dev addr %llx failed\n",
+			__func__, devnum, swr_dev->addr);
+
 	swr_dev->dev_num = devnum;
 	return 0;
 }
@@ -2015,6 +2032,27 @@ static bool get_usbc_hs_status(struct snd_soc_component *component,
 	return false;
 }
 
+int wcd938x_swr_dmic_register_notifier(struct snd_soc_component *component,
+					struct notifier_block *nblock,
+					bool enable)
+{
+	struct wcd938x_priv *wcd938x_priv;
+	if(NULL == component) {
+		pr_err("%s: wcd938x component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd938x_priv = snd_soc_component_get_drvdata(component);
+	wcd938x_priv->notify_swr_dmic = enable;
+	if (enable)
+		return blocking_notifier_chain_register(&wcd938x_priv->notifier,
+							nblock);
+	else
+		return blocking_notifier_chain_unregister(
+				&wcd938x_priv->notifier, nblock);
+}
+EXPORT_SYMBOL(wcd938x_swr_dmic_register_notifier);
+
 static int wcd938x_event_notify(struct notifier_block *block,
 				unsigned long val,
 				void *data)
@@ -2030,21 +2068,25 @@ static int wcd938x_event_notify(struct notifier_block *block,
 		if (test_bit(WCD_ADC1, &wcd938x->status_mask)) {
 			snd_soc_component_update_bits(component,
 					WCD938X_ANA_TX_CH2, 0x40, 0x00);
+			set_bit(WCD_ADC1_MODE, &wcd938x->status_mask);
 			clear_bit(WCD_ADC1, &wcd938x->status_mask);
 		}
 		if (test_bit(WCD_ADC2, &wcd938x->status_mask)) {
 			snd_soc_component_update_bits(component,
 					WCD938X_ANA_TX_CH2, 0x20, 0x00);
+			set_bit(WCD_ADC2_MODE, &wcd938x->status_mask);
 			clear_bit(WCD_ADC2, &wcd938x->status_mask);
 		}
 		if (test_bit(WCD_ADC3, &wcd938x->status_mask)) {
 			snd_soc_component_update_bits(component,
 					WCD938X_ANA_TX_CH4, 0x40, 0x00);
+			set_bit(WCD_ADC3_MODE, &wcd938x->status_mask);
 			clear_bit(WCD_ADC3, &wcd938x->status_mask);
 		}
 		if (test_bit(WCD_ADC4, &wcd938x->status_mask)) {
 			snd_soc_component_update_bits(component,
 					WCD938X_ANA_TX_CH4, 0x20, 0x00);
+			set_bit(WCD_ADC4_MODE, &wcd938x->status_mask);
 			clear_bit(WCD_ADC4, &wcd938x->status_mask);
 		}
 		break;
@@ -2058,7 +2100,13 @@ static int wcd938x_event_notify(struct notifier_block *block,
 		break;
 	case BOLERO_WCD_EVT_SSR_DOWN:
 		wcd938x->dev_up = false;
+		if(wcd938x->notify_swr_dmic)
+			blocking_notifier_call_chain(&wcd938x->notifier,
+						     WCD938X_EVT_SSR_DOWN,
+						     NULL);
 		wcd938x->mbhc->wcd_mbhc.deinit_in_progress = true;
+		wcd938x->mbhc->wcd_mbhc.plug_before_ssr =
+					wcd938x->mbhc->wcd_mbhc.current_plug;
 		mbhc = &wcd938x->mbhc->wcd_mbhc;
 		wcd938x->usbc_hs_status = get_usbc_hs_status(component,
 						mbhc->mbhc_cfg);
@@ -2089,6 +2137,10 @@ static int wcd938x_event_notify(struct notifier_block *block,
 		}
 		wcd938x->mbhc->wcd_mbhc.deinit_in_progress = false;
 		wcd938x->dev_up = true;
+		if(wcd938x->notify_swr_dmic)
+			blocking_notifier_call_chain(&wcd938x->notifier,
+						     WCD938X_EVT_SSR_UP,
+						     NULL);
 		break;
 	case BOLERO_WCD_EVT_CLK_NOTIFY:
 		snd_soc_component_update_bits(component,
@@ -2272,6 +2324,9 @@ static int wcd938x_enable_micbias(struct wcd938x_priv *wcd938x,
 		return -EINVAL;
 	};
 
+	pr_debug("%s: req: %d micb_num: %d  micb_ref: %d pullup_ref: %d\n",
+		__func__, req, micb_num, wcd938x->micb_ref[micb_index],
+		wcd938x->pullup_ref[micb_index]);
 	mutex_lock(&wcd938x->micb_lock);
 
 	switch (req) {
@@ -2336,6 +2391,8 @@ int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component,
 					int event, int micb_num)
 {
 	struct wcd938x_priv *wcd938x_priv = NULL;
+	int ret = 0;
+	int micb_index = micb_num - 1;
 
 	if(NULL == component) {
 		pr_err("%s: wcd938x component is NULL\n", __func__);
@@ -2352,6 +2409,15 @@ int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component,
 
 	wcd938x_priv = snd_soc_component_get_drvdata(component);
 
+	if (!wcd938x_priv->dev_up) {
+		if ((wcd938x_priv->pullup_ref[micb_index] > 0) &&
+			(event == SND_SOC_DAPM_POST_PMD)) {
+			wcd938x_priv->pullup_ref[micb_index]--;
+			ret = -ENODEV;
+			goto done;
+		}
+	}
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		wcd938x_wakeup(wcd938x_priv, true);
@@ -2365,7 +2431,8 @@ int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component,
 		break;
 	}
 
-	return 0;
+done:
+	return ret;
 }
 EXPORT_SYMBOL(wcd938x_codec_force_enable_micbias_v2);
 
@@ -3050,9 +3117,17 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("AMIC5"),
 	SND_SOC_DAPM_INPUT("AMIC6"),
 	SND_SOC_DAPM_INPUT("AMIC7"),
+
 	SND_SOC_DAPM_INPUT("IN1_HPHL"),
 	SND_SOC_DAPM_INPUT("IN2_HPHR"),
 	SND_SOC_DAPM_INPUT("IN3_AUX"),
+	/*
+	 * These dummy widgets are null connected to WCD938x dapm input and
+	 * output widgets which are not actual path endpoints. This ensures
+	 * dapm doesnt set these dapm input and output widgets as endpoints.
+	 */
+	SND_SOC_DAPM_INPUT("WCD_TX_DUMMY"),
+	SND_SOC_DAPM_OUTPUT("WCD_RX_DUMMY"),
 
 	/*tx widgets*/
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -3289,6 +3364,7 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
 
+	{"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"},
 	{"WCD_TX_OUTPUT", NULL, "ADC1_MIXER"},
 	{"ADC1_MIXER", "Switch", "ADC1 REQ"},
 	{"ADC1 REQ", NULL, "ADC1"},
@@ -3343,6 +3419,7 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
 	{"WCD_TX_OUTPUT", NULL, "DMIC8_MIXER"},
 	{"DMIC8_MIXER", "Switch", "DMIC8"},
 
+	{"IN1_HPHL", NULL, "WCD_RX_DUMMY"},
 	{"IN1_HPHL", NULL, "VDD_BUCK"},
 	{"IN1_HPHL", NULL, "CLS_H_PORT"},
 	{"RX1", NULL, "IN1_HPHL"},
@@ -3351,6 +3428,7 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
 	{"HPHL PGA", NULL, "HPHL_RDAC"},
 	{"HPHL", NULL, "HPHL PGA"},
 
+	{"IN2_HPHR", NULL, "WCD_RX_DUMMY"},
 	{"IN2_HPHR", NULL, "VDD_BUCK"},
 	{"IN2_HPHR", NULL, "CLS_H_PORT"},
 	{"RX2", NULL, "IN2_HPHR"},
@@ -3359,6 +3437,7 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
 	{"HPHR PGA", NULL, "HPHR_RDAC"},
 	{"HPHR", NULL, "HPHR PGA"},
 
+	{"IN3_AUX", NULL, "WCD_RX_DUMMY"},
 	{"IN3_AUX", NULL, "VDD_BUCK"},
 	{"IN3_AUX", NULL, "CLS_H_PORT"},
 	{"RX3", NULL, "IN3_AUX"},
@@ -3634,6 +3713,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");
@@ -3649,6 +3730,8 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
 	snd_soc_dapm_ignore_suspend(dapm, "AUX");
 	snd_soc_dapm_ignore_suspend(dapm, "HPHL");
 	snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+	snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_DUMMY");
+	snd_soc_dapm_ignore_suspend(dapm, "WCD_RX_DUMMY");
 	snd_soc_dapm_sync(dapm);
 
 	wcd_cls_h_init(&wcd938x->clsh_info);
@@ -3688,7 +3771,6 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
 			return ret;
 		}
 	}
-	wcd938x->dev_up = true;
 	return ret;
 
 err_hwdep:
@@ -3713,6 +3795,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 +3825,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)
@@ -4026,6 +4130,7 @@ static int wcd938x_bind(struct device *dev)
 				__func__);
 		goto err_irq;
 	}
+	wcd938x->dev_up = true;
 
 	return ret;
 err_irq:
@@ -4242,19 +4347,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
 

+ 9 - 0
asoc/codecs/wcd938x/wcd938x.h

@@ -17,6 +17,12 @@ enum {
 	WCD9385 = 5,
 };
 
+/* from WCD to SWR DMIC events */
+enum {
+	WCD938X_EVT_SSR_DOWN,
+	WCD938X_EVT_SSR_UP,
+};
+
 struct swr_slave_ch_map {
 	u8 ch_type;
 	u8 index;
@@ -62,6 +68,9 @@ int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root,
 int wcd938x_get_codec_variant(struct snd_soc_component *component);
 int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *wcd938x,
 					int event, int micb_num);
+int wcd938x_swr_dmic_register_notifier(struct snd_soc_component *wcd938x,
+                                        struct notifier_block *nblock,
+                                        bool enable);
 
 static inline int wcd938x_slave_get_master_ch_val(int ch)
 {

+ 3 - 2
asoc/codecs/wsa881x.c

@@ -1083,6 +1083,9 @@ static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
 					      0x80, 0x00);
 		if (wsa881x->visense_enable) {
 			wsa881x_visense_adc_ctrl(component, DISABLE);
+			snd_soc_component_update_bits(component,
+						WSA881X_ADC_EN_SEL_IBAIS,
+						0x07, 0x00);
 			wsa881x_visense_txfe_ctrl(component, DISABLE,
 						0x00, 0x01, 0x01);
 		}
@@ -1614,8 +1617,6 @@ static int wsa881x_swr_down(struct swr_device *pdev)
 	else
 		wsa881x->state = WSA881X_DEV_DOWN;
 
-	if (delayed_work_pending(&wsa881x->ocp_ctl_work))
-		cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
 	return ret;
 }
 

+ 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;

+ 93 - 3
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__);
@@ -598,9 +620,14 @@ static int wsa_get_temp(struct snd_kcontrol *kcontrol,
 {
 	struct snd_soc_component *component =
 			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
 	int temp = 0;
 
-	wsa883x_get_temperature(component, &temp);
+	if (test_bit(SPKR_STATUS, &wsa883x->status_mask))
+		temp = wsa883x->curr_temp;
+	else
+		wsa883x_get_temperature(component, &temp);
+
 	ucontrol->value.integer.value[0] = temp;
 
 	return 0;
@@ -989,6 +1016,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 +1026,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 +1215,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 +1236,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 +1255,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 +1287,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 +1513,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 +1548,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 +1761,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 +1786,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[] = {

+ 4 - 2
asoc/kona.c

@@ -47,9 +47,11 @@
 #define DEV_NAME_STR_LEN            32
 #define WCD_MBHC_HS_V_MAX           1600
 
-#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
 

+ 57 - 95
asoc/lahaina.c

@@ -384,9 +384,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 	{
 		.name = LPASS_BE_RT_PROXY_PCM_TX,
 		.stream_name = LPASS_BE_RT_PROXY_PCM_TX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -398,9 +395,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 	{
 		.name = LPASS_BE_RT_PROXY_PCM_RX,
 		.stream_name = LPASS_BE_RT_PROXY_PCM_RX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -412,9 +406,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 	{
 		.name = LPASS_BE_USB_AUDIO_RX,
 		.stream_name = LPASS_BE_USB_AUDIO_RX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -426,9 +417,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
 	{
 		.name = LPASS_BE_USB_AUDIO_TX,
 		.stream_name = LPASS_BE_USB_AUDIO_TX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -442,9 +430,6 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
 	{
 		.name = LPASS_BE_SLIMBUS_7_RX,
 		.stream_name = LPASS_BE_SLIMBUS_7_RX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -458,9 +443,6 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
 	{
 		.name = LPASS_BE_SLIMBUS_7_TX,
 		.stream_name = LPASS_BE_SLIMBUS_7_TX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -476,9 +458,6 @@ static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
 	{
 		.name = LPASS_BE_DISPLAY_PORT_RX,
 		.stream_name = LPASS_BE_DISPLAY_PORT_RX,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -486,22 +465,6 @@ static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
 		.ignore_suspend = 1,
 		SND_SOC_DAILINK_REG(display_port),
 	},
-#if 0
-	/* DISP PORT 1 BACK END DAI Link */
-	{
-		.name = LPASS_BE_DISPLAY_PORT1,
-		.stream_name = LPASS_BE_DISPLAY_PORT1,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
-		.playback_only = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-		SND_SOC_DAILINK_REG(display_port1),
-	},
-#endif
 };
 #endif
 
@@ -510,9 +473,6 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_WSA_CDC_DMA_RX_0,
 		.stream_name = LPASS_BE_WSA_CDC_DMA_RX_0,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -525,9 +485,6 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_WSA_CDC_DMA_RX_1,
 		.stream_name = LPASS_BE_WSA_CDC_DMA_RX_1,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -539,9 +496,6 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_WSA_CDC_DMA_TX_1,
 		.stream_name = LPASS_BE_WSA_CDC_DMA_TX_1,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -556,9 +510,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_RX_CDC_DMA_RX_0,
 		.stream_name = LPASS_BE_RX_CDC_DMA_RX_0,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -571,9 +522,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_RX_CDC_DMA_RX_1,
 		.stream_name = LPASS_BE_RX_CDC_DMA_RX_1,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -581,13 +529,11 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 		.ignore_suspend = 1,
 		.ops = &msm_common_be_ops,
 		SND_SOC_DAILINK_REG(rx_dma_rx1),
+		.init = &msm_int_audrx_init,
 	},
 	{
 		.name = LPASS_BE_RX_CDC_DMA_RX_2,
 		.stream_name = LPASS_BE_RX_CDC_DMA_RX_2,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -599,9 +545,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_RX_CDC_DMA_RX_3,
 		.stream_name = LPASS_BE_RX_CDC_DMA_RX_3,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -610,12 +553,20 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 		.ops = &msm_common_be_ops,
 		SND_SOC_DAILINK_REG(rx_dma_rx3),
 	},
+	{
+		.name = LPASS_BE_RX_CDC_DMA_RX_5,
+		.stream_name = LPASS_BE_RX_CDC_DMA_RX_5,
+		.playback_only = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+		.ops = &msm_common_be_ops,
+		SND_SOC_DAILINK_REG(rx_dma_rx5),
+	},
 	{
 		.name = LPASS_BE_RX_CDC_DMA_RX_6,
 		.stream_name = LPASS_BE_RX_CDC_DMA_RX_6,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.playback_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -628,9 +579,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_TX_CDC_DMA_TX_3,
 		.stream_name = LPASS_BE_TX_CDC_DMA_TX_3,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -641,9 +589,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_TX_CDC_DMA_TX_4,
 		.stream_name = LPASS_BE_TX_CDC_DMA_TX_4,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -657,9 +602,6 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_VA_CDC_DMA_TX_0,
 		.stream_name = LPASS_BE_VA_CDC_DMA_TX_0,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -670,9 +612,6 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_VA_CDC_DMA_TX_1,
 		.stream_name = LPASS_BE_VA_CDC_DMA_TX_1,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -683,9 +622,6 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = {
 	{
 		.name = LPASS_BE_VA_CDC_DMA_TX_2,
 		.stream_name = LPASS_BE_VA_CDC_DMA_TX_2,
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-#endif /* CONFIG_AUDIO_QGKI */
 		.capture_only = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -855,6 +791,45 @@ static const struct of_device_id lahaina_asoc_machine_of_match[]  = {
 	{},
 };
 
+static int msm_snd_card_late_probe(struct snd_soc_card *card)
+{
+	struct snd_soc_component *component = NULL;
+	const char *be_dl_name = LPASS_BE_RX_CDC_DMA_RX_0;
+	struct snd_soc_pcm_runtime *rtd;
+	int ret = 0;
+	void *mbhc_calibration;
+
+	rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+	if (!rtd) {
+		dev_err(card->dev,
+			"%s: snd_soc_get_pcm_runtime for %s failed!\n",
+			__func__, be_dl_name);
+		return -EINVAL;
+	}
+
+	component = snd_soc_rtdcom_lookup(rtd, WCD938X_DRV_NAME);
+	if (!component) {
+		pr_err("%s component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mbhc_calibration = def_wcd_mbhc_cal();
+	if (!mbhc_calibration)
+		return -ENOMEM;
+	wcd_mbhc_cfg.calibration = mbhc_calibration;
+	ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
+	if (ret) {
+		dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n",
+			__func__, ret);
+		goto err_hs_detect;
+	}
+	return 0;
+
+err_hs_detect:
+	kfree(mbhc_calibration);
+	return ret;
+}
+
 static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 {
 	struct snd_soc_card *card = NULL;
@@ -934,6 +909,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 	if (card) {
 		card->dai_link = dailink;
 		card->num_links = total_links;
+		card->late_probe = msm_snd_card_late_probe;
 	}
 
 	return card;
@@ -958,6 +934,10 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
 				snd_soc_card_get_drvdata(rtd->card);
 	int ret = 0;
 
+	if (codec_reg_done) {
+		return 0;
+	}
+
     if (pdata->wsa_max_devs > 0) {
         component = snd_soc_rtdcom_lookup(rtd, "wsa-codec.1");
         if (!component) {
@@ -1064,8 +1044,6 @@ static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_component *component = NULL;
 	struct snd_soc_dapm_context *dapm = NULL;
-	int ret = 0;
-	void *mbhc_calibration;
 	struct snd_info_entry *entry;
 	struct snd_card *card = NULL;
 	struct msm_asoc_mach_data *pdata;
@@ -1095,8 +1073,7 @@ static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd)
 		if (!entry) {
 			dev_dbg(component->dev, "%s: Cannot create codecs module entry\n",
 				 __func__);
-			ret = 0;
-			goto mbhc_cfg_cal;
+			 return 0;
 		}
 		pdata->codec_root = entry;
 	}
@@ -1121,23 +1098,8 @@ static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd)
 	}
 #endif
 
-mbhc_cfg_cal:
-	mbhc_calibration = def_wcd_mbhc_cal();
-	if (!mbhc_calibration)
-		return -ENOMEM;
-	wcd_mbhc_cfg.calibration = mbhc_calibration;
-	ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
-	if (ret) {
-		dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n",
-			__func__, ret);
-		goto err_hs_detect;
-	}
 	msm_common_dai_link_init(rtd);
 	return 0;
-
-err_hs_detect:
-	kfree(mbhc_calibration);
-	return ret;
 }
 
 static int lahaina_ssr_enable(struct device *dev, void *data)

+ 4 - 0
asoc/msm-compress-q6-v2.h

@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+*/
+int msm_compr_new(struct snd_soc_pcm_runtime *rtd, int num);

+ 6 - 2
asoc/msm_dailink.h

@@ -5,7 +5,6 @@
 
 #include <sound/soc.h>
 
-
 SND_SOC_DAILINK_DEFS(usb_audio_rx,
 	DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")),
 	DAILINK_COMP_ARRAY(COMP_DUMMY()),
@@ -16,7 +15,6 @@ SND_SOC_DAILINK_DEFS(usb_audio_tx,
 	DAILINK_COMP_ARRAY(COMP_DUMMY()),
 	DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy")));
 
-
 SND_SOC_DAILINK_DEFS(slimbus_7_rx,
 	DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")),
 	DAILINK_COMP_ARRAY(COMP_CODEC("btfmslim_slave",
@@ -96,6 +94,12 @@ SND_SOC_DAILINK_DEFS(rx_dma_rx3,
 			   COMP_CODEC("wcd938x_codec", "wcd938x_cdc")),
 	DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy")));
 
+SND_SOC_DAILINK_DEFS(rx_dma_rx5,
+	DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx5"),
+			   COMP_CODEC("wcd938x_codec", "wcd938x_cdc")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy")));
+
 SND_SOC_DAILINK_DEFS(rx_dma_rx6,
 	DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")),
 	DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx6"),

+ 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

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

+ 108 - 24
dsp/adsp-loader.c

@@ -28,6 +28,7 @@ enum apr_subsys_state {
         APR_SUBSYS_DOWN,
         APR_SUBSYS_UP,
         APR_SUBSYS_LOADED,
+	APR_SUBSYS_UNKNOWN,
 };
 
 static ssize_t adsp_boot_store(struct kobject *kobj,
@@ -61,6 +62,53 @@ static struct work_struct adsp_ldr_work;
 static struct platform_device *adsp_private;
 static void adsp_loader_unload(struct platform_device *pdev);
 
+static int adsp_restart_subsys(void)
+{
+	struct subsys_device *adsp_dev = NULL;
+	struct platform_device *pdev = adsp_private;
+	struct adsp_loader_private *priv = NULL;
+	int rc = -EINVAL;
+
+	priv = platform_get_drvdata(pdev);
+	if (!priv)
+		return rc;
+
+	adsp_dev = (struct subsys_device *)priv->pil_h;
+	if (!adsp_dev)
+		return rc;
+
+	/* subsystem_restart_dev has worker queue to handle */
+	rc = subsystem_restart_dev(adsp_dev);
+	if (rc) {
+		dev_err(&pdev->dev, "subsystem_restart_dev failed\n");
+		return rc;
+	}
+	pr_debug("%s :: Restart Success %d\n", __func__, rc);
+	return rc;
+}
+
+#if 0
+static void adsp_load_state_notify_cb(enum apr_subsys_state state,
+						void *phandle)
+{
+	struct platform_device *pdev = adsp_private;
+	struct adsp_loader_private *priv = NULL;
+
+	priv = platform_get_drvdata(pdev);
+	if (!priv)
+		return;
+	if (phandle != adsp_private) {
+		pr_err("%s:callback is not for adsp-loader client\n", __func__);
+		return;
+	}
+	pr_debug("%s:: Received cb for ADSP restart\n", __func__);
+	if (state == APR_SUBSYS_UNKNOWN)
+		adsp_restart_subsys();
+	else
+		pr_debug("%s:Ignore restart request for ADSP", __func__);
+}
+#endif
+
 static void adsp_load_fw(struct work_struct *adsp_ldr_work)
 {
 	struct platform_device *pdev = adsp_private;
@@ -69,6 +117,7 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work)
 	int rc = 0;
 	u32 adsp_state;
 	const char *img_name;
+//	void *padsp_restart_cb = &adsp_load_state_notify_cb;
 
 	if (!pdev) {
 		dev_err(&pdev->dev, "%s: Platform device null\n", __func__);
@@ -125,7 +174,7 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work)
 		}
 
 		dev_dbg(&pdev->dev, "%s: Q6/MDSP image is loaded\n", __func__);
-		return;
+		goto success;
 	}
 
 load_adsp:
@@ -159,10 +208,13 @@ load_adsp:
 		}
 
 		dev_dbg(&pdev->dev, "%s: Q6/ADSP image is loaded\n", __func__);
-		return;
+//		apr_register_adsp_state_cb(padsp_restart_cb, adsp_private);
+		goto success;
 	}
 fail:
 	dev_err(&pdev->dev, "%s: Q6 image loading failed\n", __func__);
+success:
+	return;
 }
 
 static void adsp_loader_do(struct platform_device *pdev)
@@ -176,37 +228,24 @@ static ssize_t adsp_ssr_store(struct kobject *kobj,
 	size_t count)
 {
 	int ssr_command = 0;
-	struct subsys_device *adsp_dev = NULL;
 	struct platform_device *pdev = adsp_private;
 	struct adsp_loader_private *priv = NULL;
-	int rc;
+	int rc = -EINVAL;
 
 	dev_dbg(&pdev->dev, "%s: going to call adsp ssr\n ", __func__);
 
-	if (kstrtoint(buf, 10, &ssr_command) < 0)
-		return -EINVAL;
-
-	if (ssr_command != SSR_RESET_CMD)
-		return -EINVAL;
-
 	priv = platform_get_drvdata(pdev);
 	if (!priv)
-		return -EINVAL;
+		return rc;
 
-	adsp_dev = (struct subsys_device *)priv->pil_h;
-	if (!adsp_dev)
+	if (kstrtoint(buf, 10, &ssr_command) < 0)
 		return -EINVAL;
 
-	dev_err(&pdev->dev, "requesting for ADSP restart\n");
-
-	/* subsystem_restart_dev has worker queue to handle */
-	rc = subsystem_restart_dev(adsp_dev);
-	if (rc) {
-		dev_err(&pdev->dev, "subsystem_restart_dev failed\n");
-		return rc;
-	}
+	if (ssr_command != SSR_RESET_CMD)
+		return -EINVAL;
 
-	dev_dbg(&pdev->dev, "ADSP restarted\n");
+	adsp_restart_subsys();
+	dev_dbg(&pdev->dev, "%s :: ADSP restarted\n", __func__);
 	return count;
 }
 
@@ -339,6 +378,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) {
@@ -350,15 +391,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);
 

+ 12 - 0
dsp/audio_notifier.c

@@ -606,6 +606,7 @@ static int __init audio_notifier_late_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_MSM_QDSP6_PDR
 static int __init audio_notifier_init(void)
 {
 	int ret;
@@ -624,6 +625,17 @@ static int __init audio_notifier_init(void)
 
 	return 0;
 }
+#else
+static int __init audio_notifier_init(void)
+{
+	audio_notifier_subsys_init();
+	audio_notifier_disable_service(AUDIO_NOTIFIER_PDR_SERVICE);
+
+	audio_notifier_late_init();
+
+	return 0;
+}
+#endif
 module_init(audio_notifier_init);
 
 static void __exit audio_notifier_exit(void)

+ 2 - 2
dsp/digital-cdc-rsc-mgr.c

@@ -87,13 +87,13 @@ void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle)
 }
 EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_reset);
 
-void digital_cdc_rsc_mgr_init()
+void digital_cdc_rsc_mgr_init(void)
 {
 	mutex_init(&hw_vote_lock);
 	is_init_done = true;
 }
 
-void digital_cdc_rsc_mgr_exit()
+void digital_cdc_rsc_mgr_exit(void)
 {
 	mutex_destroy(&hw_vote_lock);
 	is_init_done = false;

+ 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,

+ 13 - 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);
@@ -541,6 +551,7 @@ struct wcd_mbhc {
 	wait_queue_head_t wait_btn_press;
 	bool is_btn_press;
 	u8 current_plug;
+	u8 plug_before_ssr;
 	bool in_swch_irq_handler;
 	bool hphl_swh; /*track HPHL switch NC / NO */
 	bool gnd_swh; /*track GND switch NC / NO */
@@ -551,6 +562,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;

+ 127 - 1
include/dsp/apr_audio-v2.h

@@ -598,7 +598,7 @@ struct adm_cmd_device_open_v8 {
  * In all other use cases this should be set to 0xffff
  */
 
-	u16                  reserved;
+	u16 compressed_data_type;
 } __packed;
 
 /*
@@ -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 */
@@ -2554,6 +2557,7 @@ struct afe_port_data_cmd_rt_proxy_port_read_v2 {
 #define AFE_GENERIC_COMPRESSED           0x8
 #define AFE_LINEAR_PCM_DATA_PACKED_16BIT 0X6
 #define AFE_DSD_DOP_W_MARKER_DATA        0x9
+#define AFE_DSD_DATA                     0xA
 
 /* This param id is used to configure I2S interface */
 #define AFE_PARAM_ID_I2S_CONFIG	0x0001020D
@@ -4139,6 +4143,16 @@ struct afe_id_aptx_adaptive_enc_init
 #define AFE_MODULE_ID_DEPACKETIZER_COP        0x00013233
 #define AFE_MODULE_ID_DEPACKETIZER_COP_V1     0x000132E9
 
+/* Macros for dynamic loading of modules by AVCS */
+
+#define AVS_MODULE_ID_PACKETIZER_COP        0x0001322A
+
+#define AVS_MODULE_ID_PACKETIZER_COP_V1     0x000132E8
+
+#define AVS_MODULE_ID_DEPACKETIZER_COP      0x00013233
+
+#define AVS_MODULE_ID_DEPACKETIZER_COP_V1   0x000132E9
+
 /*
  * Depacketizer type parameter for the #AVS_MODULE_ID_DECODER module.
  * This parameter cannot be set runtime.
@@ -4734,6 +4748,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 +4940,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 +4956,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 +5460,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
@@ -8887,6 +8968,13 @@ struct asm_data_cmd_remove_silence {
 /* Shift value for the IEC 61937 to 61937 pass-through capture. */
 #define ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG           0
 
+/* Bitmask for the DSD pass-through capture. */
+#define ASM_BIT_MASK_COMPRESSED_FORMAT_FLAG             (0x00000003UL)
+
+/* Shift value for the DSD pass-through capture. */
+#define ASM_SHIFT_DSD_COMPRESSED_FORMAT_FLAG            0
+
+#define ASM_DSD_FORMAT_FLAG                             2
 struct asm_stream_cmd_open_read_compressed {
 	struct apr_hdr hdr;
 	u32                    mode_flags;
@@ -8898,6 +8986,12 @@ struct asm_stream_cmd_open_read_compressed {
  * - Use #ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG to set the bitmask
  *   and #ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG to set the shift value
  *   for this bit.
+ * Supported values for bit 1: (DSD native pass-through mode)
+ * 0 -- non DSD operation
+ * 1 -- Pass-through transfer of the DSD format stream
+ * To set this bit, use #ASM_BIT_MASK_DSD_PASS_THROUGH_FLAG and
+ * use #ASM_SHIFT_DSD_PASS_THROUGH_FLAG to set the shift value for
+ * this bit
  * Supported values for bit 4:
  * - 0 -- Return data buffer contains all encoded frames only; it does
  *      not contain frame metadata.
@@ -8914,6 +9008,9 @@ struct asm_stream_cmd_open_read_compressed {
  * Supported values: should be greater than 0 for IEC to RAW compressed
  *                   unpack mode.
  *                   Value is don't care for IEC 61937 pass-through mode.
+ * @values
+ * - >0 -- For IEC 61937-to-RAW Compressed Unpack mode
+ * - 1  -- For IEC 61937 or DSD Pass-through mode
  */
 
 } __packed;
@@ -12102,6 +12199,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,

+ 10 - 1
include/ipc/apr.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2017, 2019, 2020, The Linux Foundation. All rights reserved.
  */
 #ifndef __APR_H_
 #define __APR_H_
@@ -12,6 +12,7 @@ enum apr_subsys_state {
 	APR_SUBSYS_DOWN,
 	APR_SUBSYS_UP,
 	APR_SUBSYS_LOADED,
+	APR_SUBSYS_UNKNOWN,
 };
 
 struct apr_q6 {
@@ -19,6 +20,13 @@ struct apr_q6 {
 	atomic_t q6_state;
 	atomic_t modem_state;
 	struct mutex lock;
+/*
+ * ToDo - Multiple client support to be added.
+ * And checking for state UNKNOWN currently.
+ */
+	void (*state_notify_cb)(enum apr_subsys_state state,
+				void *client_handle);
+	void *client_handle;
 };
 
 struct apr_hdr {
@@ -186,4 +194,5 @@ const char *apr_get_lpass_subsys_name(void);
 uint16_t apr_get_reset_domain(uint16_t proc);
 int apr_start_rx_rt(void *handle);
 int apr_end_rx_rt(void *handle);
+void apr_register_adsp_state_cb(void *adsp_cb, void *client_handle);
 #endif

+ 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,

+ 4 - 1
soc/pinctrl-lpi.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/gpio.h>
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/clk.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 #include <soc/snd_event.h>
 #include <dsp/digital-cdc-rsc-mgr.h>
 #include <linux/pm_runtime.h>
@@ -489,6 +490,8 @@ static int lpi_notifier_service_cb(struct notifier_block *this,
 
 		/* Reset HW votes after SSR */
 		if (!lpi_dev_up) {
+			/* Add 100ms sleep to ensure AVS is up after SSR */
+			msleep(100);
 			if (state->lpass_core_hw_vote)
 				digital_cdc_rsc_mgr_hw_vote_reset(
 					state->lpass_core_hw_vote);

+ 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;
 }

+ 49 - 36
soc/swr-mstr-ctrl.c

@@ -41,7 +41,6 @@
 #define SWRM_DSD_PARAMS_PORT 4
 
 #define SWR_BROADCAST_CMD_ID            0x0F
-#define SWR_AUTO_SUSPEND_DELAY          1 /* delay in sec */
 #define SWR_DEV_ID_MASK			0xFFFFFFFFFFFF
 #define SWR_REG_VAL_PACK(data, dev, id, reg)	\
 			((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
@@ -82,7 +81,7 @@
 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT    0x08
 
 /* pm runtime auto suspend timer in msecs */
-static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
+static int auto_suspend_timer = 500;
 module_param(auto_suspend_timer, int, 0664);
 MODULE_PARM_DESC(auto_suspend_timer, "timer for auto suspend");
 
@@ -121,7 +120,7 @@ static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm);
 static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);
 static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
 static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);
-
+static int swrm_runtime_resume(struct device *dev);
 
 static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq)
 {
@@ -647,6 +646,7 @@ static int swr_master_bulk_write(struct swr_mstr_ctrl *swrm, u32 *reg_addr,
 			usleep_range(50, 55);
 			swr_master_write(swrm, reg_addr[i], val[i]);
 		}
+		usleep_range(100, 110);
 		mutex_unlock(&swrm->iolock);
 	}
 	return 0;
@@ -901,6 +901,8 @@ static int swrm_read(struct swr_master *master, u8 dev_num, u16 reg_addr,
 	mutex_unlock(&swrm->devlock);
 
 	pm_runtime_get_sync(swrm->dev);
+	if (swrm->req_clk_switch)
+		swrm_runtime_resume(swrm->dev);
 	ret = swrm_cmd_fifo_rd_cmd(swrm, &val, dev_num, 0, reg_addr, len);
 
 	if (!ret)
@@ -934,6 +936,8 @@ static int swrm_write(struct swr_master *master, u8 dev_num, u16 reg_addr,
 	mutex_unlock(&swrm->devlock);
 
 	pm_runtime_get_sync(swrm->dev);
+	if (swrm->req_clk_switch)
+		swrm_runtime_resume(swrm->dev);
 	ret = swrm_cmd_fifo_wr_cmd(swrm, reg_val, dev_num, 0, reg_addr);
 
 	pm_runtime_put_autosuspend(swrm->dev);
@@ -1105,6 +1109,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;
 
@@ -1871,7 +1877,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;
 			}
@@ -1923,16 +1929,22 @@ handle_irq:
 				swrm->intr_mask);
 			break;
 		case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW:
-			dev_dbg(swrm->dev, "%s: SWR read FIFO overflow\n",
-				__func__);
+			value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS);
+			dev_err(swrm->dev,
+				"%s: SWR read FIFO overflow fifo status\n",
+				__func__, value);
 			break;
 		case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW:
-			dev_dbg(swrm->dev, "%s: SWR read FIFO underflow\n",
-				__func__);
+			value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS);
+			dev_err(swrm->dev,
+				"%s: SWR read FIFO underflow fifo status\n",
+				__func__, value);
 			break;
 		case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW:
-			dev_dbg(swrm->dev, "%s: SWR write FIFO overflow\n",
-				__func__);
+			value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS);
+			dev_err(swrm->dev,
+				"%s: SWR write FIFO overflow fifo status\n",
+				__func__, value);
 			swr_master_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
 			break;
 		case SWRM_INTERRUPT_STATUS_CMD_ERROR:
@@ -2175,17 +2187,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);
@@ -2659,6 +2673,8 @@ static int swrm_probe(struct platform_device *pdev)
 	 * controller will be up now
 	 */
 	swr_master_add_boarddevices(&swrm->master);
+	if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true))
+		dev_dbg(&pdev->dev, "%s: Audio HW Vote is failed\n", __func__);
 	mutex_lock(&swrm->mlock);
 	swrm_clk_request(swrm, true);
 	swrm->version = swr_master_read(swrm, SWRM_COMP_HW_VERSION);
@@ -2721,13 +2737,13 @@ err_mstr_fail:
 		swrm->reg_irq(swrm->handle, swr_mstr_interrupt,
 				swrm, SWR_IRQ_FREE);
 	} 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);
+		free_irq(swrm->irq, swrm);
 	}
-	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);
@@ -2751,15 +2767,15 @@ static int swrm_remove(struct platform_device *pdev)
 		swrm->reg_irq(swrm->handle, swr_mstr_interrupt,
 				swrm, SWR_IRQ_FREE);
 	} 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);
+		free_irq(swrm->irq, swrm);
 	} 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);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
@@ -2799,7 +2815,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;
@@ -2815,11 +2830,9 @@ static int swrm_runtime_resume(struct device *dev)
 			__func__);
 		hw_core_err = true;
 	}
-	if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, 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 ((swrm->state == SWR_MSTR_DOWN) ||
 	    (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) {
@@ -2911,8 +2924,6 @@ static int swrm_runtime_resume(struct device *dev)
 		swrm->state = SWR_MSTR_UP;
 	}
 exit:
-	if (!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);
 	if (swrm_clk_req_err)
@@ -2921,6 +2932,8 @@ exit:
 	else
 		pm_runtime_set_autosuspend_delay(&pdev->dev,
 				auto_suspend_timer);
+	if (swrm->req_clk_switch)
+		swrm->req_clk_switch = false;
 	mutex_unlock(&swrm->reslock);
 
 	trace_printk("%s: pm_runtime: resume done, state:%d\n",
@@ -2934,7 +2947,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;
@@ -2953,11 +2965,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)) {
@@ -3036,12 +3043,14 @@ static int swrm_runtime_suspend(struct device *dev)
 		}
 
 	}
+	if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false))
+		dev_dbg(dev, "%s:lpass audio hw enable failed\n",
+			__func__);
+
 	/* Retain  SSR state until resume */
 	if (current_state != SWR_MSTR_SSR)
 		swrm->state = SWR_MSTR_DOWN;
 exit:
-	if (!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);
 	mutex_unlock(&swrm->reslock);
@@ -3214,8 +3223,12 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 		}
 		mutex_lock(&swrm->mlock);
 		if (swrm->clk_src != *(int *)data) {
-			if (swrm->state == SWR_MSTR_UP)
+			if (swrm->state == SWR_MSTR_UP) {
+				swrm->req_clk_switch = true;
 				swrm_device_suspend(&pdev->dev);
+				if (swrm->state == SWR_MSTR_UP)
+					swrm->req_clk_switch = false;
+			}
 			swrm->clk_src = *(int *)data;
 		}
 		mutex_unlock(&swrm->mlock);

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

@@ -175,6 +175,7 @@ struct swr_mstr_ctrl {
 	u32 ipc_wakeup;
 	bool dev_up;
 	bool ipc_wakeup_triggered;
+	bool req_clk_switch;
 	struct pm_qos_request pm_qos_req;
 	enum swrm_pm_state pm_state;
 	wait_queue_head_t pm_wq;