Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge remote-tracking branches 'asoc/topic/max98095', 'asoc/topic/omap', 'asoc/topic/pxa', 'asoc/topic/qcom' and 'asoc/topic/rcar' into asoc-next

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