Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3dc8f718 authored by Banajit Goswami's avatar Banajit Goswami
Browse files

ASoC: msm: add MI2S support for apq8084 devices



APQ8084 has multiple MI2S ports which are used to connect
various external devices such as FM chips, Modems and
Codecs. Add support for Quaternary MI2S port for APQ8084.

Change-Id: I0ce84d7e9587f8cda6653003c8e79c976eadb73b
Signed-off-by: default avatarBanajit Goswami <bgoswami@codeaurora.org>
parent 3a07e2da
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1036,7 +1036,7 @@ Optional properties:
- pinctrl-states: the names of the pinctrl states that used by the driver to
	configure the TLMM pins. The allowed states are subset of the following
	list: pmx-pri-mi2s-active, pmx-pri-quad-mi2s-active, pmx-quad-mi2s-active,
	 pmx-pri-quad-mi2s-sleep.
	 pmx-pri-quad-mi2s-sleep, pmx-quad-mi2s-sleep.
- pinctrl-#: a list of pinctrl phandles for the different pinctrl states. Refer
	to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" for the
	pinctrl handles definitions. Each pinctrl-# corresponds to the respective
+481 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@

static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;

#define SAMPLING_RATE_8KHZ 8000
#define SAMPLING_RATE_16KHZ 16000
@@ -147,11 +149,52 @@ struct msm_auxpcm_ctrl {
	u32 cnt;
};

static const struct afe_clk_cfg lpass_default = {
	AFE_API_VERSION_I2S_CONFIG,
	Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
	Q6AFE_LPASS_OSR_CLK_DISABLE,
	Q6AFE_LPASS_CLK_SRC_INTERNAL,
	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
	Q6AFE_LPASS_MODE_CLK1_VALID,
	0,
};

static const char *const mi2s_pin_states[] = {"Disable",
					      "quad_mi2s_active"};

/*
 * enum mi2s_pin_state - states for the mi2s pinctrl states
 * Note: these states are similar to the "pinctrl-names"
 * in board/target specific DTSI file.
 */
enum mi2s_pin_state {
	MI2S_STATE_DISABLE = 0,
	MI2S_STATE_QUAD_ON = 1
};

/*
 * struct msm_mi2s_pinctrl_info - manage all the pinctrl information
 *
 * @pinctrl:		TSC pinctrl state holder.
 * @disable:		pinctrl state to disable all the pins.
 * @quad_mi2s_active:	pinctrl state to activate Quaternary MI2S.
 * @curr_state:		the current state of the TLMM pins.
 */
struct msm_mi2s_pinctrl_info {
	struct pinctrl *pinctrl;
	struct pinctrl_state *disable;
	struct pinctrl_state *quad_mi2s_active;
	enum mi2s_pin_state curr_mi2s_state;
};

struct apq8084_asoc_mach_data {
	u32 mclk_freq;
	int us_euro_gpio;
	struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
	struct msm_auxpcm_ctrl *sec_auxpcm_ctrl;
	u32 quad_rx_clk_usrs;
	u32 quad_tx_clk_usrs;
	struct msm_mi2s_pinctrl_info mi2s_pinctrl_info;
};

