]> Pileus Git - ~andy/linux/blobdiff - sound/soc/omap/omap-mcpdm.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[~andy/linux] / sound / soc / omap / omap-mcpdm.c
index bed09c27e44cb9af6643f2e015d59405885b06bd..41d17067cc739a05ac085443cdbe1fd6e984593e 100644 (file)
@@ -1,11 +1,12 @@
 /*
  * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
  *
- * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2009 - 2011 Texas Instruments
  *
- * Author: Misael Lopez Cruz <x0052729@ti.com>
+ * 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
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/device.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/initval.h>
 #include <sound/soc.h>
 
 #include <plat/dma.h>
-#include <plat/mcbsp.h>
-#include "mcpdm.h"
+#include <plat/omap_hwmod.h>
+#include "omap-mcpdm.h"
 #include "omap-pcm.h"
 
-struct omap_mcpdm_data {
-       struct omap_mcpdm_link *links;
-       int active;
-};
+struct omap_mcpdm {
+       struct device *dev;
+       unsigned long phys_base;
+       void __iomem *io_base;
+       int irq;
 
-static struct omap_mcpdm_link omap_mcpdm_links[] = {
-       /* downlink */
-       {
-               .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
-               .threshold = 1,
-               .format = PDMOUTFORMAT_LJUST,
-       },
-       /* uplink */
-       {
-               .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
-               .threshold = 1,
-               .format = PDMOUTFORMAT_LJUST,
-       },
-};
+       struct mutex mutex;
+
+       /* channel data */
+       u32 dn_channels;
+       u32 up_channels;
+
+       /* McPDM FIFO thresholds */
+       u32 dn_threshold;
+       u32 up_threshold;
 
-static struct omap_mcpdm_data mcpdm_data = {
-       .links = omap_mcpdm_links,
-       .active = 0,
+       /* McPDM dn offsets for rx1, and 2 channels */
+       u32 dn_rx_offset;
 };
 
 /*
@@ -71,88 +73,259 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
                .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,
+               .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,
-               .packet_size = 16,
-               .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
+               .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,
        },
 };
 
-static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
+static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
 {
-       int err = 0;
+       __raw_writel(val, mcpdm->io_base + reg);
+}
 
-       if (!dai->active)
-               err = omap_mcpdm_request();
+static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
+{
+       return __raw_readl(mcpdm->io_base + reg);
+}
 
-       return err;
+#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
 
-static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
-                                   struct snd_soc_dai *dai)
+/*
+ * 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);
+
+       /* Enable DN RX1/2 offset cancellation feature, if configured */
+       if (mcpdm->dn_rx_offset) {
+               u32 dn_offset = mcpdm->dn_rx_offset;
+
+               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+               dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN);
+               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+       }
+
+       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);
+
+       /* Disable RX1/2 offset cancellation */
+       if (mcpdm->dn_rx_offset)
+               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0);
+}
+
+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)
 {
-       if (!dai->active)
-               omap_mcpdm_free();
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+       mutex_lock(&mcpdm->mutex);
+
+       if (!dai->active) {
+               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);
+       }
+
+       mutex_unlock(&mcpdm->mutex);
+
+       return 0;
 }
 
-static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
                                  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;
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
-       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;
+       mutex_lock(&mcpdm->mutex);
+
+       if (!dai->active) {
+               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);
        }
 
-       return err;
+       mutex_unlock(&mcpdm->mutex);
 }
 
 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_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
        int stream = substream->stream;
-       int channels, err, link_mask = 0;
-
-       snd_soc_dai_set_dma_data(dai, substream,
-                                &omap_mcpdm_dai_dma_params[stream]);
+       struct omap_pcm_dma_data *dma_data;
+       int channels;
+       int link_mask = 0;
 
        channels = params_channels(params);
        switch (channels) {
+       case 5:
+               if (stream == SNDRV_PCM_STREAM_CAPTURE)
+                       /* up to 3 channels for capture */
+                       return -EINVAL;
+               link_mask |= 1 << 4;
        case 4:
                if (stream == SNDRV_PCM_STREAM_CAPTURE)
-                       /* up to 2 channels for capture */
+                       /* up to 3 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;
@@ -164,95 +337,187 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       dma_data = &omap_mcpdm_dai_dma_params[stream];
+
+       /* Configure McPDM channels, and DMA packet size */
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               mcpdm_links[stream].channels = link_mask << 3;
-               err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
+               mcpdm->dn_channels = link_mask << 3;
+               dma_data->packet_size =
+                       (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
        } else {
-               mcpdm_links[stream].channels = link_mask << 0;
-               err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
+               mcpdm->up_channels = link_mask << 0;
+               dma_data->packet_size = mcpdm->up_threshold * channels;
        }
 
-       return err;
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+       return 0;
 }
 
-static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
+static int omap_mcpdm_prepare(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;
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
-       if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
-               err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
-       else
-               err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
+       if (!omap_mcpdm_active(mcpdm)) {
+               omap_mcpdm_start(mcpdm);
+               omap_mcpdm_reg_dump(mcpdm);
+       }
 
-       return err;
+       return 0;
 }
 
 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,
+       .prepare        = omap_mcpdm_prepare,
 };
 
-#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_probe(struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+       int ret;
 
-static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+       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)
 {
-       snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+       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_dai_probe,
+       .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,
+               .channels_max = 5,
                .rates = OMAP_MCPDM_RATES,
                .formats = OMAP_MCPDM_FORMATS,
        },
        .capture = {
                .channels_min = 1,
-               .channels_max = 2,
+               .channels_max = 3,
                .rates = OMAP_MCPDM_RATES,
                .formats = OMAP_MCPDM_FORMATS,
        },
        .ops = &omap_mcpdm_dai_ops,
 };
 
+void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
+                                   u8 rx1, u8 rx2)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+       mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2);
+}
+EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
+
 static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
 {
-       int ret;
+       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 = 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);
+       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);
-       omap_mcpdm_remove(pdev);
+
+       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-dai",
-                       .owner = THIS_MODULE,
+               .name   = "omap-mcpdm",
+               .owner  = THIS_MODULE,
        },
 
-       .probe = asoc_mcpdm_probe,
-       .remove = __devexit_p(asoc_mcpdm_remove),
+       .probe  = asoc_mcpdm_probe,
+       .remove = __devexit_p(asoc_mcpdm_remove),
 };
 
 static int __init snd_omap_mcpdm_init(void)
@@ -267,6 +532,6 @@ static void __exit snd_omap_mcpdm_exit(void)
 }
 module_exit(snd_omap_mcpdm_exit);
 
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
 MODULE_DESCRIPTION("OMAP PDM SoC Interface");
 MODULE_LICENSE("GPL");