aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2015-05-21 17:53:14 -0400
committerMark Brown <broonie@kernel.org>2015-05-22 08:27:06 -0400
commit4f629e4b8705fb02e9618ca257fb077f0022921b (patch)
tree8e3bc1795b25312f32c2fffb6bab004a905d2a42
parent0054055c590ae5ca69f027d42cf171493476f6d8 (diff)
ASoC: qcom: Add ability to handle interrupts per dma channel
This patch adds ablity to lpass driver to handle interrupt per dma channel. Without this patch its not possible to use multipl ports on the lpass. Tested-by: Kenneth Westfield <kwestfie@codeaurora.org> Acked-by: Kenneth Westfield <kwestfie@codeaurora.org> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/qcom/lpass-platform.c94
-rw-r--r--sound/soc/qcom/lpass.h4
2 files changed, 63 insertions, 35 deletions
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 8ab0ac1dbedc..79688aa1941a 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -356,27 +356,15 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = {
356 .mmap = lpass_platform_pcmops_mmap, 356 .mmap = lpass_platform_pcmops_mmap,
357}; 357};
358 358
359static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) 359static irqreturn_t lpass_dma_interrupt_handler(
360 struct snd_pcm_substream *substream,
361 struct lpass_data *drvdata,
362 int chan, u32 interrupts)
360{ 363{
361 struct snd_pcm_substream *substream = data;
362 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 364 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
363 struct lpass_data *drvdata =
364 snd_soc_platform_get_drvdata(soc_runtime->platform);
365 struct lpass_variant *v = drvdata->variant; 365 struct lpass_variant *v = drvdata->variant;
366 struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
367 unsigned int interrupts;
368 irqreturn_t ret = IRQ_NONE; 366 irqreturn_t ret = IRQ_NONE;
369 int rv, chan = pcm_data->rdma_ch; 367 int rv;
370
371 rv = regmap_read(drvdata->lpaif_map,
372 LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
373 if (rv) {
374 dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
375 __func__, rv);
376 return IRQ_NONE;
377 }
378
379 interrupts &= LPAIF_IRQ_ALL(chan);
380 368
381 if (interrupts & LPAIF_IRQ_PER(chan)) { 369 if (interrupts & LPAIF_IRQ_PER(chan)) {
382 rv = regmap_write(drvdata->lpaif_map, 370 rv = regmap_write(drvdata->lpaif_map,
@@ -422,6 +410,35 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
422 return ret; 410 return ret;
423} 411}
424 412
413static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
414{
415 struct lpass_data *drvdata = data;
416 struct lpass_variant *v = drvdata->variant;
417 unsigned int irqs;
418 int rv, chan;
419
420 rv = regmap_read(drvdata->lpaif_map,
421 LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
422 if (rv) {
423 pr_err("%s() error reading from irqstat reg: %d\n",
424 __func__, rv);
425 return IRQ_NONE;
426 }
427
428 /* Handle per channel interrupts */
429 for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
430 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
431 rv = lpass_dma_interrupt_handler(
432 drvdata->substream[chan],
433 drvdata, chan, irqs);
434 if (rv != IRQ_HANDLED)
435 return rv;
436 }
437 }
438
439 return IRQ_HANDLED;
440}
441
425static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, 442static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
426 struct snd_soc_pcm_runtime *soc_runtime) 443 struct snd_soc_pcm_runtime *soc_runtime)
427{ 444{
@@ -477,6 +494,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
477 if (IS_ERR_VALUE(data->rdma_ch)) 494 if (IS_ERR_VALUE(data->rdma_ch))
478 return data->rdma_ch; 495 return data->rdma_ch;
479 496
497 drvdata->substream[data->rdma_ch] = substream;
480 data->i2s_port = cpu_dai->driver->id; 498 data->i2s_port = cpu_dai->driver->id;
481 499
482 snd_soc_pcm_set_drvdata(soc_runtime, data); 500 snd_soc_pcm_set_drvdata(soc_runtime, data);
@@ -488,29 +506,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
488 if (ret) 506 if (ret)
489 return ret; 507 return ret;
490 508
491 ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
492 lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
493 "lpass-irq-lpaif", substream);
494 if (ret) {
495 dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
496 __func__, ret);
497 goto err_buf;
498 }
499
500 /* ensure audio hardware is disabled */
501 ret = regmap_write(drvdata->lpaif_map,
502 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
503 if (ret) {
504 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
505 __func__, ret);
506 return ret;
507 }
508 ret = regmap_write(drvdata->lpaif_map, 509 ret = regmap_write(drvdata->lpaif_map,
509 LPAIF_RDMACTL_REG(v, data->rdma_ch), 0); 510 LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
510 if (ret) { 511 if (ret) {
511 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 512 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
512 __func__, ret); 513 __func__, ret);
513 return ret; 514 goto err_buf;
514 } 515 }
515 516
516 return 0; 517 return 0;
@@ -530,6 +531,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
530 struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime); 531 struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
531 struct lpass_variant *v = drvdata->variant; 532 struct lpass_variant *v = drvdata->variant;
532 533
534 drvdata->substream[data->rdma_ch] = NULL;
535
533 if (v->free_dma_channel) 536 if (v->free_dma_channel)
534 v->free_dma_channel(drvdata, data->rdma_ch); 537 v->free_dma_channel(drvdata, data->rdma_ch);
535 538
@@ -545,6 +548,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = {
545int asoc_qcom_lpass_platform_register(struct platform_device *pdev) 548int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
546{ 549{
547 struct lpass_data *drvdata = platform_get_drvdata(pdev); 550 struct lpass_data *drvdata = platform_get_drvdata(pdev);
551 struct lpass_variant *v = drvdata->variant;
552 int ret;
548 553
549 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); 554 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
550 if (drvdata->lpaif_irq < 0) { 555 if (drvdata->lpaif_irq < 0) {
@@ -553,6 +558,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
553 return -ENODEV; 558 return -ENODEV;
554 } 559 }
555 560
561 /* ensure audio hardware is disabled */
562 ret = regmap_write(drvdata->lpaif_map,
563 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
564 if (ret) {
565 dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
566 __func__, ret);
567 return ret;
568 }
569
570 ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
571 lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
572 "lpass-irq-lpaif", drvdata);
573 if (ret) {
574 dev_err(&pdev->dev, "%s() irq request failed: %d\n",
575 __func__, ret);
576 return ret;
577 }
578
579
556 return devm_snd_soc_register_platform(&pdev->dev, 580 return devm_snd_soc_register_platform(&pdev->dev,
557 &lpass_platform_driver); 581 &lpass_platform_driver);
558} 582}
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 023170a0943d..d572e7b8d590 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -23,6 +23,7 @@
23 23
24#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 24#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
25#define LPASS_MAX_MI2S_PORTS (8) 25#define LPASS_MAX_MI2S_PORTS (8)
26#define LPASS_MAX_DMA_CHANNELS (8)
26 27
27/* Both the CPU DAI and platform drivers will access this data */ 28/* Both the CPU DAI and platform drivers will access this data */
28struct lpass_data { 29struct lpass_data {
@@ -47,6 +48,9 @@ struct lpass_data {
47 48
48 /* SOC specific variations in the LPASS IP integration */ 49 /* SOC specific variations in the LPASS IP integration */
49 struct lpass_variant *variant; 50 struct lpass_variant *variant;
51
52 /* used it for handling interrupt per dma channel */
53 struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
50}; 54};
51 55
52/* Vairant data per each SOC */ 56/* Vairant data per each SOC */