aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2016-10-31 07:25:43 -0400
committerMark Brown <broonie@kernel.org>2016-10-31 14:29:54 -0400
commit022d00ee0b55e6cd49048acadb9bf76c37e538d8 (patch)
tree57a5059f93b72fbb9c1e3fd82bd2f2d56ed9f609 /sound
parent1001354ca34179f3db924eb66672442a173147dc (diff)
ASoC: lpass-platform: Fix broken pcm data usage
This patch fixes lpass-platform driver which was broken in v4.9-rc1. lpass_pcm_data data structure holds information specific to stream. Holding a single private pointer to it in global lpass_data will not work, because it would be overwritten by for each pcm instance. This code was breaking playback when we have both playback and capture pcm streams, as playback settings are over written by capture settings. Fix this by moving channel allocation logic out of pcm_new to pcm_open so that we can store the stream specific information in private_data of snd_pcm_runtime. Fixes: 6adcbdcd4b6e ("ASoC: lpass-platform: don't use snd_soc_pcm_set_drvdata()") Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/qcom/lpass-platform.c165
-rw-r--r--sound/soc/qcom/lpass.h1
2 files changed, 79 insertions, 87 deletions
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index e2ff538a8aa5..07000f53db44 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -61,7 +61,40 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
61{ 61{
62 struct snd_pcm_runtime *runtime = substream->runtime; 62 struct snd_pcm_runtime *runtime = substream->runtime;
63 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 63 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
64 int ret; 64 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
65 struct lpass_data *drvdata =
66 snd_soc_platform_get_drvdata(soc_runtime->platform);
67 struct lpass_variant *v = drvdata->variant;
68 int ret, dma_ch, dir = substream->stream;
69 struct lpass_pcm_data *data;
70
71 data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
72 if (!data)
73 return -ENOMEM;
74
75 data->i2s_port = cpu_dai->driver->id;
76 runtime->private_data = data;
77
78 if (v->alloc_dma_channel)
79 dma_ch = v->alloc_dma_channel(drvdata, dir);
80 if (dma_ch < 0)
81 return dma_ch;
82
83 drvdata->substream[dma_ch] = substream;
84
85 ret = regmap_write(drvdata->lpaif_map,
86 LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
87 if (ret) {
88 dev_err(soc_runtime->dev,
89 "%s() error writing to rdmactl reg: %d\n",
90 __func__, ret);
91 return ret;
92 }
93
94 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
95 data->rdma_ch = dma_ch;
96 else
97 data->wrdma_ch = dma_ch;
65 98
66 snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); 99 snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
67 100
@@ -80,13 +113,40 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
80 return 0; 113 return 0;
81} 114}
82 115
116static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
117{
118 struct snd_pcm_runtime *runtime = substream->runtime;
119 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
120 struct lpass_data *drvdata =
121 snd_soc_platform_get_drvdata(soc_runtime->platform);
122 struct lpass_variant *v = drvdata->variant;
123 struct lpass_pcm_data *data;
124 int dma_ch, dir = substream->stream;
125
126 data = runtime->private_data;
127 v = drvdata->variant;
128
129 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
130 dma_ch = data->rdma_ch;
131 else
132 dma_ch = data->wrdma_ch;
133
134 drvdata->substream[dma_ch] = NULL;
135
136 if (v->free_dma_channel)
137 v->free_dma_channel(drvdata, dma_ch);
138
139 return 0;
140}
141
83static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, 142static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
84 struct snd_pcm_hw_params *params) 143 struct snd_pcm_hw_params *params)
85{ 144{
86 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 145 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
87 struct lpass_data *drvdata = 146 struct lpass_data *drvdata =
88 snd_soc_platform_get_drvdata(soc_runtime->platform); 147 snd_soc_platform_get_drvdata(soc_runtime->platform);
89 struct lpass_pcm_data *pcm_data = drvdata->private_data; 148 struct snd_pcm_runtime *rt = substream->runtime;
149 struct lpass_pcm_data *pcm_data = rt->private_data;
90 struct lpass_variant *v = drvdata->variant; 150 struct lpass_variant *v = drvdata->variant;
91 snd_pcm_format_t format = params_format(params); 151 snd_pcm_format_t format = params_format(params);
92 unsigned int channels = params_channels(params); 152 unsigned int channels = params_channels(params);
@@ -179,7 +239,8 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
179 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 239 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
180 struct lpass_data *drvdata = 240 struct lpass_data *drvdata =
181 snd_soc_platform_get_drvdata(soc_runtime->platform); 241 snd_soc_platform_get_drvdata(soc_runtime->platform);
182 struct lpass_pcm_data *pcm_data = drvdata->private_data; 242 struct snd_pcm_runtime *rt = substream->runtime;
243 struct lpass_pcm_data *pcm_data = rt->private_data;
183 struct lpass_variant *v = drvdata->variant; 244 struct lpass_variant *v = drvdata->variant;
184 unsigned int reg; 245 unsigned int reg;
185 int ret; 246 int ret;
@@ -203,7 +264,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
203 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 264 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
204 struct lpass_data *drvdata = 265 struct lpass_data *drvdata =
205 snd_soc_platform_get_drvdata(soc_runtime->platform); 266 snd_soc_platform_get_drvdata(soc_runtime->platform);
206 struct lpass_pcm_data *pcm_data = drvdata->private_data; 267 struct snd_pcm_runtime *rt = substream->runtime;
268 struct lpass_pcm_data *pcm_data = rt->private_data;
207 struct lpass_variant *v = drvdata->variant; 269 struct lpass_variant *v = drvdata->variant;
208 int ret, ch, dir = substream->stream; 270 int ret, ch, dir = substream->stream;
209 271
@@ -257,7 +319,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
257 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 319 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
258 struct lpass_data *drvdata = 320 struct lpass_data *drvdata =
259 snd_soc_platform_get_drvdata(soc_runtime->platform); 321 snd_soc_platform_get_drvdata(soc_runtime->platform);
260 struct lpass_pcm_data *pcm_data = drvdata->private_data; 322 struct snd_pcm_runtime *rt = substream->runtime;
323 struct lpass_pcm_data *pcm_data = rt->private_data;
261 struct lpass_variant *v = drvdata->variant; 324 struct lpass_variant *v = drvdata->variant;
262 int ret, ch, dir = substream->stream; 325 int ret, ch, dir = substream->stream;
263 326
@@ -333,7 +396,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
333 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 396 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
334 struct lpass_data *drvdata = 397 struct lpass_data *drvdata =
335 snd_soc_platform_get_drvdata(soc_runtime->platform); 398 snd_soc_platform_get_drvdata(soc_runtime->platform);
336 struct lpass_pcm_data *pcm_data = drvdata->private_data; 399 struct snd_pcm_runtime *rt = substream->runtime;
400 struct lpass_pcm_data *pcm_data = rt->private_data;
337 struct lpass_variant *v = drvdata->variant; 401 struct lpass_variant *v = drvdata->variant;
338 unsigned int base_addr, curr_addr; 402 unsigned int base_addr, curr_addr;
339 int ret, ch, dir = substream->stream; 403 int ret, ch, dir = substream->stream;
@@ -374,6 +438,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
374 438
375static const struct snd_pcm_ops lpass_platform_pcm_ops = { 439static const struct snd_pcm_ops lpass_platform_pcm_ops = {
376 .open = lpass_platform_pcmops_open, 440 .open = lpass_platform_pcmops_open,
441 .close = lpass_platform_pcmops_close,
377 .ioctl = snd_pcm_lib_ioctl, 442 .ioctl = snd_pcm_lib_ioctl,
378 .hw_params = lpass_platform_pcmops_hw_params, 443 .hw_params = lpass_platform_pcmops_hw_params,
379 .hw_free = lpass_platform_pcmops_hw_free, 444 .hw_free = lpass_platform_pcmops_hw_free,
@@ -470,117 +535,45 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
470{ 535{
471 struct snd_pcm *pcm = soc_runtime->pcm; 536 struct snd_pcm *pcm = soc_runtime->pcm;
472 struct snd_pcm_substream *psubstream, *csubstream; 537 struct snd_pcm_substream *psubstream, *csubstream;
473 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
474 struct lpass_data *drvdata =
475 snd_soc_platform_get_drvdata(soc_runtime->platform);
476 struct lpass_variant *v = drvdata->variant;
477 int ret = -EINVAL; 538 int ret = -EINVAL;
478 struct lpass_pcm_data *data;
479 size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; 539 size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
480 540
481 data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
482 if (!data)
483 return -ENOMEM;
484
485 data->i2s_port = cpu_dai->driver->id;
486 drvdata->private_data = data;
487
488 psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 541 psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
489 if (psubstream) { 542 if (psubstream) {
490 if (v->alloc_dma_channel)
491 data->rdma_ch = v->alloc_dma_channel(drvdata,
492 SNDRV_PCM_STREAM_PLAYBACK);
493
494 if (data->rdma_ch < 0)
495 return data->rdma_ch;
496
497 drvdata->substream[data->rdma_ch] = psubstream;
498
499 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, 543 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
500 soc_runtime->platform->dev, 544 soc_runtime->platform->dev,
501 size, &psubstream->dma_buffer); 545 size, &psubstream->dma_buffer);
502 if (ret)
503 goto playback_alloc_err;
504
505 ret = regmap_write(drvdata->lpaif_map,
506 LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
507 if (ret) { 546 if (ret) {
508 dev_err(soc_runtime->dev, 547 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
509 "%s() error writing to rdmactl reg: %d\n", 548 return ret;
510 __func__, ret);
511 goto capture_alloc_err;
512 } 549 }
513 } 550 }
514 551
515 csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 552 csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
516 if (csubstream) { 553 if (csubstream) {
517 if (v->alloc_dma_channel)
518 data->wrdma_ch = v->alloc_dma_channel(drvdata,
519 SNDRV_PCM_STREAM_CAPTURE);
520
521 if (data->wrdma_ch < 0) {
522 ret = data->wrdma_ch;
523 goto capture_alloc_err;
524 }
525
526 drvdata->substream[data->wrdma_ch] = csubstream;
527
528 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, 554 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
529 soc_runtime->platform->dev, 555 soc_runtime->platform->dev,
530 size, &csubstream->dma_buffer); 556 size, &csubstream->dma_buffer);
531 if (ret)
532 goto capture_alloc_err;
533
534 ret = regmap_write(drvdata->lpaif_map,
535 LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0);
536 if (ret) { 557 if (ret) {
537 dev_err(soc_runtime->dev, 558 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
538 "%s() error writing to wrdmactl reg: %d\n", 559 if (psubstream)
539 __func__, ret); 560 snd_dma_free_pages(&psubstream->dma_buffer);
540 goto capture_reg_err; 561 return ret;
541 } 562 }
563
542 } 564 }
543 565
544 return 0; 566 return 0;
545
546capture_reg_err:
547 if (csubstream)
548 snd_dma_free_pages(&csubstream->dma_buffer);
549
550capture_alloc_err:
551 if (psubstream)
552 snd_dma_free_pages(&psubstream->dma_buffer);
553
554 playback_alloc_err:
555 dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
556
557 return ret;
558} 567}
559 568
560static void lpass_platform_pcm_free(struct snd_pcm *pcm) 569static void lpass_platform_pcm_free(struct snd_pcm *pcm)
561{ 570{
562 struct snd_soc_pcm_runtime *rt;
563 struct lpass_data *drvdata;
564 struct lpass_pcm_data *data;
565 struct lpass_variant *v;
566 struct snd_pcm_substream *substream; 571 struct snd_pcm_substream *substream;
567 int ch, i; 572 int i;
568 573
569 for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { 574 for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
570 substream = pcm->streams[i].substream; 575 substream = pcm->streams[i].substream;
571 if (substream) { 576 if (substream) {
572 rt = substream->private_data;
573 drvdata = snd_soc_platform_get_drvdata(rt->platform);
574 data = drvdata->private_data;
575
576 ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
577 ? data->rdma_ch
578 : data->wrdma_ch;
579 v = drvdata->variant;
580 drvdata->substream[ch] = NULL;
581 if (v->free_dma_channel)
582 v->free_dma_channel(drvdata, ch);
583
584 snd_dma_free_pages(&substream->dma_buffer); 577 snd_dma_free_pages(&substream->dma_buffer);
585 substream->dma_buffer.area = NULL; 578 substream->dma_buffer.area = NULL;
586 substream->dma_buffer.addr = 0; 579 substream->dma_buffer.addr = 0;
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 35b3cea8207d..924971b6ded5 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -59,7 +59,6 @@ struct lpass_data {
59 struct clk *pcnoc_mport_clk; 59 struct clk *pcnoc_mport_clk;
60 struct clk *pcnoc_sway_clk; 60 struct clk *pcnoc_sway_clk;
61 61
62 void *private_data;
63}; 62};
64 63
65/* Vairant data per each SOC */ 64/* Vairant data per each SOC */