Browse Source

Merge "ASoC: codecs: remove dmic device during dev err"

qctecmdr 5 years ago
parent
commit
47aa501123

+ 7 - 1
asoc/codecs/bolero/bolero-cdc-registers.h

@@ -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.
  */
 
 #ifndef _BOLERO_CDC_REGISTERS_H
@@ -25,6 +25,12 @@
 #define BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL	(TX_START_OFFSET + 0x00CC)
 #define BOLERO_CDC_TX_TOP_CSR_SWR_AMIC0_CTL	(TX_START_OFFSET + 0x00D0)
 #define BOLERO_CDC_TX_TOP_CSR_SWR_AMIC1_CTL	(TX_START_OFFSET + 0x00D4)
+#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC2_CTL	(TX_START_OFFSET + 0x00C0)
+#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC3_CTL	(TX_START_OFFSET + 0x00C4)
+#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC4_CTL	(TX_START_OFFSET + 0x00C8)
+#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC5_CTL	(TX_START_OFFSET + 0x00CC)
+#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL	(TX_START_OFFSET + 0x00D0)
+#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL	(TX_START_OFFSET + 0x00D4)
 #define BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0	(TX_START_OFFSET + 0x0100)
 #define BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1	(TX_START_OFFSET + 0x0104)
 #define BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0	(TX_START_OFFSET + 0x0108)

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

@@ -904,6 +904,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 	u16 hpf_gate_reg = 0;
 	u16 tx_gain_ctl_reg = 0;
 	u8 hpf_cut_off_freq = 0;
+	u16 adc_mux_reg = 0;
 	int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS;
 	int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS;
 	struct device *tx_dev = NULL;
@@ -925,6 +926,8 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 				TX_MACRO_TX_PATH_OFFSET * decimator;
 	tx_gain_ctl_reg = BOLERO_CDC_TX0_TX_VOL_CTL +
 				TX_MACRO_TX_PATH_OFFSET * decimator;
+	adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+			TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1008,6 +1011,32 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 					BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40,
 					0x40);
 		}
+		if (tx_priv->version == BOLERO_VERSION_2_0) {
+			if (snd_soc_component_read32(component, adc_mux_reg)
+							& SWR_MIC) {
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_CTRL,
+					0x01, 0x01);
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL,
+					0x0E, 0x0C);
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL,
+					0x0E, 0x0C);
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_MIC2_CTL,
+					0x0E, 0x00);
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_MIC3_CTL,
+					0x0E, 0x00);
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_MIC4_CTL,
+					0x0E, 0x00);
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_MIC5_CTL,
+					0x0E, 0x00);
+			}
+		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		hpf_cut_off_freq =
@@ -1036,6 +1065,14 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
 		}
 		cancel_delayed_work_sync(
 				&tx_priv->tx_mute_dwork[decimator].dwork);
