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

Commit 47b7ce98 authored by Asish Bhattacharya's avatar Asish Bhattacharya
Browse files

ASoC: msm8x10: add support to split SD0/1 as two seperate BE



SD0 and SD1 are driven by single DMA channel. this makes it
impossible for any audio session to be sent to SD1 output
without mixing with SD0 data contents.

Allow user to route audio to a new AFE PORT introduced to
send data to SD1 without mixing with SD0 contents. The user
however needs to group the ports before opening any of the
AFE ports.

Change-Id: Icadc0f87fffc29575f069b6124dee3cf9d8a9fcd
Signed-off-by: default avatarAsish Bhattacharya <asishb@codeaurora.org>
parent 360013b1
Loading
Loading
Loading
Loading
+42 −0
Original line number Original line Diff line number Diff line
@@ -787,6 +787,7 @@ struct adm_cmd_connect_afe_port_v5 {
#define AFE_PORT_ID_SECONDARY_PCM_RX        0x100C
#define AFE_PORT_ID_SECONDARY_PCM_RX        0x100C
#define AFE_PORT_ID_SECONDARY_PCM_TX        0x100D
#define AFE_PORT_ID_SECONDARY_PCM_TX        0x100D
#define AFE_PORT_ID_MULTICHAN_HDMI_RX       0x100E
#define AFE_PORT_ID_MULTICHAN_HDMI_RX       0x100E
#define AFE_PORT_ID_SECONDARY_MI2S_RX_VIBRA	0x1010
#define AFE_PORT_ID_SPDIF_RX                0x5000
#define AFE_PORT_ID_SPDIF_RX                0x5000
#define  AFE_PORT_ID_RT_PROXY_PORT_001_RX   0x2000
#define  AFE_PORT_ID_RT_PROXY_PORT_001_RX   0x2000
#define  AFE_PORT_ID_RT_PROXY_PORT_001_TX   0x2001
#define  AFE_PORT_ID_RT_PROXY_PORT_001_TX   0x2001
@@ -7336,4 +7337,45 @@ struct afe_svc_cmd_set_clip_bank_selection {
#define US_RAW_SYNC_FORMAT      0x0001272F
#define US_RAW_SYNC_FORMAT      0x0001272F
#define US_GES_SYNC_FORMAT      0x00012730
#define US_GES_SYNC_FORMAT      0x00012730


#define AFE_MODULE_GROUP_DEVICE	0x00010254
#define AFE_PARAM_ID_GROUP_DEVICE_CFG	0x00010255
#define AFE_PARAM_ID_GROUP_DEVICE_ENABLE 0x00010256
#define AFE_GROUP_DEVICE_ID_SECONDARY_MI2S_RX	0x1102

/*  Payload of the #AFE_PARAM_ID_GROUP_DEVICE_CFG
 * parameter, which configures max of 8 AFE ports
 * into a group.
 * The fixed size of this structure is sixteen bytes.
 */
struct afe_group_device_group_cfg {
	u32 minor_version;
	u16 group_id;
	u16 num_channels;
	u16 port_id[8];
} __packed;


/*  Payload of the #AFE_PARAM_ID_GROUP_DEVICE_ENABLE
 * parameter, which enables or
 * disables any module.
 * The fixed size of this structure is four bytes.
 */

struct afe_group_device_enable {
	u16 group_id;
	/* valid value is AFE_GROUP_DEVICE_ID_SECONDARY_MI2S_RX */
	u16 enable;
/* Enables (1) or disables (0) the module. */
} __packed;

struct afe_port_group_create {
	struct apr_hdr hdr;
	struct afe_svc_cmd_set_param param;
	struct afe_port_param_data_v2 pdata;
	union {
		struct afe_group_device_group_cfg group_cfg;
		struct afe_group_device_enable group_enable;
	} __packed data;
} __packed;

#endif /*_APR_AUDIO_V2_H_ */
#endif /*_APR_AUDIO_V2_H_ */
+1 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
#define MSM_SEC_MI2S  1
#define MSM_SEC_MI2S  1
#define MSM_TERT_MI2S 2
#define MSM_TERT_MI2S 2
#define MSM_QUAT_MI2S  3
#define MSM_QUAT_MI2S  3
#define MSM_SEC_MI2S_VIBRA  4


struct msm_dai_auxpcm_config {
struct msm_dai_auxpcm_config {
	u16 mode;
	u16 mode;
+3 −0
Original line number Original line Diff line number Diff line
@@ -89,6 +89,7 @@ enum {
	IDX_SPDIF_RX = 47,
	IDX_SPDIF_RX = 47,
	IDX_GLOBAL_CFG,
	IDX_GLOBAL_CFG,
	IDX_AUDIO_PORT_ID_I2S_RX,
	IDX_AUDIO_PORT_ID_I2S_RX,
	IDX_AFE_PORT_ID_SECONDARY_MI2S_RX_VIBRA,
	AFE_MAX_PORTS
	AFE_MAX_PORTS
};
};


@@ -218,4 +219,6 @@ void afe_clear_config(enum afe_config_type config);
bool afe_has_config(enum afe_config_type config);
bool afe_has_config(enum afe_config_type config);


void afe_set_aanc_info(struct aanc_data *aanc_info);
void afe_set_aanc_info(struct aanc_data *aanc_info);
int afe_port_group_set_param(u16 *port_id, int channel_count);
int afe_port_group_enable(u16 enable);
#endif /* __Q6AFE_V2_H__ */
#endif /* __Q6AFE_V2_H__ */
+16 −1
Original line number Original line Diff line number Diff line
@@ -85,6 +85,7 @@ enum {
enum {
enum {
	AIF1_PB = 0,
	AIF1_PB = 0,
	AIF1_CAP,
	AIF1_CAP,
	AIF2_PB,
	NUM_CODEC_DAIS,
	NUM_CODEC_DAIS,
};
};


@@ -2352,6 +2353,20 @@ static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
		},
		},
		.ops = &msm8x10_wcd_dai_ops,
		.ops = &msm8x10_wcd_dai_ops,
	},
	},
	{
		.name = "msm8x10_wcd_i2s_rx2",
		.id = AIF2_PB,
		.playback = {
			.stream_name = "AIF2 Playback",
			.rates = MSM8X10_WCD_RATES,
			.formats = MSM8X10_WCD_FORMATS,
			.rate_max = 192000,
			.rate_min = 8000,
			.channels_min = 1,
			.channels_max = 3,
		},
		.ops = &msm8x10_wcd_dai_ops,
	},
};
};


