aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt2
-rw-r--r--drivers/dma/sh/rcar-dmac.c37
-rw-r--r--include/dt-bindings/sound/apq8016-lpass.h9
-rw-r--r--sound/soc/codecs/max98095.c4
-rw-r--r--sound/soc/omap/Kconfig5
-rw-r--r--sound/soc/omap/omap-twl4030.c3
-rw-r--r--sound/soc/pxa/brownstone.c25
-rw-r--r--sound/soc/pxa/poodle.c19
-rw-r--r--sound/soc/pxa/tosa.c13
-rw-r--r--sound/soc/pxa/z2.c9
-rw-r--r--sound/soc/qcom/Kconfig19
-rw-r--r--sound/soc/qcom/Makefile4
-rw-r--r--sound/soc/qcom/lpass-apq8016.c242
-rw-r--r--sound/soc/qcom/lpass-cpu.c240
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c109
-rw-r--r--sound/soc/qcom/lpass-lpaif-reg.h (renamed from sound/soc/qcom/lpass-lpaif-ipq806x.h)92
-rw-r--r--sound/soc/qcom/lpass-platform.c202
-rw-r--r--sound/soc/qcom/lpass.h51
-rw-r--r--sound/soc/sh/rcar/core.c32
-rw-r--r--sound/soc/sh/rcar/rsnd.h3
-rw-r--r--sound/soc/sh/rcar/rsrc-card.c1
-rw-r--r--sound/soc/sh/rcar/src.c11
-rw-r--r--sound/soc/sh/rcar/ssi.c70
24 files changed, 847 insertions, 368 deletions
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index e00732dac939..21c648328be9 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
4 4
5Required properties: 5Required properties:
6 6
7- compatible : "qcom,lpass-cpu" 7- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
8- clocks : Must contain an entry for each entry in clock-names. 8- clocks : Must contain an entry for each entry in clock-names.
9- clock-names : A list which must include the following entries: 9- clock-names : A list which must include the following entries:
10 * "ahbix-clk" 10 * "ahbix-clk"
11 * "mi2s-osr-clk" 11 * "mi2s-osr-clk"
12 * "mi2s-bit-clk" 12 * "mi2s-bit-clk"
13 : required clocks for "qcom,lpass-cpu-apq8016"
14 * "ahbix-clk"
15 * "mi2s-bit-clk0"
16 * "mi2s-bit-clk1"
17 * "mi2s-bit-clk2"
18 * "mi2s-bit-clk3"
19 * "pcnoc-mport-clk"
20 * "pcnoc-sway-clk"
21
13- interrupts : Must contain an entry for each entry in 22- interrupts : Must contain an entry for each entry in
14 interrupt-names. 23 interrupt-names.
15- interrupt-names : A list which must include the following entries: 24- interrupt-names : A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
22- reg-names : A list which must include the following entries: 31- reg-names : A list which must include the following entries:
23 * "lpass-lpaif" 32 * "lpass-lpaif"
24 33
34
35
25Optional properties: 36Optional properties:
26 37
27- qcom,adsp : Phandle for the audio DSP node 38- qcom,adsp : Phandle for the audio DSP node
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index 14f467345994..b6b3a786855f 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -48,7 +48,7 @@ DAI subnode properties:
48 48
49Example: 49Example:
50 50
51rcar_sound: rcar_sound@ec500000 { 51rcar_sound: sound@ec500000 {
52 #sound-dai-cells = <1>; 52 #sound-dai-cells = <1>;
53 compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2"; 53 compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
54 reg = <0 0xec500000 0 0x1000>, /* SCU */ 54 reg = <0 0xec500000 0 0x1000>, /* SCU */
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index a18d16cc4795..e0302c784ba4 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
465static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) 465static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
466{ 466{
467 struct rcar_dmac_desc_page *page; 467 struct rcar_dmac_desc_page *page;
468 unsigned long flags;
468 LIST_HEAD(list); 469 LIST_HEAD(list);
469 unsigned int i; 470 unsigned int i;
470 471
@@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
482 list_add_tail(&desc->node, &list); 483 list_add_tail(&desc->node, &list);
483 } 484 }
484 485
485 spin_lock_irq(&chan->lock); 486 spin_lock_irqsave(&chan->lock, flags);
486 list_splice_tail(&list, &chan->desc.free); 487 list_splice_tail(&list, &chan->desc.free);
487 list_add_tail(&page->node, &chan->desc.pages); 488 list_add_tail(&page->node, &chan->desc.pages);
488 spin_unlock_irq(&chan->lock); 489 spin_unlock_irqrestore(&chan->lock, flags);
489 490
490 return 0; 491 return 0;
491} 492}
@@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
516static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) 517static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
517{ 518{
518 struct rcar_dmac_desc *desc, *_desc; 519 struct rcar_dmac_desc *desc, *_desc;
520 unsigned long flags;
519 LIST_HEAD(list); 521 LIST_HEAD(list);
520 522
521 /* 523 /*
@@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
524 * list_for_each_entry_safe, isn't safe if we release the channel lock 526 * list_for_each_entry_safe, isn't safe if we release the channel lock
525 * around the rcar_dmac_desc_put() call. 527 * around the rcar_dmac_desc_put() call.
526 */ 528 */
527 spin_lock_irq(&chan->lock); 529 spin_lock_irqsave(&chan->lock, flags);
528 list_splice_init(&chan->desc.wait, &list); 530 list_splice_init(&chan->desc.wait, &list);
529 spin_unlock_irq(&chan->lock); 531 spin_unlock_irqrestore(&chan->lock, flags);
530 532
531 list_for_each_entry_safe(desc, _desc, &list, node) { 533 list_for_each_entry_safe(desc, _desc, &list, node) {
532 if (async_tx_test_ack(&desc->async_tx)) { 534 if (async_tx_test_ack(&desc->async_tx)) {
@@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
539 return; 541 return;
540 542
541 /* Put the remaining descriptors back in the wait list. */ 543 /* Put the remaining descriptors back in the wait list. */
542 spin_lock_irq(&chan->lock); 544 spin_lock_irqsave(&chan->lock, flags);
543 list_splice(&list, &chan->desc.wait); 545 list_splice(&list, &chan->desc.wait);
544 spin_unlock_irq(&chan->lock); 546 spin_unlock_irqrestore(&chan->lock, flags);
545} 547}
546 548
547/* 549/*
@@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
556static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan) 558static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
557{ 559{
558 struct rcar_dmac_desc *desc; 560 struct rcar_dmac_desc *desc;
561 unsigned long flags;
559 int ret; 562 int ret;
560 563
561 /* Recycle acked descriptors before attempting allocation. */ 564 /* Recycle acked descriptors before attempting allocation. */
562 rcar_dmac_desc_recycle_acked(chan); 565 rcar_dmac_desc_recycle_acked(chan);
563 566
564 spin_lock_irq(&chan->lock); 567 spin_lock_irqsave(&chan->lock, flags);
565 568
566 while (list_empty(&chan->desc.free)) { 569 while (list_empty(&chan->desc.free)) {
567 /* 570 /*
@@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
570 * allocated descriptors. If the allocation fails return an 573 * allocated descriptors. If the allocation fails return an
571 * error. 574 * error.
572 */ 575 */
573 spin_unlock_irq(&chan->lock); 576 spin_unlock_irqrestore(&chan->lock, flags);
574 ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT); 577 ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
575 if (ret < 0) 578 if (ret < 0)
576 return NULL; 579 return NULL;
577 spin_lock_irq(&chan->lock); 580 spin_lock_irqsave(&chan->lock, flags);
578 } 581 }
579 582
580 desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node); 583 desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
581 list_del(&desc->node); 584 list_del(&desc->node);
582 585
583 spin_unlock_irq(&chan->lock); 586 spin_unlock_irqrestore(&chan->lock, flags);
584 587
585 return desc; 588 return desc;
586} 589}
@@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
593static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) 596static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
594{ 597{
595 struct rcar_dmac_desc_page *page; 598 struct rcar_dmac_desc_page *page;
599 unsigned long flags;
596 LIST_HEAD(list); 600 LIST_HEAD(list);
597 unsigned int i; 601 unsigned int i;
598 602
@@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
606 list_add_tail(&chunk->node, &list); 610 list_add_tail(&chunk->node, &list);
607 } 611 }
608 612
609 spin_lock_irq(&chan->lock); 613 spin_lock_irqsave(&chan->lock, flags);
610 list_splice_tail(&list, &chan->desc.chunks_free); 614 list_splice_tail(&list, &chan->desc.chunks_free);
611 list_add_tail(&page->node, &chan->desc.pages); 615 list_add_tail(&page->node, &chan->desc.pages);
612 spin_unlock_irq(&chan->lock); 616 spin_unlock_irqrestore(&chan->lock, flags);
613 617
614 return 0; 618 return 0;
615} 619}
@@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk *
627rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan) 631rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
628{ 632{
629 struct rcar_dmac_xfer_chunk *chunk; 633 struct rcar_dmac_xfer_chunk *chunk;
634 unsigned long flags;
630 int ret; 635 int ret;
631 636
632 spin_lock_irq(&chan->lock); 637 spin_lock_irqsave(&chan->lock, flags);
633 638
634 while (list_empty(&chan->desc.chunks_free)) { 639 while (list_empty(&chan->desc.chunks_free)) {
635 /* 640 /*
@@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
638 * allocated descriptors. If the allocation fails return an 643 * allocated descriptors. If the allocation fails return an
639 * error. 644 * error.
640 */ 645 */
641 spin_unlock_irq(&chan->lock); 646 spin_unlock_irqrestore(&chan->lock, flags);
642 ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT); 647 ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
643 if (ret < 0) 648 if (ret < 0)
644 return NULL; 649 return NULL;
645 spin_lock_irq(&chan->lock); 650 spin_lock_irqsave(&chan->lock, flags);
646 } 651 }
647 652
648 chunk = list_first_entry(&chan->desc.chunks_free, 653 chunk = list_first_entry(&chan->desc.chunks_free,
649 struct rcar_dmac_xfer_chunk, node); 654 struct rcar_dmac_xfer_chunk, node);
650 list_del(&chunk->node); 655 list_del(&chunk->node);
651 656
652 spin_unlock_irq(&chan->lock); 657 spin_unlock_irqrestore(&chan->lock, flags);
653 658
654 return chunk; 659 return chunk;
655} 660}
diff --git a/include/dt-bindings/sound/apq8016-lpass.h b/include/dt-bindings/sound/apq8016-lpass.h
new file mode 100644
index 000000000000..499076e980a3
--- /dev/null
+++ b/include/dt-bindings/sound/apq8016-lpass.h
@@ -0,0 +1,9 @@
1#ifndef __DT_APQ8016_LPASS_H
2#define __DT_APQ8016_LPASS_H
3
4#define MI2S_PRIMARY 0
5#define MI2S_SECONDARY 1
6#define MI2S_TERTIARY 2
7#define MI2S_QUATERNARY 3
8
9#endif /* __DT_APQ8016_LPASS_H */
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 2b8b8a5f385f..9a46d3dcf703 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2301,8 +2301,8 @@ static int max98095_probe(struct snd_soc_codec *codec)
2301 /* register an audio interrupt */ 2301 /* register an audio interrupt */
2302 ret = request_threaded_irq(client->irq, NULL, 2302 ret = request_threaded_irq(client->irq, NULL,
2303 max98095_report_jack, 2303 max98095_report_jack,
2304 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 2304 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
2305 "max98095", codec); 2305 IRQF_ONESHOT, "max98095", codec);
2306 if (ret) { 2306 if (ret) {
2307 dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); 2307 dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
2308 goto err_access; 2308 goto err_access;
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 6768e4f7d7d0..30d0109703a9 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -100,12 +100,13 @@ config SND_OMAP_SOC_OMAP_TWL4030
100 100
101config SND_OMAP_SOC_OMAP_ABE_TWL6040 101config SND_OMAP_SOC_OMAP_ABE_TWL6040
102 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" 102 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
103 depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST) 103 depends on TWL6040_CORE && SND_OMAP_SOC
104 depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
104 select SND_OMAP_SOC_DMIC 105 select SND_OMAP_SOC_DMIC
105 select SND_OMAP_SOC_MCPDM 106 select SND_OMAP_SOC_MCPDM
106 select SND_SOC_TWL6040 107 select SND_SOC_TWL6040
107 select SND_SOC_DMIC 108 select SND_SOC_DMIC
108 select COMMON_CLK_PALMAS if MFD_PALMAS 109 select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)
109 help 110 help
110 Say Y if you want to add support for SoC audio on OMAP boards using 111 Say Y if you want to add support for SoC audio on OMAP boards using
111 ABE and twl6040 codec. This driver currently supports: 112 ABE and twl6040 codec. This driver currently supports:
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index 3673ada43bfb..743131473056 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -159,9 +159,8 @@ static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
159 159
160static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) 160static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
161{ 161{
162 struct snd_soc_codec *codec = rtd->codec;
163 struct snd_soc_card *card = rtd->card; 162 struct snd_soc_card *card = rtd->card;
164 struct snd_soc_dapm_context *dapm = &codec->dapm; 163 struct snd_soc_dapm_context *dapm = &card->dapm;
165 struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); 164 struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
166 struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); 165 struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
167 int ret = 0; 166 int ret = 0;
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 79936e3e80e7..2b26318bc200 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -45,29 +45,6 @@ static const struct snd_soc_dapm_route brownstone_audio_map[] = {
45 {"MICBIAS1", NULL, "Main Mic"}, 45 {"MICBIAS1", NULL, "Main Mic"},
46}; 46};
47 47
48static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd)
49{
50 struct snd_soc_codec *codec = rtd->codec;
51 struct snd_soc_dapm_context *dapm = &codec->dapm;
52
53 /* set endpoints to not connected */
54 snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
55 snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
56 snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
57 snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
58 snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
59 snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
60 snd_soc_dapm_nc_pin(dapm, "IN1LN");
61 snd_soc_dapm_nc_pin(dapm, "IN1LP");
62 snd_soc_dapm_nc_pin(dapm, "IN1RP");
63 snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
64 snd_soc_dapm_nc_pin(dapm, "IN2RN");
65 snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
66 snd_soc_dapm_nc_pin(dapm, "IN2LN");
67
68 return 0;
69}
70
71static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, 48static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
72 struct snd_pcm_hw_params *params) 49 struct snd_pcm_hw_params *params)
73{ 50{
@@ -115,7 +92,6 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
115 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 92 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
116 SND_SOC_DAIFMT_CBS_CFS, 93 SND_SOC_DAIFMT_CBS_CFS,
117 .ops = &brownstone_ops, 94 .ops = &brownstone_ops,
118 .init = brownstone_wm8994_init,
119}, 95},
120}; 96};
121 97
@@ -132,6 +108,7 @@ static struct snd_soc_card brownstone = {
132 .num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets), 108 .num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets),
133 .dapm_routes = brownstone_audio_map, 109 .dapm_routes = brownstone_audio_map,
134 .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map), 110 .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map),
111 .fully_routed = true,
135}; 112};
136 113
137static int brownstone_probe(struct platform_device *pdev) 114static int brownstone_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 0fce8c420e96..80b457ac522a 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -192,6 +192,7 @@ static int poodle_amp_event(struct snd_soc_dapm_widget *w,
192static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { 192static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
193SND_SOC_DAPM_HP("Headphone Jack", NULL), 193SND_SOC_DAPM_HP("Headphone Jack", NULL),
194SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), 194SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
195SND_SOC_DAPM_MIC("Microphone", NULL),
195}; 196};
196 197
197/* Corgi machine connections to the codec pins */ 198/* Corgi machine connections to the codec pins */
@@ -204,6 +205,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = {
204 /* speaker connected to LOUT, ROUT */ 205 /* speaker connected to LOUT, ROUT */
205 {"Ext Spk", NULL, "ROUT"}, 206 {"Ext Spk", NULL, "ROUT"},
206 {"Ext Spk", NULL, "LOUT"}, 207 {"Ext Spk", NULL, "LOUT"},
208
209 {"MICIN", NULL, "Microphone"},
207}; 210};
208 211
209static const char *jack_function[] = {"Off", "Headphone"}; 212static const char *jack_function[] = {"Off", "Headphone"};
@@ -220,20 +223,6 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
220 poodle_set_spk), 223 poodle_set_spk),
221}; 224};
222 225
223/*
224 * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
225 */
226static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
227{
228 struct snd_soc_codec *codec = rtd->codec;
229 struct snd_soc_dapm_context *dapm = &codec->dapm;
230
231 snd_soc_dapm_nc_pin(dapm, "LLINEIN");
232 snd_soc_dapm_nc_pin(dapm, "RLINEIN");
233
234 return 0;
235}
236
237/* poodle digital audio interface glue - connects codec <--> CPU */ 226/* poodle digital audio interface glue - connects codec <--> CPU */
238static struct snd_soc_dai_link poodle_dai = { 227static struct snd_soc_dai_link poodle_dai = {
239 .name = "WM8731", 228 .name = "WM8731",
@@ -242,7 +231,6 @@ static struct snd_soc_dai_link poodle_dai = {
242 .codec_dai_name = "wm8731-hifi", 231 .codec_dai_name = "wm8731-hifi",
243 .platform_name = "pxa-pcm-audio", 232 .platform_name = "pxa-pcm-audio",
244 .codec_name = "wm8731.0-001b", 233 .codec_name = "wm8731.0-001b",
245 .init = poodle_wm8731_init,
246 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 234 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
247 SND_SOC_DAIFMT_CBS_CFS, 235 SND_SOC_DAIFMT_CBS_CFS,
248 .ops = &poodle_ops, 236 .ops = &poodle_ops,
@@ -261,6 +249,7 @@ static struct snd_soc_card poodle = {
261 .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), 249 .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
262 .dapm_routes = poodle_audio_map, 250 .dapm_routes = poodle_audio_map,
263 .num_dapm_routes = ARRAY_SIZE(poodle_audio_map), 251 .num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
252 .fully_routed = true,
264}; 253};
265 254
266static int poodle_probe(struct platform_device *pdev) 255static int poodle_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index cb49284e853a..f59f566551ef 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -185,17 +185,6 @@ static const struct snd_kcontrol_new tosa_controls[] = {
185 tosa_set_spk), 185 tosa_set_spk),
186}; 186};
187 187
188static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
189{
190 struct snd_soc_codec *codec = rtd->codec;
191 struct snd_soc_dapm_context *dapm = &codec->dapm;
192
193 snd_soc_dapm_nc_pin(dapm, "OUT3");
194 snd_soc_dapm_nc_pin(dapm, "MONOOUT");
195
196 return 0;
197}
198
199static struct snd_soc_dai_link tosa_dai[] = { 188static struct snd_soc_dai_link tosa_dai[] = {
200{ 189{
201 .name = "AC97", 190 .name = "AC97",
@@ -204,7 +193,6 @@ static struct snd_soc_dai_link tosa_dai[] = {
204 .codec_dai_name = "wm9712-hifi", 193 .codec_dai_name = "wm9712-hifi",
205 .platform_name = "pxa-pcm-audio", 194 .platform_name = "pxa-pcm-audio",
206 .codec_name = "wm9712-codec", 195 .codec_name = "wm9712-codec",
207 .init = tosa_ac97_init,
208 .ops = &tosa_ops, 196 .ops = &tosa_ops,
209}, 197},
210{ 198{
@@ -230,6 +218,7 @@ static struct snd_soc_card tosa = {
230 .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets), 218 .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets),
231 .dapm_routes = audio_map, 219 .dapm_routes = audio_map,
232 .num_dapm_routes = ARRAY_SIZE(audio_map), 220 .num_dapm_routes = ARRAY_SIZE(audio_map),
221 .fully_routed = true,
233}; 222};
234 223
235static int tosa_probe(struct platform_device *pdev) 224static int tosa_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
index bcbfbe8303f7..990b1aa6d7f6 100644
--- a/sound/soc/pxa/z2.c
+++ b/sound/soc/pxa/z2.c
@@ -132,16 +132,8 @@ static const struct snd_soc_dapm_route z2_audio_map[] = {
132 */ 132 */
133static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) 133static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
134{ 134{
135 struct snd_soc_codec *codec = rtd->codec;
136 struct snd_soc_dapm_context *dapm = &codec->dapm;
137 int ret; 135 int ret;
138 136
139 /* NC codec pins */
140 snd_soc_dapm_disable_pin(dapm, "LINPUT3");
141 snd_soc_dapm_disable_pin(dapm, "RINPUT3");
142 snd_soc_dapm_disable_pin(dapm, "OUT3");
143 snd_soc_dapm_disable_pin(dapm, "MONO1");
144
145 /* Jack detection API stuff */ 137 /* Jack detection API stuff */
146 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, 138 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
147 &hs_jack, hs_jack_pins, 139 &hs_jack, hs_jack_pins,
@@ -189,6 +181,7 @@ static struct snd_soc_card snd_soc_z2 = {
189 .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), 181 .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
190 .dapm_routes = z2_audio_map, 182 .dapm_routes = z2_audio_map,
191 .num_dapm_routes = ARRAY_SIZE(z2_audio_map), 183 .num_dapm_routes = ARRAY_SIZE(z2_audio_map),
184 .fully_routed = true,
192}; 185};
193 186
194static struct platform_device *z2_snd_device; 187static struct platform_device *z2_snd_device;
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 5f58e4f1bca9..938144c59e2b 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -6,19 +6,28 @@ config SND_SOC_QCOM
6 6
7config SND_SOC_LPASS_CPU 7config SND_SOC_LPASS_CPU
8 tristate 8 tristate
9 depends on SND_SOC_QCOM
10 select REGMAP_MMIO 9 select REGMAP_MMIO
11 10
12config SND_SOC_LPASS_PLATFORM 11config SND_SOC_LPASS_PLATFORM
13 tristate 12 tristate
14 depends on SND_SOC_QCOM
15 select REGMAP_MMIO 13 select REGMAP_MMIO
16 14
17config SND_SOC_STORM 15config SND_SOC_LPASS_IPQ806X
18 tristate "ASoC I2S support for Storm boards" 16 tristate
19 depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST 17 depends on SND_SOC_QCOM
18 select SND_SOC_LPASS_CPU
19 select SND_SOC_LPASS_PLATFORM
20
21config SND_SOC_LPASS_APQ8016
22 tristate
23 depends on SND_SOC_QCOM
20 select SND_SOC_LPASS_CPU 24 select SND_SOC_LPASS_CPU
21 select SND_SOC_LPASS_PLATFORM 25 select SND_SOC_LPASS_PLATFORM
26
27config SND_SOC_STORM
28 tristate "ASoC I2S support for Storm boards"
29 depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST)
30 select SND_SOC_LPASS_IPQ806X
22 select SND_SOC_MAX98357A 31 select SND_SOC_MAX98357A
23 help 32 help
24 Say Y or M if you want add support for SoC audio on the 33 Say Y or M if you want add support for SoC audio on the
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index c5ce96c761c4..ac7630833fe5 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,9 +1,13 @@
1# Platform 1# Platform
2snd-soc-lpass-cpu-objs := lpass-cpu.o 2snd-soc-lpass-cpu-objs := lpass-cpu.o
3snd-soc-lpass-platform-objs := lpass-platform.o 3snd-soc-lpass-platform-objs := lpass-platform.o
4snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
5snd-soc-lpass-apq8016-objs := lpass-apq8016.o
4 6
5obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o 7obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
6obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o 8obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
9obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
10obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
7 11
8# Machine 12# Machine
9snd-soc-storm-objs := storm.o 13snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
new file mode 100644
index 000000000000..94efc01020c4
--- /dev/null
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -0,0 +1,242 @@
1/*
2 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
14 *
15 */
16
17
18#include <linux/clk.h>
19#include <linux/device.h>
20#include <linux/err.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/of.h>
24#include <linux/platform_device.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28#include <sound/soc-dai.h>
29
30#include <dt-bindings/sound/apq8016-lpass.h>
31#include "lpass-lpaif-reg.h"
32#include "lpass.h"
33
34static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
35 [MI2S_PRIMARY] = {
36 .id = MI2S_PRIMARY,
37 .name = "Primary MI2S",
38 .playback = {
39 .stream_name = "Primary Playback",
40 .formats = SNDRV_PCM_FMTBIT_S16 |
41 SNDRV_PCM_FMTBIT_S24 |
42 SNDRV_PCM_FMTBIT_S32,
43 .rates = SNDRV_PCM_RATE_8000 |
44 SNDRV_PCM_RATE_16000 |
45 SNDRV_PCM_RATE_32000 |
46 SNDRV_PCM_RATE_48000 |
47 SNDRV_PCM_RATE_96000,
48 .rate_min = 8000,
49 .rate_max = 96000,
50 .channels_min = 1,
51 .channels_max = 8,
52 },
53 .probe = &asoc_qcom_lpass_cpu_dai_probe,
54 .ops = &asoc_qcom_lpass_cpu_dai_ops,
55 },
56 [MI2S_SECONDARY] = {
57 .id = MI2S_SECONDARY,
58 .name = "Secondary MI2S",
59 .playback = {
60 .stream_name = "Secondary Playback",
61 .formats = SNDRV_PCM_FMTBIT_S16 |
62 SNDRV_PCM_FMTBIT_S24 |
63 SNDRV_PCM_FMTBIT_S32,
64 .rates = SNDRV_PCM_RATE_8000 |
65 SNDRV_PCM_RATE_16000 |
66 SNDRV_PCM_RATE_32000 |
67 SNDRV_PCM_RATE_48000 |
68 SNDRV_PCM_RATE_96000,
69 .rate_min = 8000,
70 .rate_max = 96000,
71 .channels_min = 1,
72 .channels_max = 8,
73 },
74 .probe = &asoc_qcom_lpass_cpu_dai_probe,
75 .ops = &asoc_qcom_lpass_cpu_dai_ops,
76 },
77 [MI2S_TERTIARY] = {
78 .id = MI2S_TERTIARY,
79 .name = "Tertiary MI2S",
80 .capture = {
81 .stream_name = "Tertiary Capture",
82 .formats = SNDRV_PCM_FMTBIT_S16 |
83 SNDRV_PCM_FMTBIT_S24 |
84 SNDRV_PCM_FMTBIT_S32,
85 .rates = SNDRV_PCM_RATE_8000 |
86 SNDRV_PCM_RATE_16000 |
87 SNDRV_PCM_RATE_32000 |
88 SNDRV_PCM_RATE_48000 |
89 SNDRV_PCM_RATE_96000,
90 .rate_min = 8000,
91 .rate_max = 96000,
92 .channels_min = 1,
93 .channels_max = 8,
94 },
95 .probe = &asoc_qcom_lpass_cpu_dai_probe,
96 .ops = &asoc_qcom_lpass_cpu_dai_ops,
97 },
98 [MI2S_QUATERNARY] = {
99 .id = MI2S_QUATERNARY,
100 .name = "Quatenary MI2S",
101 .playback = {
102 .stream_name = "Quatenary Playback",
103 .formats = SNDRV_PCM_FMTBIT_S16 |
104 SNDRV_PCM_FMTBIT_S24 |
105 SNDRV_PCM_FMTBIT_S32,
106 .rates = SNDRV_PCM_RATE_8000 |
107 SNDRV_PCM_RATE_16000 |
108 SNDRV_PCM_RATE_32000 |
109 SNDRV_PCM_RATE_48000 |
110 SNDRV_PCM_RATE_96000,
111 .rate_min = 8000,
112 .rate_max = 96000,
113 .channels_min = 1,
114 .channels_max = 8,
115 },
116 .capture = {
117 .stream_name = "Quatenary Capture",
118 .formats = SNDRV_PCM_FMTBIT_S16 |
119 SNDRV_PCM_FMTBIT_S24 |
120 SNDRV_PCM_FMTBIT_S32,
121 .rates = SNDRV_PCM_RATE_8000 |
122 SNDRV_PCM_RATE_16000 |
123 SNDRV_PCM_RATE_32000 |
124 SNDRV_PCM_RATE_48000 |
125 SNDRV_PCM_RATE_96000,
126 .rate_min = 8000,
127 .rate_max = 96000,
128 .channels_min = 1,
129 .channels_max = 8,
130 },
131 .probe = &asoc_qcom_lpass_cpu_dai_probe,
132 .ops = &asoc_qcom_lpass_cpu_dai_ops,
133 },
134};
135
136static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)
137{
138 struct lpass_variant *v = drvdata->variant;
139 int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,
140 v->rdma_channels);
141
142 if (chan >= v->rdma_channels)
143 return -EBUSY;
144
145 set_bit(chan, &drvdata->rdma_ch_bit_map);
146
147 return chan;
148}
149
150static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
151{
152 clear_bit(chan, &drvdata->rdma_ch_bit_map);
153
154 return 0;
155}
156
157static int apq8016_lpass_init(struct platform_device *pdev)
158{
159 struct lpass_data *drvdata = platform_get_drvdata(pdev);
160 struct device *dev = &pdev->dev;
161 int ret;
162
163 drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
164 if (IS_ERR(drvdata->pcnoc_mport_clk)) {
165 dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n",
166 __func__, PTR_ERR(drvdata->pcnoc_mport_clk));
167 return PTR_ERR(drvdata->pcnoc_mport_clk);
168 }
169
170 ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
171 if (ret) {
172 dev_err(&pdev->dev, "%s() Error enabling pcnoc-mport-clk: %d\n",
173 __func__, ret);
174 return ret;
175 }
176
177 drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
178 if (IS_ERR(drvdata->pcnoc_sway_clk)) {
179 dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n",
180 __func__, PTR_ERR(drvdata->pcnoc_sway_clk));
181 return PTR_ERR(drvdata->pcnoc_sway_clk);
182 }
183
184 ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
185 if (ret) {
186 dev_err(&pdev->dev, "%s() Error enabling pcnoc_sway_clk: %d\n",
187 __func__, ret);
188 return ret;
189 }
190
191 return 0;
192}
193
194static int apq8016_lpass_exit(struct platform_device *pdev)
195{
196 struct lpass_data *drvdata = platform_get_drvdata(pdev);
197
198 clk_disable_unprepare(drvdata->pcnoc_mport_clk);
199 clk_disable_unprepare(drvdata->pcnoc_sway_clk);
200
201 return 0;
202}
203
204
205static struct lpass_variant apq8016_data = {
206 .i2sctrl_reg_base = 0x1000,
207 .i2sctrl_reg_stride = 0x1000,
208 .i2s_ports = 4,
209 .irq_reg_base = 0x6000,
210 .irq_reg_stride = 0x1000,
211 .irq_ports = 3,
212 .rdma_reg_base = 0x8400,
213 .rdma_reg_stride = 0x1000,
214 .rdma_channels = 2,
215 .rdmactl_audif_start = 1,
216 .dai_driver = apq8016_lpass_cpu_dai_driver,
217 .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
218 .init = apq8016_lpass_init,
219 .exit = apq8016_lpass_exit,
220 .alloc_dma_channel = apq8016_lpass_alloc_dma_channel,
221 .free_dma_channel = apq8016_lpass_free_dma_channel,
222};
223
224static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
225 { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
226 {}
227};
228MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
229
230static struct platform_driver apq8016_lpass_cpu_platform_driver = {
231 .driver = {
232 .name = "apq8016-lpass-cpu",
233 .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id),
234 },
235 .probe = asoc_qcom_lpass_cpu_platform_probe,
236 .remove = asoc_qcom_lpass_cpu_platform_remove,
237};
238module_platform_driver(apq8016_lpass_cpu_platform_driver);
239
240MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
241MODULE_LICENSE("GPL v2");
242
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index dc790abaa331..23f3d59e6d09 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -14,21 +14,17 @@
14 */ 14 */
15 15
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/compiler.h>
18#include <linux/device.h>
19#include <linux/err.h>
20#include <linux/ioport.h>
21#include <linux/kernel.h> 17#include <linux/kernel.h>
22#include <linux/mod_devicetable.h>
23#include <linux/module.h> 18#include <linux/module.h>
24#include <linux/of.h> 19#include <linux/of.h>
20#include <linux/of_device.h>
25#include <linux/platform_device.h> 21#include <linux/platform_device.h>
26#include <sound/pcm.h> 22#include <sound/pcm.h>
27#include <sound/pcm_params.h> 23#include <sound/pcm_params.h>
28#include <linux/regmap.h> 24#include <linux/regmap.h>
29#include <sound/soc.h> 25#include <sound/soc.h>
30#include <sound/soc-dai.h> 26#include <sound/soc-dai.h>
31#include "lpass-lpaif-ipq806x.h" 27#include "lpass-lpaif-reg.h"
32#include "lpass.h" 28#include "lpass.h"
33 29
34static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, 30static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -37,7 +33,10 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
37 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 33 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
38 int ret; 34 int ret;
39 35
40 ret = clk_set_rate(drvdata->mi2s_osr_clk, freq); 36 if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
37 return 0;
38
39 ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
41 if (ret) 40 if (ret)
42 dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n", 41 dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
43 __func__, freq, ret); 42 __func__, freq, ret);
@@ -51,18 +50,23 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
51 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 50 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
52 int ret; 51 int ret;
53 52
54 ret = clk_prepare_enable(drvdata->mi2s_osr_clk); 53 if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {
55 if (ret) { 54 ret = clk_prepare_enable(
56 dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n", 55 drvdata->mi2s_osr_clk[dai->driver->id]);
57 __func__, ret); 56 if (ret) {
58 return ret; 57 dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
58 __func__, ret);
59 return ret;
60 }
59 } 61 }
60 62
61 ret = clk_prepare_enable(drvdata->mi2s_bit_clk); 63 ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
62 if (ret) { 64 if (ret) {
63 dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n", 65 dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
64 __func__, ret); 66 __func__, ret);
65 clk_disable_unprepare(drvdata->mi2s_osr_clk); 67 if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
68 clk_disable_unprepare(
69 drvdata->mi2s_osr_clk[dai->driver->id]);
66 return ret; 70 return ret;
67 } 71 }
68 72
@@ -74,8 +78,10 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
74{ 78{
75 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 79 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
76 80
77 clk_disable_unprepare(drvdata->mi2s_bit_clk); 81 clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
78 clk_disable_unprepare(drvdata->mi2s_osr_clk); 82
83 if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
84 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
79} 85}
80 86
81static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, 87static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -142,14 +148,16 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
142 } 148 }
143 149
144 ret = regmap_write(drvdata->lpaif_map, 150 ret = regmap_write(drvdata->lpaif_map,
145 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval); 151 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
152 regval);
146 if (ret) { 153 if (ret) {
147 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 154 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
148 __func__, ret); 155 __func__, ret);
149 return ret; 156 return ret;
150 } 157 }
151 158
152 ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2); 159 ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
160 rate * bitwidth * 2);
153 if (ret) { 161 if (ret) {
154 dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", 162 dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
155 __func__, rate * bitwidth * 2, ret); 163 __func__, rate * bitwidth * 2, ret);
@@ -166,7 +174,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
166 int ret; 174 int ret;
167 175
168 ret = regmap_write(drvdata->lpaif_map, 176 ret = regmap_write(drvdata->lpaif_map,
169 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); 177 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
178 0);
170 if (ret) 179 if (ret)
171 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 180 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
172 __func__, ret); 181 __func__, ret);
@@ -181,7 +190,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
181 int ret; 190 int ret;
182 191
183 ret = regmap_update_bits(drvdata->lpaif_map, 192 ret = regmap_update_bits(drvdata->lpaif_map,
184 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 193 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
185 LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); 194 LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
186 if (ret) 195 if (ret)
187 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 196 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -201,7 +210,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
201 case SNDRV_PCM_TRIGGER_RESUME: 210 case SNDRV_PCM_TRIGGER_RESUME:
202 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 211 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
203 ret = regmap_update_bits(drvdata->lpaif_map, 212 ret = regmap_update_bits(drvdata->lpaif_map,
204 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 213 LPAIF_I2SCTL_REG(drvdata->variant,
214 dai->driver->id),
205 LPAIF_I2SCTL_SPKEN_MASK, 215 LPAIF_I2SCTL_SPKEN_MASK,
206 LPAIF_I2SCTL_SPKEN_ENABLE); 216 LPAIF_I2SCTL_SPKEN_ENABLE);
207 if (ret) 217 if (ret)
@@ -212,7 +222,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
212 case SNDRV_PCM_TRIGGER_SUSPEND: 222 case SNDRV_PCM_TRIGGER_SUSPEND:
213 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 223 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
214 ret = regmap_update_bits(drvdata->lpaif_map, 224 ret = regmap_update_bits(drvdata->lpaif_map,
215 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 225 LPAIF_I2SCTL_REG(drvdata->variant,
226 dai->driver->id),
216 LPAIF_I2SCTL_SPKEN_MASK, 227 LPAIF_I2SCTL_SPKEN_MASK,
217 LPAIF_I2SCTL_SPKEN_DISABLE); 228 LPAIF_I2SCTL_SPKEN_DISABLE);
218 if (ret) 229 if (ret)
@@ -224,7 +235,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
224 return ret; 235 return ret;
225} 236}
226 237
227static struct snd_soc_dai_ops lpass_cpu_dai_ops = { 238struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
228 .set_sysclk = lpass_cpu_daiops_set_sysclk, 239 .set_sysclk = lpass_cpu_daiops_set_sysclk,
229 .startup = lpass_cpu_daiops_startup, 240 .startup = lpass_cpu_daiops_startup,
230 .shutdown = lpass_cpu_daiops_shutdown, 241 .shutdown = lpass_cpu_daiops_shutdown,
@@ -233,41 +244,23 @@ static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
233 .prepare = lpass_cpu_daiops_prepare, 244 .prepare = lpass_cpu_daiops_prepare,
234 .trigger = lpass_cpu_daiops_trigger, 245 .trigger = lpass_cpu_daiops_trigger,
235}; 246};
247EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
236 248
237static int lpass_cpu_dai_probe(struct snd_soc_dai *dai) 249int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
238{ 250{
239 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 251 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
240 int ret; 252 int ret;
241 253
242 /* ensure audio hardware is disabled */ 254 /* ensure audio hardware is disabled */
243 ret = regmap_write(drvdata->lpaif_map, 255 ret = regmap_write(drvdata->lpaif_map,
244 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); 256 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
245 if (ret) 257 if (ret)
246 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", 258 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
247 __func__, ret); 259 __func__, ret);
248 260
249 return ret; 261 return ret;
250} 262}
251 263EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
252static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
253 .playback = {
254 .stream_name = "lpass-cpu-playback",
255 .formats = SNDRV_PCM_FMTBIT_S16 |
256 SNDRV_PCM_FMTBIT_S24 |
257 SNDRV_PCM_FMTBIT_S32,
258 .rates = SNDRV_PCM_RATE_8000 |
259 SNDRV_PCM_RATE_16000 |
260 SNDRV_PCM_RATE_32000 |
261 SNDRV_PCM_RATE_48000 |
262 SNDRV_PCM_RATE_96000,
263 .rate_min = 8000,
264 .rate_max = 96000,
265 .channels_min = 1,
266 .channels_max = 8,
267 },
268 .probe = &lpass_cpu_dai_probe,
269 .ops = &lpass_cpu_dai_ops,
270};
271 264
272static const struct snd_soc_component_driver lpass_cpu_comp_driver = { 265static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
273 .name = "lpass-cpu", 266 .name = "lpass-cpu",
@@ -275,27 +268,29 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
275 268
276static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) 269static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
277{ 270{
271 struct lpass_data *drvdata = dev_get_drvdata(dev);
272 struct lpass_variant *v = drvdata->variant;
278 int i; 273 int i;
279 274
280 for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) 275 for (i = 0; i < v->i2s_ports; ++i)
281 if (reg == LPAIF_I2SCTL_REG(i)) 276 if (reg == LPAIF_I2SCTL_REG(v, i))
282 return true; 277 return true;
283 278
284 for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { 279 for (i = 0; i < v->irq_ports; ++i) {
285 if (reg == LPAIF_IRQEN_REG(i)) 280 if (reg == LPAIF_IRQEN_REG(v, i))
286 return true; 281 return true;
287 if (reg == LPAIF_IRQCLEAR_REG(i)) 282 if (reg == LPAIF_IRQCLEAR_REG(v, i))
288 return true; 283 return true;
289 } 284 }
290 285
291 for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { 286 for (i = 0; i < v->rdma_channels; ++i) {
292 if (reg == LPAIF_RDMACTL_REG(i)) 287 if (reg == LPAIF_RDMACTL_REG(v, i))
293 return true; 288 return true;
294 if (reg == LPAIF_RDMABASE_REG(i)) 289 if (reg == LPAIF_RDMABASE_REG(v, i))
295 return true; 290 return true;
296 if (reg == LPAIF_RDMABUFF_REG(i)) 291 if (reg == LPAIF_RDMABUFF_REG(v, i))
297 return true; 292 return true;
298 if (reg == LPAIF_RDMAPER_REG(i)) 293 if (reg == LPAIF_RDMAPER_REG(v, i))
299 return true; 294 return true;
300 } 295 }
301 296
@@ -304,29 +299,31 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
304 299
305static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) 300static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
306{ 301{
302 struct lpass_data *drvdata = dev_get_drvdata(dev);
303 struct lpass_variant *v = drvdata->variant;
307 int i; 304 int i;
308 305
309 for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) 306 for (i = 0; i < v->i2s_ports; ++i)
310 if (reg == LPAIF_I2SCTL_REG(i)) 307 if (reg == LPAIF_I2SCTL_REG(v, i))
311 return true; 308 return true;
312 309
313 for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { 310 for (i = 0; i < v->irq_ports; ++i) {
314 if (reg == LPAIF_IRQEN_REG(i)) 311 if (reg == LPAIF_IRQEN_REG(v, i))
315 return true; 312 return true;
316 if (reg == LPAIF_IRQSTAT_REG(i)) 313 if (reg == LPAIF_IRQSTAT_REG(v, i))
317 return true; 314 return true;
318 } 315 }
319 316
320 for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { 317 for (i = 0; i < v->rdma_channels; ++i) {
321 if (reg == LPAIF_RDMACTL_REG(i)) 318 if (reg == LPAIF_RDMACTL_REG(v, i))
322 return true; 319 return true;
323 if (reg == LPAIF_RDMABASE_REG(i)) 320 if (reg == LPAIF_RDMABASE_REG(v, i))
324 return true; 321 return true;
325 if (reg == LPAIF_RDMABUFF_REG(i)) 322 if (reg == LPAIF_RDMABUFF_REG(v, i))
326 return true; 323 return true;
327 if (reg == LPAIF_RDMACURR_REG(i)) 324 if (reg == LPAIF_RDMACURR_REG(v, i))
328 return true; 325 return true;
329 if (reg == LPAIF_RDMAPER_REG(i)) 326 if (reg == LPAIF_RDMAPER_REG(v, i))
330 return true; 327 return true;
331 } 328 }
332 329
@@ -335,36 +332,41 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
335 332
336static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) 333static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
337{ 334{
335 struct lpass_data *drvdata = dev_get_drvdata(dev);
336 struct lpass_variant *v = drvdata->variant;
338 int i; 337 int i;
339 338
340 for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) 339 for (i = 0; i < v->irq_ports; ++i)
341 if (reg == LPAIF_IRQSTAT_REG(i)) 340 if (reg == LPAIF_IRQSTAT_REG(v, i))
342 return true; 341 return true;
343 342
344 for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) 343 for (i = 0; i < v->rdma_channels; ++i)
345 if (reg == LPAIF_RDMACURR_REG(i)) 344 if (reg == LPAIF_RDMACURR_REG(v, i))
346 return true; 345 return true;
347 346
348 return false; 347 return false;
349} 348}
350 349
351static const struct regmap_config lpass_cpu_regmap_config = { 350static struct regmap_config lpass_cpu_regmap_config = {
352 .reg_bits = 32, 351 .reg_bits = 32,
353 .reg_stride = 4, 352 .reg_stride = 4,
354 .val_bits = 32, 353 .val_bits = 32,
355 .max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX),
356 .writeable_reg = lpass_cpu_regmap_writeable, 354 .writeable_reg = lpass_cpu_regmap_writeable,
357 .readable_reg = lpass_cpu_regmap_readable, 355 .readable_reg = lpass_cpu_regmap_readable,
358 .volatile_reg = lpass_cpu_regmap_volatile, 356 .volatile_reg = lpass_cpu_regmap_volatile,
359 .cache_type = REGCACHE_FLAT, 357 .cache_type = REGCACHE_FLAT,
360}; 358};
361 359
362static int lpass_cpu_platform_probe(struct platform_device *pdev) 360int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
363{ 361{
364 struct lpass_data *drvdata; 362 struct lpass_data *drvdata;
365 struct device_node *dsp_of_node; 363 struct device_node *dsp_of_node;
366 struct resource *res; 364 struct resource *res;
367 int ret; 365 struct lpass_variant *variant;
366 struct device *dev = &pdev->dev;
367 const struct of_device_id *match;
368 char clk_name[16];
369 int ret, i, dai_id;
368 370
369 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); 371 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
370 if (dsp_of_node) { 372 if (dsp_of_node) {
@@ -379,11 +381,14 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
379 return -ENOMEM; 381 return -ENOMEM;
380 platform_set_drvdata(pdev, drvdata); 382 platform_set_drvdata(pdev, drvdata);
381 383
384 match = of_match_device(dev->driver->of_match_table, dev);
385 if (!match || !match->data)
386 return -EINVAL;
387
388 drvdata->variant = (struct lpass_variant *)match->data;
389 variant = drvdata->variant;
390
382 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); 391 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
383 if (!res) {
384 dev_err(&pdev->dev, "%s() error getting resource\n", __func__);
385 return -ENODEV;
386 }
387 392
388 drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res); 393 drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
389 if (IS_ERR((void const __force *)drvdata->lpaif)) { 394 if (IS_ERR((void const __force *)drvdata->lpaif)) {
@@ -393,6 +398,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
393 return PTR_ERR((void const __force *)drvdata->lpaif); 398 return PTR_ERR((void const __force *)drvdata->lpaif);
394 } 399 }
395 400
401 lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
402 variant->rdma_channels);
403
396 drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif, 404 drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
397 &lpass_cpu_regmap_config); 405 &lpass_cpu_regmap_config);
398 if (IS_ERR(drvdata->lpaif_map)) { 406 if (IS_ERR(drvdata->lpaif_map)) {
@@ -401,18 +409,38 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
401 return PTR_ERR(drvdata->lpaif_map); 409 return PTR_ERR(drvdata->lpaif_map);
402 } 410 }
403 411
404 drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk"); 412 if (variant->init)
405 if (IS_ERR(drvdata->mi2s_osr_clk)) { 413 variant->init(pdev);
406 dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n", 414
407 __func__, PTR_ERR(drvdata->mi2s_osr_clk)); 415 for (i = 0; i < variant->num_dai; i++) {
408 return PTR_ERR(drvdata->mi2s_osr_clk); 416 dai_id = variant->dai_driver[i].id;
409 } 417 if (variant->num_dai > 1)
410 418 sprintf(clk_name, "mi2s-osr-clk%d", i);
411 drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk"); 419 else
412 if (IS_ERR(drvdata->mi2s_bit_clk)) { 420 sprintf(clk_name, "mi2s-osr-clk");
413 dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n", 421
414 __func__, PTR_ERR(drvdata->mi2s_bit_clk)); 422 drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
415 return PTR_ERR(drvdata->mi2s_bit_clk); 423 clk_name);
424 if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
425 dev_warn(&pdev->dev,
426 "%s() error getting mi2s-osr-clk: %ld\n",
427 __func__,
428 PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
429 }
430
431 if (variant->num_dai > 1)
432 sprintf(clk_name, "mi2s-bit-clk%d", i);
433 else
434 sprintf(clk_name, "mi2s-bit-clk");
435
436 drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
437 clk_name);
438 if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
439 dev_err(&pdev->dev,
440 "%s() error getting mi2s-bit-clk: %ld\n",
441 __func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
442 return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
443 }
416 } 444 }
417 445
418 drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk"); 446 drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
@@ -439,7 +467,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
439 } 467 }
440 468
441 ret = devm_snd_soc_register_component(&pdev->dev, 469 ret = devm_snd_soc_register_component(&pdev->dev,
442 &lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1); 470 &lpass_cpu_comp_driver,
471 variant->dai_driver,
472 variant->num_dai);
443 if (ret) { 473 if (ret) {
444 dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n", 474 dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
445 __func__, ret); 475 __func__, ret);
@@ -459,33 +489,17 @@ err_clk:
459 clk_disable_unprepare(drvdata->ahbix_clk); 489 clk_disable_unprepare(drvdata->ahbix_clk);
460 return ret; 490 return ret;
461} 491}
492EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
462 493
463static int lpass_cpu_platform_remove(struct platform_device *pdev) 494int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
464{ 495{
465 struct lpass_data *drvdata = platform_get_drvdata(pdev); 496 struct lpass_data *drvdata = platform_get_drvdata(pdev);
466 497
498 if (drvdata->variant->exit)
499 drvdata->variant->exit(pdev);
500
467 clk_disable_unprepare(drvdata->ahbix_clk); 501 clk_disable_unprepare(drvdata->ahbix_clk);
468 502
469 return 0; 503 return 0;
470} 504}
471 505EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
472#ifdef CONFIG_OF
473static const struct of_device_id lpass_cpu_device_id[] = {
474 { .compatible = "qcom,lpass-cpu" },
475 {}
476};
477MODULE_DEVICE_TABLE(of, lpass_cpu_device_id);
478#endif
479
480static struct platform_driver lpass_cpu_platform_driver = {
481 .driver = {
482 .name = "lpass-cpu",
483 .of_match_table = of_match_ptr(lpass_cpu_device_id),
484 },
485 .probe = lpass_cpu_platform_probe,
486 .remove = lpass_cpu_platform_remove,
487};
488module_platform_driver(lpass_cpu_platform_driver);
489
490MODULE_DESCRIPTION("QTi LPASS CPU Driver");
491MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
new file mode 100644
index 000000000000..7356d3a766d6
--- /dev/null
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -0,0 +1,109 @@
1/*
2 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS
14 * Splited out the IPQ8064 soc specific from lpass-cpu.c
15 */
16
17#include <linux/clk.h>
18#include <linux/device.h>
19#include <linux/err.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/platform_device.h>
24#include <sound/pcm.h>
25#include <sound/soc.h>
26#include <sound/soc-dai.h>
27
28#include "lpass-lpaif-reg.h"
29#include "lpass.h"
30
31enum lpaif_i2s_ports {
32 IPQ806X_LPAIF_I2S_PORT_CODEC_SPK,
33 IPQ806X_LPAIF_I2S_PORT_CODEC_MIC,
34 IPQ806X_LPAIF_I2S_PORT_SEC_SPK,
35 IPQ806X_LPAIF_I2S_PORT_SEC_MIC,
36 IPQ806X_LPAIF_I2S_PORT_MI2S,
37};
38
39enum lpaif_dma_channels {
40 IPQ806X_LPAIF_RDMA_CHAN_MI2S,
41 IPQ806X_LPAIF_RDMA_CHAN_PCM0,
42 IPQ806X_LPAIF_RDMA_CHAN_PCM1,
43};
44
45static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
46 .id = IPQ806X_LPAIF_I2S_PORT_MI2S,
47 .playback = {
48 .stream_name = "lpass-cpu-playback",
49 .formats = SNDRV_PCM_FMTBIT_S16 |
50 SNDRV_PCM_FMTBIT_S24 |
51 SNDRV_PCM_FMTBIT_S32,
52 .rates = SNDRV_PCM_RATE_8000 |
53 SNDRV_PCM_RATE_16000 |
54 SNDRV_PCM_RATE_32000 |
55 SNDRV_PCM_RATE_48000 |
56 SNDRV_PCM_RATE_96000,
57 .rate_min = 8000,
58 .rate_max = 96000,
59 .channels_min = 1,
60 .channels_max = 8,
61 },
62 .probe = &asoc_qcom_lpass_cpu_dai_probe,
63 .ops = &asoc_qcom_lpass_cpu_dai_ops,
64};
65
66static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)
67{
68 return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
69}
70
71static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
72{
73 return 0;
74}
75
76struct lpass_variant ipq806x_data = {
77 .i2sctrl_reg_base = 0x0010,
78 .i2sctrl_reg_stride = 0x04,
79 .i2s_ports = 5,
80 .irq_reg_base = 0x3000,
81 .irq_reg_stride = 0x1000,
82 .irq_ports = 3,
83 .rdma_reg_base = 0x6000,
84 .rdma_reg_stride = 0x1000,
85 .rdma_channels = 4,
86 .dai_driver = &ipq806x_lpass_cpu_dai_driver,
87 .num_dai = 1,
88 .alloc_dma_channel = ipq806x_lpass_alloc_dma_channel,
89 .free_dma_channel = ipq806x_lpass_free_dma_channel,
90};
91
92static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
93 { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
94 {}
95};
96MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
97
98static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
99 .driver = {
100 .name = "lpass-cpu",
101 .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id),
102 },
103 .probe = asoc_qcom_lpass_cpu_platform_probe,
104 .remove = asoc_qcom_lpass_cpu_platform_remove,
105};
106module_platform_driver(ipq806x_lpass_cpu_platform_driver);
107
108MODULE_DESCRIPTION("QTi LPASS CPU Driver");
109MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-reg.h
index dc423b888842..95e22f131052 100644
--- a/sound/soc/qcom/lpass-lpaif-ipq806x.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -9,37 +9,17 @@
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details. 11 * GNU General Public License for more details.
12 *
13 * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS
14 */ 12 */
15 13
16#ifndef __LPASS_LPAIF_H__ 14#ifndef __LPASS_LPAIF_REG_H__
17#define __LPASS_LPAIF_H__ 15#define __LPASS_LPAIF_REG_H__
18
19#define LPAIF_BANK_OFFSET 0x1000
20 16
21/* LPAIF I2S */ 17/* LPAIF I2S */
22 18
23#define LPAIF_I2SCTL_REG_BASE 0x0010 19#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
24#define LPAIF_I2SCTL_REG_STRIDE 0x4 20 (v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
25#define LPAIF_I2SCTL_REG_ADDR(addr, port) \
26 (LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port)))
27
28enum lpaif_i2s_ports {
29 LPAIF_I2S_PORT_MIN = 0,
30
31 LPAIF_I2S_PORT_CODEC_SPK = 0,
32 LPAIF_I2S_PORT_CODEC_MIC = 1,
33 LPAIF_I2S_PORT_SEC_SPK = 2,
34 LPAIF_I2S_PORT_SEC_MIC = 3,
35 LPAIF_I2S_PORT_MI2S = 4,
36
37 LPAIF_I2S_PORT_MAX = 4,
38 LPAIF_I2S_PORT_NUM = 5,
39};
40
41#define LPAIF_I2SCTL_REG(port) LPAIF_I2SCTL_REG_ADDR(0x0, (port))
42 21
22#define LPAIF_I2SCTL_REG(v, port) LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
43#define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000 23#define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000
44#define LPAIF_I2SCTL_LOOPBACK_SHIFT 15 24#define LPAIF_I2SCTL_LOOPBACK_SHIFT 15
45#define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT) 25#define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
@@ -79,55 +59,36 @@ enum lpaif_i2s_ports {
79#define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT) 59#define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
80 60
81/* LPAIF IRQ */ 61/* LPAIF IRQ */
62#define LPAIF_IRQ_REG_ADDR(v, addr, port) \
63 (v->irq_reg_base + (addr) + v->irq_reg_stride * (port))
82 64
83#define LPAIF_IRQ_REG_BASE 0x3000 65#define LPAIF_IRQ_PORT_HOST 0
84#define LPAIF_IRQ_REG_STRIDE 0x1000
85#define LPAIF_IRQ_REG_ADDR(addr, port) \
86 (LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port)))
87
88enum lpaif_irq_ports {
89 LPAIF_IRQ_PORT_MIN = 0,
90 66
91 LPAIF_IRQ_PORT_HOST = 0, 67#define LPAIF_IRQEN_REG(v, port) LPAIF_IRQ_REG_ADDR(v, 0x0, (port))
92 LPAIF_IRQ_PORT_ADSP = 1, 68#define LPAIF_IRQSTAT_REG(v, port) LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
93 69#define LPAIF_IRQCLEAR_REG(v, port) LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
94 LPAIF_IRQ_PORT_MAX = 2,
95 LPAIF_IRQ_PORT_NUM = 3,
96};
97
98#define LPAIF_IRQEN_REG(port) LPAIF_IRQ_REG_ADDR(0x0, (port))
99#define LPAIF_IRQSTAT_REG(port) LPAIF_IRQ_REG_ADDR(0x4, (port))
100#define LPAIF_IRQCLEAR_REG(port) LPAIF_IRQ_REG_ADDR(0xC, (port))
101 70
102#define LPAIF_IRQ_BITSTRIDE 3 71#define LPAIF_IRQ_BITSTRIDE 3
72
103#define LPAIF_IRQ_PER(chan) (1 << (LPAIF_IRQ_BITSTRIDE * (chan))) 73#define LPAIF_IRQ_PER(chan) (1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
104#define LPAIF_IRQ_XRUN(chan) (2 << (LPAIF_IRQ_BITSTRIDE * (chan))) 74#define LPAIF_IRQ_XRUN(chan) (2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
105#define LPAIF_IRQ_ERR(chan) (4 << (LPAIF_IRQ_BITSTRIDE * (chan))) 75#define LPAIF_IRQ_ERR(chan) (4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
76
106#define LPAIF_IRQ_ALL(chan) (7 << (LPAIF_IRQ_BITSTRIDE * (chan))) 77#define LPAIF_IRQ_ALL(chan) (7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
107 78
108/* LPAIF DMA */ 79/* LPAIF DMA */
109 80
110#define LPAIF_RDMA_REG_BASE 0x6000 81#define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
111#define LPAIF_RDMA_REG_STRIDE 0x1000 82 (v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
112#define LPAIF_RDMA_REG_ADDR(addr, chan) \
113 (LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan)))
114
115enum lpaif_dma_channels {
116 LPAIF_RDMA_CHAN_MIN = 0,
117
118 LPAIF_RDMA_CHAN_MI2S = 0,
119 LPAIF_RDMA_CHAN_PCM0 = 1,
120 LPAIF_RDMA_CHAN_PCM1 = 2,
121 83
122 LPAIF_RDMA_CHAN_MAX = 4, 84#define LPAIF_RDMACTL_AUDINTF(id) (id << LPAIF_RDMACTL_AUDINTF_SHIFT)
123 LPAIF_RDMA_CHAN_NUM = 5,
124};
125 85
126#define LPAIF_RDMACTL_REG(chan) LPAIF_RDMA_REG_ADDR(0x00, (chan)) 86#define LPAIF_RDMACTL_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x00, (chan))
127#define LPAIF_RDMABASE_REG(chan) LPAIF_RDMA_REG_ADDR(0x04, (chan)) 87#define LPAIF_RDMABASE_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x04, (chan))
128#define LPAIF_RDMABUFF_REG(chan) LPAIF_RDMA_REG_ADDR(0x08, (chan)) 88#define LPAIF_RDMABUFF_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x08, (chan))
129#define LPAIF_RDMACURR_REG(chan) LPAIF_RDMA_REG_ADDR(0x0C, (chan)) 89#define LPAIF_RDMACURR_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x0C, (chan))
130#define LPAIF_RDMAPER_REG(chan) LPAIF_RDMA_REG_ADDR(0x10, (chan)) 90#define LPAIF_RDMAPER_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
91#define LPAIF_RDMAPERCNT_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x14, (chan))
131 92
132#define LPAIF_RDMACTL_BURSTEN_MASK 0x800 93#define LPAIF_RDMACTL_BURSTEN_MASK 0x800
133#define LPAIF_RDMACTL_BURSTEN_SHIFT 11 94#define LPAIF_RDMACTL_BURSTEN_SHIFT 11
@@ -145,13 +106,6 @@ enum lpaif_dma_channels {
145 106
146#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0 107#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0
147#define LPAIF_RDMACTL_AUDINTF_SHIFT 4 108#define LPAIF_RDMACTL_AUDINTF_SHIFT 4
148#define LPAIF_RDMACTL_AUDINTF_NONE (0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
149#define LPAIF_RDMACTL_AUDINTF_CODEC (1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
150#define LPAIF_RDMACTL_AUDINTF_PCM (2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
151#define LPAIF_RDMACTL_AUDINTF_SEC_I2S (3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
152#define LPAIF_RDMACTL_AUDINTF_MI2S (4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
153#define LPAIF_RDMACTL_AUDINTF_HDMI (5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
154#define LPAIF_RDMACTL_AUDINTF_SEC_PCM (7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
155 109
156#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E 110#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E
157#define LPAIF_RDMACTL_FIFOWM_SHIFT 1 111#define LPAIF_RDMACTL_FIFOWM_SHIFT 1
@@ -169,4 +123,4 @@ enum lpaif_dma_channels {
169#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) 123#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT)
170#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) 124#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT)
171 125
172#endif /* __LPASS_LPAIF_H__ */ 126#endif /* __LPASS_LPAIF_REG_H__ */
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 2fa6280dfb23..79688aa1941a 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -13,23 +13,22 @@
13 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS 13 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
14 */ 14 */
15 15
16#include <linux/compiler.h>
17#include <linux/device.h>
18#include <linux/dma-mapping.h> 16#include <linux/dma-mapping.h>
19#include <linux/err.h>
20#include <linux/export.h> 17#include <linux/export.h>
21#include <linux/kernel.h> 18#include <linux/kernel.h>
22#include <linux/module.h> 19#include <linux/module.h>
23#include <linux/io.h>
24#include <linux/platform_device.h> 20#include <linux/platform_device.h>
25#include <sound/memalloc.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h> 21#include <sound/pcm_params.h>
28#include <linux/regmap.h> 22#include <linux/regmap.h>
29#include <sound/soc.h> 23#include <sound/soc.h>
30#include "lpass-lpaif-ipq806x.h" 24#include "lpass-lpaif-reg.h"
31#include "lpass.h" 25#include "lpass.h"
32 26
27struct lpass_pcm_data {
28 int rdma_ch;
29 int i2s_port;
30};
31
33#define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024) 32#define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024)
34#define LPASS_PLATFORM_PERIODS 2 33#define LPASS_PLATFORM_PERIODS 2
35 34
@@ -84,13 +83,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
84 struct snd_pcm_hw_params *params) 83 struct snd_pcm_hw_params *params)
85{ 84{
86 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 85 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
86 struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
87 struct lpass_data *drvdata = 87 struct lpass_data *drvdata =
88 snd_soc_platform_get_drvdata(soc_runtime->platform); 88 snd_soc_platform_get_drvdata(soc_runtime->platform);
89 struct lpass_variant *v = drvdata->variant;
89 snd_pcm_format_t format = params_format(params); 90 snd_pcm_format_t format = params_format(params);
90 unsigned int channels = params_channels(params); 91 unsigned int channels = params_channels(params);
91 unsigned int regval; 92 unsigned int regval;
92 int bitwidth; 93 int bitwidth;
93 int ret; 94 int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
94 95
95 bitwidth = snd_pcm_format_width(format); 96 bitwidth = snd_pcm_format_width(format);
96 if (bitwidth < 0) { 97 if (bitwidth < 0) {
@@ -100,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
100 } 101 }
101 102
102 regval = LPAIF_RDMACTL_BURSTEN_INCR4 | 103 regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
103 LPAIF_RDMACTL_AUDINTF_MI2S | 104 LPAIF_RDMACTL_AUDINTF(rdma_port) |
104 LPAIF_RDMACTL_FIFOWM_8; 105 LPAIF_RDMACTL_FIFOWM_8;
105 106
106 switch (bitwidth) { 107 switch (bitwidth) {
@@ -156,7 +157,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
156 } 157 }
157 158
158 ret = regmap_write(drvdata->lpaif_map, 159 ret = regmap_write(drvdata->lpaif_map,
159 LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval); 160 LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);
160 if (ret) { 161 if (ret) {
161 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 162 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
162 __func__, ret); 163 __func__, ret);
@@ -169,12 +170,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
169static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) 170static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
170{ 171{
171 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 172 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
173 struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
172 struct lpass_data *drvdata = 174 struct lpass_data *drvdata =
173 snd_soc_platform_get_drvdata(soc_runtime->platform); 175 snd_soc_platform_get_drvdata(soc_runtime->platform);
176 struct lpass_variant *v = drvdata->variant;
174 int ret; 177 int ret;
175 178
176 ret = regmap_write(drvdata->lpaif_map, 179 ret = regmap_write(drvdata->lpaif_map,
177 LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0); 180 LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);
178 if (ret) 181 if (ret)
179 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 182 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
180 __func__, ret); 183 __func__, ret);
@@ -186,12 +189,14 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
186{ 189{
187 struct snd_pcm_runtime *runtime = substream->runtime; 190 struct snd_pcm_runtime *runtime = substream->runtime;
188 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 191 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
192 struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
189 struct lpass_data *drvdata = 193 struct lpass_data *drvdata =
190 snd_soc_platform_get_drvdata(soc_runtime->platform); 194 snd_soc_platform_get_drvdata(soc_runtime->platform);
191 int ret; 195 struct lpass_variant *v = drvdata->variant;
196 int ret, ch = pcm_data->rdma_ch;
192 197
193 ret = regmap_write(drvdata->lpaif_map, 198 ret = regmap_write(drvdata->lpaif_map,
194 LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), 199 LPAIF_RDMABASE_REG(v, ch),
195 runtime->dma_addr); 200 runtime->dma_addr);
196 if (ret) { 201 if (ret) {
197 dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", 202 dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -200,7 +205,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
200 } 205 }
201 206
202 ret = regmap_write(drvdata->lpaif_map, 207 ret = regmap_write(drvdata->lpaif_map,
203 LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S), 208 LPAIF_RDMABUFF_REG(v, ch),
204 (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); 209 (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
205 if (ret) { 210 if (ret) {
206 dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n", 211 dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -209,7 +214,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
209 } 214 }
210 215
211 ret = regmap_write(drvdata->lpaif_map, 216 ret = regmap_write(drvdata->lpaif_map,
212 LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S), 217 LPAIF_RDMAPER_REG(v, ch),
213 (snd_pcm_lib_period_bytes(substream) >> 2) - 1); 218 (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
214 if (ret) { 219 if (ret) {
215 dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n", 220 dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -218,7 +223,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
218 } 223 }
219 224
220 ret = regmap_update_bits(drvdata->lpaif_map, 225 ret = regmap_update_bits(drvdata->lpaif_map,
221 LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 226 LPAIF_RDMACTL_REG(v, ch),
222 LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON); 227 LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
223 if (ret) { 228 if (ret) {
224 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", 229 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -233,9 +238,11 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
233 int cmd) 238 int cmd)
234{ 239{
235 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 240 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
241 struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
236 struct lpass_data *drvdata = 242 struct lpass_data *drvdata =
237 snd_soc_platform_get_drvdata(soc_runtime->platform); 243 snd_soc_platform_get_drvdata(soc_runtime->platform);
238 int ret; 244 struct lpass_variant *v = drvdata->variant;
245 int ret, ch = pcm_data->rdma_ch;
239 246
240 switch (cmd) { 247 switch (cmd) {
241 case SNDRV_PCM_TRIGGER_START: 248 case SNDRV_PCM_TRIGGER_START:
@@ -243,8 +250,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
243 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 250 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
244 /* clear status before enabling interrupts */ 251 /* clear status before enabling interrupts */
245 ret = regmap_write(drvdata->lpaif_map, 252 ret = regmap_write(drvdata->lpaif_map,
246 LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), 253 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
247 LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S)); 254 LPAIF_IRQ_ALL(ch));
248 if (ret) { 255 if (ret) {
249 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", 256 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
250 __func__, ret); 257 __func__, ret);
@@ -252,9 +259,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
252 } 259 }
253 260
254 ret = regmap_update_bits(drvdata->lpaif_map, 261 ret = regmap_update_bits(drvdata->lpaif_map,
255 LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 262 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
256 LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 263 LPAIF_IRQ_ALL(ch),
257 LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S)); 264 LPAIF_IRQ_ALL(ch));
258 if (ret) { 265 if (ret) {
259 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", 266 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
260 __func__, ret); 267 __func__, ret);
@@ -262,7 +269,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
262 } 269 }
263 270
264 ret = regmap_update_bits(drvdata->lpaif_map, 271 ret = regmap_update_bits(drvdata->lpaif_map,
265 LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 272 LPAIF_RDMACTL_REG(v, ch),
266 LPAIF_RDMACTL_ENABLE_MASK, 273 LPAIF_RDMACTL_ENABLE_MASK,
267 LPAIF_RDMACTL_ENABLE_ON); 274 LPAIF_RDMACTL_ENABLE_ON);
268 if (ret) { 275 if (ret) {
@@ -275,7 +282,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
275 case SNDRV_PCM_TRIGGER_SUSPEND: 282 case SNDRV_PCM_TRIGGER_SUSPEND:
276 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 283 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
277 ret = regmap_update_bits(drvdata->lpaif_map, 284 ret = regmap_update_bits(drvdata->lpaif_map,
278 LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 285 LPAIF_RDMACTL_REG(v, ch),
279 LPAIF_RDMACTL_ENABLE_MASK, 286 LPAIF_RDMACTL_ENABLE_MASK,
280 LPAIF_RDMACTL_ENABLE_OFF); 287 LPAIF_RDMACTL_ENABLE_OFF);
281 if (ret) { 288 if (ret) {
@@ -285,8 +292,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
285 } 292 }
286 293
287 ret = regmap_update_bits(drvdata->lpaif_map, 294 ret = regmap_update_bits(drvdata->lpaif_map,
288 LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 295 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
289 LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0); 296 LPAIF_IRQ_ALL(ch), 0);
290 if (ret) { 297 if (ret) {
291 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", 298 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
292 __func__, ret); 299 __func__, ret);
@@ -302,13 +309,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
302 struct snd_pcm_substream *substream) 309 struct snd_pcm_substream *substream)
303{ 310{
304 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 311 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
312 struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
305 struct lpass_data *drvdata = 313 struct lpass_data *drvdata =
306 snd_soc_platform_get_drvdata(soc_runtime->platform); 314 snd_soc_platform_get_drvdata(soc_runtime->platform);
315 struct lpass_variant *v = drvdata->variant;
307 unsigned int base_addr, curr_addr; 316 unsigned int base_addr, curr_addr;
308 int ret; 317 int ret, ch = pcm_data->rdma_ch;
309 318
310 ret = regmap_read(drvdata->lpaif_map, 319 ret = regmap_read(drvdata->lpaif_map,
311 LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr); 320 LPAIF_RDMABASE_REG(v, ch), &base_addr);
312 if (ret) { 321 if (ret) {
313 dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n", 322 dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
314 __func__, ret); 323 __func__, ret);
@@ -316,7 +325,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
316 } 325 }
317 326
318 ret = regmap_read(drvdata->lpaif_map, 327 ret = regmap_read(drvdata->lpaif_map,
319 LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr); 328 LPAIF_RDMACURR_REG(v, ch), &curr_addr);
320 if (ret) { 329 if (ret) {
321 dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n", 330 dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
322 __func__, ret); 331 __func__, ret);
@@ -347,29 +356,20 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = {
347 .mmap = lpass_platform_pcmops_mmap, 356 .mmap = lpass_platform_pcmops_mmap,
348}; 357};
349 358
350static 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)
351{ 363{
352 struct snd_pcm_substream *substream = data;
353 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 364 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
354 struct lpass_data *drvdata = 365 struct lpass_variant *v = drvdata->variant;
355 snd_soc_platform_get_drvdata(soc_runtime->platform);
356 unsigned int interrupts;
357 irqreturn_t ret = IRQ_NONE; 366 irqreturn_t ret = IRQ_NONE;
358 int rv; 367 int rv;
359 368
360 rv = regmap_read(drvdata->lpaif_map, 369 if (interrupts & LPAIF_IRQ_PER(chan)) {
361 LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
362 if (rv) {
363 dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
364 __func__, rv);
365 return IRQ_NONE;
366 }
367 interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);
368
369 if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
370 rv = regmap_write(drvdata->lpaif_map, 370 rv = regmap_write(drvdata->lpaif_map,
371 LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), 371 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
372 LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)); 372 LPAIF_IRQ_PER(chan));
373 if (rv) { 373 if (rv) {
374 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", 374 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
375 __func__, rv); 375 __func__, rv);
@@ -379,10 +379,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
379 ret = IRQ_HANDLED; 379 ret = IRQ_HANDLED;
380 } 380 }
381 381
382 if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) { 382 if (interrupts & LPAIF_IRQ_XRUN(chan)) {
383 rv = regmap_write(drvdata->lpaif_map, 383 rv = regmap_write(drvdata->lpaif_map,
384 LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), 384 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
385 LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)); 385 LPAIF_IRQ_XRUN(chan));
386 if (rv) { 386 if (rv) {
387 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", 387 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
388 __func__, rv); 388 __func__, rv);
@@ -393,10 +393,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
393 ret = IRQ_HANDLED; 393 ret = IRQ_HANDLED;
394 } 394 }
395 395
396 if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) { 396 if (interrupts & LPAIF_IRQ_ERR(chan)) {
397 rv = regmap_write(drvdata->lpaif_map, 397 rv = regmap_write(drvdata->lpaif_map,
398 LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), 398 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
399 LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)); 399 LPAIF_IRQ_ERR(chan));
400 if (rv) { 400 if (rv) {
401 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", 401 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
402 __func__, rv); 402 __func__, rv);
@@ -410,6 +410,35 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
410 return ret; 410 return ret;
411} 411}
412 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
413static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, 442static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
414 struct snd_soc_pcm_runtime *soc_runtime) 443 struct snd_soc_pcm_runtime *soc_runtime)
415{ 444{
@@ -448,9 +477,27 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
448 struct snd_pcm *pcm = soc_runtime->pcm; 477 struct snd_pcm *pcm = soc_runtime->pcm;
449 struct snd_pcm_substream *substream = 478 struct snd_pcm_substream *substream =
450 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 479 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
480 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
451 struct lpass_data *drvdata = 481 struct lpass_data *drvdata =
452 snd_soc_platform_get_drvdata(soc_runtime->platform); 482 snd_soc_platform_get_drvdata(soc_runtime->platform);
483 struct lpass_variant *v = drvdata->variant;
453 int ret; 484 int ret;
485 struct lpass_pcm_data *data;
486
487 data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
488 if (!data)
489 return -ENOMEM;
490
491 if (v->alloc_dma_channel)
492 data->rdma_ch = v->alloc_dma_channel(drvdata);
493
494 if (IS_ERR_VALUE(data->rdma_ch))
495 return data->rdma_ch;
496
497 drvdata->substream[data->rdma_ch] = substream;
498 data->i2s_port = cpu_dai->driver->id;
499
500 snd_soc_pcm_set_drvdata(soc_runtime, data);
454 501
455 soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32); 502 soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
456 soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask; 503 soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
@@ -459,29 +506,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
459 if (ret) 506 if (ret)
460 return ret; 507 return ret;
461 508
462 ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
463 lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
464 "lpass-irq-lpaif", substream);
465 if (ret) {
466 dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
467 __func__, ret);
468 goto err_buf;
469 }
470
471 /* ensure audio hardware is disabled */
472 ret = regmap_write(drvdata->lpaif_map, 509 ret = regmap_write(drvdata->lpaif_map,
473 LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0); 510 LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
474 if (ret) {
475 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
476 __func__, ret);
477 return ret;
478 }
479 ret = regmap_write(drvdata->lpaif_map,
480 LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
481 if (ret) { 511 if (ret) {
482 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",
483 __func__, ret); 513 __func__, ret);
484 return ret; 514 goto err_buf;
485 } 515 }
486 516
487 return 0; 517 return 0;
@@ -496,6 +526,15 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
496 struct snd_pcm_substream *substream = 526 struct snd_pcm_substream *substream =
497 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 527 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
498 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; 528 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
529 struct lpass_data *drvdata =
530 snd_soc_platform_get_drvdata(soc_runtime->platform);
531 struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
532 struct lpass_variant *v = drvdata->variant;
533
534 drvdata->substream[data->rdma_ch] = NULL;
535
536 if (v->free_dma_channel)
537 v->free_dma_channel(drvdata, data->rdma_ch);
499 538
500 lpass_platform_free_buffer(substream, soc_runtime); 539 lpass_platform_free_buffer(substream, soc_runtime);
501} 540}
@@ -509,6 +548,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = {
509int asoc_qcom_lpass_platform_register(struct platform_device *pdev) 548int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
510{ 549{
511 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;
512 553
513 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); 554 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
514 if (drvdata->lpaif_irq < 0) { 555 if (drvdata->lpaif_irq < 0) {
@@ -517,6 +558,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
517 return -ENODEV; 558 return -ENODEV;
518 } 559 }
519 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
520 return devm_snd_soc_register_platform(&pdev->dev, 580 return devm_snd_soc_register_platform(&pdev->dev,
521 &lpass_platform_driver); 581 &lpass_platform_driver);
522} 582}
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 5c99b3dace86..d6e86c119e74 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -22,6 +22,8 @@
22#include <linux/regmap.h> 22#include <linux/regmap.h>
23 23
24#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 24#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
25#define LPASS_MAX_MI2S_PORTS (8)
26#define LPASS_MAX_DMA_CHANNELS (8)
25 27
26/* Both the CPU DAI and platform drivers will access this data */ 28/* Both the CPU DAI and platform drivers will access this data */
27struct lpass_data { 29struct lpass_data {
@@ -30,10 +32,10 @@ struct lpass_data {
30 struct clk *ahbix_clk; 32 struct clk *ahbix_clk;
31 33
32 /* MI2S system clock */ 34 /* MI2S system clock */
33 struct clk *mi2s_osr_clk; 35 struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];
34 36
35 /* MI2S bit clock (derived from system clock by a divider */ 37 /* MI2S bit clock (derived from system clock by a divider */
36 struct clk *mi2s_bit_clk; 38 struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
37 39
38 /* low-power audio interface (LPAIF) registers */ 40 /* low-power audio interface (LPAIF) registers */
39 void __iomem *lpaif; 41 void __iomem *lpaif;
@@ -43,9 +45,54 @@ struct lpass_data {
43 45
44 /* interrupts from the low-power audio interface (LPAIF) */ 46 /* interrupts from the low-power audio interface (LPAIF) */
45 int lpaif_irq; 47 int lpaif_irq;
48
49 /* SOC specific variations in the LPASS IP integration */
50 struct lpass_variant *variant;
51
52 /* bit map to keep track of static channel allocations */
53 unsigned long rdma_ch_bit_map;
54
55 /* used it for handling interrupt per dma channel */
56 struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
57
58 /* 8016 specific */
59 struct clk *pcnoc_mport_clk;
60 struct clk *pcnoc_sway_clk;
61};
62
63/* Vairant data per each SOC */
64struct lpass_variant {
65 u32 i2sctrl_reg_base;
66 u32 i2sctrl_reg_stride;
67 u32 i2s_ports;
68 u32 irq_reg_base;
69 u32 irq_reg_stride;
70 u32 irq_ports;
71 u32 rdma_reg_base;
72 u32 rdma_reg_stride;
73 u32 rdma_channels;
74
75 /**
76 * on SOCs like APQ8016 the channel control bits start
77 * at different offset to ipq806x
78 **/
79 u32 rdmactl_audif_start;
80 /* SOC specific intialization like clocks */
81 int (*init)(struct platform_device *pdev);
82 int (*exit)(struct platform_device *pdev);
83 int (*alloc_dma_channel)(struct lpass_data *data);
84 int (*free_dma_channel)(struct lpass_data *data, int ch);
85
86 /* SOC specific dais */
87 struct snd_soc_dai_driver *dai_driver;
88 int num_dai;
46}; 89};
47 90
48/* register the platform driver from the CPU DAI driver */ 91/* register the platform driver from the CPU DAI driver */
49int asoc_qcom_lpass_platform_register(struct platform_device *); 92int asoc_qcom_lpass_platform_register(struct platform_device *);
93int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
94int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
95int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
96extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
50 97
51#endif /* __LPASS_H__ */ 98#endif /* __LPASS_H__ */
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 9f48d75fa992..d460d2aa82ee 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -170,6 +170,14 @@ void rsnd_mod_quit(struct rsnd_mod *mod)
170 clk_unprepare(mod->clk); 170 clk_unprepare(mod->clk);
171} 171}
172 172
173int rsnd_mod_is_working(struct rsnd_mod *mod)
174{
175 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
176
177 /* see rsnd_dai_stream_init/quit() */
178 return !!io->substream;
179}
180
173/* 181/*
174 * settting function 182 * settting function
175 */ 183 */
@@ -272,9 +280,10 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
272 return priv->rdai + id; 280 return priv->rdai + id;
273} 281}
274 282
283#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
275static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) 284static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
276{ 285{
277 struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); 286 struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
278 287
279 return rsnd_rdai_get(priv, dai->id); 288 return rsnd_rdai_get(priv, dai->id);
280} 289}
@@ -314,7 +323,7 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
314 } 323 }
315} 324}
316 325
317static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, 326static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
318 struct snd_pcm_substream *substream) 327 struct snd_pcm_substream *substream)
319{ 328{
320 struct snd_pcm_runtime *runtime = substream->runtime; 329 struct snd_pcm_runtime *runtime = substream->runtime;
@@ -326,8 +335,11 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
326 runtime->channels * 335 runtime->channels *
327 samples_to_bytes(runtime, 1); 336 samples_to_bytes(runtime, 1);
328 io->next_period_byte = io->byte_per_period; 337 io->next_period_byte = io->byte_per_period;
338}
329 339
330 return 0; 340static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
341{
342 io->substream = NULL;
331} 343}
332 344
333static 345static
@@ -351,20 +363,18 @@ struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
351static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 363static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
352 struct snd_soc_dai *dai) 364 struct snd_soc_dai *dai)
353{ 365{
354 struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); 366 struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
355 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); 367 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
356 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); 368 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
357 int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); 369 int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
358 int ret; 370 int ret;
359 unsigned long flags; 371 unsigned long flags;
360 372
361 rsnd_lock(priv, flags); 373 spin_lock_irqsave(&priv->lock, flags);
362 374
363 switch (cmd) { 375 switch (cmd) {
364 case SNDRV_PCM_TRIGGER_START: 376 case SNDRV_PCM_TRIGGER_START:
365 ret = rsnd_dai_stream_init(io, substream); 377 rsnd_dai_stream_init(io, substream);
366 if (ret < 0)
367 goto dai_trigger_end;
368 378
369 ret = rsnd_platform_call(priv, dai, start, ssi_id); 379 ret = rsnd_platform_call(priv, dai, start, ssi_id);
370 if (ret < 0) 380 if (ret < 0)
@@ -390,13 +400,15 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
390 ret = rsnd_platform_call(priv, dai, stop, ssi_id); 400 ret = rsnd_platform_call(priv, dai, stop, ssi_id);
391 if (ret < 0) 401 if (ret < 0)
392 goto dai_trigger_end; 402 goto dai_trigger_end;
403
404 rsnd_dai_stream_quit(io);
393 break; 405 break;
394 default: 406 default:
395 ret = -EINVAL; 407 ret = -EINVAL;
396 } 408 }
397 409
398dai_trigger_end: 410dai_trigger_end:
399 rsnd_unlock(priv, flags); 411 spin_unlock_irqrestore(&priv->lock, flags);
400 412
401 return ret; 413 return ret;
402} 414}
@@ -833,12 +845,14 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
833 struct rsnd_kctrl_cfg *cfg, 845 struct rsnd_kctrl_cfg *cfg,
834 void (*update)(struct rsnd_mod *mod)) 846 void (*update)(struct rsnd_mod *mod))
835{ 847{
848 struct snd_soc_card *soc_card = rtd->card;
836 struct snd_card *card = rtd->card->snd_card; 849 struct snd_card *card = rtd->card->snd_card;
837 struct snd_kcontrol *kctrl; 850 struct snd_kcontrol *kctrl;
838 struct snd_kcontrol_new knew = { 851 struct snd_kcontrol_new knew = {
839 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 852 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
840 .name = name, 853 .name = name,
841 .info = rsnd_kctrl_info, 854 .info = rsnd_kctrl_info,
855 .index = rtd - soc_card->rtd,
842 .get = rsnd_kctrl_get, 856 .get = rsnd_kctrl_get,
843 .put = rsnd_kctrl_put, 857 .put = rsnd_kctrl_put,
844 .private_value = (unsigned long)cfg, 858 .private_value = (unsigned long)cfg,
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 4e6de6804cfb..03ff071d012f 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -303,6 +303,7 @@ int rsnd_mod_init(struct rsnd_mod *mod,
303 int id); 303 int id);
304void rsnd_mod_quit(struct rsnd_mod *mod); 304void rsnd_mod_quit(struct rsnd_mod *mod);
305char *rsnd_mod_name(struct rsnd_mod *mod); 305char *rsnd_mod_name(struct rsnd_mod *mod);
306int rsnd_mod_is_working(struct rsnd_mod *mod);
306struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod); 307struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
307 308
308/* 309/*
@@ -449,8 +450,6 @@ struct rsnd_priv {
449#define rsnd_priv_to_pdev(priv) ((priv)->pdev) 450#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
450#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) 451#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
451#define rsnd_priv_to_info(priv) ((priv)->info) 452#define rsnd_priv_to_info(priv) ((priv)->info)
452#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
453#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
454 453
455/* 454/*
456 * rsnd_kctrl 455 * rsnd_kctrl
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c
index a68517afe615..050b0dbcee65 100644
--- a/sound/soc/sh/rcar/rsrc-card.c
+++ b/sound/soc/sh/rcar/rsrc-card.c
@@ -232,6 +232,7 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv,
232 if (args_count) { 232 if (args_count) {
233 *args_count = args.args_count; 233 *args_count = args.args_count;
234 dai_link->dynamic = 1; 234 dai_link->dynamic = 1;
235 dai_link->dpcm_merged_format = 1;
235 } else { 236 } else {
236 dai_link->no_pcm = 1; 237 dai_link->no_pcm = 1;
237 priv->codec_conf.of_node = (*p_node); 238 priv->codec_conf.of_node = (*p_node);
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 3beb32eb412a..fbe9166e26d1 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -673,10 +673,13 @@ static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
673static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) 673static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
674{ 674{
675 struct rsnd_mod *mod = data; 675 struct rsnd_mod *mod = data;
676 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); 676 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
677
678 spin_lock(&priv->lock);
677 679
678 if (!io) 680 /* ignore all cases if not working */
679 return IRQ_NONE; 681 if (!rsnd_mod_is_working(mod))
682 goto rsnd_src_interrupt_gen2_out;
680 683
681 if (rsnd_src_error_record_gen2(mod)) { 684 if (rsnd_src_error_record_gen2(mod)) {
682 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 685 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
@@ -692,6 +695,8 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
692 else 695 else
693 dev_warn(dev, "no more SRC restart\n"); 696 dev_warn(dev, "no more SRC restart\n");
694 } 697 }
698rsnd_src_interrupt_gen2_out:
699 spin_unlock(&priv->lock);
695 700
696 return IRQ_HANDLED; 701 return IRQ_HANDLED;
697} 702}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 7bb9c087f3dc..50fa3928a003 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -66,6 +66,7 @@ struct rsnd_ssi {
66 66
67 u32 cr_own; 67 u32 cr_own;
68 u32 cr_clk; 68 u32 cr_clk;
69 int chan;
69 int err; 70 int err;
70 unsigned int usrcnt; 71 unsigned int usrcnt;
71}; 72};
@@ -80,7 +81,7 @@ struct rsnd_ssi {
80#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) 81#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
81#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) 82#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
82#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) 83#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
83#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) 84#define rsnd_ssi_parent(ssi) ((ssi)->parent)
84#define rsnd_ssi_mode_flags(p) ((p)->info->flags) 85#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
85#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) 86#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
86#define rsnd_ssi_of_node(priv) \ 87#define rsnd_ssi_of_node(priv) \
@@ -189,8 +190,10 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
189 rsnd_mod_hw_start(&ssi->mod); 190 rsnd_mod_hw_start(&ssi->mod);
190 191
191 if (rsnd_rdai_is_clk_master(rdai)) { 192 if (rsnd_rdai_is_clk_master(rdai)) {
192 if (rsnd_ssi_clk_from_parent(ssi)) 193 struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
193 rsnd_ssi_hw_start(ssi->parent, io); 194
195 if (ssi_parent)
196 rsnd_ssi_hw_start(ssi_parent, io);
194 else 197 else
195 rsnd_ssi_master_clk_start(ssi, io); 198 rsnd_ssi_master_clk_start(ssi, io);
196 } 199 }
@@ -229,8 +232,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
229 struct device *dev = rsnd_priv_to_dev(priv); 232 struct device *dev = rsnd_priv_to_dev(priv);
230 u32 cr; 233 u32 cr;
231 234
232 if (0 == ssi->usrcnt) /* stop might be called without start */ 235 if (0 == ssi->usrcnt) {
236 dev_err(dev, "%s called without starting\n", __func__);
233 return; 237 return;
238 }
234 239
235 ssi->usrcnt--; 240 ssi->usrcnt--;
236 241
@@ -253,13 +258,17 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
253 rsnd_ssi_status_check(&ssi->mod, IIRQ); 258 rsnd_ssi_status_check(&ssi->mod, IIRQ);
254 259
255 if (rsnd_rdai_is_clk_master(rdai)) { 260 if (rsnd_rdai_is_clk_master(rdai)) {
256 if (rsnd_ssi_clk_from_parent(ssi)) 261 struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
257 rsnd_ssi_hw_stop(ssi->parent); 262
263 if (ssi_parent)
264 rsnd_ssi_hw_stop(ssi_parent);
258 else 265 else
259 rsnd_ssi_master_clk_stop(ssi); 266 rsnd_ssi_master_clk_stop(ssi);
260 } 267 }
261 268
262 rsnd_mod_hw_stop(&ssi->mod); 269 rsnd_mod_hw_stop(&ssi->mod);
270
271 ssi->chan = 0;
263 } 272 }
264 273
265 dev_dbg(dev, "%s[%d] hw stopped\n", 274 dev_dbg(dev, "%s[%d] hw stopped\n",
@@ -336,6 +345,35 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
336 return 0; 345 return 0;
337} 346}
338 347
348static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
349 struct snd_pcm_substream *substream,
350 struct snd_pcm_hw_params *params)
351{
352 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
353 struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
354 int chan = params_channels(params);
355
356 /*
357 * Already working.
358 * It will happen if SSI has parent/child connection.
359 */
360 if (ssi->usrcnt) {
361 /*
362 * it is error if child <-> parent SSI uses
363 * different channels.
364 */
365 if (ssi->chan != chan)
366 return -EIO;
367 }
368
369 /* It will be removed on rsnd_ssi_hw_stop */
370 ssi->chan = chan;
371 if (ssi_parent)
372 return rsnd_ssi_hw_params(&ssi_parent->mod, substream, params);
373
374 return 0;
375}
376
339static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) 377static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
340{ 378{
341 /* under/over flow error */ 379 /* under/over flow error */
@@ -385,10 +423,15 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
385 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 423 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
386 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); 424 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
387 int is_dma = rsnd_ssi_is_dma_mode(mod); 425 int is_dma = rsnd_ssi_is_dma_mode(mod);
388 u32 status = rsnd_mod_read(mod, SSISR); 426 u32 status;
427
428 spin_lock(&priv->lock);
389 429
390 if (!io) 430 /* ignore all cases if not working */
391 return IRQ_NONE; 431 if (!rsnd_mod_is_working(mod))
432 goto rsnd_ssi_interrupt_out;
433
434 status = rsnd_mod_read(mod, SSISR);
392 435
393 /* PIO only */ 436 /* PIO only */
394 if (!is_dma && (status & DIRQ)) { 437 if (!is_dma && (status & DIRQ)) {
@@ -428,6 +471,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
428 471
429 rsnd_ssi_record_error(ssi, status); 472 rsnd_ssi_record_error(ssi, status);
430 473
474rsnd_ssi_interrupt_out:
475 spin_unlock(&priv->lock);
476
431 return IRQ_HANDLED; 477 return IRQ_HANDLED;
432} 478}
433 479
@@ -456,6 +502,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
456 .quit = rsnd_ssi_quit, 502 .quit = rsnd_ssi_quit,
457 .start = rsnd_ssi_start, 503 .start = rsnd_ssi_start,
458 .stop = rsnd_ssi_stop, 504 .stop = rsnd_ssi_stop,
505 .hw_params = rsnd_ssi_hw_params,
459}; 506};
460 507
461static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, 508static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
@@ -565,6 +612,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
565 .start = rsnd_ssi_dma_start, 612 .start = rsnd_ssi_dma_start,
566 .stop = rsnd_ssi_dma_stop, 613 .stop = rsnd_ssi_dma_stop,
567 .fallback = rsnd_ssi_fallback, 614 .fallback = rsnd_ssi_fallback,
615 .hw_params = rsnd_ssi_hw_params,
568}; 616};
569 617
570int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) 618int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
@@ -598,7 +646,7 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
598 return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); 646 return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
599} 647}
600 648
601static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) 649static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
602{ 650{
603 if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) 651 if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
604 return; 652 return;
@@ -732,7 +780,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
732 if (ret) 780 if (ret)
733 return ret; 781 return ret;
734 782
735 rsnd_ssi_parent_clk_setup(priv, ssi); 783 rsnd_ssi_parent_setup(priv, ssi);
736 } 784 }
737 785
738 return 0; 786 return 0;