+
+		if (tx_priv->version == BOLERO_VERSION_2_0) {
+			if (snd_soc_component_read32(component, adc_mux_reg)
+							& SWR_MIC)
+				snd_soc_component_update_bits(component,
+					BOLERO_CDC_TX_TOP_CSR_SWR_CTRL,
+					0x01, 0x00);
+		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_component_update_bits(component, tx_vol_ctl_reg,

+ 190 - 264
asoc/codecs/swr-dmic.c

@@ -27,13 +27,25 @@
 #include <asoc/msm-cdc-pinctrl.h>
 #include <asoc/msm-cdc-supply.h>
 #include <dt-bindings/sound/audio-codec-port-types.h>
+#include "wcd938x/wcd938x.h"
 #include "swr-dmic.h"
 
-#define itoa(x)                   ('0' + x)
-#define DAI_NAME_NUM_INDEX        11
-#define AIF_NAME_NUM_INDEX        12
-#define DEFAULT_CODEC_NAME        "swr_dmic_tx0"
-#define DEFAULT_AIF_NAME          "SWR_DMIC_AIF0 Playback"
+static int swr_master_channel_map[] = {
+	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,
+	SWRM_TX3_CH1,
+	SWRM_TX3_CH2,
+	SWRM_TX3_CH3,
+	SWRM_TX3_CH4,
+	SWRM_PCM_IN,
+};
 
 /*
  * Private data Structure for swr-dmic. All parameters related to
@@ -44,12 +56,12 @@ struct swr_dmic_priv {
 	struct swr_device *swr_slave;
 	struct snd_soc_component *component;
 	struct snd_soc_component_driver *driver;
-	struct snd_soc_dai_driver *dai_driver;
-	const char *supply_name;
+	struct snd_soc_component *supply_component;
+	u32 micb_num;
 	struct device_node *wcd_handle;
-	struct cdc_wcd_supply *cdc_supply;
 	bool is_wcd_supply;
-	int tx_mode;
+	int is_en_supply;
+	int port_type;
 	u8 tx_master_port_map[SWR_DMIC_MAX_PORTS];
 };
 
@@ -58,127 +70,34 @@ const char *codec_name_list[] = {
 	"swr-dmic-02",
 	"swr-dmic-03",
 	"swr-dmic-04",
-	"swr-dmic-05",
 };
 
-static int get_master_port(int val)
-{
-	int master_port = 0;
-
-	switch(val) {
-	case 0:
-		master_port = SWRM_TX1_CH1;
-		break;
-	case 1:
-		master_port = SWRM_TX1_CH2;
-		break;
-	case 2:
-		master_port = SWRM_TX1_CH3;
-		break;
-	case 3:
-		master_port = SWRM_TX1_CH4;
-		break;
-	case 4:
-		master_port = SWRM_TX2_CH1;
-		break;
-	case 5:
-		master_port = SWRM_TX2_CH2;
-		break;
-	case 6:
-		master_port = SWRM_TX2_CH3;
-		break;
-	case 7:
-		master_port = SWRM_TX2_CH4;
-		break;
-	case 8:
-		master_port = SWRM_TX3_CH1;
-		break;
-	case 9:
-		master_port = SWRM_TX3_CH2;
-		break;
-	case 10:
-		master_port = SWRM_TX3_CH3;
-		break;
-	case 11:
-		master_port = SWRM_TX3_CH4;
-		break;
-	case 12:
-		master_port = SWRM_PCM_IN;
-		break;
-	default:
-		master_port = SWRM_TX1_CH1;
-		pr_debug("%s: undefined value, fall back to default master_port: %d\n",
-			 __func__, master_port);
-		break;
-	}
-
-	pr_debug("%s: master_port: %d\n", __func__, master_port);
-	return master_port;
-}
-
-static int get_master_port_val(int master_port)
-{
-	int val = 0;
+const char *dai_name_list[] = {
+	"swr_dmic_tx0",
+	"swr_dmic_tx1",
+	"swr_dmic_tx2",
+	"swr_dmic_tx3",
+};
 
-	switch (master_port) {
-	case SWRM_TX1_CH1:
-		val = 0;
-		break;
-	case SWRM_TX1_CH2:
-		val = 1;
-		break;
-	case SWRM_TX1_CH3:
-		val = 2;
-		break;
-	case SWRM_TX1_CH4:
-		val = 3;
-		break;
-	case SWRM_TX2_CH1:
-		val = 4;
-		break;
-	case SWRM_TX2_CH2:
-		val = 5;
-		break;
-	case SWRM_TX2_CH3:
-		val = 6;
-		break;
-	case SWRM_TX2_CH4:
-		val = 7;
-		break;
-	case SWRM_TX3_CH1:
-		val = 8;
-		break;
-	case SWRM_TX3_CH2:
-		val = 9;
-		break;
-	case SWRM_TX3_CH3:
-		val = 10;
-		break;
-	case SWRM_TX3_CH4:
-		val = 11;
-		break;
-	case SWRM_PCM_IN:
-		val = 12;
-		break;
-	default:
-		val = 0;
-		pr_debug("%s: undefined master_port:%d, fallback to default val: %d\n",
-			 __func__, master_port, val);
-		break;
-	}
+const char *aif_name_list[] = {
+	"SWR_DMIC_AIF0 Playback",
+	"SWR_DMIC_AIF1 Playback",
+	"SWR_DMIC_AIF2 Playback",
+	"SWR_DMIC_AIF3 Playback",
+};
 
-	pr_debug("%s: master_port:%d val: %d\n", __func__, master_port, val);
-	return val;
-}
+static int swr_dmic_reset(struct swr_device *pdev);
+static int swr_dmic_up(struct swr_device *pdev);
+static int swr_dmic_down(struct swr_device *pdev);
 
 static inline int swr_dmic_tx_get_slave_port_type_idx(const char *wname,
 				      unsigned int *port_idx)
 {
 	u8 port_type;
 
-	if (strnstr(wname, "HIFI", sizeof("HIFI")))
+	if (strnstr(wname, "HIFI", strlen(wname)))
 		port_type = SWR_DMIC_HIFI_PORT;
-	else if (strnstr(wname, "LP", sizeof("LP")))
+	else if (strnstr(wname, "LP", strlen(wname)))
 		port_type = SWR_DMIC_LP_PORT;
 	else
 		return -EINVAL;
@@ -187,6 +106,16 @@ static inline int swr_dmic_tx_get_slave_port_type_idx(const char *wname,
 	return 0;
 }
 
+static inline int swr_dmic_get_master_port_val(int port)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(swr_master_channel_map); i++)
+		if (port == swr_master_channel_map[i])
+			return i;
+	return 0;
+}
+
 static int swr_dmic_tx_master_port_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
@@ -202,14 +131,15 @@ static int swr_dmic_tx_master_port_get(struct snd_kcontrol *kcontrol,
 		dev_dbg(component->dev, "%s: invalid port string\n", __func__);
 		return ret;
 	}
+	swr_dmic->port_type = slave_port_idx;
 
-	if (slave_port_idx >= 0 &&
-		slave_port_idx < SWR_DMIC_MAX_PORTS)
-		ucontrol->value.integer.value[0] = get_master_port_val(
+	ucontrol->value.integer.value[0] =
+			swr_dmic_get_master_port_val(
 				swr_dmic->tx_master_port_map[slave_port_idx]);
 
 	dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
 			__func__, ucontrol->value.integer.value[0]);
+
 	return 0;
 }
 
@@ -228,17 +158,13 @@ static int swr_dmic_tx_master_port_put(struct snd_kcontrol *kcontrol,
 		dev_dbg(component->dev, "%s: invalid port string\n", __func__);
 		return ret;
 	}
+	swr_dmic->port_type = slave_port_idx;
 
-
-	dev_dbg(component->dev, "%s: slave_port_idx: %d",
-			__func__, slave_port_idx);
-	dev_dbg(component->dev, "%s: ucontrol->value.enumerated.item[0] = %ld\n",
-			__func__, ucontrol->value.enumerated.item[0]);
-	if (slave_port_idx >= 0 &&
-		slave_port_idx < SWR_DMIC_MAX_PORTS)
-		swr_dmic->tx_master_port_map[slave_port_idx] =
-				get_master_port(
-					ucontrol->value.enumerated.item[0]);
+	swr_dmic->tx_master_port_map[slave_port_idx] =
+		swr_master_channel_map[ucontrol->value.enumerated.item[0]];
+	dev_dbg(component->dev, "%s: slv port id: %d, master_port_type: %d\n",
+		__func__, slave_port_idx,
+		swr_dmic->tx_master_port_map[slave_port_idx]);
 
 	return 0;
 }
@@ -254,20 +180,27 @@ static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w,
 
 	u8 num_ch = 1;
 	u8 ch_mask = 0x01; // only DpnChannelEN1 register is available
-	u8 port_type = 0;
-	u32 ch_rate = 0;
+	u32 ch_rate = SWR_CLK_RATE_4P8MHZ;
 	u8 num_port = 1;
+	u8 port_type = 0;
+	u8 port_id = swr_dmic->port_type;
+
 	/*
 	 * Port 1 is high quality / 2.4 or 3.072 Mbps
 	 * Port 2 is listen low power / 0.6 or 0.768 Mbps
 	 */
-	u8 port_id = swr_dmic->tx_mode;
+	if(swr_dmic->port_type)
+		ch_rate = SWR_CLK_RATE_2P4MHZ;
+	else
+		ch_rate = SWR_CLK_RATE_4P8MHZ;
+
 	port_type = swr_dmic->tx_master_port_map[port_id];
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		ret = swr_connect_port(swr_dmic->swr_slave, &port_id, num_port,
-			&ch_mask, &ch_rate, &num_ch, &port_type);
+		ret = swr_connect_port(swr_dmic->swr_slave, &port_id,
+					num_port, &ch_mask, &ch_rate,
+					&num_ch, &port_type);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		ret = swr_slvdev_datapath_control(swr_dmic->swr_slave,
@@ -278,56 +211,48 @@ static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w,
 			swr_dmic->swr_slave->dev_num, false);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		ret = swr_disconnect_port(swr_dmic->swr_slave, &port_id,
-					  num_port, &ch_mask, &port_type);
+		ret = swr_disconnect_port(swr_dmic->swr_slave,
+				&port_id, num_port, &ch_mask, &port_type);
 		break;
 	};
 
 	return ret;
 }
 
-static const char * const tx_mode_text_swr_mic[] = {
-	"MIC_HIFI", "MIC_LP",
-};
-
-static int swr_mic_tx_mode_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
+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_kcontrol_component(kcontrol);
+			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: tx_mode  = %ld\n",
-		__func__, ucontrol->value.integer.value[0]);
-
-	swr_dmic->tx_mode =  ucontrol->value.integer.value[0];
-
-	return 0;
-}
-
-static int swr_mic_tx_mode_get(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_component *component =
-			snd_soc_kcontrol_component(kcontrol);
-	struct swr_dmic_priv *swr_dmic =
-			snd_soc_component_get_drvdata(component);
+	dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
 
-	ucontrol->value.integer.value[0] = swr_dmic->tx_mode;
+	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;
+	}
 
-	dev_dbg(component->dev, "%s: tx_mode = 0x%x\n", __func__,
-			swr_dmic->tx_mode);
+	if (ret)
+		dev_dbg(component->dev, "%s wname: %s event: %d ret : %d\n",
+			__func__, w->name, event, ret);
 
-	return 0;
+	return ret;
 }
 
-static const struct soc_enum tx_mode_enum_swr_mic =
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_text_swr_mic),
-			    tx_mode_text_swr_mic);
-
 static const char * const tx_master_port_text[] = {
-	"SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4",
+	"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",
 	"SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", "SWRM_TX3_CH4",
 	"SWRM_PCM_IN",
@@ -338,9 +263,6 @@ static const struct soc_enum tx_master_port_enum =
 				tx_master_port_text);
 
 static const struct snd_kcontrol_new swr_dmic_snd_controls[] = {
-	SOC_ENUM_EXT("TX MODE", tx_mode_enum_swr_mic,
-			swr_mic_tx_mode_get, swr_mic_tx_mode_put),
-
 	SOC_ENUM_EXT("HIFI PortMap", tx_master_port_enum,
 		swr_dmic_tx_master_port_get, swr_dmic_tx_master_port_put),
 	SOC_ENUM_EXT("LP PortMap", tx_master_port_enum,
@@ -352,17 +274,23 @@ static const struct snd_kcontrol_new dmic_switch[] = {
 };
 
 static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = {
-	SND_SOC_DAPM_MIXER_E("DMIC_SWR_MIXER", SND_SOC_NOPM, 0, 0,
+	SND_SOC_DAPM_MIXER_E("SWR_DMIC_MIXER", SND_SOC_NOPM, 0, 0,
 			dmic_switch, ARRAY_SIZE(dmic_switch), dmic_swr_ctrl,
 			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
 	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_OUTPUT("SWR_DMIC_OUTPUT"),
 };
 
 static const struct snd_soc_dapm_route swr_dmic_audio_map[] = {
+	{"SWR_DMIC", NULL, "SMIC_SUPPLY"},
 	{"SWR_DMIC_MIXER", "Switch", "SWR_DMIC"},
 	{"SWR_DMIC_OUTPUT", NULL, "SWR_DMIC_MIXER"},
 };
@@ -400,55 +328,63 @@ static const struct snd_soc_component_driver soc_codec_dev_swr_dmic = {
 	.num_dapm_routes = ARRAY_SIZE(swr_dmic_audio_map),
 };
 
-static struct snd_soc_dai_ops wsa_dai_ops = {
-};
+static int enable_wcd_codec_supply(struct swr_dmic_priv *swr_dmic, bool enable)
+{
+	int rc = 0;
+	int micb_num = swr_dmic->micb_num;
+	struct snd_soc_component *component = swr_dmic->supply_component;
 
-static struct snd_soc_dai_driver swr_dmic_dai[] = {
-	{
-		.name = "",
-		.id = 0,
-		.playback = {
-			.stream_name = "",
-			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
-				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
-				SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
-			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
-				SNDRV_PCM_FMTBIT_S24_LE |
-				SNDRV_PCM_FMTBIT_S32_LE),
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 2,
-		},
-		.ops = &wsa_dai_ops,
-	},
-};
+	if (!component) {
+		pr_err("%s: component is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (enable)
+		rc = wcd938x_codec_force_enable_micbias_v2(component,
+					SND_SOC_DAPM_PRE_PMU, micb_num);
+	else
+		rc = wcd938x_codec_force_enable_micbias_v2(component,
+					SND_SOC_DAPM_POST_PMD, micb_num);
+
+	return rc;
+}
+
+static int swr_dmic_parse_supply(struct device_node *np,
+				struct swr_dmic_priv *swr_dmic)
+{
+	struct platform_device *pdev = NULL;
+
+	if (!np || !swr_dmic)
+		return -EINVAL;
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev)
+		return -EINVAL;
+
+	swr_dmic->supply_component = snd_soc_lookup_component(&pdev->dev, NULL);
+
+	return 0;
+}
 
 static int swr_dmic_probe(struct swr_device *pdev)
 {
 	int ret = 0;
-	struct swr_dmic_priv *swr_dmic;
 	int i = 0;
-	u8 devnum = 0;
+	u8 swr_devnum = 0;
+	int dev_index = -1;
+	char* prefix_name = NULL;
+	struct swr_dmic_priv *swr_dmic = NULL;
 	const char *swr_dmic_name_prefix_of = NULL;
 	const char *swr_dmic_codec_name_of = NULL;
-	struct snd_soc_component *component;
-	char *dai_name;
-	char *aif_name;
+	struct snd_soc_component *component = NULL;
 
 	swr_dmic = devm_kzalloc(&pdev->dev, sizeof(struct swr_dmic_priv),
 			    GFP_KERNEL);
 	if (!swr_dmic)
 		return -ENOMEM;
 
-	swr_dmic->cdc_supply = devm_kzalloc(&pdev->dev,
-					sizeof(struct cdc_wcd_supply),
-					GFP_KERNEL);
-	if (!swr_dmic->cdc_supply)
-		return -ENOMEM;
-
-	ret = of_property_read_string(pdev->dev.of_node, "qcom,swr-dmic-supply",
-				&swr_dmic->supply_name);
+	ret = of_property_read_u32(pdev->dev.of_node, "qcom,swr-dmic-supply",
+				&swr_dmic->micb_num);
 	if (ret) {
 		dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
 		__func__, "qcom,swr-dmic-supply",
@@ -462,17 +398,17 @@ static int swr_dmic_probe(struct swr_device *pdev)
 			__func__);
 		swr_dmic->is_wcd_supply = false;
 	} else {
-		msm_cdc_init_wcd_supply(swr_dmic->wcd_handle,
-				swr_dmic->supply_name, swr_dmic->cdc_supply);
+		swr_dmic_parse_supply(swr_dmic->wcd_handle, swr_dmic);
 		swr_dmic->is_wcd_supply = true;
 	}
 
 	if (swr_dmic->is_wcd_supply) {
-		ret = msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, true);
+		ret = enable_wcd_codec_supply(swr_dmic, true);
 		if (ret) {
 			ret = -EPROBE_DEFER;
 			goto err;
 		}
+		++swr_dmic->is_en_supply;
 	}
 
 	swr_set_dev_data(pdev, swr_dmic);
@@ -485,7 +421,7 @@ static int swr_dmic_probe(struct swr_device *pdev)
 		dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
 		__func__, "qcom,swr-dmic-prefix",
 		pdev->dev.of_node->full_name);
-		goto err;
+		goto dev_err;
 	}
 
 	ret = of_property_read_string(pdev->dev.of_node, "qcom,codec-name",
@@ -494,7 +430,7 @@ static int swr_dmic_probe(struct swr_device *pdev)
 		dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
 		__func__, "qcom,codec-name",
 		pdev->dev.of_node->full_name);
-		goto err;
+		goto dev_err;
 	}
 
 	/*
@@ -503,14 +439,16 @@ 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, &devnum);
+	ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum);
 	if (ret) {
 		dev_dbg(&pdev->dev,
 			"%s get devnum %d for dev addr %lx failed\n",
-			__func__, devnum, pdev->addr);
-		goto dev_err;
+			__func__, swr_devnum, pdev->addr);
+		ret = -EPROBE_DEFER;
+		goto err;
 	}
-	pdev->dev_num = devnum;
+	pdev->dev_num = swr_devnum;
+
 
 	swr_dmic->driver = devm_kzalloc(&pdev->dev,
 			sizeof(struct snd_soc_component_driver), GFP_KERNEL);
@@ -521,53 +459,23 @@ static int swr_dmic_probe(struct swr_device *pdev)
 
 	memcpy(swr_dmic->driver, &soc_codec_dev_swr_dmic,
 			sizeof(struct snd_soc_component_driver));
-	swr_dmic->driver->name = devm_kzalloc(&pdev->dev,
-			strlen(swr_dmic_codec_name_of), GFP_KERNEL);
-	if (!swr_dmic->driver->name) {
-		ret = -ENOMEM;
-		goto dev_err;
-	}
 
 	for (i = 0; i < ARRAY_SIZE(codec_name_list); i++) {
-		if (!strcmp(swr_dmic_codec_name_of, codec_name_list[i]))
+		if (!strcmp(swr_dmic_codec_name_of, codec_name_list[i])) {
+			dev_index = i;
 			break;
-	}
-	if (i == ARRAY_SIZE(codec_name_list))
-		goto dev_err;
-
-	swr_dmic->dai_driver = devm_kzalloc(&pdev->dev,
-			sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
-	if (!swr_dmic->dai_driver) {
-		ret = -ENOMEM;
-		goto dev_err;
-	}
-
-	memcpy(swr_dmic->dai_driver, swr_dmic_dai,
-			sizeof(struct snd_soc_dai_driver));
-	dai_name = devm_kzalloc(&pdev->dev, strlen(DEFAULT_CODEC_NAME),
-			GFP_KERNEL);
-	if (!dai_name) {
-		ret = -ENOMEM;
-		goto dev_err;
+		}
 	}
 
-	memcpy(dai_name, DEFAULT_CODEC_NAME, strlen(DEFAULT_CODEC_NAME));
-	dai_name[DAI_NAME_NUM_INDEX] = itoa(i);
-	swr_dmic->dai_driver->name = dai_name;
-	swr_dmic->dai_driver->id = i;
-	aif_name = devm_kzalloc(&pdev->dev, strlen(DEFAULT_AIF_NAME),
-			GFP_KERNEL);
-	if (!aif_name) {
-		ret = -ENOMEM;
+	if (dev_index < 0) {
+		ret = -EINVAL;
 		goto dev_err;
 	}
 
-	memcpy(aif_name, DEFAULT_AIF_NAME, strlen(DEFAULT_AIF_NAME));
-	aif_name[AIF_NAME_NUM_INDEX] = itoa(i);
-	swr_dmic->dai_driver->playback.stream_name = aif_name;
+	swr_dmic->driver->name = dai_name_list[dev_index];
 
 	ret = snd_soc_register_component(&pdev->dev, swr_dmic->driver,
-				swr_dmic->dai_driver, 1);
+				NULL, 0);
 	if (ret) {
 		dev_err(&pdev->dev, "%s: Codec registration failed\n",
 			__func__);
@@ -577,19 +485,26 @@ static int swr_dmic_probe(struct swr_device *pdev)
 	component = snd_soc_lookup_component(&pdev->dev,
 						swr_dmic->driver->name);
 	swr_dmic->component = component;
-	component->name_prefix = devm_kzalloc(&pdev->dev,
+	prefix_name = devm_kzalloc(&pdev->dev,
 					strlen(swr_dmic_name_prefix_of),
-	   GFP_KERNEL);
-	if (!component->name_prefix) {
+					GFP_KERNEL);
+	if (!prefix_name) {
 		ret = -ENOMEM;
 		goto dev_err;
 	}
+	strlcpy(prefix_name, swr_dmic_name_prefix_of,
+			strlen(swr_dmic_name_prefix_of));
+	component->name_prefix = prefix_name;
 
 	return 0;
 
 dev_err:
-	if (swr_dmic->is_wcd_supply)
-		msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, false);
+	if (swr_dmic->is_en_supply == 1) {
+		enable_wcd_codec_supply(swr_dmic, false);
+		--swr_dmic->is_en_supply;
+	}
+	swr_dmic->is_wcd_supply = false;
+	swr_dmic->wcd_handle = NULL;
 	swr_remove_device(pdev);
 err:
 	return ret;
@@ -620,8 +535,10 @@ static int swr_dmic_up(struct swr_device *pdev)
 		dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__);
 		return -EINVAL;
 	}
-	if (swr_dmic->is_wcd_supply)
-		ret = msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, true);
+
+	++swr_dmic->is_en_supply;
+	if (swr_dmic->is_en_supply == 1)
+		ret = enable_wcd_codec_supply(swr_dmic, true);
 
 	return ret;
 }
@@ -636,9 +553,18 @@ static int swr_dmic_down(struct swr_device *pdev)
 		dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__);
 		return -EINVAL;
 	}
-	if (swr_dmic->is_wcd_supply)
-		ret = msm_cdc_enable_wcd_supply(swr_dmic->cdc_supply, false);
 
+	--swr_dmic->is_en_supply;
+	if (swr_dmic->is_en_supply < 0) {
+		dev_warn(&pdev->dev, "%s: mismatch in supply count %d\n",
+			__func__, swr_dmic->is_en_supply);
+		swr_dmic->is_en_supply = 0;
+		goto done;
+	}
+	if (!swr_dmic->is_en_supply)
+		enable_wcd_codec_supply(swr_dmic, false);
+
+done:
 	return ret;
 }
 

+ 3 - 5
asoc/lahaina-port-config.h

@@ -43,11 +43,9 @@ static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = {
 
 /* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */
 static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = {
-	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},/* PCM OUT */
-	{1,  1,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},  /* TX1 */
-	{1,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1},  /* TX2 */
-	{3,  2,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},  /* TX3 */
-	{3,  0,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1},  /* TX4 */
+	{3,  1,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},  /* TX1 */
+	{3,  2,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},  /* TX2 */
+	{3,  1,  0,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},  /* TX3 */
 };
 
 /* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */

