]> Pileus Git - ~andy/linux/blobdiff - sound/soc/omap/omap-mcpdm.c
Merge tag 'mfd-3.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd...
[~andy/linux] / sound / soc / omap / omap-mcpdm.c
index 6e19f440a28c78dcd66c1c072460f523340a5afd..eb05c7ed6d053519a13ec989efd81c890aa10c72 100644 (file)
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "omap-mcpdm.h"
-#include "omap-pcm.h"
-
-#define OMAP44XX_MCPDM_L3_BASE         0x49032000
 
 struct mcpdm_link_config {
        u32 link_mask; /* channel mask for the direction */
@@ -63,19 +61,17 @@ struct omap_mcpdm {
 
        /* McPDM dn offsets for rx1, and 2 channels */
        u32 dn_rx_offset;
+
+       /* McPDM needs to be restarted due to runtime reconfiguration */
+       bool restart;
+
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       unsigned int dma_req[2];
 };
 
 /*
  * Stream DMA parameters
  */
-static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
-       {
-               .name = "Audio playback",
-       },
-       {
-               .name = "Audio capture",
-       },
-};
 
 static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
 {
@@ -149,7 +145,7 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
 static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
 {
        u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
-       u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
+       u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
 
        ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
@@ -271,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
        mutex_unlock(&mcpdm->mutex);
 
        snd_soc_dai_set_dma_data(dai, substream,
-                                &omap_mcpdm_dai_dma_params[substream->stream]);
+                                &mcpdm->dma_data[substream->stream]);
 
        return 0;
 }
@@ -287,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
                if (omap_mcpdm_active(mcpdm)) {
                        omap_mcpdm_stop(mcpdm);
                        omap_mcpdm_close_streams(mcpdm);
+                       mcpdm->config[0].link_mask = 0;
+                       mcpdm->config[1].link_mask = 0;
                }
        }
 
@@ -299,7 +297,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 {
        struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
        int stream = substream->stream;
-       struct omap_pcm_dma_data *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
        u32 threshold;
        int channels;
        int link_mask = 0;
@@ -334,11 +332,26 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
        /* Configure McPDM channels, and DMA packet size */
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                link_mask <<= 3;
-               dma_data->packet_size =
+
+               /* If capture is not running assume a stereo stream to come */
+               if (!mcpdm->config[!stream].link_mask)
+                       mcpdm->config[!stream].link_mask = 0x3;
+
+               dma_data->maxburst =
                                (MCPDM_DN_THRES_MAX - threshold) * channels;
        } else {
-               dma_data->packet_size = threshold * channels;
+               /* If playback is not running assume a stereo stream to come */
+               if (!mcpdm->config[!stream].link_mask)
+                       mcpdm->config[!stream].link_mask = (0x3 << 3);
+
+               dma_data->maxburst = threshold * channels;
        }
+
+       /* Check if we need to restart McPDM with this stream */
+       if (mcpdm->config[stream].link_mask &&
+           mcpdm->config[stream].link_mask != link_mask)
+               mcpdm->restart = true;
+
        mcpdm->config[stream].link_mask = link_mask;
 
        return 0;
@@ -352,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
        if (!omap_mcpdm_active(mcpdm)) {
                omap_mcpdm_start(mcpdm);
                omap_mcpdm_reg_dump(mcpdm);
+       } else if (mcpdm->restart) {
+               omap_mcpdm_stop(mcpdm);
+               omap_mcpdm_start(mcpdm);
+               mcpdm->restart = false;
+               omap_mcpdm_reg_dump(mcpdm);
        }
 
        return 0;
@@ -426,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
        .ops = &omap_mcpdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcpdm_component = {
+       .name           = "omap-mcpdm",
+};
+
 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
                                    u8 rx1, u8 rx2)
 {
@@ -452,20 +474,22 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
        if (res == NULL)
                return -ENOMEM;
 
-       omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
-       omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
+       mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
+       mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
        if (!res)
                return -ENODEV;
 
-       omap_mcpdm_dai_dma_params[0].dma_req = res->start;
+       mcpdm->dma_req[0] = res->start;
+       mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
        if (!res)
                return -ENODEV;
 
-       omap_mcpdm_dai_dma_params[1].dma_req = res->start;
+       mcpdm->dma_req[1] = res->start;
+       mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
        if (res == NULL)
@@ -481,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 
        mcpdm->dev = &pdev->dev;
 
-       return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+       return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
+                                         &omap_mcpdm_dai, 1);
 }
 
 static int asoc_mcpdm_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }