All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] ASoC: omap-mcpdm: New McPDM driver
@ 2011-08-26 13:33 Peter Ujfalusi
  2011-08-26 13:33 ` [PATCH v3 1/3] ASoC: DAPM: Add private data pointer for DAPM widget Peter Ujfalusi
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Peter Ujfalusi @ 2011-08-26 13:33 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood; +Cc: alsa-devel, Misael Lopez Cruz

Hello,

Changes since v2 [1]:
- Code for the DAPM_SUPPLY widget attach has been moved to core (Request from
  Mark, if I understood correctly).
 - Makes it reusable in other drivers
 - Additional code still needed in DAI (event handler, selection of the dai),
   and machine drivers (DAPM routing)
 - Should work even if we have multiple instances of the DAI (coment from
   Lars-Peter Clausen)

[1]
http://mailman.alsa-project.org/pipermail/alsa-devel/2011-August/042923.html

Regards,
Peter

---
Misael Lopez Cruz (1):
  ASoC: omap-mcpdm: Replace legacy driver

Peter Ujfalusi (2):
  ASoC: DAPM: Add private data pointer for DAPM widget
  ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai

 include/sound/soc-dapm.h    |   18 +
 sound/soc/omap/Makefile     |    2 +-
 sound/soc/omap/mcpdm.c      |  474 -------------------------
 sound/soc/omap/mcpdm.h      |  152 --------
 sound/soc/omap/omap-mcpdm.c |  813 ++++++++++++++++++++++++++++---------------
 sound/soc/omap/omap-mcpdm.h |   97 +++++
 sound/soc/omap/sdp4430.c    |   14 +-
 sound/soc/soc-dapm.c        |   27 ++
 8 files changed, 690 insertions(+), 907 deletions(-)
 delete mode 100644 sound/soc/omap/mcpdm.c
 delete mode 100644 sound/soc/omap/mcpdm.h
 rewrite sound/soc/omap/omap-mcpdm.c (46%)
 create mode 100644 sound/soc/omap/omap-mcpdm.h

-- 
1.7.6.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 1/3] ASoC: DAPM: Add private data pointer for DAPM widget
  2011-08-26 13:33 [PATCH v3 0/3] ASoC: omap-mcpdm: New McPDM driver Peter Ujfalusi
@ 2011-08-26 13:33 ` Peter Ujfalusi
  2011-08-26 13:33 ` [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai Peter Ujfalusi
  2011-08-26 13:33 ` [PATCH v3 3/3] ASoC: omap-mcpdm: Replace legacy driver Peter Ujfalusi
  2 siblings, 0 replies; 11+ messages in thread
From: Peter Ujfalusi @ 2011-08-26 13:33 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood; +Cc: alsa-devel, Misael Lopez Cruz

Support for using custom private data assigned
per DAPM widget.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 include/sound/soc-dapm.h |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index e0583b7..c10d4cc 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -474,6 +474,7 @@ struct snd_soc_dapm_widget {
 	unsigned char force:1;			/* force state */
 	unsigned char ignore_suspend:1;         /* kept enabled over suspend */
 	int subseq;				/* sort within widget type */
+	void *private_data;			/* for widget specific data */
 
 	int (*power_check)(struct snd_soc_dapm_widget *w);
 
@@ -535,4 +536,16 @@ struct snd_soc_dapm_widget_list {
 	struct snd_soc_dapm_widget *widgets[0];
 };
 
+/* Accessors for snd_soc_dapm_widget->private_data */
+static inline void *snd_soc_dapm_widget_get_pdata(struct snd_soc_dapm_widget *w)
+{
+	return w->private_data;
+}
+
+static inline void snd_soc_dapm_widget_set_pdata(struct snd_soc_dapm_widget *w,
+		void *data)
+{
+	w->private_data = data;
+}
+
 #endif
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-08-26 13:33 [PATCH v3 0/3] ASoC: omap-mcpdm: New McPDM driver Peter Ujfalusi
  2011-08-26 13:33 ` [PATCH v3 1/3] ASoC: DAPM: Add private data pointer for DAPM widget Peter Ujfalusi
@ 2011-08-26 13:33 ` Peter Ujfalusi
  2011-08-26 19:05   ` Mark Brown
  2011-08-26 13:33 ` [PATCH v3 3/3] ASoC: omap-mcpdm: Replace legacy driver Peter Ujfalusi
  2 siblings, 1 reply; 11+ messages in thread
From: Peter Ujfalusi @ 2011-08-26 13:33 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood; +Cc: alsa-devel, Misael Lopez Cruz

There are cpu dais, which require special ordering during stream
stop (OMAP4's McPDM interface for example) in a system level.
OMAP4 McPDM required to be stopped after the attached codec's
(twl6040) DAC/ADC has been stopped.

This requironment can be solved with a use of DAPM_SUPPLY
widget attached to the codec's ADC/DAC from machine driver.

Provide generic enough API from core which can be used from
other drivers, if needed.

The snd_soc_dapm_attach_dai_supply function can be used to attach
the DAPM_SUPPLY widget to the specified dapm_context.
The resulting widget's private_data will be initialized with
the dai's drvdata.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 include/sound/soc-dapm.h |    5 +++++
 sound/soc/soc-dapm.c     |   27 +++++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c10d4cc..e540bb2 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -381,6 +381,11 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 				const char *pin);
 
+int snd_soc_dapm_attach_dai_supply(struct snd_soc_dapm_context *dapm,
+	struct snd_soc_dai *dai, char *wname,
+	int (*wevent)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int),
+	unsigned short wflags);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
 	snd_soc_dapm_input = 0,		/* input pin */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7e15914..8839202 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2776,6 +2776,33 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