+ 177 - 14
asoc/lahaina.c

@@ -172,13 +172,6 @@ enum {
 	AFE_LOOPBACK_TX_IDX_MAX,
 };
 
-#if IS_ENABLED(CONFIG_AUDIO_QGKI)
-static const char* wsa883x_devices[] = {
-	"wsa883x.202170221",
-	"wsa883x.202170222",
-};
-#endif /* CONFIG_AUDIO_QGKI */
-
 struct msm_asoc_mach_data {
 	struct snd_info_entry *codec_root;
 	int usbc_en2_gpio; /* used by gpio driver API */
@@ -223,6 +216,11 @@ struct aux_codec_dev_info {
 	u32 index;
 };
 
+struct msm_swr_dmic_dev_info {
+	struct device_node *of_node;
+	u32 index;
+};
+
 struct dev_config {
 	u32 sample_rate;
 	u32 bit_format;
@@ -7281,28 +7279,47 @@ err_hs_detect:
 	return ret;
 }
 
+static int msm_swr_dmic_init(struct snd_soc_component *component)
+{
+	/* TODO: add sound wire dmic initialization */
+
+	if (NULL == component) {
+		pr_err("%s: swr dmic component is NULL\n", __func__);
+		return 0;
+	}
+
+	return 0;
+}
+
 static int msm_init_aux_dev(struct platform_device *pdev,
 				struct snd_soc_card *card)
 {
 	struct device_node *wsa_of_node;
 	struct device_node *aux_codec_of_node;
+	struct device_node *swr_dmic_of_node;
 	u32 wsa_max_devs;
 	u32 wsa_dev_cnt;
 	u32 codec_max_aux_devs = 0;
 	u32 codec_aux_dev_cnt = 0;
+	u32 swr_dmic_max_devs = 0;
+	u32 swr_dmic_dev_cnt = 0;
+	int swr_dmic_index = 0;
 	int i;
 	struct msm_wsa883x_dev_info *wsa883x_dev_info;
 	struct aux_codec_dev_info *aux_cdc_dev_info = NULL;
+	struct msm_swr_dmic_dev_info *swr_dmic_dev_info = NULL;
 	struct snd_soc_dai_link_component *dlc;
 	const char *auxdev_name_prefix[1];
 	char *dev_name_str = NULL;
 	int found = 0;
 	int codecs_found = 0;
+	int dmics_found = 0;
 	int ret = 0;
 
 	dlc = devm_kcalloc(&pdev->dev, 1,
 			sizeof(struct snd_soc_dai_link_component),
 			GFP_KERNEL);
+
 	/* Get maximum WSA device count for this platform */
 	ret = of_property_read_u32(pdev->dev.of_node,
 				   "qcom,wsa-max-devs", &wsa_max_devs);
@@ -7419,13 +7436,13 @@ codec_aux_dev:
 			 "%s: codec-max-aux-devs property missing in DT %s, ret = %d\n",
 			 __func__, pdev->dev.of_node->full_name, ret);
 		codec_max_aux_devs = 0;
-		goto aux_dev_register;
+		goto dmic_aux_dev;
 	}
 	if (codec_max_aux_devs == 0) {
 		dev_dbg(&pdev->dev,
 			 "%s: Max aux codec devices is 0 for this target?\n",
 			 __func__);
-		goto aux_dev_register;
+		goto dmic_aux_dev;
 	}
 
 	/* Get count of aux codec device phandles for this platform */
