1 /* 2 * omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port 3 * 4 * Copyright (C) 2009 - 2011 Texas Instruments 5 * 6 * Author: Misael Lopez Cruz <misael.lopez@ti.com> 7 * Contact: Jorge Eduardo Candelaria <x0107209@ti.com> 8 * Margarita Olaya <magi.olaya@ti.com> 9 * Peter Ujfalusi <peter.ujfalusi@ti.com> 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * version 2 as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 23 * 02110-1301 USA 24 * 25 */ 26 27 #include <linux/init.h> 28 #include <linux/module.h> 29 #include <linux/platform_device.h> 30 #include <linux/interrupt.h> 31 #include <linux/err.h> 32 #include <linux/io.h> 33 #include <linux/irq.h> 34 #include <linux/slab.h> 35 #include <linux/pm_runtime.h> 36 #include <linux/of_device.h> 37 38 #include <sound/core.h> 39 #include <sound/pcm.h> 40 #include <sound/pcm_params.h> 41 #include <sound/soc.h> 42 #include <sound/dmaengine_pcm.h> 43 44 #include "omap-mcpdm.h" 45 #include "sdma-pcm.h" 46 47 struct mcpdm_link_config { 48 u32 link_mask; /* channel mask for the direction */ 49 u32 threshold; /* FIFO threshold */ 50 }; 51 52 struct omap_mcpdm { 53 struct device *dev; 54 unsigned long phys_base; 55 void __iomem *io_base; 56 int irq; 57 struct pm_qos_request pm_qos_req; 58 int latency[2]; 59 60 struct mutex mutex; 61 62 /* Playback/Capture configuration */ 63 struct mcpdm_link_config config[2]; 64 65 /* McPDM dn offsets for rx1, and 2 channels */ 66 u32 dn_rx_offset; 67 68 /* McPDM needs to be restarted due to runtime reconfiguration */ 69 bool restart; 70 71 /* pm state for suspend/resume handling */ 72 int pm_active_count; 73 74 struct snd_dmaengine_dai_dma_data dma_data[2]; 75 }; 76 77 /* 78 * Stream DMA parameters 79 */ 80 81 static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val) 82 { 83 writel_relaxed(val, mcpdm->io_base + reg); 84 } 85 86 static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg) 87 { 88 return readl_relaxed(mcpdm->io_base + reg); 89 } 90 91 #ifdef DEBUG 92 static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) 93 { 94 dev_dbg(mcpdm->dev, "***********************\n"); 95 dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", 96 omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW)); 97 dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", 98 omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS)); 99 dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", 100 omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET)); 101 dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", 102 omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR)); 103 dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", 104 omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN)); 105 dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", 106 omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET)); 107 dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", 108 omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR)); 109 dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", 110 omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN)); 111 dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", 112 omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL)); 113 dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", 114 omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA)); 115 dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", 116 omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA)); 117 dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", 118 omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN)); 119 dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", 120 omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP)); 121 dev_dbg(mcpdm->dev, "***********************\n"); 122 } 123 #else 124 static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} 125 #endif 126 127 /* 128 * Enables the transfer through the PDM interface to/from the Phoenix 129 * codec by enabling the corresponding UP or DN channels. 130 */ 131 static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) 132 { 133 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 134 u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; 135 136 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 137 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 138 139 ctrl |= link_mask; 140 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 141 142 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 143 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 144 } 145 146 /* 147 * Disables the transfer through the PDM interface to/from the Phoenix 148 * codec by disabling the corresponding UP or DN channels. 149 */ 150 static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) 151 { 152 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 153 u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK; 154 155 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 156 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 157 158 ctrl &= ~(link_mask); 159 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 160 161 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 162 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 163 164 } 165 166 /* 167 * Is the physical McPDM interface active. 168 */ 169 static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) 170 { 171 return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) & 172 (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK); 173 } 174 175 /* 176 * Configures McPDM uplink, and downlink for audio. 177 * This function should be called before omap_mcpdm_start. 178 */ 179 static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) 180 { 181 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 182 183 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); 184 185 omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, 186 MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | 187 MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); 188 189 /* Enable DN RX1/2 offset cancellation feature, if configured */ 190 if (mcpdm->dn_rx_offset) { 191 u32 dn_offset = mcpdm->dn_rx_offset; 192 193 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); 194 dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN); 195 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); 196 } 197 198 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, 199 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold); 200 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, 201 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold); 202 203 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, 204 MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); 205 } 206 207 /* 208 * Cleans McPDM uplink, and downlink configuration. 209 * This function should be called when the stream is closed. 210 */ 211 static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm) 212 { 213 /* Disable irq request generation for downlink */ 214 omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR, 215 MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL); 216 217 /* Disable DMA request generation for downlink */ 218 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE); 219 220 /* Disable irq request generation for uplink */ 221 omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR, 222 MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); 223 224 /* Disable DMA request generation for uplink */ 225 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE); 226 227 /* Disable RX1/2 offset cancellation */ 228 if (mcpdm->dn_rx_offset) 229 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0); 230 } 231 232 static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) 233 { 234 struct omap_mcpdm *mcpdm = dev_id; 235 int irq_status; 236 237 irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS); 238 239 /* Acknowledge irq event */ 240 omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status); 241 242 if (irq_status & MCPDM_DN_IRQ_FULL) 243 dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n"); 244 245 if (irq_status & MCPDM_DN_IRQ_EMPTY) 246 dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n"); 247 248 if (irq_status & MCPDM_DN_IRQ) 249 dev_dbg(mcpdm->dev, "DN (playback) write request\n"); 250 251 if (irq_status & MCPDM_UP_IRQ_FULL) 252 dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n"); 253 254 if (irq_status & MCPDM_UP_IRQ_EMPTY) 255 dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n"); 256 257 if (irq_status & MCPDM_UP_IRQ) 258 dev_dbg(mcpdm->dev, "UP (capture) write request\n"); 259 260 return IRQ_HANDLED; 261 } 262 263 static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, 264 struct snd_soc_dai *dai) 265 { 266 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 267 268 mutex_lock(&mcpdm->mutex); 269 270 if (!dai->active) 271 omap_mcpdm_open_streams(mcpdm); 272 273 mutex_unlock(&mcpdm->mutex); 274 275 return 0; 276 } 277 278 static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, 279 struct snd_soc_dai *dai) 280 { 281 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 282 int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 283 int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; 284 int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; 285 286 mutex_lock(&mcpdm->mutex); 287 288 if (!dai->active) { 289 if (omap_mcpdm_active(mcpdm)) { 290 omap_mcpdm_stop(mcpdm); 291 omap_mcpdm_close_streams(mcpdm); 292 mcpdm->config[0].link_mask = 0; 293 mcpdm->config[1].link_mask = 0; 294 } 295 } 296 297 if (mcpdm->latency[stream2]) 298 pm_qos_update_request(&mcpdm->pm_qos_req, 299 mcpdm->latency[stream2]); 300 else if (mcpdm->latency[stream1]) 301 pm_qos_remove_request(&mcpdm->pm_qos_req); 302 303 mcpdm->latency[stream1] = 0; 304 305 mutex_unlock(&mcpdm->mutex); 306 } 307 308 static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, 309 struct snd_pcm_hw_params *params, 310 struct snd_soc_dai *dai) 311 { 312 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 313 int stream = substream->stream; 314 struct snd_dmaengine_dai_dma_data *dma_data; 315 u32 threshold; 316 int channels, latency; 317 int link_mask = 0; 318 319 channels = params_channels(params); 320 switch (channels) { 321 case 5: 322 if (stream == SNDRV_PCM_STREAM_CAPTURE) 323 /* up to 3 channels for capture */ 324 return -EINVAL; 325 link_mask |= 1 << 4; 326 /* fall through */ 327 case 4: 328 if (stream == SNDRV_PCM_STREAM_CAPTURE) 329 /* up to 3 channels for capture */ 330 return -EINVAL; 331 link_mask |= 1 << 3; 332 /* fall through */ 333 case 3: 334 link_mask |= 1 << 2; 335 /* fall through */ 336 case 2: 337 link_mask |= 1 << 1; 338 /* fall through */ 339 case 1: 340 link_mask |= 1 << 0; 341 break; 342 default: 343 /* unsupported number of channels */ 344 return -EINVAL; 345 } 346 347 dma_data = snd_soc_dai_get_dma_data(dai, substream); 348 349 threshold = mcpdm->config[stream].threshold; 350 /* Configure McPDM channels, and DMA packet size */ 351 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 352 link_mask <<= 3; 353 354 /* If capture is not running assume a stereo stream to come */ 355 if (!mcpdm->config[!stream].link_mask) 356 mcpdm->config[!stream].link_mask = 0x3; 357 358 dma_data->maxburst = 359 (MCPDM_DN_THRES_MAX - threshold) * channels; 360 latency = threshold; 361 } else { 362 /* If playback is not running assume a stereo stream to come */ 363 if (!mcpdm->config[!stream].link_mask) 364 mcpdm->config[!stream].link_mask = (0x3 << 3); 365 366 dma_data->maxburst = threshold * channels; 367 latency = (MCPDM_DN_THRES_MAX - threshold); 368 } 369 370 /* 371 * The DMA must act to a DMA request within latency time (usec) to avoid 372 * under/overflow 373 */ 374 mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params); 375 376 if (!mcpdm->latency[stream]) 377 mcpdm->latency[stream] = 10; 378 379 /* Check if we need to restart McPDM with this stream */ 380 if (mcpdm->config[stream].link_mask && 381 mcpdm->config[stream].link_mask != link_mask) 382 mcpdm->restart = true; 383 384 mcpdm->config[stream].link_mask = link_mask; 385 386 return 0; 387 } 388 389 static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, 390 struct snd_soc_dai *dai) 391 { 392 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 393 struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req; 394 int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 395 int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; 396 int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; 397 int latency = mcpdm->latency[stream2]; 398 399 /* Prevent omap hardware from hitting off between FIFO fills */ 400 if (!latency || mcpdm->latency[stream1] < latency) 401 latency = mcpdm->latency[stream1]; 402 403 if (pm_qos_request_active(pm_qos_req)) 404 pm_qos_update_request(pm_qos_req, latency); 405 else if (latency) 406 pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency); 407 408 if (!omap_mcpdm_active(mcpdm)) { 409 omap_mcpdm_start(mcpdm); 410 omap_mcpdm_reg_dump(mcpdm); 411 } else if (mcpdm->restart) { 412 omap_mcpdm_stop(mcpdm); 413 omap_mcpdm_start(mcpdm); 414 mcpdm->restart = false; 415 omap_mcpdm_reg_dump(mcpdm); 416 } 417 418 return 0; 419 } 420 421 static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { 422 .startup = omap_mcpdm_dai_startup, 423 .shutdown = omap_mcpdm_dai_shutdown, 424 .hw_params = omap_mcpdm_dai_hw_params, 425 .prepare = omap_mcpdm_prepare, 426 }; 427 428 static int omap_mcpdm_probe(struct snd_soc_dai *dai) 429 { 430 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 431 int ret; 432 433 pm_runtime_enable(mcpdm->dev); 434 435 /* Disable lines while request is ongoing */ 436 pm_runtime_get_sync(mcpdm->dev); 437 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); 438 439 ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM", 440 (void *)mcpdm); 441 442 pm_runtime_put_sync(mcpdm->dev); 443 444 if (ret) { 445 dev_err(mcpdm->dev, "Request for IRQ failed\n"); 446 pm_runtime_disable(mcpdm->dev); 447 } 448 449 /* Configure McPDM threshold values */ 450 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2; 451 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold = 452 MCPDM_UP_THRES_MAX - 3; 453 454 snd_soc_dai_init_dma_data(dai, 455 &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK], 456 &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]); 457 458 return ret; 459 } 460 461 static int omap_mcpdm_remove(struct snd_soc_dai *dai) 462 { 463 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 464 465 free_irq(mcpdm->irq, (void *)mcpdm); 466 pm_runtime_disable(mcpdm->dev); 467 468 if (pm_qos_request_active(&mcpdm->pm_qos_req)) 469 pm_qos_remove_request(&mcpdm->pm_qos_req); 470 471 return 0; 472 } 473 474 #ifdef CONFIG_PM_SLEEP 475 static int omap_mcpdm_suspend(struct snd_soc_dai *dai) 476 { 477 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 478 479 if (dai->active) { 480 omap_mcpdm_stop(mcpdm); 481 omap_mcpdm_close_streams(mcpdm); 482 } 483 484 mcpdm->pm_active_count = 0; 485 while (pm_runtime_active(mcpdm->dev)) { 486 pm_runtime_put_sync(mcpdm->dev); 487 mcpdm->pm_active_count++; 488 } 489 490 return 0; 491 } 492 493 static int omap_mcpdm_resume(struct snd_soc_dai *dai) 494 { 495 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 496 497 if (mcpdm->pm_active_count) { 498 while (mcpdm->pm_active_count--) 499 pm_runtime_get_sync(mcpdm->dev); 500 501 if (dai->active) { 502 omap_mcpdm_open_streams(mcpdm); 503 omap_mcpdm_start(mcpdm); 504 } 505 } 506 507 508 return 0; 509 } 510 #else 511 #define omap_mcpdm_suspend NULL 512 #define omap_mcpdm_resume NULL 513 #endif 514 515 #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 516 #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE 517 518 static struct snd_soc_dai_driver omap_mcpdm_dai = { 519 .probe = omap_mcpdm_probe, 520 .remove = omap_mcpdm_remove, 521 .suspend = omap_mcpdm_suspend, 522 .resume = omap_mcpdm_resume, 523 .probe_order = SND_SOC_COMP_ORDER_LATE, 524 .remove_order = SND_SOC_COMP_ORDER_EARLY, 525 .playback = { 526 .channels_min = 1, 527 .channels_max = 5, 528 .rates = OMAP_MCPDM_RATES, 529 .formats = OMAP_MCPDM_FORMATS, 530 .sig_bits = 24, 531 }, 532 .capture = { 533 .channels_min = 1, 534 .channels_max = 3, 535 .rates = OMAP_MCPDM_RATES, 536 .formats = OMAP_MCPDM_FORMATS, 537 .sig_bits = 24, 538 }, 539 .ops = &omap_mcpdm_dai_ops, 540 }; 541 542 static const struct snd_soc_component_driver omap_mcpdm_component = { 543 .name = "omap-mcpdm", 544 }; 545 546 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, 547 u8 rx1, u8 rx2) 548 { 549 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai); 550 551 mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2); 552 } 553 EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets); 554 555 static int asoc_mcpdm_probe(struct platform_device *pdev) 556 { 557 struct omap_mcpdm *mcpdm; 558 struct resource *res; 559 int ret; 560 561 mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL); 562 if (!mcpdm) 563 return -ENOMEM; 564 565 platform_set_drvdata(pdev, mcpdm); 566 567 mutex_init(&mcpdm->mutex); 568 569 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); 570 if (res == NULL) 571 return -ENOMEM; 572 573 mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA; 574 mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA; 575 576 mcpdm->dma_data[0].filter_data = "dn_link"; 577 mcpdm->dma_data[1].filter_data = "up_link"; 578 579 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 580 mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); 581 if (IS_ERR(mcpdm->io_base)) 582 return PTR_ERR(mcpdm->io_base); 583 584 mcpdm->irq = platform_get_irq(pdev, 0); 585 if (mcpdm->irq < 0) 586 return mcpdm->irq; 587 588 mcpdm->dev = &pdev->dev; 589 590 ret = devm_snd_soc_register_component(&pdev->dev, 591 &omap_mcpdm_component, 592 &omap_mcpdm_dai, 1); 593 if (ret) 594 return ret; 595 596 return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link"); 597 } 598 599 static const struct of_device_id omap_mcpdm_of_match[] = { 600 { .compatible = "ti,omap4-mcpdm", }, 601 { } 602 }; 603 MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match); 604 605 static struct platform_driver asoc_mcpdm_driver = { 606 .driver = { 607 .name = "omap-mcpdm", 608 .of_match_table = omap_mcpdm_of_match, 609 }, 610 611 .probe = asoc_mcpdm_probe, 612 }; 613 614 module_platform_driver(asoc_mcpdm_driver); 615 616 MODULE_ALIAS("platform:omap-mcpdm"); 617 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); 618 MODULE_DESCRIPTION("OMAP PDM SoC Interface"); 619 MODULE_LICENSE("GPL"); 620