+/**
+ * snd_soc_dapm_attach_dai_supply - attach supply widget on behalf of a dai
+ * @dapm: DAPM context
+ * @dai: DAI, which requesting the widget
+ * @wname: name of the DAPM_SUPPLY widget
+ * @wevent: event handler callback
+ * @wflags: DAPM event flags
+ *
+ * Creates DAPM_SUPPLY widget on behalf of a dai. The new widget's private_data
+ * will inherit the dai's driver data pointer, which is going to be available
+ * in the event handler.
+ */
+int snd_soc_dapm_attach_dai_supply(struct snd_soc_dapm_context *dapm,
+	struct snd_soc_dai *dai, char *wname,
+	int (*wevent)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int),
+	unsigned short wflags)
+{
+	void *pdata = snd_soc_dai_get_drvdata(dai);
+	struct snd_soc_dapm_widget dai_widget =
+		SND_SOC_DAPM_SUPPLY(wname, SND_SOC_NOPM, 0, 0, wevent, wflags);
+
+	snd_soc_dapm_widget_set_pdata(&dai_widget, pdata);
+
+	return snd_soc_dapm_new_control(dapm, &dai_widget);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_attach_dai_supply);
+
 static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
 {
 	struct snd_soc_dapm_widget *w;
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 3/3] ASoC: omap-mcpdm: Replace legacy driver
  2011-08-26 13:33 [PATCH v3 0/3] ASoC: omap-mcpdm: New McPDM driver Peter Ujfalusi
  2011-08-26 13:33 ` [PATCH v3 1/3] ASoC: DAPM: Add private data pointer for DAPM widget Peter Ujfalusi
  2011-08-26 13:33 ` [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai Peter Ujfalusi
@ 2011-08-26 13:33 ` Peter Ujfalusi
  2 siblings, 0 replies; 11+ messages in thread
From: Peter Ujfalusi @ 2011-08-26 13:33 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood; +Cc: alsa-devel, Misael Lopez Cruz

From: Misael Lopez Cruz <misael.lopez@ti.com>

Reasons for the replacement:
The current driver for McPDM was developed to support the legacy mode only.
In preparation for the ABE support the current driver stack need the be
replaced.
The new driver is much simpler, easier to extend, and it also fixes some of the
issues with the old stack.

Main changes:
- single file for omap-mcpdm (mcpdm.c/h removed)
- Define names for registers, bits cleaned up, prefixed
- Full-duplex audio operation (arecord | aplay) has been fixed
- Less code

McPDM need to be turned off _after_ the codec's DAC/ADC has been powered down.
This can be achieved by attaching DAPM_SUPPLY widget to the current dapm_context
using the snd_soc_dapm_attach_dai_supply call.
The machine driver connects the "OMAP McPDM Interface" to the codec's DAC/ADC,
so after audio activity we can be sure that the host side McPDM is turned off
at the correct time (this takes place in the DAPM_SUPPLY's event handler).

Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 sound/soc/omap/Makefile     |    2 +-
 sound/soc/omap/mcpdm.c      |  474 -------------------------
 sound/soc/omap/mcpdm.h      |  152 --------
 sound/soc/omap/omap-mcpdm.c |  813 ++++++++++++++++++++++++++++---------------
 sound/soc/omap/omap-mcpdm.h |   97 +++++
 sound/soc/omap/sdp4430.c    |   14 +-
 6 files changed, 645 insertions(+), 907 deletions(-)
 delete mode 100644 sound/soc/omap/mcpdm.c
 delete mode 100644 sound/soc/omap/mcpdm.h
 rewrite sound/soc/omap/omap-mcpdm.c (46%)
 create mode 100644 sound/soc/omap/omap-mcpdm.h

diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 59e2c8d..052fd75 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,7 +1,7 @@
 # OMAP Platform Support
 snd-soc-omap-objs := omap-pcm.o
 snd-soc-omap-mcbsp-objs := omap-mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
 snd-soc-omap-hdmi-objs := omap-hdmi.o
 
 obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
deleted file mode 100644
index d29cc98..0000000
--- a/sound/soc/omap/mcpdm.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * mcpdm.c  --	McPDM interface driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- * Copyright (C) 2009 - Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/pm_runtime.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include "mcpdm.h"
-
-static struct omap_mcpdm *mcpdm;
-
-static inline void omap_mcpdm_write(u16 reg, u32 val)
-{
-	__raw_writel(val, mcpdm->io_base + reg);
-}
-
-static inline int omap_mcpdm_read(u16 reg)
-{
-	return __raw_readl(mcpdm->io_base + reg);
-}
-
-static void omap_mcpdm_reg_dump(void)
-{
-	dev_dbg(mcpdm->dev, "***********************\n");
-	dev_dbg(mcpdm->dev, "IRQSTATUS_RAW:  0x%04x\n",
-			omap_mcpdm_read(MCPDM_IRQSTATUS_RAW));
-	dev_dbg(mcpdm->dev, "IRQSTATUS:	0x%04x\n",
-			omap_mcpdm_read(MCPDM_IRQSTATUS));
-	dev_dbg(mcpdm->dev, "IRQENABLE_SET:  0x%04x\n",
-			omap_mcpdm_read(MCPDM_IRQENABLE_SET));
-	dev_dbg(mcpdm->dev, "IRQENABLE_CLR:  0x%04x\n",
-			omap_mcpdm_read(MCPDM_IRQENABLE_CLR));
-	dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
-			omap_mcpdm_read(MCPDM_IRQWAKE_EN));
-	dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
-			omap_mcpdm_read(MCPDM_DMAENABLE_SET));
-	dev_dbg(mcpdm->dev, "DMAENABLE_CLR:  0x%04x\n",
-			omap_mcpdm_read(MCPDM_DMAENABLE_CLR));
-	dev_dbg(mcpdm->dev, "DMAWAKEEN:	0x%04x\n",
-			omap_mcpdm_read(MCPDM_DMAWAKEEN));
-	dev_dbg(mcpdm->dev, "CTRL:	0x%04x\n",
-			omap_mcpdm_read(MCPDM_CTRL));
-	dev_dbg(mcpdm->dev, "DN_DATA:  0x%04x\n",
-			omap_mcpdm_read(MCPDM_DN_DATA));
-	dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
-			omap_mcpdm_read(MCPDM_UP_DATA));
-	dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
-			omap_mcpdm_read(MCPDM_FIFO_CTRL_DN));
-	dev_dbg(mcpdm->dev, "FIFO_CTRL_UP:  0x%04x\n",
-			omap_mcpdm_read(MCPDM_FIFO_CTRL_UP));
-	dev_dbg(mcpdm->dev, "DN_OFFSET:	0x%04x\n",
-			omap_mcpdm_read(MCPDM_DN_OFFSET));
-	dev_dbg(mcpdm->dev, "***********************\n");
-}
-
-/*
- * Takes the McPDM module in and out of reset state.
- * Uplink and downlink can be reset individually.
- */
-static void omap_mcpdm_reset_capture(int reset)
-{
-	int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
-	if (reset)
-		ctrl |= SW_UP_RST;
-	else
-		ctrl &= ~SW_UP_RST;
-
-	omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-static void omap_mcpdm_reset_playback(int reset)
-{
-	int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
-	if (reset)
-		ctrl |= SW_DN_RST;
-	else
-		ctrl &= ~SW_DN_RST;
-
-	omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Enables the transfer through the PDM interface to/from the Phoenix
- * codec by enabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_start(int stream)
-{
-	int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
-	if (stream)
-		ctrl |= mcpdm->up_channels;
-	else
-		ctrl |= mcpdm->dn_channels;
-
-	omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Disables the transfer through the PDM interface to/from the Phoenix
- * codec by disabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_stop(int stream)
-{
-	int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
-	if (stream)
-		ctrl &= ~mcpdm->up_channels;
-	else
-		ctrl &= ~mcpdm->dn_channels;
-
-	omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Configures McPDM uplink for audio recording.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink)
-{
-	int irq_mask = 0;
-	int ctrl;
-
-	if (!uplink)
-		return -EINVAL;
-
-	mcpdm->uplink = uplink;
-
-	/* Enable irq request generation */
-	irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
-	omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
-	/* Configure uplink threshold */
-	if (uplink->threshold > UP_THRES_MAX)
-		uplink->threshold = UP_THRES_MAX;
-
-	omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold);
-
-	/* Configure DMA controller */
-	omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
-
-	/* Set pdm out format */
-	ctrl = omap_mcpdm_read(MCPDM_CTRL);
-	ctrl &= ~PDMOUTFORMAT;
-	ctrl |= uplink->format & PDMOUTFORMAT;
-
-	/* Uplink channels */
-	mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
-
-	omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
-	return 0;
-}
-
-/*
- * Configures McPDM downlink for audio playback.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink)
-{
-	int irq_mask = 0;
-	int ctrl;
-
-	if (!downlink)
-		return -EINVAL;
-
-	mcpdm->downlink = downlink;
-
-	/* Enable irq request generation */
-	irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
-	omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
-	/* Configure uplink threshold */
-	if (downlink->threshold > DN_THRES_MAX)
-		downlink->threshold = DN_THRES_MAX;
-
-	omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold);
-
-	/* Enable DMA request generation */
-	omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
-
-	/* Set pdm out format */
-	ctrl = omap_mcpdm_read(MCPDM_CTRL);
-	ctrl &= ~PDMOUTFORMAT;
-	ctrl |= downlink->format & PDMOUTFORMAT;
-
-	/* Downlink channels */
-	mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
-
-	omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
-	return 0;
-}
-
-/*
- * Cleans McPDM uplink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink)
-{
-	int irq_mask = 0;
-
-	if (!uplink)
-		return -EINVAL;
-
-	/* Disable irq request generation */
-	irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
-	omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
-	/* Disable DMA request generation */
-	omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
-
-	/* Clear Downlink channels */
-	mcpdm->up_channels = 0;
-
-	mcpdm->uplink = NULL;
-
-	return 0;
-}
-
-/*
- * Cleans McPDM downlink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink)
-{
-	int irq_mask = 0;
-
-	if (!downlink)
-		return -EINVAL;
-
-	/* Disable irq request generation */
-	irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
-	omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
-	/* Disable DMA request generation */
-	omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
-
-	/* clear Downlink channels */
-	mcpdm->dn_channels = 0;
-
-	mcpdm->downlink = NULL;
-
-	return 0;
-}
-
-static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
-{
-	struct omap_mcpdm *mcpdm_irq = dev_id;
-	int irq_status;
-
-	irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS);
-
-	/* Acknowledge irq event */
-	omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status);
-
-	if (irq & MCPDM_DN_IRQ_FULL) {
-		dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
-		omap_mcpdm_reset_playback(1);
-		omap_mcpdm_playback_open(mcpdm_irq->downlink);
-		omap_mcpdm_reset_playback(0);
-	}
-
-	if (irq & MCPDM_DN_IRQ_EMPTY) {
-		dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
-		omap_mcpdm_reset_playback(1);
-		omap_mcpdm_playback_open(mcpdm_irq->downlink);
-		omap_mcpdm_reset_playback(0);
-	}
-
-	if (irq & MCPDM_DN_IRQ) {
-		dev_dbg(mcpdm_irq->dev, "DN write request\n");
-	}
-
-	if (irq & MCPDM_UP_IRQ_FULL) {
-		dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
-		omap_mcpdm_reset_capture(1);
-		omap_mcpdm_capture_open(mcpdm_irq->uplink);
-		omap_mcpdm_reset_capture(0);
-	}
-
-	if (irq & MCPDM_UP_IRQ_EMPTY) {
-		dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
-		omap_mcpdm_reset_capture(1);
-		omap_mcpdm_capture_open(mcpdm_irq->uplink);
-		omap_mcpdm_reset_capture(0);
-	}
-
-	if (irq & MCPDM_UP_IRQ) {
-		dev_dbg(mcpdm_irq->dev, "UP write request\n");
-	}
-
-	return IRQ_HANDLED;
-}
-
-			int omap_mcpdm_request(void)
-{
-	int ret;
-
-	pm_runtime_get_sync(mcpdm->dev);
-
-	spin_lock(&mcpdm->lock);
-
-	if (!mcpdm->free) {
-		dev_err(mcpdm->dev, "McPDM interface is in use\n");
-		spin_unlock(&mcpdm->lock);
-		ret = -EBUSY;
-		goto err;
-	}
-	mcpdm->free = 0;
-
-	spin_unlock(&mcpdm->lock);
-
-	/* Disable lines while request is ongoing */
-	omap_mcpdm_write(MCPDM_CTRL, 0x00);
-
-	ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
-				0, "McPDM", (void *)mcpdm);
-	if (ret) {
-		dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n");
-		goto err;
-	}
-
-	return 0;
-
-err:
-	mcpdm->free = 1;
-	pm_runtime_put_sync(mcpdm->dev);
-	return ret;
-}
-
-void omap_mcpdm_free(void)
-{
-	spin_lock(&mcpdm->lock);
-	if (mcpdm->free) {
-		dev_err(mcpdm->dev, "McPDM interface is already free\n");
-		spin_unlock(&mcpdm->lock);
-		return;
-	}
-	mcpdm->free = 1;
-	spin_unlock(&mcpdm->lock);
-
-	pm_runtime_put_sync(mcpdm->dev);
-
-	free_irq(mcpdm->irq, (void *)mcpdm);
-}
-
-/* Enable/disable DC offset cancelation for the analog
- * headset path (PDM channels 1 and 2).
- */
-int omap_mcpdm_set_offset(int offset1, int offset2)
-{
-	int offset;
-
-	if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX))
-		return -EINVAL;
-
-	offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2);
-
-	/* offset cancellation for channel 1 */
-	if (offset1)
-		offset |= DN_OFST_RX1_EN;
-	else
-		offset &= ~DN_OFST_RX1_EN;
-
-	/* offset cancellation for channel 2 */
-	if (offset2)
-		offset |= DN_OFST_RX2_EN;
-	else
-		offset &= ~DN_OFST_RX2_EN;
-
-	omap_mcpdm_write(MCPDM_DN_OFFSET, offset);
-
-	return 0;
-}
-
-int __devinit omap_mcpdm_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	int ret = 0;
-
-	mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
-	if (!mcpdm) {
-		ret = -ENOMEM;
-		goto exit;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no resource\n");
-		goto err_resource;
-	}
-
-	spin_lock_init(&mcpdm->lock);
-	mcpdm->free = 1;
-
-	if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
-		ret = -EBUSY;
-		goto err_resource;
-	}
-
-	mcpdm->io_base = ioremap(res->start, resource_size(res));
-	if (!mcpdm->io_base) {
-		ret = -ENOMEM;
-		goto err_remap;
-	}
-
-	mcpdm->irq = platform_get_irq(pdev, 0);
-
-	mcpdm->dev = &pdev->dev;
-	platform_set_drvdata(pdev, mcpdm);
-
-	pm_runtime_enable(mcpdm->dev);
-
-	return 0;
-
-err_remap:
-	release_mem_region(res->start, resource_size(res));
-err_resource:
-	kfree(mcpdm);
-exit:
-	return ret;
-}
-
-int __devexit omap_mcpdm_remove(struct platform_device *pdev)
-{
-	struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
-	struct resource *res;
-
-	platform_set_drvdata(pdev, NULL);
-
-	pm_runtime_disable(mcpdm_ptr->dev);
-
-	iounmap(mcpdm_ptr->io_base);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	mcpdm_ptr->free = 0;
-	mcpdm_ptr->dev = NULL;
-
-	kfree(mcpdm_ptr);
-
-	return 0;
-}
-
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
deleted file mode 100644
index b055ad1..0000000
--- a/sound/soc/omap/mcpdm.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * mcpdm.h -- Defines for McPDM driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-/* McPDM registers */
-
-#define MCPDM_REVISION         0x00
-#define MCPDM_SYSCONFIG                0x10
-#define MCPDM_IRQSTATUS_RAW    0x24
-#define MCPDM_IRQSTATUS                0x28
-#define MCPDM_IRQENABLE_SET    0x2C
-#define MCPDM_IRQENABLE_CLR    0x30
-#define MCPDM_IRQWAKE_EN       0x34
-#define MCPDM_DMAENABLE_SET    0x38
-#define MCPDM_DMAENABLE_CLR    0x3C
-#define MCPDM_DMAWAKEEN                0x40
-#define MCPDM_CTRL             0x44
-#define MCPDM_DN_DATA          0x48
-#define MCPDM_UP_DATA          0x4C
-#define MCPDM_FIFO_CTRL_DN     0x50
-#define MCPDM_FIFO_CTRL_UP     0x54
-#define MCPDM_DN_OFFSET                0x58
-
-/*
- * MCPDM_IRQ bit fields
- * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
- */
-
-#define MCPDM_DN_IRQ                   (1 << 0)
-#define MCPDM_DN_IRQ_EMPTY             (1 << 1)
-#define MCPDM_DN_IRQ_ALMST_EMPTY       (1 << 2)
-#define MCPDM_DN_IRQ_FULL              (1 << 3)
-
-#define MCPDM_UP_IRQ                   (1 << 8)
-#define MCPDM_UP_IRQ_EMPTY             (1 << 9)
-#define MCPDM_UP_IRQ_ALMST_FULL                (1 << 10)
-#define MCPDM_UP_IRQ_FULL              (1 << 11)
-
-#define MCPDM_DOWNLINK_IRQ_MASK                0x00F
-#define MCPDM_UPLINK_IRQ_MASK          0xF00
-
-/*
- * MCPDM_DMAENABLE bit fields
- */
-
-#define DMA_DN_ENABLE          0x1
-#define DMA_UP_ENABLE          0x2
-
-/*
- * MCPDM_CTRL bit fields
- */
-
-#define PDM_UP1_EN             0x0001
-#define PDM_UP2_EN             0x0002
-#define PDM_UP3_EN             0x0004
-#define PDM_DN1_EN             0x0008
-#define PDM_DN2_EN             0x0010
-#define PDM_DN3_EN             0x0020
-#define PDM_DN4_EN             0x0040
-#define PDM_DN5_EN             0x0080
-#define PDMOUTFORMAT           0x0100
-#define CMD_INT                        0x0200
-#define STATUS_INT             0x0400
-#define SW_UP_RST              0x0800
-#define SW_DN_RST              0x1000
-#define PDM_UP_MASK            0x007
-#define PDM_DN_MASK            0x0F8
-#define PDM_CMD_MASK           0x200
-#define PDM_STATUS_MASK                0x400
-
-
-#define PDMOUTFORMAT_LJUST     (0 << 8)
-#define PDMOUTFORMAT_RJUST     (1 << 8)
-
-/*
- * MCPDM_FIFO_CTRL bit fields
- */
-
-#define UP_THRES_MAX           0xF
-#define DN_THRES_MAX           0xF
-
-/*
- * MCPDM_DN_OFFSET bit fields
- */
-
-#define DN_OFST_RX1_EN         0x0001
-#define DN_OFST_RX2_EN         0x0100
-
-#define DN_OFST_RX1            1
-#define DN_OFST_RX2            9
-#define DN_OFST_MAX            0x1F
-
-#define MCPDM_UPLINK           1
-#define MCPDM_DOWNLINK         2
-
-struct omap_mcpdm_link {
-       int irq_mask;
-       int threshold;
-       int format;
-       int channels;
-};
-
-struct omap_mcpdm_platform_data {
-       unsigned long phys_base;
-       u16 irq;
-};
-
-struct omap_mcpdm {
-       struct device *dev;
-       unsigned long phys_base;
-       void __iomem *io_base;
-       u8 free;
-       int irq;
-
-       spinlock_t lock;
-       struct omap_mcpdm_platform_data *pdata;
-       struct omap_mcpdm_link *downlink;
-       struct omap_mcpdm_link *uplink;
-       struct completion irq_completion;
-
-       int dn_channels;
-       int up_channels;
-};
-
-extern void omap_mcpdm_start(int stream);
-extern void omap_mcpdm_stop(int stream);
-extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_request(void);
-extern void omap_mcpdm_free(void);
-extern int omap_mcpdm_set_offset(int offset1, int offset2);
-int __devinit omap_mcpdm_probe(struct platform_device *pdev);
-int __devexit omap_mcpdm_remove(struct platform_device *pdev);
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
dissimilarity index 46%
index 0820b9e..329a3c6 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -1,279 +1,534 @@
-/*
- * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * Author: Misael Lopez Cruz <x0052729@ti.com>
- * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
- *          Margarita Olaya <magi.olaya@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <plat/dma.h>
-#include <plat/mcbsp.h>
-#include "mcpdm.h"
-#include "omap-pcm.h"
-
-struct omap_mcpdm_data {
-	struct omap_mcpdm_link *links;
-	int active;
-};
-
-static struct omap_mcpdm_link omap_mcpdm_links[] = {
-	/* downlink */
-	{
-		.irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
-		.threshold = 2,
-		.format = PDMOUTFORMAT_LJUST,
-	},
-	/* uplink */
-	{
-		.irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
-		.threshold = UP_THRES_MAX - 3,
-		.format = PDMOUTFORMAT_LJUST,
-	},
-};
-
-static struct omap_mcpdm_data mcpdm_data = {
-	.links = omap_mcpdm_links,
-	.active = 0,
-};
-
-/*
- * Stream DMA parameters
- */
-static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
-	{
-		.name = "Audio playback",
-		.dma_req = OMAP44XX_DMA_MCPDM_DL,
-		.data_type = OMAP_DMA_DATA_TYPE_S32,
-		.sync_mode = OMAP_DMA_SYNC_PACKET,
-		.packet_size = 16,
-		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
-	},
-	{
-		.name = "Audio capture",
-		.dma_req = OMAP44XX_DMA_MCPDM_UP,
-		.data_type = OMAP_DMA_DATA_TYPE_S32,
-		.sync_mode = OMAP_DMA_SYNC_PACKET,
-		.packet_size = 16,
-		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
-	},
-};
-
-static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dai)
-{
-	int err = 0;
-
-	if (!dai->active)
-		err = omap_mcpdm_request();
-
-	return err;
-}
-
-static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
-				    struct snd_soc_dai *dai)
-{
-	if (!dai->active)
-		omap_mcpdm_free();
-}
-
-static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-				  struct snd_soc_dai *dai)
-{
-	struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
-	int stream = substream->stream;
-	int err = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!mcpdm_priv->active++)
-			omap_mcpdm_start(stream);
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (!--mcpdm_priv->active)
-			omap_mcpdm_stop(stream);
-		break;
-	default:
-		err = -EINVAL;
-	}
-
-	return err;
-}
-
-static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
-				    struct snd_pcm_hw_params *params,
-				    struct snd_soc_dai *dai)
-{
-	struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
-	struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
-	struct omap_pcm_dma_data *dma_data;
-	int threshold;
-	int stream = substream->stream;
-	int channels, err, link_mask = 0;
-
-	channels = params_channels(params);
-	switch (channels) {
-	case 4:
-		if (stream == SNDRV_PCM_STREAM_CAPTURE)
-			/* up to 2 channels for capture */
-			return -EINVAL;
-		link_mask |= 1 << 3;
-	case 3:
-		if (stream == SNDRV_PCM_STREAM_CAPTURE)
-			/* up to 2 channels for capture */
-			return -EINVAL;
-		link_mask |= 1 << 2;
-	case 2:
-		link_mask |= 1 << 1;
-	case 1:
-		link_mask |= 1 << 0;
-		break;
-	default:
-		/* unsupported number of channels */
-		return -EINVAL;
-	}
-
-	dma_data = &omap_mcpdm_dai_dma_params[stream];
-	threshold = mcpdm_links[stream].threshold;
-
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		mcpdm_links[stream].channels = link_mask << 3;
-		dma_data->packet_size = (DN_THRES_MAX - threshold) * channels;
-
-		err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
-	} else {
-		mcpdm_links[stream].channels = link_mask << 0;
-		dma_data->packet_size = threshold * channels;
-
-		err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
-	}
-
-	snd_soc_dai_set_dma_data(dai, substream, dma_data);
-	return err;
-}
-
-static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dai)
-{
-	struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
-	struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
-	int stream = substream->stream;
-	int err;
-
-	if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
-		err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
-	else
-		err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
-
-	return err;
-}
-
-static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
-	.startup	= omap_mcpdm_dai_startup,
-	.shutdown	= omap_mcpdm_dai_shutdown,
-	.trigger	= omap_mcpdm_dai_trigger,
-	.hw_params	= omap_mcpdm_dai_hw_params,
-	.hw_free	= omap_mcpdm_dai_hw_free,
-};
-
-#define OMAP_MCPDM_RATES	(SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define OMAP_MCPDM_FORMATS	(SNDRV_PCM_FMTBIT_S32_LE)
-
-static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
-{
-	snd_soc_dai_set_drvdata(dai, &mcpdm_data);
-	return 0;
-}
-
-static struct snd_soc_dai_driver omap_mcpdm_dai = {
-	.probe = omap_mcpdm_dai_probe,
-	.playback = {
-		.channels_min = 1,
-		.channels_max = 4,
-		.rates = OMAP_MCPDM_RATES,
-		.formats = OMAP_MCPDM_FORMATS,
-	},
-	.capture = {
-		.channels_min = 1,
-		.channels_max = 2,
-		.rates = OMAP_MCPDM_RATES,
-		.formats = OMAP_MCPDM_FORMATS,
-	},
-	.ops = &omap_mcpdm_dai_ops,
-};
-
-static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	ret = omap_mcpdm_probe(pdev);
-	if (ret < 0)
-		return ret;
-	ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
-	if (ret < 0)
-		omap_mcpdm_remove(pdev);
-	return ret;
-}
-
-static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_dai(&pdev->dev);
-	omap_mcpdm_remove(pdev);
-	return 0;
-}
-
-static struct platform_driver asoc_mcpdm_driver = {
-	.driver = {
-			.name = "omap-mcpdm",
-			.owner = THIS_MODULE,
-	},
-
-	.probe = asoc_mcpdm_probe,
-	.remove = __devexit_p(asoc_mcpdm_remove),
-};
-
-static int __init snd_omap_mcpdm_init(void)
-{
-	return platform_driver_register(&asoc_mcpdm_driver);
-}
-module_init(snd_omap_mcpdm_init);
-
-static void __exit snd_omap_mcpdm_exit(void)
-{
-	platform_driver_unregister(&asoc_mcpdm_driver);
-}
-module_exit(snd_omap_mcpdm_exit);
-
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
-MODULE_DESCRIPTION("OMAP PDM SoC Interface");
-MODULE_LICENSE("GPL");
+/*
+ * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
+ *
+ * Copyright (C) 2009 - 2011 Texas Instruments
+ *
+ * Author: Misael Lopez Cruz <misael.lopez@ti.com>
+ * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
+ *          Margarita Olaya <magi.olaya@ti.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include "omap-mcpdm.h"
+#include "omap-pcm.h"
+
+struct omap_mcpdm {
+	struct device *dev;
+	unsigned long phys_base;
+	void __iomem *io_base;
+	int irq;
+
+	struct mutex mutex;
+
+	/* channel data */
+	u32 dn_channels;
+	u32 up_channels;
+
+	/* McPDM FIFO thresholds */
+	u32 dn_threshold;
+	u32 up_threshold;
+
+	int enabled;
+};
+
+/*
+ * Stream DMA parameters
+ */
+static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
+	{
+		.name = "Audio playback",
+		.dma_req = OMAP44XX_DMA_MCPDM_DL,
+		.data_type = OMAP_DMA_DATA_TYPE_S32,
+		.sync_mode = OMAP_DMA_SYNC_PACKET,
+		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_DN_DATA,
+	},
+	{
+		.name = "Audio capture",
+		.dma_req = OMAP44XX_DMA_MCPDM_UP,
+		.data_type = OMAP_DMA_DATA_TYPE_S32,
+		.sync_mode = OMAP_DMA_SYNC_PACKET,
+		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,
+	},
+};
+
+static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
+{
+	__raw_writel(val, mcpdm->io_base + reg);
+}
+
+static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
+{
+	return __raw_readl(mcpdm->io_base + reg);
+}
+
+#ifdef DEBUG
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
+{
+	dev_dbg(mcpdm->dev, "***********************\n");
+	dev_dbg(mcpdm->dev, "IRQSTATUS_RAW:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW));
+	dev_dbg(mcpdm->dev, "IRQSTATUS:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS));
+	dev_dbg(mcpdm->dev, "IRQENABLE_SET:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET));
+	dev_dbg(mcpdm->dev, "IRQENABLE_CLR:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR));
+	dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN));
+	dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET));
+	dev_dbg(mcpdm->dev, "DMAENABLE_CLR:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR));
+	dev_dbg(mcpdm->dev, "DMAWAKEEN:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN));
+	dev_dbg(mcpdm->dev, "CTRL:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL));
+	dev_dbg(mcpdm->dev, "DN_DATA:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA));
+	dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA));
+	dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN));
+	dev_dbg(mcpdm->dev, "FIFO_CTRL_UP:  0x%04x\n",
+			omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP));
+	dev_dbg(mcpdm->dev, "***********************\n");
+}
+#else
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
+#endif
+
+/*
+ * Enables the transfer through the PDM interface to/from the Phoenix
+ * codec by enabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
+{
+	u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+	ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+	ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+	ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+}
+
+/*
+ * Disables the transfer through the PDM interface to/from the Phoenix
+ * codec by disabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
+{
+	u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+	ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+	ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+	ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+}
+
+/*
+ * Is the physical McPDM interface active.
+ */
+static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm)
+{
+	return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) &
+					(MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK);
+}
+
+/*
+ * Configures McPDM uplink, and downlink for audio.
+ * This function should be called before omap_mcpdm_start.
+ */
+static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
+{
+	omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET,
+			MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
+			MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+	omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
+
+	omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
+			MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
+}
+
+/*
+ * Cleans McPDM uplink, and downlink configuration.
+ * This function should be called when the stream is closed.
+ */
+static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
+{
+	/* Disable irq request generation for downlink */
+	omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+			MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
+
+	/* Disable DMA request generation for downlink */
+	omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
+
+	/* Disable irq request generation for uplink */
+	omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+			MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+	/* Disable DMA request generation for uplink */
+	omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
+}
+
+static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
+{
+	struct omap_mcpdm *mcpdm = dev_id;
+	int irq_status;
+
+	irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS);
+
+	/* Acknowledge irq event */
+	omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status);
+
+	if (irq_status & MCPDM_DN_IRQ_FULL)
+		dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n");
+
+	if (irq_status & MCPDM_DN_IRQ_EMPTY)
+		dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n");
+
+	if (irq_status & MCPDM_DN_IRQ)
+		dev_dbg(mcpdm->dev, "DN (playback) write request\n");
+
+	if (irq_status & MCPDM_UP_IRQ_FULL)
+		dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n");
+
+	if (irq_status & MCPDM_UP_IRQ_EMPTY)
+		dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n");
+
+	if (irq_status & MCPDM_UP_IRQ)
+		dev_dbg(mcpdm->dev, "UP (capture) write request\n");
+
+	return IRQ_HANDLED;
+}
+
+static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+	mutex_lock(&mcpdm->mutex);
+
+	if (!mcpdm->enabled) {
+		pm_runtime_get_sync(mcpdm->dev);
+
+		/* Enable watch dog for ES above ES 1.0 to avoid saturation */
+		if (omap_rev() != OMAP4430_REV_ES1_0) {
+			u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+			omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL,
+					 ctrl | MCPDM_WD_EN);
+		}
+		omap_mcpdm_open_streams(mcpdm);
+		mcpdm->enabled = 1;
+	}
+
+	mutex_unlock(&mcpdm->mutex);
+
+	return 0;
+}
+
+static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai)
+{
+	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+	int stream = substream->stream;
+	struct omap_pcm_dma_data *dma_data;
+	int channels;
+	int link_mask = 0;
+
+	channels = params_channels(params);
+	switch (channels) {
+	case 4:
+		if (stream == SNDRV_PCM_STREAM_CAPTURE)
+			/* up to 2 channels for capture */
+			return -EINVAL;
+		link_mask |= 1 << 3;
+	case 3:
+		if (stream == SNDRV_PCM_STREAM_CAPTURE)
+			/* up to 2 channels for capture */
+			return -EINVAL;
+		link_mask |= 1 << 2;
+	case 2:
+		link_mask |= 1 << 1;
+	case 1:
+		link_mask |= 1 << 0;
+		break;
+	default:
+		/* unsupported number of channels */
+		return -EINVAL;
+	}
+
+	dma_data = &omap_mcpdm_dai_dma_params[stream];
+
+	/* Configure McPDM channels, and DMA packet size */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mcpdm->dn_channels = link_mask << 3;
+		dma_data->packet_size =
+			(MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
+	} else {
+		mcpdm->up_channels = link_mask << 0;
+		dma_data->packet_size = mcpdm->up_threshold * channels;
+	}
+
+	snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+	return 0;
+}
+
+static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+	if (!omap_mcpdm_active(mcpdm)) {
+		omap_mcpdm_start(mcpdm);
+		omap_mcpdm_reg_dump(mcpdm);
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
+	.startup	= omap_mcpdm_dai_startup,
+	.hw_params	= omap_mcpdm_dai_hw_params,
+	.prepare	= omap_mcpdm_prepare,
+};
+
+static int omap_mcpdm_probe(struct snd_soc_dai *dai)
+{
+	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+	int ret;
+
+	pm_runtime_enable(mcpdm->dev);
+
+	/* Disable lines while request is ongoing */
+	pm_runtime_get_sync(mcpdm->dev);
+	omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
+
+	ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+				0, "McPDM", (void *)mcpdm);
+
+	pm_runtime_put_sync(mcpdm->dev);
+
+	if (ret) {
+		dev_err(mcpdm->dev, "Request for IRQ failed\n");
+		pm_runtime_disable(mcpdm->dev);
+	}
+
+	/* Configure McPDM threshold values */
+	mcpdm->dn_threshold = 2;
+	mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
+	return ret;
+}
+
+static int omap_mcpdm_remove(struct snd_soc_dai *dai)
+{
+	struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+	free_irq(mcpdm->irq, (void *)mcpdm);
+	pm_runtime_disable(mcpdm->dev);
+
+	return 0;
+}
+
+#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 = {
+	.probe = omap_mcpdm_probe,
+	.remove = omap_mcpdm_remove,
+	.probe_order = SND_SOC_COMP_ORDER_LATE,
+	.remove_order = SND_SOC_COMP_ORDER_EARLY,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = OMAP_MCPDM_RATES,
+		.formats = OMAP_MCPDM_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = OMAP_MCPDM_RATES,
+		.formats = OMAP_MCPDM_FORMATS,
+	},
+	.ops = &omap_mcpdm_dai_ops,
+};
+
+/*
+ * DAPM event function to ensure, that the host side McPDM interface is turned
+ * off after the codec's DAC.
+ */
+static int omap_mcpdm_interface_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct omap_mcpdm *mcpdm = snd_soc_dapm_widget_get_pdata(w);
+
+	mutex_lock(&mcpdm->mutex);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		if (unlikely(!mcpdm->enabled)) {
+			dev_err(mcpdm->dev, "%s: Not enabled\n", __func__);
+			goto out;
+		}
+		if (omap_mcpdm_active(mcpdm)) {
+			omap_mcpdm_stop(mcpdm);
+			omap_mcpdm_close_streams(mcpdm);
+		}
+
+		if (!omap_mcpdm_active(mcpdm))
+			pm_runtime_put_sync(mcpdm->dev);
+
+		mcpdm->enabled = 0;
+		break;
+	}
+out:
+	mutex_unlock(&mcpdm->mutex);
+	return 0;
+}
+
+int omap_mcpdm_add_dapm_widget(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	return snd_soc_dapm_attach_dai_supply(dapm, rtd->cpu_dai,
+		"OMAP McPDM Interface", omap_mcpdm_interface_event,
+		SND_SOC_DAPM_POST_PMD);
+}
+
+static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
+{
+	struct omap_mcpdm *mcpdm;
+	struct resource *res;
+	int ret = 0;
+
+	mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+	if (!mcpdm)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, mcpdm);
+
+	mutex_init(&mcpdm->mutex);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no resource\n");
+		goto err_res;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
+		ret = -EBUSY;
+		goto err_res;
+	}
+
+	mcpdm->io_base = ioremap(res->start, resource_size(res));
+	if (!mcpdm->io_base) {
+		ret = -ENOMEM;
+		goto err_iomap;
+	}
+
+	mcpdm->irq = platform_get_irq(pdev, 0);
+	if (mcpdm->irq < 0) {
+		ret = mcpdm->irq;
+		goto err_irq;
+	}
+
+	mcpdm->dev = &pdev->dev;
+
+	ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+	if (!ret)
+		return 0;
+
+err_irq:
+	iounmap(mcpdm->io_base);
+err_iomap:
+	release_mem_region(res->start, resource_size(res));
+err_res:
+	kfree(mcpdm);
+	return ret;
+}
+
+static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
+{
+	struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(mcpdm->io_base);
+	release_mem_region(res->start, resource_size(res));
+
+	kfree(mcpdm);
+	return 0;
+}
+
+static struct platform_driver asoc_mcpdm_driver = {
+	.driver = {
+		.name	= "omap-mcpdm",
+		.owner	= THIS_MODULE,
+	},
+
+	.probe	= asoc_mcpdm_probe,
+	.remove	= __devexit_p(asoc_mcpdm_remove),
+};
+
+static int __init snd_omap_mcpdm_init(void)
+{
+	return platform_driver_register(&asoc_mcpdm_driver);
+}
+module_init(snd_omap_mcpdm_init);
+
+static void __exit snd_omap_mcpdm_exit(void)
+{
+	platform_driver_unregister(&asoc_mcpdm_driver);
+}
+module_exit(snd_omap_mcpdm_exit);
+
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
+MODULE_DESCRIPTION("OMAP PDM SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
new file mode 100644
index 0000000..742dcab
--- /dev/null
+++ b/sound/soc/omap/omap-mcpdm.h
@@ -0,0 +1,97 @@
+/*
+ * omap-mcpdm.h
+ *
+ * Copyright (C) 2009 - 2011 Texas Instruments
+ *
+ * Contact: Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_MCPDM_H__
+#define __OMAP_MCPDM_H__
+
+#define MCPDM_REG_REVISION		0x00
+#define MCPDM_REG_SYSCONFIG		0x10
+#define MCPDM_REG_IRQSTATUS_RAW		0x24
+#define MCPDM_REG_IRQSTATUS		0x28
+#define MCPDM_REG_IRQENABLE_SET		0x2C
+#define MCPDM_REG_IRQENABLE_CLR		0x30
+#define MCPDM_REG_IRQWAKE_EN		0x34
+#define MCPDM_REG_DMAENABLE_SET		0x38
+#define MCPDM_REG_DMAENABLE_CLR		0x3C
+#define MCPDM_REG_DMAWAKEEN		0x40
+#define MCPDM_REG_CTRL			0x44
+#define MCPDM_REG_DN_DATA		0x48
+#define MCPDM_REG_UP_DATA		0x4C
+#define MCPDM_REG_FIFO_CTRL_DN		0x50
+#define MCPDM_REG_FIFO_CTRL_UP		0x54
+#define MCPDM_REG_DN_OFFSET		0x58
+
+/*
+ * MCPDM_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define MCPDM_DN_IRQ			(1 << 0)
+#define MCPDM_DN_IRQ_EMPTY		(1 << 1)
+#define MCPDM_DN_IRQ_ALMST_EMPTY	(1 << 2)
+#define MCPDM_DN_IRQ_FULL		(1 << 3)
+
+#define MCPDM_UP_IRQ			(1 << 8)
+#define MCPDM_UP_IRQ_EMPTY		(1 << 9)
+#define MCPDM_UP_IRQ_ALMST_FULL		(1 << 10)
+#define MCPDM_UP_IRQ_FULL		(1 << 11)
+
+#define MCPDM_DOWNLINK_IRQ_MASK		0x00F
+#define MCPDM_UPLINK_IRQ_MASK		0xF00
+
+/*
+ * MCPDM_DMAENABLE bit fields
+ */
+
+#define MCPDM_DMA_DN_ENABLE		(1 << 0)
+#define MCPDM_DMA_UP_ENABLE		(1 << 1)
+
+/*
+ * MCPDM_CTRL bit fields
+ */
+
+#define MCPDM_PDM_UPLINK_EN(x)		(1 << (x - 1)) /* ch1 is at bit 0 */
+#define MCPDM_PDM_DOWNLINK_EN(x)	(1 << (x + 2)) /* ch1 is at bit 3 */
+#define MCPDM_PDMOUTFORMAT		(1 << 8)
+#define MCPDM_CMD_INT			(1 << 9)
+#define MCPDM_STATUS_INT		(1 << 10)
+#define MCPDM_SW_UP_RST			(1 << 11)
+#define MCPDM_SW_DN_RST			(1 << 12)
+#define MCPDM_WD_EN			(1 << 14)
+#define MCPDM_PDM_UP_MASK		0x7
+#define MCPDM_PDM_DN_MASK		(0x1f << 3)
+
+
+#define MCPDM_PDMOUTFORMAT_LJUST	(0 << 8)
+#define MCPDM_PDMOUTFORMAT_RJUST	(1 << 8)
+
+/*
+ * MCPDM_FIFO_CTRL bit fields
+ */
+
+#define MCPDM_UP_THRES_MAX		0xF
+#define MCPDM_DN_THRES_MAX		0xF
+
+int omap_mcpdm_add_dapm_widget(struct snd_soc_pcm_runtime *rtd);
+
+#endif	/* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index eec77fe..2b56b81 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -32,7 +32,7 @@
 #include <plat/hardware.h>
 #include <plat/mux.h>
 
-#include "mcpdm.h"
+#include "omap-mcpdm.h"
 #include "omap-pcm.h"
 #include "../codecs/twl6040.h"
 
@@ -115,6 +115,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	/* Aux/FM Stereo In: AFML, AFMR */
 	{"AFML", NULL, "FM Stereo In"},
 	{"AFMR", NULL, "FM Stereo In"},
+
+	/* OMAP4 McPDM interface */
+	{"ADC Left",	NULL, "OMAP McPDM Interface"},
+	{"ADC Right",	NULL, "OMAP McPDM Interface"},
+	{"HSDAC Left",	NULL, "OMAP McPDM Interface"},
+	{"HSDAC Right",	NULL, "OMAP McPDM Interface"},
+	{"HFDAC Left",	NULL, "OMAP McPDM Interface"},
+	{"HFDAC Right",	NULL, "OMAP McPDM Interface"},
 };
 
 static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
@@ -129,6 +137,10 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
+	ret = omap_mcpdm_add_dapm_widget(rtd);
+	if (ret)
+		return ret;
+
 	/* Set up SDP4430 specific audio path audio_map */
 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-08-26 13:33 ` [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai Peter Ujfalusi
@ 2011-08-26 19:05   ` Mark Brown
  2011-08-29  8:22     ` Péter Ujfalusi
  0 siblings, 1 reply; 11+ messages in thread
From: Mark Brown @ 2011-08-26 19:05 UTC (permalink / raw)
  To: Peter Ujfalusi; +Cc: alsa-devel, Liam Girdwood, Misael Lopez Cruz

On Fri, Aug 26, 2011 at 04:33:22PM +0300, Peter Ujfalusi wrote:
> There are cpu dais, which require special ordering during stream
> stop (OMAP4's McPDM interface for example) in a system level.
> OMAP4 McPDM required to be stopped after the attached codec's
> (twl6040) DAC/ADC has been stopped.

> This requironment can be solved with a use of DAPM_SUPPLY
> widget attached to the codec's ADC/DAC from machine driver.

This wasn't really what I meant - what I meant was that we ought to be
able to change the ordering of DAPM with regard to the stream shutdown
without having to have anything more than flags in the devices that can
or need to do it (I'd expect more the CODECs more than the CPUs).

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-08-26 19:05   ` Mark Brown
@ 2011-08-29  8:22     ` Péter Ujfalusi
  2011-08-29  9:16       ` Mark Brown
  0 siblings, 1 reply; 11+ messages in thread
From: Péter Ujfalusi @ 2011-08-29  8:22 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Girdwood, Liam, Lopez Cruz, Misael

On Friday 26 August 2011 21:05:02 Mark Brown wrote:
> This wasn't really what I meant - what I meant was that we ought to be
> able to change the ordering of DAPM with regard to the stream shutdown
> without having to have anything more than flags in the devices that can
> or need to do it (I'd expect more the CODECs more than the CPUs).

I see, but this is not what I'm trying to achieve here.
Even, if we could re-order the stream shutdown (for DAIs mostly) and DAPM 
sequence it won't work for me:
I need to make sure that the cpu_dai (McPDM) is shut down _after the DAC/ADC, 
and _before_ the codec is powered down - which would stop the McPDM clocks - 
which in turn used by McPDM as functional clock.
So if we would somehow execute the DAPM first followed by the stream shutdown, 
I can be in a situation, when McPDM is not accessible (missing clocks).

If we really want to reorder the stream shutdown and DAPM, we need to quite a 
bit of change, since we need to be able to 'delay' the shutdown operations for 
DAIs/platforms at least. But. Since the stream has been already closed, we can 
not refer to it anymore in case of pmdown_time > 0 (playback only issue).

One way would be to have special DAPM widget for DAI/platform event, and hook 
that up somewhere at some point that it will do what it is intended to be 
doing.
Or some callback function for DAIs/platforms, which would be called from the  
dapm_power_widgets function.

These would work, mostly, but I'm not convinced, that it would work for me, so 
I anyway need to do something similar as in this series.

--
Péter

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-08-29  8:22     ` Péter Ujfalusi
@ 2011-08-29  9:16       ` Mark Brown
  2011-08-29 11:41         ` Péter Ujfalusi
  0 siblings, 1 reply; 11+ messages in thread
From: Mark Brown @ 2011-08-29  9:16 UTC (permalink / raw)
  To: Péter Ujfalusi; +Cc: alsa-devel, Girdwood, Liam, Lopez Cruz, Misael

On Mon, Aug 29, 2011 at 11:22:52AM +0300, Péter Ujfalusi wrote:
> On Friday 26 August 2011 21:05:02 Mark Brown wrote:
> > This wasn't really what I meant - what I meant was that we ought to be
> > able to change the ordering of DAPM with regard to the stream shutdown
> > without having to have anything more than flags in the devices that can
> > or need to do it (I'd expect more the CODECs more than the CPUs).

> I see, but this is not what I'm trying to achieve here.
> Even, if we could re-order the stream shutdown (for DAIs mostly) and DAPM 
> sequence it won't work for me:
> I need to make sure that the cpu_dai (McPDM) is shut down _after the DAC/ADC, 
> and _before_ the codec is powered down - which would stop the McPDM clocks - 
> which in turn used by McPDM as functional clock.

That's not what you said before...  I did post the sequence I was
suggesting and you seemed fine with it.  Please try to be clear about
what you're trying to do here - previously you'd just said that you
needed to make sure the CODEC was powered down prior to the CPU being
stopped but now you're adding additional stuff here.

Could you please clarify what exactly the system looks like here and
what you need to do?  I'm struggling to understand how you've got PDM
output links providing clocks back into the CPU - usually a PDM output
is two wires going in one direction.  I also don't entirely understand
why your current approach will be robust, though it should be an
improvement on the original change to just put a delay in the shutdown.
You can't rely on pmdown_time happening at all as it's user configurable
and only happens for some cases even when it's there.

> If we really want to reorder the stream shutdown and DAPM, we need to quite a 
> bit of change, since we need to be able to 'delay' the shutdown operations for 
> DAIs/platforms at least. But. Since the stream has been already closed, we can 
> not refer to it anymore in case of pmdown_time > 0 (playback only issue).

Part of what I'm suggesting is that we may as well not bother with the
pmdown_time timeout if we need to shut the DAI down while we're shutting
the CODEC down anyway, the whole thing may as well get shut down at once
which will be a little more power efficient.

> These would work, mostly, but I'm not convinced, that it would work for me, so 
> I anyway need to do something similar as in this series.

Like I say I'm not convinced I understand what you need to do yet.  It
would be easier if we could merge the updated McPDM driver and worry
about this separately; I don't understand why you can't just inline the
event into the regular teardown (it will be noisy but it should at least
run).

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-08-29  9:16       ` Mark Brown
@ 2011-08-29 11:41         ` Péter Ujfalusi
  2011-09-03  6:31           ` Mark Brown
  0 siblings, 1 reply; 11+ messages in thread
From: Péter Ujfalusi @ 2011-08-29 11:41 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Girdwood, Liam, Lopez Cruz, Misael

On Monday 29 August 2011 11:16:04 Mark Brown wrote:
> That's not what you said before...  I did post the sequence I was
> suggesting and you seemed fine with it.  Please try to be clear about
> what you're trying to do here - previously you'd just said that you
> needed to make sure the CODEC was powered down prior to the CPU being
> stopped but now you're adding additional stuff here.

Hrm, yes i did agreed with your sequence until I started to look at the other 
implications. However at least I was consistent in the commit messages about 
the sequence requirements (OMAP4 McPDM should be stopped after the codec's 
DAC/ADC).
 
> Could you please clarify what exactly the system looks like here and
> what you need to do?  I'm struggling to understand how you've got PDM
> output links providing clocks back into the CPU - usually a PDM output
> is two wires going in one direction.

McPDM uses 5 wires.
clks is coming from the codec, and this signal is used within OMAP4 McPDM as 
functional clock (we have frame sync, ul data, dl data, and clock loopback 
wires). Chapter 23.6.2.2 of OMAP4430_ES2.x_PUBLIC_TRM_vW.pdf

The sequence I'm looking for is:
1. pcm_trigger: stop DMA
2. DAPM sequence starts
3. DAC is turned off on the codec side
4. OMAP4 McPDM can be stopped - stop it
5. DAPM finishes up
6. codec can be turned off

> I also don't entirely understand
> why your current approach will be robust, though it should be an
> improvement on the original change to just put a delay in the shutdown.
> You can't rely on pmdown_time happening at all as it's user configurable
> and only happens for some cases even when it's there.

I'm not relaying on the pmdown_time but I'm relying on DAPM to handle the 
power down of the cpu_dai. The pmdown_time does not matter anymore.
I do not remember saying that it is robust, but I might meant that this 
approach needs small amount of code, and it is handled by a well tested/proven  
piece of code (DAPM).

> Like I say I'm not convinced I understand what you need to do yet.  It
> would be easier if we could merge the updated McPDM driver and worry
> about this separately; I don't understand why you can't just inline the
> event into the regular teardown (it will be noisy but it should at least
> run).

OK, let's take this part out for now.

I'll send a single patch for replacing the legacy driver with the new one, but 
without the pop avoiding delay magic.

--
Péter

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-08-29 11:41         ` Péter Ujfalusi
@ 2011-09-03  6:31           ` Mark Brown
  2011-09-06 10:21             ` Péter Ujfalusi
  0 siblings, 1 reply; 11+ messages in thread
From: Mark Brown @ 2011-09-03  6:31 UTC (permalink / raw)
  To: P?ter Ujfalusi; +Cc: alsa-devel, Girdwood, Liam, Lopez Cruz, Misael

On Mon, Aug 29, 2011 at 02:41:30PM +0300, P?ter Ujfalusi wrote:
> On Monday 29 August 2011 11:16:04 Mark Brown wrote:
> > That's not what you said before...  I did post the sequence I was
> > suggesting and you seemed fine with it.  Please try to be clear about
> > what you're trying to do here - previously you'd just said that you
> > needed to make sure the CODEC was powered down prior to the CPU being
> > stopped but now you're adding additional stuff here.

> Hrm, yes i did agreed with your sequence until I started to look at the other 
> implications. However at least I was consistent in the commit messages about 
> the sequence requirements (OMAP4 McPDM should be stopped after the codec's 
> DAC/ADC).

Right, but there was an important additional bit.

> > Could you please clarify what exactly the system looks like here and
> > what you need to do?  I'm struggling to understand how you've got PDM
> > output links providing clocks back into the CPU - usually a PDM output
> > is two wires going in one direction.

> The sequence I'm looking for is:
> 1. pcm_trigger: stop DMA
> 2. DAPM sequence starts
> 3. DAC is turned off on the codec side
> 4. OMAP4 McPDM can be stopped - stop it
> 5. DAPM finishes up
> 6. codec can be turned off

Actually I think this is fine with my suggestion so long as you make the
CODEC SYSCLK visible to DAPM and have the machine driver turn it off at
some later point in the shutdown process (eg, in shutdown()).  That way
the data paths will still be torn down by DAPM immediately but SYSCLK
will still be generated.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-09-03  6:31           ` Mark Brown
@ 2011-09-06 10:21             ` Péter Ujfalusi
  2011-09-06 15:09               ` Mark Brown
  0 siblings, 1 reply; 11+ messages in thread
From: Péter Ujfalusi @ 2011-09-06 10:21 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Girdwood, Liam, Lopez Cruz, Misael

On Saturday 03 September 2011 07:31:19 Mark Brown wrote:
> > The sequence I'm looking for is:
> > 1. pcm_trigger: stop DMA
> > 2. DAPM sequence starts
> > 3. DAC is turned off on the codec side
> > 4. OMAP4 McPDM can be stopped - stop it
> > 5. DAPM finishes up
> > 6. codec can be turned off
> 
> Actually I think this is fine with my suggestion so long as you make the
> CODEC SYSCLK visible to DAPM and have the machine driver turn it off at
> some later point in the shutdown process (eg, in shutdown()).  That way
> the data paths will still be torn down by DAPM immediately but SYSCLK
> will still be generated.

I need to think about this.
Not sure how it will affect our system, if we do not have pmdown_time in the 
future, when we add full ABE support.
As a side note: I have found an issue with my earlier proposal (DAPM_SUPPLY 
attached to the codec's DAC/ADC): I can end up turning off the host side McPDM 
during audio activity (by muting the outputs/inputs runtime). It has the side 
effect of not recovering :o (also DMA stops, since the dai is stopped)

I'll get back to you on this soon (probably with a patch).

--
Péter

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai
  2011-09-06 10:21             ` Péter Ujfalusi
@ 2011-09-06 15:09               ` Mark Brown
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-09-06 15:09 UTC (permalink / raw)
  To: Péter Ujfalusi; +Cc: alsa-devel, Girdwood, Liam, Lopez Cruz, Misael

On Tue, Sep 06, 2011 at 01:21:56PM +0300, Péter Ujfalusi wrote:
> On Saturday 03 September 2011 07:31:19 Mark Brown wrote:

> > Actually I think this is fine with my suggestion so long as you make the
> > CODEC SYSCLK visible to DAPM and have the machine driver turn it off at
> > some later point in the shutdown process (eg, in shutdown()).  That way
> > the data paths will still be torn down by DAPM immediately but SYSCLK
> > will still be generated.
> 
> I need to think about this.
> Not sure how it will affect our system, if we do not have pmdown_time in the 
> future, when we add full ABE support.

pmdown_time is irrelevant here, it only inserts a delay in the sequence
so if it's not there the delay just goes to zero and the sequence of
events is the same but quicker.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-09-06 15:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-26 13:33 [PATCH v3 0/3] ASoC: omap-mcpdm: New McPDM driver Peter Ujfalusi
2011-08-26 13:33 ` [PATCH v3 1/3] ASoC: DAPM: Add private data pointer for DAPM widget Peter Ujfalusi
2011-08-26 13:33 ` [PATCH v3 2/3] ASoC: soc-dapm: API to attach DAPM_SUPPLY to be used for dai Peter Ujfalusi
2011-08-26 19:05   ` Mark Brown
2011-08-29  8:22     ` Péter Ujfalusi
2011-08-29  9:16       ` Mark Brown
2011-08-29 11:41         ` Péter Ujfalusi
2011-09-03  6:31           ` Mark Brown
2011-09-06 10:21             ` Péter Ujfalusi
2011-09-06 15:09               ` Mark Brown
2011-08-26 13:33 ` [PATCH v3 3/3] ASoC: omap-mcpdm: Replace legacy driver Peter Ujfalusi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.