diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-03 13:12:53 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-03 13:12:53 -0400 |
commit | 2735e6cd2b8d7cbf4c096b3cb19d637efb7a3ffc (patch) | |
tree | 9016804e806539a847a9325991856e2f8d16badd /sound/soc/omap/omap-mcpdm.c | |
parent | 85c9f9c5f9d09ea43daf4f1a8b81d3c7b7394d27 (diff) | |
parent | 167b5b93a4d53f29d4fda55f96116f525b2eb3d6 (diff) |
Merge branch 'topic/omap' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into HEAD
Diffstat (limited to 'sound/soc/omap/omap-mcpdm.c')
-rw-r--r-- | sound/soc/omap/omap-mcpdm.c | 80 |
1 files changed, 52 insertions, 28 deletions
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 5ca11bdac21e..e1d3998cb0a5 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c | |||
@@ -43,7 +43,10 @@ | |||
43 | #include "omap-mcpdm.h" | 43 | #include "omap-mcpdm.h" |
44 | #include "omap-pcm.h" | 44 | #include "omap-pcm.h" |
45 | 45 | ||
46 | #define OMAP44XX_MCPDM_L3_BASE 0x49032000 | 46 | struct mcpdm_link_config { |
47 | u32 link_mask; /* channel mask for the direction */ | ||
48 | u32 threshold; /* FIFO threshold */ | ||
49 | }; | ||
47 | 50 | ||
48 | struct omap_mcpdm { | 51 | struct omap_mcpdm { |
49 | struct device *dev; | 52 | struct device *dev; |
@@ -53,16 +56,14 @@ 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; | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | /* | 69 | /* |
@@ -130,11 +131,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} | |||
130 | static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) | 131 | static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) |
131 | { | 132 | { |
132 | u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); | 133 | u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); |
134 | u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; | ||
133 | 135 | ||
134 | ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); | 136 | ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); |
135 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); | 137 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); |
136 | 138 | ||
137 | ctrl |= mcpdm->dn_channels | mcpdm->up_channels; | 139 | ctrl |= link_mask; |
138 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); | 140 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); |
139 | 141 | ||
140 | ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); | 142 | ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); |
@@ -148,11 +150,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) | |||
148 | static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) | 150 | static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) |
149 | { | 151 | { |
150 | u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); | 152 | u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); |
153 | u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK; | ||
151 | 154 | ||
152 | ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); | 155 | ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); |
153 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); | 156 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); |
154 | 157 | ||
155 | ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels); | 158 | ctrl &= ~(link_mask); |
156 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); | 159 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); |
157 | 160 | ||
158 | ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); | 161 | ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); |
@@ -188,8 +191,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) | |||
188 | omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); | 191 | omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); |
189 | } | 192 | } |
190 | 193 | ||
191 | omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold); | 194 | omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, |
192 | omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold); | 195 | mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold); |
196 | omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, | ||
197 | mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold); | ||
193 | 198 | ||
194 | omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, | 199 | omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, |
195 | MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); | 200 | MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); |
@@ -283,6 +288,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, | |||
283 | if (omap_mcpdm_active(mcpdm)) { | 288 | if (omap_mcpdm_active(mcpdm)) { |
284 | omap_mcpdm_stop(mcpdm); | 289 | omap_mcpdm_stop(mcpdm); |
285 | omap_mcpdm_close_streams(mcpdm); | 290 | omap_mcpdm_close_streams(mcpdm); |
291 | mcpdm->config[0].link_mask = 0; | ||
292 | mcpdm->config[1].link_mask = 0; | ||
286 | } | 293 | } |
287 | } | 294 | } |
288 | 295 | ||
@@ -296,6 +303,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, | |||
296 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); | 303 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); |
297 | int stream = substream->stream; | 304 | int stream = substream->stream; |
298 | struct omap_pcm_dma_data *dma_data; | 305 | struct omap_pcm_dma_data *dma_data; |
306 | u32 threshold; | ||
299 | int channels; | 307 | int channels; |
300 | int link_mask = 0; | 308 | int link_mask = 0; |
301 | 309 | ||
@@ -325,16 +333,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, | |||
325 | 333 | ||
326 | dma_data = snd_soc_dai_get_dma_data(dai, substream); | 334 | dma_data = snd_soc_dai_get_dma_data(dai, substream); |
327 | 335 | ||
336 | threshold = mcpdm->config[stream].threshold; | ||
328 | /* Configure McPDM channels, and DMA packet size */ | 337 | /* Configure McPDM channels, and DMA packet size */ |
329 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 338 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
330 | mcpdm->dn_channels = link_mask << 3; | 339 | link_mask <<= 3; |
340 | |||
341 | /* If capture is not running assume a stereo stream to come */ | ||
342 | if (!mcpdm->config[!stream].link_mask) | ||
343 | mcpdm->config[!stream].link_mask = 0x3; | ||
344 | |||
331 | dma_data->packet_size = | 345 | dma_data->packet_size = |
332 | (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels; | 346 | (MCPDM_DN_THRES_MAX - threshold) * channels; |
333 | } else { | 347 | } else { |
334 | mcpdm->up_channels = link_mask << 0; | 348 | /* If playback is not running assume a stereo stream to come */ |
335 | dma_data->packet_size = mcpdm->up_threshold * channels; | 349 | if (!mcpdm->config[!stream].link_mask) |
350 | mcpdm->config[!stream].link_mask = (0x3 << 3); | ||
351 | |||
352 | dma_data->packet_size = threshold * channels; | ||
336 | } | 353 | } |
337 | 354 | ||
355 | /* Check if we need to restart McPDM with this stream */ | ||
356 | if (mcpdm->config[stream].link_mask && | ||
357 | mcpdm->config[stream].link_mask != link_mask) | ||
358 | mcpdm->restart = true; | ||
359 | |||
360 | mcpdm->config[stream].link_mask = link_mask; | ||
361 | |||
338 | return 0; | 362 | return 0; |
339 | } | 363 | } |
340 | 364 | ||
@@ -346,6 +370,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, | |||
346 | if (!omap_mcpdm_active(mcpdm)) { | 370 | if (!omap_mcpdm_active(mcpdm)) { |
347 | omap_mcpdm_start(mcpdm); | 371 | omap_mcpdm_start(mcpdm); |
348 | omap_mcpdm_reg_dump(mcpdm); | 372 | omap_mcpdm_reg_dump(mcpdm); |
373 | } else if (mcpdm->restart) { | ||
374 | omap_mcpdm_stop(mcpdm); | ||
375 | omap_mcpdm_start(mcpdm); | ||
376 | mcpdm->restart = false; | ||
377 | omap_mcpdm_reg_dump(mcpdm); | ||
349 | } | 378 | } |
350 | 379 | ||
351 | return 0; | 380 | return 0; |
@@ -369,7 +398,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) | |||
369 | pm_runtime_get_sync(mcpdm->dev); | 398 | pm_runtime_get_sync(mcpdm->dev); |
370 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); | 399 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); |
371 | 400 | ||
372 | ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, | 401 | ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler, |
373 | 0, "McPDM", (void *)mcpdm); | 402 | 0, "McPDM", (void *)mcpdm); |
374 | 403 | ||
375 | pm_runtime_put_sync(mcpdm->dev); | 404 | pm_runtime_put_sync(mcpdm->dev); |
@@ -380,8 +409,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) | |||
380 | } | 409 | } |
381 | 410 | ||
382 | /* Configure McPDM threshold values */ | 411 | /* Configure McPDM threshold values */ |
383 | mcpdm->dn_threshold = 2; | 412 | mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2; |
384 | mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3; | 413 | mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold = |
414 | MCPDM_UP_THRES_MAX - 3; | ||
385 | return ret; | 415 | return ret; |
386 | } | 416 | } |
387 | 417 | ||
@@ -389,7 +419,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) | |||
389 | { | 419 | { |
390 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); | 420 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); |
391 | 421 | ||
392 | free_irq(mcpdm->irq, (void *)mcpdm); | ||
393 | pm_runtime_disable(mcpdm->dev); | 422 | pm_runtime_disable(mcpdm->dev); |
394 | 423 | ||
395 | return 0; | 424 | return 0; |
@@ -465,14 +494,9 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) | |||
465 | if (res == NULL) | 494 | if (res == NULL) |
466 | return -ENOMEM; | 495 | return -ENOMEM; |
467 | 496 | ||
468 | if (!devm_request_mem_region(&pdev->dev, res->start, | 497 | mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); |
469 | resource_size(res), "McPDM")) | 498 | if (IS_ERR(mcpdm->io_base)) |
470 | return -EBUSY; | 499 | 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 | 500 | ||
477 | mcpdm->irq = platform_get_irq(pdev, 0); | 501 | mcpdm->irq = platform_get_irq(pdev, 0); |
478 | if (mcpdm->irq < 0) | 502 | if (mcpdm->irq < 0) |