asoc: msm: update asm channel map for push pull mode

In noirq push pull mode channel map needs to be set during
ASM open shared io stream. Add support for no irq driver to
set channel map during ASM shared io stream open.

CRs-Fixed: 2267809
Change-Id: Ic1abfe60bb54b6529fbb4cf999e50196befaba46
Signed-off-by: Surendar Karka <skarka@codeaurora.org>
diff --git a/asoc/msm-pcm-q6-noirq.c b/asoc/msm-pcm-q6-noirq.c
index 249f8a5..c89efb9 100644
--- a/asoc/msm-pcm-q6-noirq.c
+++ b/asoc/msm-pcm-q6-noirq.c
@@ -275,6 +275,8 @@
 	int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
 	unsigned long topology;
 	int perf_mode;
+	bool use_default_chmap = true;
+	char *chmap = NULL;
 
 	pdata = (struct msm_plat_data *)
 		dev_get_drvdata(soc_prtd->platform->dev);
@@ -311,6 +313,13 @@
 	if (prtd->enabled)
 		return 0;
 
+	if (pdata->ch_map[soc_prtd->dai_link->id]) {
+		use_default_chmap =
+			!(pdata->ch_map[soc_prtd->dai_link->id]->set_ch_map);
+		chmap =
+			pdata->ch_map[soc_prtd->dai_link->id]->channel_map;
+	}
+
 	switch (runtime->format) {
 	case SNDRV_PCM_FORMAT_S24_LE:
 		bits_per_sample = 24;
@@ -335,7 +344,8 @@
 	config.bufsz = params_buffer_bytes(params) / params_periods(params);
 	config.bufcnt = params_periods(params);
 
-	ret = q6asm_open_shared_io(prtd->audio_client, &config, dir);
+	ret = q6asm_open_shared_io(prtd->audio_client, &config, dir,
+				   use_default_chmap, chmap);
 	if (ret) {
 		pr_err("%s: q6asm_open_write_shared_io failed ret: %d\n",
 		       __func__, ret);
@@ -718,89 +728,126 @@
 	return 0;
 }
 
-static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
+static int msm_pcm_channel_map_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
 {
-	int i;
-	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	struct snd_pcm_substream *substream;
-	struct msm_audio *prtd;
+	struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+	u64 fe_id = kcontrol->private_value;
+	struct msm_plat_data *pdata = (struct msm_plat_data *)
+			snd_soc_component_get_drvdata(pcm);
+	int rc = 0, i = 0;
 
-	pr_debug("%s", __func__);
-	substream = snd_pcm_chmap_substream(info, idx);
-	if (!substream)
-		return -ENODEV;
-	if (!substream->runtime)
-		return 0;
+	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
 
-	prtd = substream->runtime->private_data;
-	if (prtd) {
-		prtd->set_channel_map = true;
-			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
-				prtd->channel_map[i] =
-				(char)(ucontrol->value.integer.value[i]);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds fe_id %llu\n",
+			__func__, fe_id);
+		rc = -EINVAL;
+		goto end;
 	}
+
+	if (pdata->ch_map[fe_id]) {
+		pdata->ch_map[fe_id]->set_ch_map = true;
+		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+			pdata->ch_map[fe_id]->channel_map[i] =
+				(char)(ucontrol->value.integer.value[i]);
+	} else {
+		pr_debug("%s: no memory for ch_map, default will be set\n",
+			__func__);
+	}
+end:
+	pr_debug("%s: ret %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_pcm_channel_map_info(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 8;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFFFFFFFF;
 	return 0;
 }
 
-static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
+static int msm_pcm_channel_map_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
 {
-	int i;
-	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	struct snd_pcm_substream *substream;
-	struct msm_audio *prtd;
+	struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+	u64 fe_id = kcontrol->private_value;
+	struct msm_plat_data *pdata = (struct msm_plat_data *)
+			snd_soc_component_get_drvdata(pcm);
+	int rc = 0, i = 0;
 
-	pr_debug("%s", __func__);
-	substream = snd_pcm_chmap_substream(info, idx);
-	if (!substream)
-		return -ENODEV;
-	memset(ucontrol->value.integer.value, 0,
-		sizeof(ucontrol->value.integer.value));
-	if (!substream->runtime)
-		return 0; /* no channels set */
-
-	prtd = substream->runtime->private_data;
-
-	if (prtd && prtd->set_channel_map == true) {
+	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s: Received out of bounds fe_id %llu\n",
+			__func__, fe_id);
+		rc = -EINVAL;
+		goto end;
+	}
+	if (pdata->ch_map[fe_id]) {
 		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
 			ucontrol->value.integer.value[i] =
-					(int)prtd->channel_map[i];
-	} else {
-		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
-			ucontrol->value.integer.value[i] = 0;
+				pdata->ch_map[fe_id]->channel_map[i];
 	}
-
-	return 0;
+end:
+	pr_debug("%s: ret %d\n", __func__, rc);
+	return rc;
 }
 
-static int msm_pcm_add_chmap_control(struct snd_soc_pcm_runtime *rtd)
+static int msm_pcm_add_channel_map_control(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_pcm *pcm = rtd->pcm;
-	struct snd_pcm_chmap *chmap_info;
-	struct snd_kcontrol *kctl;
-	char device_num[12];
-	int i, ret;
+	const char *mixer_ctl_name = "Playback Channel Map";
+	const char *deviceNo       = "NN";
+	char *mixer_str = NULL;
+	struct msm_plat_data *pdata = NULL;
+	int ctl_len = 0;
+	struct snd_kcontrol_new fe_channel_map_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_map_info,
+		.get = msm_pcm_channel_map_get,
+		.put = msm_pcm_channel_map_put,
+		.private_value = 0,
+		}
+	};
 
-	pr_debug("%s, Channel map cntrl add\n", __func__);
-	ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				     snd_pcm_std_chmaps,
-				     PCM_FORMAT_MAX_NUM_CHANNEL, 0,
-				     &chmap_info);
-	if (ret)
-		return ret;
+	if (!rtd) {
+		pr_err("%s: NULL rtd\n", __func__);
+		return -EINVAL;
+	}
 
-	kctl = chmap_info->kctl;
-	for (i = 0; i < kctl->count; i++)
-		kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
-	snprintf(device_num, sizeof(device_num), "%d", pcm->device);
-	strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
-	pr_debug("%s, Overwriting channel map control name to: %s",
-		__func__, kctl->id.name);
-	kctl->put = msm_pcm_chmap_ctl_put;
-	kctl->get = msm_pcm_chmap_ctl_get;
+	pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+
+	ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s%d", mixer_ctl_name, rtd->pcm->device);
+
+	fe_channel_map_control[0].name = mixer_str;
+	fe_channel_map_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	snd_soc_add_platform_controls(rtd->platform,
+				fe_channel_map_control,
+				ARRAY_SIZE(fe_channel_map_control));
+
+	pdata = snd_soc_platform_get_drvdata(rtd->platform);
+	pdata->ch_map[rtd->dai_link->id] =
+		 kzalloc(sizeof(struct msm_pcm_ch_map), GFP_KERNEL);
+	if (!pdata->ch_map[rtd->dai_link->id]) {
+		pr_err("%s: Could not allocate memory for channel map\n",
+			__func__);
+		kfree(mixer_str);
+		return -ENOMEM;
+	}
+	kfree(mixer_str);
 	return 0;
 }
 
@@ -1155,11 +1202,11 @@
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	ret = msm_pcm_add_chmap_control(rtd);
-	if (ret) {
-		pr_err("%s failed to add chmap cntls\n", __func__);
-		goto exit;
-	}
+	ret = msm_pcm_add_channel_map_control(rtd);
+	if (ret)
+		pr_err("%s: Could not add pcm Channel Map Control\n",
+			__func__);
+
 	ret = msm_pcm_add_volume_control(rtd);
 	if (ret) {
 		pr_err("%s: Could not add pcm Volume Control %d\n",
@@ -1181,7 +1228,7 @@
 	if (ret)
 		pr_err("%s: Could not add hw dep node\n", __func__);
 	pcm->nonatomic = true;
-exit:
+
 	return ret;
 }