struct apq8084_asoc_wcd93xx_codec {
@@ -185,6 +228,7 @@ static char *msm_sec_auxpcm_gpio_name[][2] = {

void *lpaif_pri_muxsel_virt_addr;
void *lpaif_sec_muxsel_virt_addr;
void *lpaif_quad_muxsel_virt_addr;

struct apq8084_liquid_dock_dev {
	int dock_plug_gpio;
@@ -243,6 +287,12 @@ static int clk_users;
static atomic_t prim_auxpcm_rsc_ref;
static atomic_t sec_auxpcm_rsc_ref;
static bool codec_reg_done;
static int apq8084_mi2s_rx_ch = 1;
static int apq8084_mi2s_tx_ch = 1;
static atomic_t quad_mi2s_ref_count;

static const char *const mi2s_tx_ch_text[] = {"One", "Two"};
static const char *const mi2s_rx_ch_text[] = {"One", "Two"};

static int apq8084_liquid_ext_spk_power_amp_init(void)
{
@@ -1289,6 +1339,322 @@ static struct snd_soc_ops msm_sec_auxpcm_be_ops = {
	.shutdown = msm_sec_auxpcm_shutdown,
};

static int msm_quad_mi2s_set_pinctrl(struct apq8084_asoc_mach_data *pdata)
{
	struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info;
	int ret = 0;

	pr_debug("%s: curr_mi2s_state = %s\n", __func__,
		 mi2s_pin_states[pinctrl_info->curr_mi2s_state]);
	/* Enable Quaternary MI2S TLMM pins and set to appropriate state */
	switch (pinctrl_info->curr_mi2s_state) {
	case MI2S_STATE_DISABLE:
		ret = pinctrl_select_state(pinctrl_info->pinctrl,
					   pinctrl_info->quad_mi2s_active);
		if (ret) {
			pr_err("%s: pinctrl_select_state failed with %d\n",
				__func__, ret);
			ret = -EIO;
			goto err;
		}
		pinctrl_info->curr_mi2s_state = MI2S_STATE_QUAD_ON;
		break;
	case MI2S_STATE_QUAD_ON:
		pr_err("%s: MI2S TLMM pins already set\n", __func__);
		break;
	default:
		pr_err("%s: MI2S TLMM pin state is invalid\n", __func__);
		return -EINVAL;
	}

err:
	return ret;
}

static int msm_quad_mi2s_reset_pinctrl(struct apq8084_asoc_mach_data *pdata)
{
	struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info;
	int ret = 0;

	pr_debug("%s: curr_mi2s_state = %s\n", __func__,
		 mi2s_pin_states[pinctrl_info->curr_mi2s_state]);
	/* Reset Quaternary MI2S TLMM pins and set to appropriate state */
	switch (pinctrl_info->curr_mi2s_state) {
	case MI2S_STATE_QUAD_ON:
		ret = pinctrl_select_state(pinctrl_info->pinctrl,
					   pinctrl_info->disable);
		if (ret) {
			pr_err("%s: pinctrl_select_state failed with %d\n",
				__func__, ret);
			ret = -EIO;
			goto err;
		}
		pinctrl_info->curr_mi2s_state = MI2S_STATE_DISABLE;
		break;
	case MI2S_STATE_DISABLE:
		pr_err("%s: MI2S TLMM pins already disabled\n", __func__);
		break;
	default:
		pr_err("%s: MI2S TLMM pin state is invalid\n", __func__);
		return -EINVAL;
	}

err:
	return ret;
}

static int apq8084_quad_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd,
				bool enable,
				struct snd_pcm_substream *substream)
{
	struct snd_soc_card *card = rtd->card;
	struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	struct afe_clk_cfg *lpass_clk = NULL;
	int ret = 0;
	u32 afe_port_id;

	if (pdata == NULL) {
		pr_err("%s:platform data is null\n", __func__);
		return -EINVAL;
	}
	lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
	if (lpass_clk == NULL) {
		pr_err("%s:Failed to allocate memory\n", __func__);
		return -ENOMEM;
	}
	memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
	pr_debug("%s: lpass clock enable = %d\n", __func__, enable);
	if (enable) {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
			if (pdata->quad_rx_clk_usrs == 0) {
				lpass_clk->clk_val1 =
					    Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
				lpass_clk->clk_set_mode =
						Q6AFE_LPASS_MODE_CLK1_VALID;
			}
			ret = afe_set_lpass_clock(afe_port_id, lpass_clk);
			if (ret < 0) {
				pr_err("%s:afe_set_lpass_clock failed with %d\n",
					__func__, ret);
				goto err;
			} else {
				pdata->quad_rx_clk_usrs++;
			}
		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
			if (pdata->quad_tx_clk_usrs == 0) {
				lpass_clk->clk_val1 =
					    Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
				lpass_clk->clk_set_mode =
						Q6AFE_LPASS_MODE_CLK1_VALID;
			}
			ret = afe_set_lpass_clock(afe_port_id, lpass_clk);
			if (ret < 0) {
				pr_err("%s:afe_set_lpass_clock failed with %d\n",
					__func__, ret);
				goto err;
			} else {
				pdata->quad_tx_clk_usrs++;
			}
		}
	} else {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
			if (pdata->quad_rx_clk_usrs > 0)
				pdata->quad_rx_clk_usrs--;
			if (pdata->quad_rx_clk_usrs == 0) {
				lpass_clk->clk_val1 =
						Q6AFE_LPASS_IBIT_CLK_DISABLE;
				lpass_clk->clk_set_mode =
						Q6AFE_LPASS_MODE_CLK1_VALID;
			}
			ret = afe_set_lpass_clock(afe_port_id, lpass_clk);
			if (ret < 0) {
				pr_err("%s:afe_set_lpass_clock failed with %d\n",
					__func__, ret);
				goto err;
			}
		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
			afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
			if (pdata->quad_tx_clk_usrs > 0)
				pdata->quad_tx_clk_usrs--;
			if (pdata->quad_tx_clk_usrs == 0) {
				lpass_clk->clk_val1 =
						Q6AFE_LPASS_IBIT_CLK_DISABLE;
				lpass_clk->clk_set_mode =
						Q6AFE_LPASS_MODE_CLK1_VALID;
			}
			ret = afe_set_lpass_clock(afe_port_id, lpass_clk);
			if (ret < 0) {
				pr_err("%s:afe_set_lpass_clock failed with %d\n",
					__func__, ret);
				goto err;
			}
		}
	}
	pr_debug("%s: clk 1 = 0x%x clk2 = 0x%x mode = 0x%x\n",
			 __func__, lpass_clk->clk_val1,
			lpass_clk->clk_val2,
			lpass_clk->clk_set_mode);
	ret = 0;
err:
	kfree(lpass_clk);
	return ret;
}

static int msm_quad_mi2s_startup(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_card *card = rtd->card;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	int ret = 0;
	uint32_t pcm_sel_reg;

	pr_debug("%s(): substream = %s, quad_mi2s_ref_count = %d\n",
		 __func__, substream->name, atomic_read(&quad_mi2s_ref_count));

	if (pdata == NULL || lpaif_quad_muxsel_virt_addr == NULL) {
		pr_err("%s: Invalid parameters for Quad MI2S\n", __func__);
		ret = -EINVAL;
		goto err;
	}
	if (atomic_inc_return(&quad_mi2s_ref_count) == 1) {
		pcm_sel_reg = ioread32(lpaif_quad_muxsel_virt_addr);
		if (pcm_sel_reg & (I2S_PCM_SEL << I2S_PCM_SEL_OFFSET)) {
			iowrite32(pcm_sel_reg &
				~(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET),
				  lpaif_quad_muxsel_virt_addr);
		}

		ret = msm_quad_mi2s_set_pinctrl(pdata);
		if (ret) {
			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
				__func__, ret);
			return ret;
		}

		ret = apq8084_quad_mi2s_clk_ctl(rtd, true, substream);
		if (ret) {
			pr_err("%s: Setting clk control failed with %d\n",
				__func__, ret);
			return ret;
		}
		/* This sets the CONFIG PARAMETER WS_SRC.
		 * SND_SOC_DAIFMT_CBS_CFS means internal clock/master mode.
		 * SND_SOC_DAIFMT_CBM_CFM means external clock/slave mode.
		 */
		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
		if (ret)
			pr_err("%s: set fmt cpu dai failed with %d\n",
				__func__, ret);
	}
err:
	return ret;
}

