0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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;
0035 u32 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
0049 struct mcpdm_link_config config[2];
0050
0051
0052 u32 dn_rx_offset;
0053
0054
0055 bool restart;
0056
0057
0058 int pm_active_count;
0059
0060 struct snd_dmaengine_dai_dma_data dma_data[2];
0061 };
0062
0063
0064
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
0115
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
0134
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
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
0163
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
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
0195
0196
0197 static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
0198 {
0199
0200 omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
0201 MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
0202
0203
0204 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
0205
0206
0207 omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
0208 MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
0209
0210
0211 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
0212
0213
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
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
0310 return -EINVAL;
0311 link_mask |= 1 << 4;
0312 fallthrough;
0313 case 4:
0314 if (stream == SNDRV_PCM_STREAM_CAPTURE)
0315
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
0330 return -EINVAL;
0331 }
0332
0333 dma_data = snd_soc_dai_get_dma_data(dai, substream);
0334
0335 threshold = mcpdm->config[stream].threshold;
0336
0337 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
0338 link_mask <<= 3;
0339
0340
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
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
0358
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
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
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
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
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");