@@ -7507,9 +7524,122 @@ codec_aux_dev:
 		"%s: found %d AUX codecs registered with ALSA core\n",
 		__func__, codecs_found);
 
+dmic_aux_dev:
+	/* Get maximum WSA device count for this platform */
+	ret = of_property_read_u32(pdev->dev.of_node,
+				   "qcom,swr-dmic-max-devs",
+				   &swr_dmic_max_devs);
+	if (ret) {
+		dev_info(&pdev->dev,
+			 "%s: swr-dmic-max-devs property missing in DT %s,"
+			 " ret = %d\n",
+			 __func__, pdev->dev.of_node->full_name, ret);
+		swr_dmic_max_devs = 0;
+		goto aux_dev_register;
+	}
+	if (swr_dmic_max_devs == 0) {
+		dev_warn(&pdev->dev,
+			 "%s: Max SWR DMIC devices is 0 for this target?\n",
+			 __func__);
+		goto aux_dev_register;
+	}
+
+	/* Get count of SWR DMIC device phandles for this platform */
+	swr_dmic_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
+						 "qcom,swr-dmic-devs", NULL);
+	if (swr_dmic_dev_cnt == -ENOENT) {
+		dev_warn(&pdev->dev, "%s: No swr_dmic device defined in DT.\n",
+			 __func__);
+		goto err;
+	} else if (swr_dmic_dev_cnt <= 0) {
+		dev_err(&pdev->dev,
+			"%s: Error reading swr_dmic device from DT."
+			" swr_dmic_dev_cnt = %d\n",
+			__func__, swr_dmic_dev_cnt);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/*
+	 * Expect total phandles count to be NOT less than maximum possible
+	 * SWR DMIC count. However, if it is less, then assign same value to
+	 * max count as well.
+	 */
+	if (swr_dmic_dev_cnt < swr_dmic_max_devs) {
+		dev_dbg(&pdev->dev,
+			"%s: swr_dmic_max_devs = %d cannot exceed "
+			"swr_dmic_dev_cnt = %d\n",
+			__func__, swr_dmic_max_devs, swr_dmic_dev_cnt);
+		swr_dmic_max_devs = swr_dmic_dev_cnt;
+	}
+
+	/* Make sure prefix string passed for each WSA device */
+	ret = of_property_count_strings(pdev->dev.of_node,
+					"qcom,swr-dmic-prefix");
+	if (ret != swr_dmic_dev_cnt) {
+		dev_err(&pdev->dev,
+			"%s: expecting %d swr_dmic prefix. Defined only %d "
+			"in DT\n", __func__, swr_dmic_dev_cnt, ret);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/*
+	 * Alloc mem to store phandle and index info of WSA device, if already
+	 * registered with ALSA core
+	 */
+	swr_dmic_dev_info = devm_kcalloc(&pdev->dev, swr_dmic_max_devs,
+					sizeof(struct msm_swr_dmic_dev_info),
+					GFP_KERNEL);
+	if (!swr_dmic_dev_info) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/*
+	 * search and check whether all WSA devices are already
+	 * registered with ALSA core or not. If found a node, store
+	 * the node and the index in a local array of struct for later
+	 * use.
+	 */
+	for (i = 0; i < swr_dmic_max_devs; i++) {
+		swr_dmic_of_node = of_parse_phandle(pdev->dev.of_node,
+					    "qcom,swr-dmic-devs", i);
+		if (unlikely(!swr_dmic_of_node)) {
+			/* we should not be here */
+			dev_err(&pdev->dev,
+				"%s: swr_dmic dev node is not present\n",
+				__func__);
+			ret = -EINVAL;
+			goto err;
+		}
+		dlc->of_node = swr_dmic_of_node;
+		dlc->name = NULL;
+		if (soc_find_component(dlc)) {
+			/* WSA device registered with ALSA core */
+			swr_dmic_dev_info[dmics_found].of_node =
+							swr_dmic_of_node;
+			swr_dmic_dev_info[dmics_found].index = i;
+			dmics_found++;
+			if (dmics_found == swr_dmic_max_devs)
+				break;
+		}
+	}
+
+	if (dmics_found < swr_dmic_max_devs) {
+		dev_err(&pdev->dev,
+			"%s: failed to find %d components. Found only %d\n",
+			__func__, swr_dmic_max_devs, dmics_found);
+		return -EPROBE_DEFER;
+	}
+	dev_info(&pdev->dev,
+		"%s: found %d swr_dmic devices registered with ALSA core\n",
+		__func__, dmics_found);
+
 aux_dev_register:
-	card->num_aux_devs = wsa_max_devs + codec_aux_dev_cnt;
-	card->num_configs = wsa_max_devs + codec_aux_dev_cnt;
+	card->num_aux_devs = wsa_max_devs + codec_aux_dev_cnt +
+				swr_dmic_max_devs;
+	card->num_configs = card->num_aux_devs;
 
 	/* Alloc array of AUX devs struct */
 	msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
@@ -7543,13 +7673,13 @@ aux_dev_register:
 						    auxdev_name_prefix);
 		if (ret) {
 			dev_err(&pdev->dev,
-				"%s: failed to read wsa aux dev prefix, ret = %d\n",
-				__func__, ret);
+				"%s: failed to read wsa aux dev prefix, "
+				"ret = %d\n", __func__, ret);
 			ret = -EINVAL;
 			goto err;
 		}
 