static void msm_quad_mi2s_shutdown(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_card *card = rtd->card;
	struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	int ret;

	pr_debug("%s(): substream = %s, quad_mi2s_ref_count = %d\n",
		 __func__, substream->name, atomic_read(&quad_mi2s_ref_count));

	if (pdata == NULL) {
		pr_err("%s: Invalid platform data\n", __func__);
		return;
	}

	if (atomic_dec_return(&quad_mi2s_ref_count) == 0) {
		ret = msm_quad_mi2s_reset_pinctrl(pdata);
		if (ret)
			pr_err("%s Reset pinctrl failed with %d\n",
				__func__, ret);
		ret = apq8084_quad_mi2s_clk_ctl(rtd, false, substream);
		if (ret)
			pr_err("%s Clock disable failed with %d\n",
				__func__, ret);
	}
}

static struct snd_soc_ops apq8084_quad_mi2s_be_ops = {
	.startup = msm_quad_mi2s_startup,
	.shutdown = msm_quad_mi2s_shutdown,
};

static int apq8084_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					     struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
						SNDRV_PCM_HW_PARAM_RATE);
	struct snd_interval *channels = hw_param_interval(params,
						SNDRV_PCM_HW_PARAM_CHANNELS);
	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
				mi2s_tx_bit_format);
	rate->min = rate->max = SAMPLING_RATE_48KHZ;
	channels->min = channels->max = apq8084_mi2s_tx_ch;
	pr_debug("%s: format = %d rate = %d, channels = %d\n",
			__func__, params_format(params), params_rate(params),
			apq8084_mi2s_tx_ch);
	return 0;
}

static int apq8084_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	pr_debug("%s: apq8084_i2s_tx_ch  = %d\n", __func__,
		 apq8084_mi2s_tx_ch);
	ucontrol->value.integer.value[0] = apq8084_mi2s_tx_ch - 1;
	return 0;
}

static int apq8084_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	apq8084_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
	pr_debug("%s: apq8084_i2s_tx_ch = %d\n", __func__,
		 apq8084_mi2s_tx_ch);
	return 1;
}
static int apq8084_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					     struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
						SNDRV_PCM_HW_PARAM_RATE);
	struct snd_interval *channels = hw_param_interval(params,
						SNDRV_PCM_HW_PARAM_CHANNELS);
	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
				mi2s_rx_bit_format);
	rate->min = rate->max = SAMPLING_RATE_48KHZ;
	channels->min = channels->max = apq8084_mi2s_rx_ch;
	pr_debug("%s: format = %d rate = %d, channels = %d\n",
			__func__, params_format(params), params_rate(params),
			apq8084_mi2s_rx_ch);
	return 0;
}

static int apq8084_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	pr_debug("%s: apq8084_i2s_rx_ch  = %d\n", __func__,
		 apq8084_mi2s_rx_ch);
	ucontrol->value.integer.value[0] = apq8084_mi2s_rx_ch - 1;
	return 0;
}

static int apq8084_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	apq8084_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
	pr_debug("%s: apq8084_i2s_rx_ch = %d\n", __func__,
		 apq8084_mi2s_tx_ch);
	return 1;
}

static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					    struct snd_pcm_hw_params *params)
{
@@ -1504,6 +1870,8 @@ static const struct soc_enum msm_snd_enum[] = {
	SOC_ENUM_SINGLE_EXT(2, slim1_tx_ch_text),
	SOC_ENUM_SINGLE_EXT(3, slim1_rate_text),
	SOC_ENUM_SINGLE_EXT(3, slim3_rx_ch_text),
	SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text),
	SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text),
};

static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -1535,6 +1903,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
			msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
	SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
		msm_incall_rec_mode_get, msm_incall_rec_mode_put),
	SOC_ENUM_EXT("QUAT_MI2S_RX Channels", msm_snd_enum[11],
			apq8084_mi2s_rx_ch_get, apq8084_mi2s_rx_ch_put),
	SOC_ENUM_EXT("QUAT_MI2S_TX Channels", msm_snd_enum[12],
			apq8084_mi2s_tx_ch_get, apq8084_mi2s_tx_ch_put),
};

static bool apq8084_swap_gnd_mic(struct snd_soc_codec *codec)
@@ -3027,6 +3399,34 @@ static struct snd_soc_dai_link apq8084_common_be_dai_links[] = {
		.ops = &apq8084_slimbus_6_be_ops,
		.ignore_suspend = 1,
	},
	/* MI2S Backend DAI Links */
	{
		.name = LPASS_BE_QUAT_MI2S_RX,
		.stream_name = "Quaternary MI2S Playback",
		.cpu_dai_name = "msm-dai-q6-mi2s.3",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-rx",
		.no_pcm = 1,
		.be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
		.be_hw_params_fixup = &apq8084_mi2s_rx_be_hw_params_fixup,
		.ops = &apq8084_quad_mi2s_be_ops,
		.ignore_suspend = 1,
		.ignore_pmdown_time = 1,
	},
	{
		.name = LPASS_BE_QUAT_MI2S_TX,
		.stream_name = "Quaternary MI2S Capture",
		.cpu_dai_name = "msm-dai-q6-mi2s.3",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-tx",
		.no_pcm = 1,
		.be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
		.be_hw_params_fixup = &apq8084_mi2s_tx_be_hw_params_fixup,
		.ops = &apq8084_quad_mi2s_be_ops,
		.ignore_suspend = 1,
	},
};

