Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
0004  *
0005  * Copyright (C) 2009 - 2011 Texas Instruments
0006  *
0007  * Author: Misael Lopez Cruz <misael.lopez@ti.com>
0008  * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
0009  *          Margarita Olaya <magi.olaya@ti.com>
0010  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
0011  */
0012 
0013 #include <linux/init.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/err.h>
0018 #include <linux/io.h>
0019 #include <linux/irq.h>
0020 #include <linux/slab.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/of_device.h>
0023 
0024 #include <sound/core.h>
0025 #include <sound/pcm.h>
0026 #include <sound/pcm_params.h>
0027 #include <sound/soc.h>
0028 #include <sound/dmaengine_pcm.h>
0029 
0030 #include "omap-mcpdm.h"
0031 #include "sdma-pcm.h"
0032 
0033 struct mcpdm_link_config {
0034     u32 link_mask; /* channel mask for the direction */
0035     u32 threshold; /* FIFO threshold */
0036 };
0037 
0038 struct omap_mcpdm {
0039     struct device *dev;
0040     unsigned long phys_base;
0041     void __iomem *io_base;
0042     int irq;
0043     struct pm_qos_request pm_qos_req;
0044     int latency[2];
0045 
0046     struct mutex mutex;
0047 
0048     /* Playback/Capture configuration */
0049     struct mcpdm_link_config config[2];
0050 
0051     /* McPDM dn offsets for rx1, and 2 channels */
0052     u32 dn_rx_offset;
0053 
0054     /* McPDM needs to be restarted due to runtime reconfiguration */
0055     bool restart;
0056 
0057     /* pm state for suspend/resume handling */
0058     int pm_active_count;
0059 
0060     struct snd_dmaengine_dai_dma_data dma_data[2];
0061 };
0062 
0063 /*
0064  * Stream DMA parameters
0065  */
0066 
0067 static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
0068 {
0069     writel_relaxed(val, mcpdm->io_base + reg);
0070 }
0071 
0072 static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
0073 {
0074     return readl_relaxed(mcpdm->io_base + reg);
0075 }
0076 
0077 #ifdef DEBUG
0078 static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
0079 {
0080     dev_dbg(mcpdm->dev, "***********************\n");
0081     dev_dbg(mcpdm->dev, "IRQSTATUS_RAW:  0x%04x\n",
0082             omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW));
0083     dev_dbg(mcpdm->dev, "IRQSTATUS:  0x%04x\n",
0084             omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS));
0085     dev_dbg(mcpdm->dev, "IRQENABLE_SET:  0x%04x\n",
0086             omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET));
0087     dev_dbg(mcpdm->dev, "IRQENABLE_CLR:  0x%04x\n",
0088             omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR));
0089     dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
0090             omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN));
0091     dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
0092             omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET));
0093     dev_dbg(mcpdm->dev, "DMAENABLE_CLR:  0x%04x\n",
0094             omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR));
0095     dev_dbg(mcpdm->dev, "DMAWAKEEN:  0x%04x\n",
0096             omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN));
0097     dev_dbg(mcpdm->dev, "CTRL:  0x%04x\n",
0098             omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL));
0099     dev_dbg(mcpdm->dev, "DN_DATA:  0x%04x\n",
0100             omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA));
0101     dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
0102             omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA));
0103     dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
0104             omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN));
0105     dev_dbg(mcpdm->dev, "FIFO_CTRL_UP:  0x%04x\n",
0106             omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP));
0107     dev_dbg(mcpdm->dev, "***********************\n");
0108 }
0109 #else
0110 static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
0111 #endif
0112 
0113 /*
0114  * Enables the transfer through the PDM interface to/from the Phoenix
0115  * codec by enabling the corresponding UP or DN channels.
0116  */
0117 static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
0118 {
0119     u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
0120     u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
0121 
0122     ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
0123     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
0124 
0125     ctrl |= link_mask;
0126     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
0127 
0128     ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
0129     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
0130 }
0131 
0132 /*
0133  * Disables the transfer through the PDM interface to/from the Phoenix
0134  * codec by disabling the corresponding UP or DN channels.
0135  */
0136 static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
0137 {
0138     u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
0139     u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
0140 
0141     ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
0142     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
0143 
0144     ctrl &= ~(link_mask);
0145     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
0146 
0147     ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
0148     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
0149 
0150 }
0151 
0152 /*
0153  * Is the physical McPDM interface active.
0154  */
0155 static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm)
0156 {
0157     return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) &
0158                     (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK);
0159 }
0160 
0161 /*
0162  * Configures McPDM uplink, and downlink for audio.
0163  * This function should be called before omap_mcpdm_start.
0164  */
0165 static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
0166 {
0167     u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
0168 
0169     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN);
0170 
0171     omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET,
0172             MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
0173             MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
0174 
0175     /* Enable DN RX1/2 offset cancellation feature, if configured */
0176     if (mcpdm->dn_rx_offset) {
0177         u32 dn_offset = mcpdm->dn_rx_offset;
0178 
0179         omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
0180         dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN);
0181         omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
0182     }
0183 
0184     omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
0185              mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
0186     omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
0187              mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
0188 
0189     omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
0190             MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
0191 }
0192 
0193 /*
0194  * Cleans McPDM uplink, and downlink configuration.
0195  * This function should be called when the stream is closed.
0196  */
0197 static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
0198 {
0199     /* Disable irq request generation for downlink */
0200     omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
0201             MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
0202 
0203     /* Disable DMA request generation for downlink */
0204     omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
0205 
0206     /* Disable irq request generation for uplink */
0207     omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
0208             MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
0209 
0210     /* Disable DMA request generation for uplink */
0211     omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
0212 
0213     /* Disable RX1/2 offset cancellation */
0214     if (mcpdm->dn_rx_offset)
0215         omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0);
0216 }
0217 
0218 static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
0219 {
0220     struct omap_mcpdm *mcpdm = dev_id;
0221     int irq_status;
0222 
0223     irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS);
0224 
0225     /* Acknowledge irq event */
0226     omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status);
0227 
0228     if (irq_status & MCPDM_DN_IRQ_FULL)
0229         dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n");
0230 
0231     if (irq_status & MCPDM_DN_IRQ_EMPTY)
0232         dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n");
0233 
0234     if (irq_status & MCPDM_DN_IRQ)
0235         dev_dbg(mcpdm->dev, "DN (playback) write request\n");
0236 
0237     if (irq_status & MCPDM_UP_IRQ_FULL)
0238         dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n");
0239 
0240     if (irq_status & MCPDM_UP_IRQ_EMPTY)
0241         dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n");
0242 
0243     if (irq_status & MCPDM_UP_IRQ)
0244         dev_dbg(mcpdm->dev, "UP (capture) write request\n");
0245 
0246     return IRQ_HANDLED;
0247 }
0248 
0249 static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
0250                   struct snd_soc_dai *dai)
0251 {
0252     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
0253 
0254     mutex_lock(&mcpdm->mutex);
0255 
0256     if (!snd_soc_dai_active(dai))
0257         omap_mcpdm_open_streams(mcpdm);
0258 
0259     mutex_unlock(&mcpdm->mutex);
0260 
0261     return 0;
0262 }
0263 
0264 static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
0265                   struct snd_soc_dai *dai)
0266 {
0267     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
0268     int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0269     int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
0270     int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
0271 
0272     mutex_lock(&mcpdm->mutex);
0273 
0274     if (!snd_soc_dai_active(dai)) {
0275         if (omap_mcpdm_active(mcpdm)) {
0276             omap_mcpdm_stop(mcpdm);
0277             omap_mcpdm_close_streams(mcpdm);
0278             mcpdm->config[0].link_mask = 0;
0279             mcpdm->config[1].link_mask = 0;
0280         }
0281     }
0282 
0283     if (mcpdm->latency[stream2])
0284         cpu_latency_qos_update_request(&mcpdm->pm_qos_req,
0285                            mcpdm->latency[stream2]);
0286     else if (mcpdm->latency[stream1])
0287         cpu_latency_qos_remove_request(&mcpdm->pm_qos_req);
0288 
0289     mcpdm->latency[stream1] = 0;
0290 
0291     mutex_unlock(&mcpdm->mutex);
0292 }
0293 
0294 static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
0295                     struct snd_pcm_hw_params *params,
0296                     struct snd_soc_dai *dai)
0297 {
0298     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
0299     int stream = substream->stream;
0300     struct snd_dmaengine_dai_dma_data *dma_data;
0301     u32 threshold;
0302     int channels, latency;
0303     int link_mask = 0;
0304 
0305     channels = params_channels(params);
0306     switch (channels) {
0307     case 5:
0308         if (stream == SNDRV_PCM_STREAM_CAPTURE)
0309             /* up to 3 channels for capture */
0310             return -EINVAL;
0311         link_mask |= 1 << 4;
0312         fallthrough;
0313     case 4:
0314         if (stream == SNDRV_PCM_STREAM_CAPTURE)
0315             /* up to 3 channels for capture */
0316             return -EINVAL;
0317         link_mask |= 1 << 3;
0318         fallthrough;
0319     case 3:
0320         link_mask |= 1 << 2;
0321         fallthrough;
0322     case 2:
0323         link_mask |= 1 << 1;
0324         fallthrough;
0325     case 1:
0326         link_mask |= 1 << 0;
0327         break;
0328     default:
0329         /* unsupported number of channels */
0330         return -EINVAL;
0331     }
0332 
0333     dma_data = snd_soc_dai_get_dma_data(dai, substream);
0334 
0335     threshold = mcpdm->config[stream].threshold;
0336     /* Configure McPDM channels, and DMA packet size */
0337     if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
0338         link_mask <<= 3;
0339 
0340         /* If capture is not running assume a stereo stream to come */
0341         if (!mcpdm->config[!stream].link_mask)
0342             mcpdm->config[!stream].link_mask = 0x3;
0343 
0344         dma_data->maxburst =
0345                 (MCPDM_DN_THRES_MAX - threshold) * channels;
0346         latency = threshold;
0347     } else {
0348         /* If playback is not running assume a stereo stream to come */
0349         if (!mcpdm->config[!stream].link_mask)
0350             mcpdm->config[!stream].link_mask = (0x3 << 3);
0351 
0352         dma_data->maxburst = threshold * channels;
0353         latency = (MCPDM_DN_THRES_MAX - threshold);
0354     }
0355 
0356     /*
0357      * The DMA must act to a DMA request within latency time (usec) to avoid
0358      * under/overflow
0359      */
0360     mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params);
0361 
0362     if (!mcpdm->latency[stream])
0363         mcpdm->latency[stream] = 10;
0364 
0365     /* Check if we need to restart McPDM with this stream */
0366     if (mcpdm->config[stream].link_mask &&
0367         mcpdm->config[stream].link_mask != link_mask)
0368         mcpdm->restart = true;
0369 
0370     mcpdm->config[stream].link_mask = link_mask;
0371 
0372     return 0;
0373 }
0374 
0375 static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
0376                   struct snd_soc_dai *dai)
0377 {
0378     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
0379     struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req;
0380     int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0381     int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
0382     int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
0383     int latency = mcpdm->latency[stream2];
0384 
0385     /* Prevent omap hardware from hitting off between FIFO fills */
0386     if (!latency || mcpdm->latency[stream1] < latency)
0387         latency = mcpdm->latency[stream1];
0388 
0389     if (cpu_latency_qos_request_active(pm_qos_req))
0390         cpu_latency_qos_update_request(pm_qos_req, latency);
0391     else if (latency)
0392         cpu_latency_qos_add_request(pm_qos_req, latency);
0393 
0394     if (!omap_mcpdm_active(mcpdm)) {
0395         omap_mcpdm_start(mcpdm);
0396         omap_mcpdm_reg_dump(mcpdm);
0397     } else if (mcpdm->restart) {
0398         omap_mcpdm_stop(mcpdm);
0399         omap_mcpdm_start(mcpdm);
0400         mcpdm->restart = false;
0401         omap_mcpdm_reg_dump(mcpdm);
0402     }
0403 
0404     return 0;
0405 }
0406 
0407 static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
0408     .startup    = omap_mcpdm_dai_startup,
0409     .shutdown   = omap_mcpdm_dai_shutdown,
0410     .hw_params  = omap_mcpdm_dai_hw_params,
0411     .prepare    = omap_mcpdm_prepare,
0412 };
0413 
0414 static int omap_mcpdm_probe(struct snd_soc_dai *dai)
0415 {
0416     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
0417     int ret;
0418 
0419     pm_runtime_enable(mcpdm->dev);
0420 
0421     /* Disable lines while request is ongoing */
0422     pm_runtime_get_sync(mcpdm->dev);
0423     omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
0424 
0425     ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM",
0426               (void *)mcpdm);
0427 
0428     pm_runtime_put_sync(mcpdm->dev);
0429 
0430     if (ret) {
0431         dev_err(mcpdm->dev, "Request for IRQ failed\n");
0432         pm_runtime_disable(mcpdm->dev);
0433     }
0434 
0435     /* Configure McPDM threshold values */
0436     mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
0437     mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
0438                             MCPDM_UP_THRES_MAX - 3;
0439 
0440     snd_soc_dai_init_dma_data(dai,
0441                   &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
0442                   &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
0443 
0444     return ret;
0445 }
0446 
0447 static int omap_mcpdm_remove(struct snd_soc_dai *dai)
0448 {
0449     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
0450 
0451     free_irq(mcpdm->irq, (void *)mcpdm);
0452     pm_runtime_disable(mcpdm->dev);
0453 
0454     if (cpu_latency_qos_request_active(&mcpdm->pm_qos_req))
0455         cpu_latency_qos_remove_request(&mcpdm->pm_qos_req);
0456 
0457     return 0;
0458 }
0459 
0460 #ifdef CONFIG_PM_SLEEP
0461 static int omap_mcpdm_suspend(struct snd_soc_component *component)
0462 {
0463     struct omap_mcpdm *mcpdm = snd_soc_component_get_drvdata(component);
0464 
0465     if (snd_soc_component_active(component)) {
0466         omap_mcpdm_stop(mcpdm);
0467         omap_mcpdm_close_streams(mcpdm);
0468     }
0469 
0470     mcpdm->pm_active_count = 0;
0471     while (pm_runtime_active(mcpdm->dev)) {
0472         pm_runtime_put_sync(mcpdm->dev);
0473         mcpdm->pm_active_count++;
0474     }
0475 
0476     return 0;
0477 }
0478 
0479 static int omap_mcpdm_resume(struct snd_soc_component *component)
0480 {
0481     struct omap_mcpdm *mcpdm = snd_soc_component_get_drvdata(component);
0482 
0483     if (mcpdm->pm_active_count) {
0484         while (mcpdm->pm_active_count--)
0485             pm_runtime_get_sync(mcpdm->dev);
0486 
0487         if (snd_soc_component_active(component)) {
0488             omap_mcpdm_open_streams(mcpdm);
0489             omap_mcpdm_start(mcpdm);
0490         }
0491     }
0492 
0493 
0494     return 0;
0495 }
0496 #else
0497 #define omap_mcpdm_suspend NULL
0498 #define omap_mcpdm_resume NULL
0499 #endif
0500 
0501 #define OMAP_MCPDM_RATES    (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
0502 #define OMAP_MCPDM_FORMATS  SNDRV_PCM_FMTBIT_S32_LE
0503 
0504 static struct snd_soc_dai_driver omap_mcpdm_dai = {
0505     .probe = omap_mcpdm_probe,
0506     .remove = omap_mcpdm_remove,
0507     .probe_order = SND_SOC_COMP_ORDER_LATE,
0508     .remove_order = SND_SOC_COMP_ORDER_EARLY,
0509     .playback = {
0510         .channels_min = 1,
0511         .channels_max = 5,
0512         .rates = OMAP_MCPDM_RATES,
0513         .formats = OMAP_MCPDM_FORMATS,
0514         .sig_bits = 24,
0515     },
0516     .capture = {
0517         .channels_min = 1,
0518         .channels_max = 3,
0519         .rates = OMAP_MCPDM_RATES,
0520         .formats = OMAP_MCPDM_FORMATS,
0521         .sig_bits = 24,
0522     },
0523     .ops = &omap_mcpdm_dai_ops,
0524 };
0525 
0526 static const struct snd_soc_component_driver omap_mcpdm_component = {
0527     .name           = "omap-mcpdm",
0528     .suspend        = omap_mcpdm_suspend,
0529     .resume         = omap_mcpdm_resume,
0530     .legacy_dai_naming  = 1,
0531 };
0532 
0533 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
0534                     u8 rx1, u8 rx2)
0535 {
0536     struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
0537 
0538     mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2);
0539 }
0540 EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
0541 
0542 static int asoc_mcpdm_probe(struct platform_device *pdev)
0543 {
0544     struct omap_mcpdm *mcpdm;
0545     struct resource *res;
0546     int ret;
0547 
0548     mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
0549     if (!mcpdm)
0550         return -ENOMEM;
0551 
0552     platform_set_drvdata(pdev, mcpdm);
0553 
0554     mutex_init(&mcpdm->mutex);
0555 
0556     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
0557     if (res == NULL)
0558         return -ENOMEM;
0559 
0560     mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
0561     mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
0562 
0563     mcpdm->dma_data[0].filter_data = "dn_link";
0564     mcpdm->dma_data[1].filter_data = "up_link";
0565 
0566     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
0567     mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
0568     if (IS_ERR(mcpdm->io_base))
0569         return PTR_ERR(mcpdm->io_base);
0570 
0571     mcpdm->irq = platform_get_irq(pdev, 0);
0572     if (mcpdm->irq < 0)
0573         return mcpdm->irq;
0574 
0575     mcpdm->dev = &pdev->dev;
0576 
0577     ret =  devm_snd_soc_register_component(&pdev->dev,
0578                            &omap_mcpdm_component,
0579                            &omap_mcpdm_dai, 1);
0580     if (ret)
0581         return ret;
0582 
0583     return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link");
0584 }
0585 
0586 static const struct of_device_id omap_mcpdm_of_match[] = {
0587     { .compatible = "ti,omap4-mcpdm", },
0588     { }
0589 };
0590 MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match);
0591 
0592 static struct platform_driver asoc_mcpdm_driver = {
0593     .driver = {
0594         .name   = "omap-mcpdm",
0595         .of_match_table = omap_mcpdm_of_match,
0596     },
0597 
0598     .probe  = asoc_mcpdm_probe,
0599 };
0600 
0601 module_platform_driver(asoc_mcpdm_driver);
0602 
0603 MODULE_ALIAS("platform:omap-mcpdm");
0604 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
0605 MODULE_DESCRIPTION("OMAP PDM SoC Interface");
0606 MODULE_LICENSE("GPL");