static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
@@ -2389,7 +2404,7 @@ static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {


	SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
	SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),


	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),


	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),


+160 −2
Original line number Original line Diff line number Diff line
@@ -46,6 +46,8 @@
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
static int msm_btsco_ch = 1;


static int msm_sec_mi2s_rx2_group;

static int msm_proxy_rx_ch = 2;
static int msm_proxy_rx_ch = 2;
static struct platform_device *spdev;
static struct platform_device *spdev;
static int ext_spk_amp_gpio = -1;
static int ext_spk_amp_gpio = -1;
@@ -55,6 +57,7 @@ static void __iomem *pcbcr;
static void __iomem *prcgr;
static void __iomem *prcgr;


static int msm_sec_mi2s_rx_ch = 1;
static int msm_sec_mi2s_rx_ch = 1;
static int msm_sec_mi2s_rx2_ch = 1;
static int msm_pri_mi2s_tx_ch = 1;
static int msm_pri_mi2s_tx_ch = 1;
static int msm_sec_mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_sec_mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;


@@ -275,6 +278,21 @@ static int msm_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
	return 0;
	return 0;
}
}


static int msm_rx2_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);

	pr_debug("%s(): channel:%d\n", __func__, msm_sec_mi2s_rx2_ch);
	rate->min = rate->max = 48000;
	channels->min = channels->max = msm_sec_mi2s_rx2_ch;

	return 0;
}