static struct snd_soc_dai_link apq8084_tomtom_be_dai_links[] = {
@@ -3345,6 +3745,65 @@ err:
	return ret;
}

/**
 * msm_mi2s_get_pinctrl() - Get the MI2S pinctrl definitions.
 *
 * @pdev:	A pointer to the Audio platform device.
 *
 * Get the pinctrl states' handles from the device tree. The function doesn't
 * enforce wrong pinctrl definitions, i.e. it's the client's responsibility to
 * define all the necessary states for the board being used.
 *
 * Return 0 on success, error value otherwise.
 */
static int msm_mi2s_get_pinctrl(struct platform_device *pdev)
{
	struct snd_soc_card *card = platform_get_drvdata(pdev);
	struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info;
	struct pinctrl *pinctrl;
	int ret;

	pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR_OR_NULL(pinctrl)) {
		pr_err("%s: Unable to get pinctrl handle\n", __func__);
		return -EINVAL;
	}
	pinctrl_info->pinctrl = pinctrl;

	/* get all the states handles from Device Tree*/
	pinctrl_info->disable = pinctrl_lookup_state(pinctrl,
						"pmx-quad-mi2s-sleep");
	if (IS_ERR(pinctrl_info->disable)) {
		pr_err("%s: could not get disable pinstate\n", __func__);
		goto err;
	}

	pinctrl_info->quad_mi2s_active = pinctrl_lookup_state(pinctrl,
						"pmx-quad-mi2s-active");
	if (IS_ERR(pinctrl_info->quad_mi2s_active)) {
		pr_err("%s: could not get quad_mi2s_active pinstate\n",
			__func__);
		goto err;
	}

	/* Reset the MI2S TLMM pins to a default state */
	ret = pinctrl_select_state(pinctrl_info->pinctrl,
					pinctrl_info->disable);
	if (ret != 0) {
		pr_err("%s: Disable MI2S TLMM pins failed with %d\n",
			__func__, ret);
		return -EIO;
	}
	pinctrl_info->curr_mi2s_state = MI2S_STATE_DISABLE;
	return 0;

err:
	devm_pinctrl_put(pinctrl);
	pinctrl_info->pinctrl = NULL;
	return -EINVAL;
}

static int apq8084_prepare_us_euro(struct snd_soc_card *card)
{
	struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
@@ -3537,6 +3996,24 @@ static int apq8084_asoc_machine_probe(struct platform_device *pdev)
		goto err;
	}

	/* Parse pinctrl info for MI2S ports, if defined */
	ret = msm_mi2s_get_pinctrl(pdev);
	if (!ret) {
		pr_debug("%s: MI2S pinctrl parsing successful\n", __func__);
		lpaif_quad_muxsel_virt_addr =
				ioremap(LPAIF_QUAD_MODE_MUXSEL, 4);
		if (lpaif_quad_muxsel_virt_addr == NULL) {
			pr_err("%s Quad MI2S mux virt addr is null\n",
				__func__);
			ret = -EINVAL;
			goto err;
		}
	} else {
		dev_info(&pdev->dev,
			"%s: Parsing pinctrl failed with %d. Cannot use MI2S Ports\n",
			__func__, ret);
	}

	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
				"qcom,us-euro-gpios", 0);
	if (pdata->us_euro_gpio < 0) {
@@ -3586,6 +4063,10 @@ static int apq8084_asoc_machine_probe(struct platform_device *pdev)
	return 0;

err:
	if (pdata->mi2s_pinctrl_info.pinctrl) {
		dev_dbg(&pdev->dev, "%s: freeing MI2S pinctrl\n", __func__);
		devm_pinctrl_put(pdata->mi2s_pinctrl_info.pinctrl);
	}
	if (pdata->us_euro_gpio > 0) {
		dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
			__func__, pdata->us_euro_gpio);