ASoC: msm: Support send flush to DSP Multichannel PCM playback

In the use case of multi channel PCM playback with the playback
control sequence of Pause, Flush, Resume; residual data buffered in
DSP is played when resuming the playback after seek or flush.
Add support to send CMD_FLUSH to DSP to flush the buffered residual
data after Pause.

CRs-Fixed: 380473
Change-Id: I1d099d28e51858c7c22df88253cd6f83a9c3ca56
Signed-off-by: Subhash Chandra Bose Naripeddy <snariped@codeaurora.org>
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index bd4a521..6cad0af 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -236,6 +236,11 @@
 			}
 			atomic_set(&prtd->start, 1);
 			break;
+		case ASM_STREAM_CMD_FLUSH:
+			pr_debug("ASM_STREAM_CMD_FLUSH\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.flush_wait);
+			break;
 		default:
 			break;
 		}
@@ -800,13 +805,52 @@
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	return 0;
 }
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+			unsigned int cmd, void *arg)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0, rc;
+
+	pr_debug("%s\n", __func__);
+	ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+	if (ret < 0) {
+		pr_err("%s, snd_pcm_lib_ioctl error\n", __func__);
+		return ret;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL1_RESET:
+		pr_debug("%s, SNDRV_PCM_IOCTL1_RESET\n", __func__);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			prtd->cmd_ack = 0;
+			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			if (rc < 0) {
+				pr_err("%s: flush cmd failed rc=%d\n",
+					 __func__, rc);
+				break;
+			}
+			rc = wait_event_timeout(the_locks.flush_wait,
+				 prtd->cmd_ack, 5 * HZ);
+			if (rc < 0)
+				pr_err("Flush cmd timeout\n");
+			prtd->pcm_irq_pos = 0;
+			atomic_set(&prtd->out_count, runtime->periods);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
 
 static struct snd_pcm_ops msm_pcm_ops = {
 	.open           = msm_pcm_open,
 	.copy		= msm_pcm_copy,
 	.hw_params	= msm_pcm_hw_params,
 	.close          = msm_pcm_close,
-	.ioctl          = snd_pcm_lib_ioctl,
+	.ioctl          = msm_pcm_ioctl,
 	.prepare        = msm_pcm_prepare,
 	.trigger        = msm_pcm_trigger,
 	.pointer        = msm_pcm_pointer,
@@ -894,6 +938,7 @@
 	init_waitqueue_head(&the_locks.eos_wait);
 	init_waitqueue_head(&the_locks.write_wait);
 	init_waitqueue_head(&the_locks.read_wait);
+	init_waitqueue_head(&the_locks.flush_wait);
 
 	return platform_driver_register(&msm_pcm_driver);
 }