aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/omap/omap-mcpdm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap/omap-mcpdm.c')
-rw-r--r--sound/soc/omap/omap-mcpdm.c118
1 files changed, 72 insertions, 46 deletions
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 5ca11bdac21e..eb05c7ed6d05 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -39,11 +39,14 @@
39#include <sound/pcm.h> 39#include <sound/pcm.h>
40#include <sound/pcm_params.h> 40#include <sound/pcm_params.h>
41#include <sound/soc.h> 41#include <sound/soc.h>
42#include <sound/dmaengine_pcm.h>
42 43
43#include "omap-mcpdm.h" 44#include "omap-mcpdm.h"
44#include "omap-pcm.h"
45 45
46#define OMAP44XX_MCPDM_L3_BASE 0x49032000 46struct mcpdm_link_config {
47 u32 link_mask; /* channel mask for the direction */
48 u32 threshold; /* FIFO threshold */
49};
47 50
48struct omap_mcpdm { 51struct omap_mcpdm {
49 struct device *dev; 52 struct device *dev;
@@ -53,29 +56,22 @@ struct omap_mcpdm {
53 56
54 struct mutex mutex; 57 struct mutex mutex;
55 58
56 /* channel data */ 59 /* Playback/Capture configuration */
57 u32 dn_channels; 60 struct mcpdm_link_config config[2];
58 u32 up_channels;
59
60 /* McPDM FIFO thresholds */
61 u32 dn_threshold;
62 u32 up_threshold;
63 61
64 /* McPDM dn offsets for rx1, and 2 channels */ 62 /* McPDM dn offsets for rx1, and 2 channels */
65 u32 dn_rx_offset; 63 u32 dn_rx_offset;
64
65 /* McPDM needs to be restarted due to runtime reconfiguration */
66 bool restart;
67
68 struct snd_dmaengine_dai_dma_data dma_data[2];
69 unsigned int dma_req[2];
66}; 70};
67 71
68/* 72/*
69 * Stream DMA parameters 73 * Stream DMA parameters
70 */ 74 */
71static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
72 {
73 .name = "Audio playback",
74 },
75 {
76 .name = "Audio capture",
77 },
78};
79 75
80static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val) 76static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
81{ 77{
@@ -130,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
130static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) 126static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
131{ 127{
132 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 128 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
129 u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
133 130
134 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 131 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
135 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 132 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
136 133
137 ctrl |= mcpdm->dn_channels | mcpdm->up_channels; 134 ctrl |= link_mask;
138 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 135 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
139 136
140 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 137 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -148,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
148static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) 145static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
149{ 146{
150 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 147 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
148 u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
151 149
152 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 150 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
153 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 151 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
154 152
155 ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels); 153 ctrl &= ~(link_mask);
156 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 154 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
157 155
158 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 156 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -188,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
188 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); 186 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
189 } 187 }
190 188
191 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold); 189 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
192 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold); 190 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
191 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
192 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
193 193
194 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, 194 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
195 MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); 195 MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
@@ -267,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
267 mutex_unlock(&mcpdm->mutex); 267 mutex_unlock(&mcpdm->mutex);
268 268
269 snd_soc_dai_set_dma_data(dai, substream, 269 snd_soc_dai_set_dma_data(dai, substream,
270 &omap_mcpdm_dai_dma_params[substream->stream]); 270 &mcpdm->dma_data[substream->stream]);
271 271
272 return 0; 272 return 0;
273} 273}
@@ -283,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
283 if (omap_mcpdm_active(mcpdm)) { 283 if (omap_mcpdm_active(mcpdm)) {
284 omap_mcpdm_stop(mcpdm); 284 omap_mcpdm_stop(mcpdm);
285 omap_mcpdm_close_streams(mcpdm); 285 omap_mcpdm_close_streams(mcpdm);
286 mcpdm->config[0].link_mask = 0;
287 mcpdm->config[1].link_mask = 0;
286 } 288 }
287 } 289 }
288 290
@@ -295,7 +297,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
295{ 297{
296 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 298 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
297 int stream = substream->stream; 299 int stream = substream->stream;
298 struct omap_pcm_dma_data *dma_data; 300 struct snd_dmaengine_dai_dma_data *dma_data;
301 u32 threshold;
299 int channels; 302 int channels;
300 int link_mask = 0; 303 int link_mask = 0;
301 304
@@ -325,16 +328,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
325 328
326 dma_data = snd_soc_dai_get_dma_data(dai, substream); 329 dma_data = snd_soc_dai_get_dma_data(dai, substream);
327 330
331 threshold = mcpdm->config[stream].threshold;
328 /* Configure McPDM channels, and DMA packet size */ 332 /* Configure McPDM channels, and DMA packet size */
329 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 333 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
330 mcpdm->dn_channels = link_mask << 3; 334 link_mask <<= 3;
331 dma_data->packet_size = 335
332 (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels; 336 /* If capture is not running assume a stereo stream to come */
337 if (!mcpdm->config[!stream].link_mask)
338 mcpdm->config[!stream].link_mask = 0x3;
339
340 dma_data->maxburst =
341 (MCPDM_DN_THRES_MAX - threshold) * channels;
333 } else { 342 } else {
334 mcpdm->up_channels = link_mask << 0; 343 /* If playback is not running assume a stereo stream to come */
335 dma_data->packet_size = mcpdm->up_threshold * channels; 344 if (!mcpdm->config[!stream].link_mask)
345 mcpdm->config[!stream].link_mask = (0x3 << 3);
346
347 dma_data->maxburst = threshold * channels;
336 } 348 }
337 349
350 /* Check if we need to restart McPDM with this stream */
351 if (mcpdm->config[stream].link_mask &&
352 mcpdm->config[stream].link_mask != link_mask)
353 mcpdm->restart = true;
354
355 mcpdm->config[stream].link_mask = link_mask;
356
338 return 0; 357 return 0;
339} 358}
340 359
@@ -346,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
346 if (!omap_mcpdm_active(mcpdm)) { 365 if (!omap_mcpdm_active(mcpdm)) {
347 omap_mcpdm_start(mcpdm); 366 omap_mcpdm_start(mcpdm);
348 omap_mcpdm_reg_dump(mcpdm); 367 omap_mcpdm_reg_dump(mcpdm);
368 } else if (mcpdm->restart) {
369 omap_mcpdm_stop(mcpdm);
370 omap_mcpdm_start(mcpdm);
371 mcpdm->restart = false;
372 omap_mcpdm_reg_dump(mcpdm);
349 } 373 }
350 374
351 return 0; 375 return 0;
@@ -369,7 +393,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
369 pm_runtime_get_sync(mcpdm->dev); 393 pm_runtime_get_sync(mcpdm->dev);
370 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); 394 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
371 395
372 ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 396 ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
373 0, "McPDM", (void *)mcpdm); 397 0, "McPDM", (void *)mcpdm);
374 398
375 pm_runtime_put_sync(mcpdm->dev); 399 pm_runtime_put_sync(mcpdm->dev);
@@ -380,8 +404,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
380 } 404 }
381 405
382 /* Configure McPDM threshold values */ 406 /* Configure McPDM threshold values */
383 mcpdm->dn_threshold = 2; 407 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
384 mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3; 408 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
409 MCPDM_UP_THRES_MAX - 3;
385 return ret; 410 return ret;
386} 411}
387 412
@@ -389,7 +414,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
389{ 414{
390 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 415 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
391 416
392 free_irq(mcpdm->irq, (void *)mcpdm);
393 pm_runtime_disable(mcpdm->dev); 417 pm_runtime_disable(mcpdm->dev);
394 418
395 return 0; 419 return 0;
@@ -420,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
420 .ops = &omap_mcpdm_dai_ops, 444 .ops = &omap_mcpdm_dai_ops,
421}; 445};
422 446
447static const struct snd_soc_component_driver omap_mcpdm_component = {
448 .name = "omap-mcpdm",
449};
450
423void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, 451void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
424 u8 rx1, u8 rx2) 452 u8 rx1, u8 rx2)
425{ 453{
@@ -446,33 +474,30 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
446 if (res == NULL) 474 if (res == NULL)
447 return -ENOMEM; 475 return -ENOMEM;
448 476
449 omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA; 477 mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
450 omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA; 478 mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
451 479
452 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link"); 480 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
453 if (!res) 481 if (!res)
454 return -ENODEV; 482 return -ENODEV;
455 483
456 omap_mcpdm_dai_dma_params[0].dma_req = res->start; 484 mcpdm->dma_req[0] = res->start;
485 mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
457 486
458 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link"); 487 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
459 if (!res) 488 if (!res)
460 return -ENODEV; 489 return -ENODEV;
461 490
462 omap_mcpdm_dai_dma_params[1].dma_req = res->start; 491 mcpdm->dma_req[1] = res->start;
492 mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
463 493
464 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 494 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
465 if (res == NULL) 495 if (res == NULL)
466 return -ENOMEM; 496 return -ENOMEM;
467 497
468 if (!devm_request_mem_region(&pdev->dev, res->start, 498 mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
469 resource_size(res), "McPDM")) 499 if (IS_ERR(mcpdm->io_base))
470 return -EBUSY; 500 return PTR_ERR(mcpdm->io_base);
471
472 mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
473 resource_size(res));
474 if (!mcpdm->io_base)
475 return -ENOMEM;
476 501
477 mcpdm->irq = platform_get_irq(pdev, 0); 502 mcpdm->irq = platform_get_irq(pdev, 0);
478 if (mcpdm->irq < 0) 503 if (mcpdm->irq < 0)
@@ -480,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
480 505
481 mcpdm->dev = &pdev->dev; 506 mcpdm->dev = &pdev->dev;
482 507
483 return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); 508 return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
509 &omap_mcpdm_dai, 1);
484} 510}
485 511
486static int asoc_mcpdm_remove(struct platform_device *pdev) 512static int asoc_mcpdm_remove(struct platform_device *pdev)
487{ 513{
488 snd_soc_unregister_dai(&pdev->dev); 514 snd_soc_unregister_component(&pdev->dev);
489 return 0; 515 return 0;
490} 516}
491 517