static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
				struct snd_pcm_hw_params *params)
				struct snd_pcm_hw_params *params)
{
{
@@ -328,6 +346,23 @@ static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
	return 0;
	return 0;
}
}


static int msm_mi2s_rx2_init(void)
{
	int ret = 0;

	pr_debug("%s()\n", __func__);
	if (msm_sec_mi2s_rx2_group) {
		u16 port_id[8] = {
			AFE_PORT_ID_SECONDARY_MI2S_RX,
			AFE_PORT_ID_SECONDARY_MI2S_RX_VIBRA,
			0, 0, 0, 0, 0, 0};
		ret = afe_port_group_set_param(port_id, 4);
	}
	if (!ret)
		return afe_port_group_enable(msm_sec_mi2s_rx2_group);
	return 0;
}

static int msm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
static int msm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
	struct snd_ctl_elem_value *ucontrol)
{
{
@@ -347,6 +382,25 @@ static int msm_sec_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
	return 1;
	return 1;
}
}


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

static int msm_sec_mi2s_rx2_ch_put(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	msm_sec_mi2s_rx2_ch = ucontrol->value.integer.value[0] + 1;

	pr_debug("%s: msm_sec_mi2s_rx2_ch = %d\n", __func__,
		msm_sec_mi2s_rx2_ch);
	return 1;
}

static int msm_pri_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
static int msm_pri_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
	struct snd_ctl_elem_value *ucontrol)
{
{
@@ -388,6 +442,42 @@ static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream,
	return 0;
	return 0;
}
}


static int mi2s_clk_ctl_vibra(struct snd_pcm_substream *substream, bool enable)
{
	int ret = 0;

	if (enable) {
		digital_cdc_clk.clk_val = 9600000;
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
			mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
			ret = afe_set_lpass_clock(
				AFE_PORT_ID_SECONDARY_MI2S_RX_VIBRA,
				&mi2s_rx_clk);
		} else
			pr_err("%s:Not valid substream.\n", __func__);

		if (ret < 0)
			pr_err("%s:afe_set_lpass_clock failed\n", __func__);

	} else {
		digital_cdc_clk.clk_val = 0;
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
			mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
			ret = afe_set_lpass_clock(
				AFE_PORT_ID_SECONDARY_MI2S_RX_VIBRA,
				&mi2s_rx_clk);
		} else
			pr_err("%s:Not valid substream.\n", __func__);

		if (ret < 0)
			pr_err("%s:afe_set_lpass_clock failed\n", __func__);

	}
	return ret;
}

static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
{
{
	int ret = 0;
	int ret = 0;
@@ -474,15 +564,44 @@ static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
	}
	}
}
}


static void msm_mi2s_sec_snd_shutdown(struct snd_pcm_substream *substream)
{
	int ret = 0;

	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
		 substream->name, substream->stream);
	ret = mi2s_clk_ctl_vibra(substream, false);
	if (ret < 0)
		pr_err("%s:clock disable failed\n", __func__);
}

static int msm_mi2s_sec_snd_startup(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	int ret = 0;

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

	ret = mi2s_clk_ctl_vibra(substream, true);

	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		pr_err("set fmt cpu dai failed\n");

	return ret;
}

static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
{
{
	int ret;
	int ret = 0;


	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
		 substream->name, substream->stream);
		 substream->name, substream->stream);
	ret = mi2s_clk_ctl(substream, false);
	ret = mi2s_clk_ctl(substream, false);
	if (ret < 0)
	if (ret < 0)
		pr_err("%s:clock disable failed\n", __func__);
		pr_err("%s:clock disable failed ret(%d)\n", __func__, ret);
}
}


static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
@@ -515,6 +634,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
			msm_sec_mi2s_rx_ch_get, msm_sec_mi2s_rx_ch_put),
			msm_sec_mi2s_rx_ch_get, msm_sec_mi2s_rx_ch_put),
	SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1],
	SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1],
			msm_pri_mi2s_tx_ch_get, msm_pri_mi2s_tx_ch_put),
			msm_pri_mi2s_tx_ch_get, msm_pri_mi2s_tx_ch_put),
	SOC_ENUM_EXT("MI2S_RX_VIBRA Channels", msm_snd_enum[0],
			msm_sec_mi2s_rx2_ch_get, msm_sec_mi2s_rx2_ch_put),
};
};


static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -664,6 +785,13 @@ static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
	rate->min = rate->max = 48000;
	rate->min = rate->max = 48000;
	return 0;
	return 0;
}
}

static struct snd_soc_ops msm8x10_mi2s_sec_be_ops = {
	.startup = msm_mi2s_sec_snd_startup,
	.hw_params = msm_mi2s_snd_hw_params,
	.shutdown = msm_mi2s_sec_snd_shutdown,
};

static struct snd_soc_ops msm8x10_mi2s_be_ops = {
static struct snd_soc_ops msm8x10_mi2s_be_ops = {
	.startup = msm_mi2s_snd_startup,
	.startup = msm_mi2s_snd_startup,
	.hw_params = msm_mi2s_snd_hw_params,
	.hw_params = msm_mi2s_snd_hw_params,
@@ -906,6 +1034,21 @@ static struct snd_soc_dai_link msm8x10_dai[] = {
		.codec_name = "snd-soc-dummy",
		.codec_name = "snd-soc-dummy",
		.be_id = MSM_FRONTEND_DAI_QCHAT,
		.be_id = MSM_FRONTEND_DAI_QCHAT,
	},
	},
	{/* hw:x,16 */
		.name = "MSM8x10 Vibra",
		.stream_name = "MultiMedia6",
		.cpu_dai_name   = "MultiMedia6",
		.platform_name  = "msm-pcm-dsp.2",
		.dynamic = 1,
		.codec_dai_name = "snd-soc-dummy-dai",
		.codec_name = "snd-soc-dummy",
		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
				SND_SOC_DPCM_TRIGGER_POST},
		.ignore_suspend = 1,
		/* this dainlink has playback support */
		.ignore_pmdown_time = 1,
		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
	},
	/* Backend I2S DAI Links */
	/* Backend I2S DAI Links */
	{
	{
		.name = LPASS_BE_SEC_MI2S_RX,
		.name = LPASS_BE_SEC_MI2S_RX,
@@ -921,6 +1064,19 @@ static struct snd_soc_dai_link msm8x10_dai[] = {
		.ops = &msm8x10_mi2s_be_ops,
		.ops = &msm8x10_mi2s_be_ops,
		.ignore_suspend = 1,
		.ignore_suspend = 1,
	},
	},
	{
		.name = LPASS_BE_SEC_MI2S_RX_VIBRA,
		.stream_name = "Secondary MI2S Playback Vibra",
		.cpu_dai_name = "msm-dai-q6-mi2s.4",
		.platform_name = "msm-pcm-routing",
		.codec_name     = MSM8X10_CODEC_NAME,
		.codec_dai_name = "msm8x10_wcd_i2s_rx2",
		.no_pcm = 1,
		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX_VIBRA,
		.be_hw_params_fixup = msm_rx2_be_hw_params_fixup,
		.ops = &msm8x10_mi2s_sec_be_ops,
		.ignore_suspend = 1,
	},
	{
	{
		.name = LPASS_BE_PRI_MI2S_TX,
		.name = LPASS_BE_PRI_MI2S_TX,
		.stream_name = "Primary MI2S Capture",
		.stream_name = "Primary MI2S Capture",
@@ -1142,6 +1298,8 @@ static int msm8x10_asoc_machine_probe(struct platform_device *pdev)
		goto err;
		goto err;
	}
	}
	atomic_set(&mclk_rsc_ref, 0);
	atomic_set(&mclk_rsc_ref, 0);
	if (msm_sec_mi2s_rx2_group)
		msm_mi2s_rx2_init();
	return 0;
	return 0;
err:
err:
	return ret;
	return ret;
Loading