diff options
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 | ||
| 5 | Required properties: | 5 | Required 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 | |||
| 25 | Optional properties: | 36 | Optional 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 | ||
| 49 | Example: | 49 | Example: |
| 50 | 50 | ||
| 51 | rcar_sound: rcar_sound@ec500000 { | 51 | rcar_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) | |||
| 465 | static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) | 465 | static 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, | |||
| 516 | static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) | 517 | static 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) | |||
| 556 | static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan) | 558 | static 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) | |||
| 593 | static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) | 596 | static 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 * | |||
| 627 | rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan) | 631 | rcar_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 | ||
| 101 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 | 101 | config 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 | ||
| 160 | static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) | 160 | static 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 | ||
| 48 | static 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 | |||
| 71 | static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, | 48 | static 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 | ||
| 137 | static int brownstone_probe(struct platform_device *pdev) | 114 | static 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, | |||
| 192 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | 192 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { |
| 193 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 193 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
| 194 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), | 194 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), |
| 195 | SND_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 | ||
| 209 | static const char *jack_function[] = {"Off", "Headphone"}; | 212 | static 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 | */ | ||
| 226 | static 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 */ |
| 238 | static struct snd_soc_dai_link poodle_dai = { | 227 | static 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 | ||
| 266 | static int poodle_probe(struct platform_device *pdev) | 255 | static 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 | ||
| 188 | static 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 | |||
| 199 | static struct snd_soc_dai_link tosa_dai[] = { | 188 | static 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 | ||
| 235 | static int tosa_probe(struct platform_device *pdev) | 224 | static 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 | */ |
| 133 | static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) | 133 | static 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 | ||
| 194 | static struct platform_device *z2_snd_device; | 187 | static 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 | ||
| 7 | config SND_SOC_LPASS_CPU | 7 | config SND_SOC_LPASS_CPU |
| 8 | tristate | 8 | tristate |
| 9 | depends on SND_SOC_QCOM | ||
| 10 | select REGMAP_MMIO | 9 | select REGMAP_MMIO |
| 11 | 10 | ||
| 12 | config SND_SOC_LPASS_PLATFORM | 11 | config SND_SOC_LPASS_PLATFORM |
| 13 | tristate | 12 | tristate |
| 14 | depends on SND_SOC_QCOM | ||
| 15 | select REGMAP_MMIO | 13 | select REGMAP_MMIO |
| 16 | 14 | ||
| 17 | config SND_SOC_STORM | 15 | config 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 | |||
| 21 | config 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 | |||
| 27 | config 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 |
| 2 | snd-soc-lpass-cpu-objs := lpass-cpu.o | 2 | snd-soc-lpass-cpu-objs := lpass-cpu.o |
| 3 | snd-soc-lpass-platform-objs := lpass-platform.o | 3 | snd-soc-lpass-platform-objs := lpass-platform.o |
| 4 | snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o | ||
| 5 | snd-soc-lpass-apq8016-objs := lpass-apq8016.o | ||
| 4 | 6 | ||
| 5 | obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o | 7 | obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o |
| 6 | obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o | 8 | obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o |
| 9 | obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o | ||
| 10 | obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o | ||
| 7 | 11 | ||
| 8 | # Machine | 12 | # Machine |
| 9 | snd-soc-storm-objs := storm.o | 13 | snd-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 | |||
| 34 | static 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 | |||
| 136 | static 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 | |||
| 150 | static 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 | |||
| 157 | static 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 | |||
| 194 | static 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 | |||
| 205 | static 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 | |||
| 224 | static const struct of_device_id apq8016_lpass_cpu_device_id[] = { | ||
| 225 | { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data }, | ||
| 226 | {} | ||
| 227 | }; | ||
| 228 | MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id); | ||
| 229 | |||
| 230 | static 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 | }; | ||
| 238 | module_platform_driver(apq8016_lpass_cpu_platform_driver); | ||
| 239 | |||
| 240 | MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver"); | ||
| 241 | MODULE_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 | ||
| 34 | static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 30 | static 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 | ||
| 81 | static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, | 87 | static 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 | ||
| 227 | static struct snd_soc_dai_ops lpass_cpu_dai_ops = { | 238 | struct 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 | }; |
| 247 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); | ||
| 236 | 248 | ||
| 237 | static int lpass_cpu_dai_probe(struct snd_soc_dai *dai) | 249 | int 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 | 263 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); | |
| 252 | static 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 | ||
| 272 | static const struct snd_soc_component_driver lpass_cpu_comp_driver = { | 265 | static 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 | ||
| 276 | static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) | 269 | static 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 | ||
| 305 | static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) | 300 | static 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 | ||
| 336 | static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) | 333 | static 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 | ||
| 351 | static const struct regmap_config lpass_cpu_regmap_config = { | 350 | static 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 | ||
| 362 | static int lpass_cpu_platform_probe(struct platform_device *pdev) | 360 | int 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 | } |
| 492 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe); | ||
| 462 | 493 | ||
| 463 | static int lpass_cpu_platform_remove(struct platform_device *pdev) | 494 | int 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 | 505 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); | |
| 472 | #ifdef CONFIG_OF | ||
| 473 | static const struct of_device_id lpass_cpu_device_id[] = { | ||
| 474 | { .compatible = "qcom,lpass-cpu" }, | ||
| 475 | {} | ||
| 476 | }; | ||
| 477 | MODULE_DEVICE_TABLE(of, lpass_cpu_device_id); | ||
| 478 | #endif | ||
| 479 | |||
| 480 | static 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 | }; | ||
| 488 | module_platform_driver(lpass_cpu_platform_driver); | ||
| 489 | |||
| 490 | MODULE_DESCRIPTION("QTi LPASS CPU Driver"); | ||
| 491 | MODULE_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 | |||
| 31 | enum 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 | |||
| 39 | enum lpaif_dma_channels { | ||
| 40 | IPQ806X_LPAIF_RDMA_CHAN_MI2S, | ||
| 41 | IPQ806X_LPAIF_RDMA_CHAN_PCM0, | ||
| 42 | IPQ806X_LPAIF_RDMA_CHAN_PCM1, | ||
| 43 | }; | ||
| 44 | |||
| 45 | static 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 | |||
| 66 | static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata) | ||
| 67 | { | ||
| 68 | return IPQ806X_LPAIF_RDMA_CHAN_MI2S; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) | ||
| 72 | { | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | struct 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 | |||
| 92 | static const struct of_device_id ipq806x_lpass_cpu_device_id[] = { | ||
| 93 | { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data }, | ||
| 94 | {} | ||
| 95 | }; | ||
| 96 | MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id); | ||
| 97 | |||
| 98 | static 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 | }; | ||
| 106 | module_platform_driver(ipq806x_lpass_cpu_platform_driver); | ||
| 107 | |||
| 108 | MODULE_DESCRIPTION("QTi LPASS CPU Driver"); | ||
| 109 | MODULE_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 | |||
| 28 | enum 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 | |||
| 88 | enum 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 | |||
| 115 | enum 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 | ||
| 27 | struct 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, | |||
| 169 | static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) | 170 | static 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 | ||
| 350 | static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) | 359 | static 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 | ||
| 413 | static 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 | |||
| 413 | static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, | 442 | static 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 = { | |||
| 509 | int asoc_qcom_lpass_platform_register(struct platform_device *pdev) | 548 | int 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 */ |
| 27 | struct lpass_data { | 29 | struct 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 */ | ||
| 64 | struct 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 */ |
| 49 | int asoc_qcom_lpass_platform_register(struct platform_device *); | 92 | int asoc_qcom_lpass_platform_register(struct platform_device *); |
| 93 | int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); | ||
| 94 | int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); | ||
| 95 | int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); | ||
| 96 | extern 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 | ||
| 173 | int 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) | ||
| 275 | static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) | 284 | static 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 | ||
| 317 | static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, | 326 | static 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; | 340 | static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) |
| 341 | { | ||
| 342 | io->substream = NULL; | ||
| 331 | } | 343 | } |
| 332 | 344 | ||
| 333 | static | 345 | static |
| @@ -351,20 +363,18 @@ struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, | |||
| 351 | static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | 363 | static 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 | ||
| 398 | dai_trigger_end: | 410 | dai_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); |
| 304 | void rsnd_mod_quit(struct rsnd_mod *mod); | 304 | void rsnd_mod_quit(struct rsnd_mod *mod); |
| 305 | char *rsnd_mod_name(struct rsnd_mod *mod); | 305 | char *rsnd_mod_name(struct rsnd_mod *mod); |
| 306 | int rsnd_mod_is_working(struct rsnd_mod *mod); | ||
| 306 | struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod); | 307 | struct 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) | |||
| 673 | static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) | 673 | static 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 | } |
| 698 | rsnd_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 | ||
| 348 | static 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 | |||
| 339 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | 377 | static 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 | ||
| 474 | rsnd_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 | ||
| 461 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | 508 | static 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 | ||
| 570 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | 618 | int 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 | ||
| 601 | static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) | 649 | static 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; |
