From 11bc8d6972f3a908700cc12d6ba86d847594e979 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <lrg@slimlogic.co.uk>
Date: Tue, 15 Feb 2011 03:09:22 -0600
Subject: [PATCH 34/60] ASoC: McPDM: Split out McPDM into 4 logical DAIs

commit 55ce9aa30d36867b224d6acfb7033f4d4501db58 upstream

McPDM interface contains following DAIs: PDM_DL1,
PDM_DL2, PDM_UL and VIB_DL.

Change-Id: I984f58b656a8182e6a62750c675e3770f2e34695
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Margarita Olaya Cabrera <magi.olaya@ti.com>
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Integrated-by: Jingdong Lu <jingdong.lu@windriver.com>
---
 sound/soc/omap/omap-mcpdm.c |   82 +++++++++++++++++++++++++++++--------------
 1 files changed, 55 insertions(+), 27 deletions(-)

diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index e8715b0..67ce001 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -50,7 +50,6 @@
 
 struct omap_mcpdm_data {
 	struct omap_mcpdm_link *links;
-	int active;
 };
 
 struct omap_mcpdm {
@@ -68,6 +67,8 @@ struct omap_mcpdm {
 
 	int dn_channels;
 	int up_channels;
+	int dl_active;
+	int ul_active;
 };
 
 static struct omap_mcpdm_link omap_mcpdm_links[] = {
@@ -248,7 +249,6 @@ static int omap_mcpdm_capture_open(struct omap_mcpdm *mcpdm,
 
 	/* Uplink channels */
 	mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
-
 	omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
 
 	return 0;
@@ -283,8 +283,7 @@ static int omap_mcpdm_playback_open(struct omap_mcpdm *mcpdm,
 	ctrl |= downlink->format & PDMOUTFORMAT;
 
 	/* Downlink channels */
-	mcpdm->dn_channels = (PDM_DN_MASK | PDM_CMD_MASK);
-
+	mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
 	omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
 
 	return 0;
@@ -489,8 +488,12 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 	int err = 0;
 
-	if (!dai->active)
+	dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active);
+
+	if (!dai->active && mcpdm->free) {
 		err = omap_mcpdm_request(mcpdm);
+		omap_mcpdm_set_offset(mcpdm);
+	}
 
 	return err;
 }
@@ -500,8 +503,21 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
 {
 	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
-	if (!dai->active)
-		omap_mcpdm_free(mcpdm);
+	dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mcpdm->dl_active--;
+		if (mcpdm->dl_active == 0)
+			omap_mcpdm_playback_close(mcpdm, mcpdm->downlink);
+	} else
+		mcpdm->ul_active--;
+
+	if (!dai->active) {
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			omap_mcpdm_capture_close(mcpdm, mcpdm->uplink);
+		if (!mcpdm->free && !mcpdm->dl_active && !mcpdm->ul_active)
+			omap_mcpdm_free(mcpdm);
+	}
 }
 
 static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
@@ -548,20 +564,6 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 	return err;
 }
 
-static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dai)
-{
-	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-	int err;
-
-	if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
-		err = omap_mcpdm_playback_close(mcpdm, mcpdm->downlink);
-	else
-		err = omap_mcpdm_capture_close(mcpdm, mcpdm->uplink);
-
-	return err;
-}
-
 static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream,
 				  int cmd, struct snd_soc_dai *dai)
 {
@@ -592,20 +594,45 @@ static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
 	.startup	= omap_mcpdm_dai_startup,
 	.shutdown	= omap_mcpdm_dai_shutdown,
 	.hw_params	= omap_mcpdm_dai_hw_params,
-	.hw_free	= omap_mcpdm_dai_hw_free,
 	.trigger	= omap_mcpdm_dai_trigger,
 };
 
 #define OMAP_MCPDM_RATES	(SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 #define OMAP_MCPDM_FORMATS	(SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_driver omap_mcpdm_dai = {
+static struct snd_soc_dai_driver omap_mcpdm_dai[] = {
+{
+	.name = "mcpdm-dl1",
 	.playback = {
 		.channels_min = 1,
-		.channels_max = 4,
+		.channels_max = 2,
 		.rates = OMAP_MCPDM_RATES,
 		.formats = OMAP_MCPDM_FORMATS,
 	},
+	.ops = &omap_mcpdm_dai_ops,
+},
+{
+	.name = "mcpdm-dl2",
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = OMAP_MCPDM_RATES,
+		.formats = OMAP_MCPDM_FORMATS,
+	},
+	.ops = &omap_mcpdm_dai_ops,
+},
+{
+	.name = "mcpdm-vib",
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = OMAP_MCPDM_RATES,
+		.formats = OMAP_MCPDM_FORMATS,
+	},
+	.ops = &omap_mcpdm_dai_ops,
+},
+{
+	.name = "mcpdm-ul1",
 	.capture = {
 		.channels_min = 1,
 		.channels_max = 2,
@@ -613,7 +640,7 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
 		.formats = OMAP_MCPDM_FORMATS,
 	},
 	.ops = &omap_mcpdm_dai_ops,
-};
+}, };
 
 static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
 {
@@ -654,7 +681,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
 
 	mcpdm->dev = &pdev->dev;
 
-	ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+	ret = snd_soc_register_dais(&pdev->dev, omap_mcpdm_dai,
+				    ARRAY_SIZE(omap_mcpdm_dai));
 	if (ret == 0)
 		return 0;
 
@@ -667,7 +695,7 @@ static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
 {
 	struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_dai(&pdev->dev);
+	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_mcpdm_dai));
 	pm_runtime_put_sync(&pdev->dev);
 	kfree(mcpdm);
 	return 0;
-- 
1.7.4.1