-		msm_aux_dev[i].dlc.name = wsa883x_devices[i];
+		msm_aux_dev[i].dlc.name = NULL;
 		msm_aux_dev[i].dlc.dai_name = NULL;
 		msm_aux_dev[i].dlc.of_node =
 					wsa883x_dev_info[i].of_node;
@@ -7573,6 +7703,39 @@ aux_dev_register:
 				aux_cdc_dev_info[i].of_node;
 	}
 
+	for (i = 0; i < swr_dmic_max_devs; i++) {
+		dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
+					    GFP_KERNEL);
+		if (!dev_name_str) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ret = of_property_read_string_index(pdev->dev.of_node,
+						    "qcom,swr-dmic-prefix",
+						    swr_dmic_dev_info[i].index,
+						    auxdev_name_prefix);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: failed to read swr dmic dev prefix, "
+				"ret = %d\n", __func__, ret);
+			ret = -EINVAL;
+			goto err;
+		}
+		swr_dmic_index = wsa_max_devs + codec_aux_dev_cnt + i;
+
+		msm_aux_dev[swr_dmic_index].dlc.name = NULL;
+		msm_aux_dev[swr_dmic_index].dlc.dai_name = NULL;
+		msm_aux_dev[swr_dmic_index].dlc.of_node =
+					swr_dmic_dev_info[i].of_node;
+		msm_aux_dev[swr_dmic_index].init = msm_swr_dmic_init;
+		msm_codec_conf[swr_dmic_index].dev_name = NULL;
+		msm_codec_conf[swr_dmic_index].name_prefix =
+						auxdev_name_prefix[0];
+		msm_codec_conf[swr_dmic_index].of_node =
+						swr_dmic_dev_info[i].of_node;
+	}
+
 	card->codec_conf = msm_codec_conf;
 	card->aux_dev = msm_aux_dev;
 err: