root/sound/soc/ti/omap-mcpdm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. omap_mcpdm_write
  2. omap_mcpdm_read
  3. omap_mcpdm_reg_dump
  4. omap_mcpdm_reg_dump
  5. omap_mcpdm_start
  6. omap_mcpdm_stop
  7. omap_mcpdm_active
  8. omap_mcpdm_open_streams
  9. omap_mcpdm_close_streams
  10. omap_mcpdm_irq_handler
  11. omap_mcpdm_dai_startup
  12. omap_mcpdm_dai_shutdown
  13. omap_mcpdm_dai_hw_params
  14. omap_mcpdm_prepare
  15. omap_mcpdm_probe
  16. omap_mcpdm_remove
  17. omap_mcpdm_suspend
  18. omap_mcpdm_resume
  19. omap_mcpdm_configure_dn_offsets
  20. asoc_mcpdm_probe

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

/* [<][>][^][v][top][bottom][index][help] */