]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge branch 'asoc-4.19' into asoc-next
authorMark Brown <broonie@kernel.org>
Thu, 9 Aug 2018 13:47:05 +0000 (14:47 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 9 Aug 2018 13:47:05 +0000 (14:47 +0100)
312 files changed:
Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/amlogic,axg-tdm-iface.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel-i2s.txt
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Documentation/devicetree/bindings/sound/dioo,dio2125.txt [deleted file]
Documentation/devicetree/bindings/sound/everest,es7134.txt
Documentation/devicetree/bindings/sound/everest,es7241.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/marvell,pxa2xx-ac97.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt
Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt [deleted file]
Documentation/devicetree/bindings/sound/name-prefix.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,apq8096.txt
Documentation/devicetree/bindings/sound/qcom,q6adm.txt
Documentation/devicetree/bindings/sound/qcom,q6afe.txt
Documentation/devicetree/bindings/sound/qcom,q6asm.txt
Documentation/devicetree/bindings/sound/qcom,sdm845.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,wcd9335.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/rockchip-i2s.txt
Documentation/devicetree/bindings/sound/rt5682.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/sgtl5000.txt
Documentation/devicetree/bindings/sound/simple-amplifier.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tas571x.txt
Documentation/sound/soc/dpcm.rst
MAINTAINERS
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/plat-pxa/ssp.c
drivers/ata/pata_pxa.c
drivers/clk/clk.c
drivers/dma/pxa_dma.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/intel_audio.c
drivers/media/platform/pxa_camera.c
drivers/mmc/host/pxamci.c
drivers/mtd/nand/raw/marvell_nand.c
include/drm/drm_audio_component.h [new file with mode: 0644]
include/drm/i915_component.h
include/linux/clk-provider.h
include/linux/clk.h
include/linux/dma/pxa-dma.h
include/linux/platform_data/mmp_dma.h
include/linux/pxa2xx_ssp.h
include/sound/ac97/codec.h
include/sound/ac97/compat.h
include/sound/ac97/controller.h
include/sound/ac97/regs.h
include/sound/ac97_codec.h
include/sound/compress_driver.h
include/sound/dmaengine_pcm.h
include/sound/hda_component.h [new file with mode: 0644]
include/sound/hda_i915.h
include/sound/hdaudio.h
include/sound/hdaudio_ext.h
include/sound/memalloc.h
include/sound/pcm_params.h
include/sound/pxa2xx-lib.h
include/sound/rt5682.h [new file with mode: 0644]
include/sound/sh_fsi.h
include/sound/simple_card.h
include/sound/simple_card_utils.h
include/sound/soc-acpi-intel-match.h
include/sound/soc-acpi.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc-dpcm.h
include/sound/soc-topology.h
include/sound/soc.h
include/trace/events/clk.h
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/pxa2xx-ac97-lib.c
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm-lib.c
sound/arm/pxa2xx-pcm.c [deleted file]
sound/arm/pxa2xx-pcm.h [deleted file]
sound/hda/Kconfig
sound/hda/Makefile
sound/hda/ext/hdac_ext_bus.c
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_stream.c
sound/hda/hdac_component.c [new file with mode: 0644]
sound/hda/hdac_i915.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/patch_hdmi.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/amd/Kconfig
sound/soc/amd/acp-da7219-max98357a.c
sound/soc/amd/acp-pcm-dma.c
sound/soc/amd/acp.h
sound/soc/atmel/atmel-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau17x1.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4458.c
sound/soc/codecs/ak4554.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak5558.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs47l24.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da7219-aad.c
sound/soc/codecs/da7219.c
sound/soc/codecs/da7219.h
sound/soc/codecs/da9055.c
sound/soc/codecs/es7134.c
sound/soc/codecs/es7241.c [new file with mode: 0644]
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/max9850.c
sound/soc/codecs/nau8540.c
sound/soc/codecs/nau8824.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/pcm1789.c
sound/soc/codecs/pcm186x.c
sound/soc/codecs/rt1305.c
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5651.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5682.c [new file with mode: 0644]
sound/soc/codecs/rt5682.h [new file with mode: 0644]
sound/soc/codecs/simple-amplifier.c [moved from sound/soc/codecs/dio2125.c with 68% similarity]
sound/soc/codecs/tas571x.c
sound/soc/codecs/tas571x.h
sound/soc/codecs/tda7419.c
sound/soc/codecs/tscs42xx.c
sound/soc/codecs/tscs42xx.h
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100-tables.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wmfw.h
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_asrc.h
sound/soc/fsl/fsl_asrc_dma.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_utils.c
sound/soc/fsl/fsl_utils.h
sound/soc/fsl/imx-sgtl5000.c
sound/soc/generic/audio-graph-card.c
sound/soc/generic/audio-graph-scu-card.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.c
sound/soc/generic/simple-scu-card.c
sound/soc/intel/atom/sst/sst_drv_interface.c
sound/soc/intel/atom/sst/sst_loader.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/glk_rt5682_max98357a.c [new file with mode: 0644]
sound/soc/intel/boards/kbl_da7219_max98357a.c
sound/soc/intel/boards/kbl_rt5663_max98927.c
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/common/Makefile
sound/soc/intel/common/soc-acpi-intel-bxt-match.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-byt-match.c
sound/soc/intel/common/soc-acpi-intel-cht-match.c
sound/soc/intel/common/soc-acpi-intel-cnl-match.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-glk-match.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
sound/soc/intel/common/soc-acpi-intel-kbl-match.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-skl-match.c [new file with mode: 0644]
sound/soc/intel/common/sst-firmware.c
sound/soc/intel/haswell/sst-haswell-dsp.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-cldma.c
sound/soc/intel/skylake/skl-sst-cldma.h
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/mediatek/common/mtk-afe-platform-driver.c
sound/soc/mediatek/common/mtk-base-afe.h
sound/soc/mediatek/mt6797/mt6797-afe-common.h
sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
sound/soc/mediatek/mt6797/mt6797-dai-adda.c
sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
sound/soc/meson/Kconfig [new file with mode: 0644]
sound/soc/meson/Makefile [new file with mode: 0644]
sound/soc/meson/axg-card.c [new file with mode: 0644]
sound/soc/meson/axg-fifo.c [new file with mode: 0644]
sound/soc/meson/axg-fifo.h [new file with mode: 0644]
sound/soc/meson/axg-frddr.c [new file with mode: 0644]
sound/soc/meson/axg-spdifout.c [new file with mode: 0644]
sound/soc/meson/axg-tdm-formatter.c [new file with mode: 0644]
sound/soc/meson/axg-tdm-formatter.h [new file with mode: 0644]
sound/soc/meson/axg-tdm-interface.c [new file with mode: 0644]
sound/soc/meson/axg-tdm.h [new file with mode: 0644]
sound/soc/meson/axg-tdmin.c [new file with mode: 0644]
sound/soc/meson/axg-tdmout.c [new file with mode: 0644]
sound/soc/meson/axg-toddr.c [new file with mode: 0644]
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-mcpdm.c
sound/soc/pxa/Kconfig
sound/soc/pxa/magician.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/zylonite.c
sound/soc/qcom/Kconfig
sound/soc/qcom/Makefile
sound/soc/qcom/apq8096.c
sound/soc/qcom/common.c [new file with mode: 0644]
sound/soc/qcom/common.h [new file with mode: 0644]
sound/soc/qcom/lpass-platform.c
sound/soc/qcom/qdsp6/q6adm.c
sound/soc/qcom/qdsp6/q6afe-dai.c
sound/soc/qcom/qdsp6/q6afe.c
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/qcom/qdsp6/q6asm.c
sound/soc/qcom/qdsp6/q6routing.c
sound/soc/qcom/sdm845.c [new file with mode: 0644]
sound/soc/rockchip/Makefile
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_pcm.c [new file with mode: 0644]
sound/soc/rockchip/rockchip_pcm.h [new file with mode: 0644]
sound/soc/rockchip/rockchip_rt5645.c
sound/soc/samsung/i2s.c
sound/soc/sh/Kconfig
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/sh/migor.c
sound/soc/sh/rcar/Makefile
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/cmd.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/siu.h
sound/soc/sh/siu_dai.c
sound/soc/sh/siu_pcm.c
sound/soc/sh/ssi.c
sound/soc/sirf/sirf-usp.c
sound/soc/soc-ac97.c
sound/soc/soc-acpi.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-devres.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-io.c
sound/soc/soc-jack.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/soc-utils.c
sound/soc/sti/uniperif_player.c
sound/soc/sti/uniperif_reader.c
sound/soc/stm/Kconfig
sound/soc/stm/stm32_adfsdm.c
sound/soc/stm/stm32_sai_sub.c
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_rt5677.c
sound/soc/uniphier/aio-core.c
sound/soc/uniphier/aio-cpu.c
sound/soc/uniphier/aio-ld11.c
sound/soc/uniphier/aio-reg.h
sound/soc/uniphier/aio.h
sound/soc/zte/zx-tdm.c

diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
new file mode 100644 (file)
index 0000000..3dfc251
--- /dev/null
@@ -0,0 +1,23 @@
+* Amlogic Audio FIFO controllers
+
+Required properties:
+- compatible: 'amlogic,axg-toddr' or
+             'amlogic,axg-frddr'
+- reg: physical base address of the controller and length of memory
+       mapped region.
+- interrupts: interrupt specifier for the fifo.
+- clocks: phandle to the fifo peripheral clock provided by the audio
+         clock controller.
+- resets: phandle to memory ARB line provided by the arb reset controller.
+- #sound-dai-cells: must be 0.
+
+Example of FRDDR A on the A113 SoC:
+
+frddr_a: audio-controller@1c0 {
+       compatible = "amlogic,axg-frddr";
+       reg = <0x0 0x1c0 0x0 0x1c>;
+       #sound-dai-cells = <0>;
+       interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
+       clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
+       resets = <&arb AXG_ARB_FRDDR_A>;
+};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.txt
new file mode 100644 (file)
index 0000000..80b4112
--- /dev/null
@@ -0,0 +1,124 @@
+Amlogic AXG sound card:
+
+Required properties:
+
+- compatible: "amlogic,axg-sound-card"
+- model : User specified audio sound card name, one string
+
+Optional properties:
+
+- audio-aux-devs : List of phandles pointing to auxiliary devices
+- audio-widgets : Please refer to widgets.txt.
+- audio-routing : A list of the connections between audio components.
+
+Subnodes:
+
+- dai-link: Container for dai-link level properties and the CODEC
+           sub-nodes. There should be at least one (and probably more)
+           subnode of this type.
+
+Required dai-link properties:
+
+- sound-dai: phandle and port of the CPU DAI.
+
+Required TDM Backend dai-link properties:
+- dai-format : CPU/CODEC common audio format
+
+Optional TDM Backend dai-link properties:
+- dai-tdm-slot-rx-mask-{0,1,2,3}: Receive direction slot masks
+- dai-tdm-slot-tx-mask-{0,1,2,3}: Transmit direction slot masks
+                                 When omitted, mask is assumed to have to no
+                                 slots. A valid must have at one slot, so at
+                                 least one these mask should be provided with
+                                 an enabled slot.
+- dai-tdm-slot-num : Please refer to tdm-slot.txt.
+                    If omitted, slot number is set to accommodate the largest
+                    mask provided.
+- dai-tdm-slot-width : Please refer to tdm-slot.txt. default to 32 if omitted.
+- mclk-fs : Multiplication factor between stream rate and mclk
+
+Backend dai-link subnodes:
+
+- codec: dai-link representing backend links should have at least one subnode.
+        One subnode for each codec of the dai-link.
+        dai-link representing frontend links have no codec, therefore have no
+        subnodes
+
+Required codec subnodes properties:
+
+- sound-dai: phandle and port of the CODEC DAI.
+
+Optional codec subnodes properties:
+
+- dai-tdm-slot-tx-mask : Please refer to tdm-slot.txt.
+- dai-tdm-slot-rx-mask : Please refer to tdm-slot.txt.
+
+Example:
+
+sound {
+       compatible = "amlogic,axg-sound-card";
+       model = "AXG-S420";
+       audio-aux-devs = <&tdmin_a>, <&tdmout_c>;
+       audio-widgets = "Line", "Lineout",
+                       "Line", "Linein",
+                       "Speaker", "Speaker1 Left",
+                       "Speaker", "Speaker1 Right";
+                       "Speaker", "Speaker2 Left",
+                       "Speaker", "Speaker2 Right";
+       audio-routing = "TDMOUT_C IN 0", "FRDDR_A OUT 2",
+                       "SPDIFOUT IN 0", "FRDDR_A OUT 3",
+                       "TDM_C Playback", "TDMOUT_C OUT",
+                       "TDMIN_A IN 2", "TDM_C Capture",
+                       "TDMIN_A IN 5", "TDM_C Loopback",
+                       "TODDR_A IN 0", "TDMIN_A OUT",
+                       "Lineout", "Lineout AOUTL",
+                       "Lineout", "Lineout AOUTR",
+                       "Speaker1 Left", "SPK1 OUT_A",
+                       "Speaker2 Left", "SPK2 OUT_A",
+                       "Speaker1 Right", "SPK1 OUT_B",
+                       "Speaker2 Right", "SPK2 OUT_B",
+                       "Linein AINL", "Linein",
+                       "Linein AINR", "Linein";
+
+       dai-link@0 {
+               sound-dai = <&frddr_a>;
+       };
+
+       dai-link@1 {
+               sound-dai = <&toddr_a>;
+       };
+
+       dai-link@2 {
+               sound-dai = <&tdmif_c>;
+               dai-format = "i2s";
+               dai-tdm-slot-tx-mask-2 = <1 1>;
+               dai-tdm-slot-tx-mask-3 = <1 1>;
+               dai-tdm-slot-rx-mask-1 = <1 1>;
+               mclk-fs = <256>;
+
+               codec@0 {
+                       sound-dai = <&lineout>;
+               };
+
+               codec@1 {
+                       sound-dai = <&speaker_amp1>;
+               };
+
+               codec@2 {
+                       sound-dai = <&speaker_amp2>;
+               };
+
+               codec@3 {
+                       sound-dai = <&linein>;
+               };
+
+       };
+
+       dai-link@3 {
+               sound-dai = <&spdifout>;
+
+               codec {
+                       sound-dai = <&spdif_dit>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt
new file mode 100644 (file)
index 0000000..521c38a
--- /dev/null
@@ -0,0 +1,20 @@
+* Amlogic Audio SPDIF Output
+
+Required properties:
+- compatible: 'amlogic,axg-spdifout'
+- clocks: list of clock phandle, one for each entry clock-names.
+- clock-names: should contain the following:
+  * "pclk" : peripheral clock.
+  * "mclk" : master clock
+- #sound-dai-cells: must be 0.
+
+Example on the A113 SoC:
+
+spdifout: audio-controller@480 {
+       compatible = "amlogic,axg-spdifout";
+       reg = <0x0 0x480 0x0 0x50>;
+       #sound-dai-cells = <0>;
+       clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>,
+                <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>;
+       clock-names = "pclk", "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt
new file mode 100644 (file)
index 0000000..1c1b749
--- /dev/null
@@ -0,0 +1,28 @@
+* Amlogic Audio TDM formatters
+
+Required properties:
+- compatible: 'amlogic,axg-tdmin' or
+             'amlogic,axg-tdmout'
+- reg: physical base address of the controller and length of memory
+       mapped region.
+- clocks: list of clock phandle, one for each entry clock-names.
+- clock-names: should contain the following:
+  * "pclk"     : peripheral clock.
+  * "sclk"     : bit clock.
+  * "sclk_sel" : bit clock input multiplexer.
+  * "lrclk"    : sample clock
+  * "lrclk_sel": sample clock input multiplexer
+
+Example of TDMOUT_A on the A113 SoC:
+
+tdmout_a: audio-controller@500 {
+       compatible = "amlogic,axg-tdmout";
+       reg = <0x0 0x500 0x0 0x40>;
+       clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>,
+                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>,
+                <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>,
+                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>,
+                <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>;
+       clock-names = "pclk", "sclk", "sclk_sel",
+                     "lrclk", "lrclk_sel";
+};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-iface.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-iface.txt
new file mode 100644 (file)
index 0000000..cabfb26
--- /dev/null
@@ -0,0 +1,22 @@
+* Amlogic Audio TDM Interfaces
+
+Required properties:
+- compatible: 'amlogic,axg-tdm-iface'
+- clocks: list of clock phandle, one for each entry clock-names.
+- clock-names: should contain the following:
+  * "sclk" : bit clock.
+  * "lrclk": sample clock
+  * "mclk" : master clock
+            -> optional if the interface is in clock slave mode.
+- #sound-dai-cells: must be 0.
+
+Example of TDM_A on the A113 SoC:
+
+tdmif_a: audio-controller@0 {
+       compatible = "amlogic,axg-tdm-iface";
+       #sound-dai-cells = <0>;
+       clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>,
+                <&clkc_audio AUD_CLKID_MST_A_SCLK>,
+                <&clkc_audio AUD_CLKID_MST_A_LRCLK>;
+       clock-names = "mclk", "sclk", "lrclk";
+};
index 735368b8a73fe5149fbb13f03741fecf6dad4094..40549f496a81ccdfb59d49da32682ab8cba2107f 100644 (file)
@@ -15,7 +15,6 @@ Required properties:
 - clock-names:    Should be one of each entry matching the clocks phandles list:
                   - "pclk" (peripheral clock) Required.
                   - "gclk" (generated clock) Optional (1).
-                  - "aclk" (Audio PLL clock) Optional (1).
                   - "muxclk" (I2S mux clock) Optional (1).
 
 Optional properties:
@@ -23,9 +22,9 @@ Optional properties:
 - princtrl-names: Should contain only one value - "default".
 
 
-(1) : Only the peripheral clock is required. The generated clock, the Audio
-      PLL clock adn the I2S mux clock are optional and should only be set
-      together, when Master Mode is required.
+(1) : Only the peripheral clock is required. The generated clock and the I2S
+      mux clock are optional and should only be set together, when Master Mode
+      is required.
 
 Example:
 
@@ -40,8 +39,8 @@ Example:
                        (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
                         AT91_XDMAC_DT_PERID(32))>;
                dma-names = "tx", "rx";
-               clocks = <&i2s0_clk>, <&i2s0_gclk>, <&audio_pll_pmc>, <&i2s0muxck>;
-               clock-names = "pclk", "gclk", "aclk", "muxclk";
+               clocks = <&i2s0_clk>, <&i2s0_gclk>, <&i2s0muxck>;
+               clock-names = "pclk", "gclk", "muxclk";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_i2s0_default>;
        };
index d04ea3b1a1dd5d7710da9c25b76372a8aadb6347..7e63e53a901c65db905b4ded8b46462de43a5267 100644 (file)
@@ -18,6 +18,8 @@ Below are same as Simple-Card.
 - bitclock-inversion
 - frame-inversion
 - mclk-fs
+- hp-det-gpio
+- mic-det-gpio
 - dai-tdm-slot-num
 - dai-tdm-slot-width
 - clocks / system-clock-frequency
diff --git a/Documentation/devicetree/bindings/sound/dioo,dio2125.txt b/Documentation/devicetree/bindings/sound/dioo,dio2125.txt
deleted file mode 100644 (file)
index 63dbfe0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-DIO2125 Audio Driver
-
-Required properties:
-- compatible : "dioo,dio2125"
-- enable-gpios : the gpio connected to the enable pin of the dio2125
-
-Example:
-
-amp: analog-amplifier {
-       compatible = "dioo,dio2125";
-       enable-gpios = <&gpio GPIOH_3 0>;
-};
index 5495a3cb8b7bc2b2e6fe7925038caa9b86040ede..091666069bde1e6d885a05346499fc0e651c7d34 100644 (file)
@@ -1,10 +1,15 @@
 ES7134 i2s DA converter
 
 Required properties:
-- compatible : "everest,es7134" or "everest,es7144"
+- compatible : "everest,es7134" or
+               "everest,es7144" or
+              "everest,es7154"
+- VDD-supply : regulator phandle for the VDD supply
+- PVDD-supply: regulator phandle for the PVDD supply for the es7154
 
 Example:
 
 i2s_codec: external-codec {
        compatible = "everest,es7134";
+       VDD-supply = <&vcc_5v>;
 };
diff --git a/Documentation/devicetree/bindings/sound/everest,es7241.txt b/Documentation/devicetree/bindings/sound/everest,es7241.txt
new file mode 100644 (file)
index 0000000..28f82cf
--- /dev/null
@@ -0,0 +1,28 @@
+ES7241 i2s AD converter
+
+Required properties:
+- compatible : "everest,es7241"
+- VDDP-supply: regulator phandle for the VDDA supply
+- VDDA-supply: regulator phandle for the VDDP supply
+- VDDD-supply: regulator phandle for the VDDD supply
+
+Optional properties:
+- reset-gpios: gpio connected to the reset pin
+- m0-gpios   : gpio connected to the m0 pin
+- m1-gpios   : gpio connected to the m1 pin
+- everest,sdout-pull-down:
+   Format used by the serial interface is controlled by pulling
+   the sdout. If the sdout is pulled down, leftj format is used.
+   If this property is not provided, sdout is assumed to pulled
+   up and i2s format is used
+
+Example:
+
+linein: audio-codec@2 {
+       #sound-dai-cells = <0>;
+       compatible = "everest,es7241";
+       VDDA-supply = <&vcc_3v3>;
+       VDDP-supply = <&vcc_3v3>;
+       VDDD-supply = <&vcc_3v3>;
+       reset-gpios = <&gpio GPIOH_42>;
+};
diff --git a/Documentation/devicetree/bindings/sound/marvell,pxa2xx-ac97.txt b/Documentation/devicetree/bindings/sound/marvell,pxa2xx-ac97.txt
new file mode 100644 (file)
index 0000000..2ea85d5
--- /dev/null
@@ -0,0 +1,27 @@
+Marvell PXA2xx audio complex
+
+This descriptions matches the AC97 controller found in pxa2xx and pxa3xx series.
+
+Required properties:
+  - compatible: should be one of the following:
+    "marvell,pxa250-ac97"
+    "marvell,pxa270-ac97"
+    "marvell,pxa300-ac97"
+  - reg: device MMIO address space
+  - interrupts: single interrupt generated by AC97 IP
+  - clocks: input clock of the AC97 IP, refer to clock-bindings.txt
+
+Optional properties:
+  - pinctrl-names, pinctrl-0: refer to pinctrl-bindings.txt
+  - reset-gpios: gpio used for AC97 reset, refer to gpio.txt
+
+Example:
+       ac97: sound@40500000 {
+               compatible = "marvell,pxa250-ac97";
+               reg = < 0x40500000 0x1000 >;
+               interrupts = <14>;
+               reset-gpios = <&gpio 113 GPIO_ACTIVE_HIGH>;
+               #sound-dai-cells = <1>;
+               pinctrl-names = "default";
+               pinctrl-0 = < &pmux_ac97_default >;
+       };
index 74c9ba6c2823d9d1dc0704bc7338f8b3414e2eca..93b982e9419fd9c6bdadd361c9266efb24f95422 100644 (file)
@@ -5,6 +5,14 @@ Required properties:
        compatible      Must be "mrvl,pxa-ssp-dai"
        port            A phandle reference to a PXA ssp upstream device
 
+Optional properties:
+
+       clock-names
+       clocks          Through "clock-names" and "clocks", external clocks
+                       can be configured. If a clock names "extclk" exists,
+                       it will be set to the mclk rate of the audio stream
+                       and be used as clock provider of the DAI.
+
 Example:
 
        /* upstream device */
diff --git a/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt b/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt
deleted file mode 100644 (file)
index 551fbb8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-DT bindings for ARM PXA2xx PCM platform driver
-
-This is just a dummy driver that registers the PXA ASoC platform driver.
-It does not have any resources assigned.
-
-Required properties:
-
-       - compatible            'mrvl,pxa-pcm-audio'
-
-Example:
-
-       pxa_pcm_audio: snd_soc_pxa_audio {
-               compatible = "mrvl,pxa-pcm-audio";
-       };
-
diff --git a/Documentation/devicetree/bindings/sound/name-prefix.txt b/Documentation/devicetree/bindings/sound/name-prefix.txt
new file mode 100644 (file)
index 0000000..6457759
--- /dev/null
@@ -0,0 +1,24 @@
+Name prefix:
+
+Card implementing the routing property define the connection between
+audio components as list of string pair. Component using the same
+sink/source names may use the name prefix property to prepend the
+name of their sinks/sources with the provided string.
+
+Optional name prefix property:
+- sound-name-prefix : string using as prefix for the sink/source names of
+                     the component.
+
+Example: Two instances of the same component.
+
+amp0: analog-amplifier@0 {
+       compatible = "simple-audio-amplifier";
+       enable-gpios = <&gpio GPIOH_3 0>;
+       sound-name-prefix = "FRONT";
+};
+
+amp1: analog-amplifier@1 {
+       compatible = "simple-audio-amplifier";
+       enable-gpios = <&gpio GPIOH_4 0>;
+       sound-name-prefix = "BACK";
+};
index c7600a93ab39e58bb62cc02e1f77a2d5132f1b08..c814e867850fac66010ca1c1e50410de899e08c2 100644 (file)
@@ -7,7 +7,7 @@ This binding describes the APQ8096 sound card, which uses qdsp for audio.
        Value type: <stringlist>
        Definition: must be "qcom,apq8096-sndcard"
 
-- qcom,audio-routing:
+- audio-routing:
        Usage: Optional
        Value type: <stringlist>
        Definition:  A list of the connections between audio components.
@@ -49,6 +49,12 @@ This binding describes the APQ8096 sound card, which uses qdsp for audio.
                        "DMIC1"
                        "DMIC2"
                        "DMIC3"
+
+- model:
+       Usage: required
+       Value type: <stringlist>
+       Definition: The user-visible name of this sound card.
+
 = dailinks
 Each subnode of sndcard represents either a dailink, and subnodes of each
 dailinks would be cpu/codec/platform dais.
@@ -79,11 +85,16 @@ dailinks would be cpu/codec/platform dais.
        Value type: <phandle with arguments>
        Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node.
 
+Obsolete:
+       qcom,model: String for soundcard name (Use model instead)
+       qcom,audio-routing: A list of the connections between audio components.
+                           (Use audio-routing instead)
+
 Example:
 
 audio {
        compatible = "qcom,apq8096-sndcard";
-       qcom,model = "DB820c";
+       model = "DB820c";
 
        mm1-dai-link {
                link-name = "MultiMedia1";
index cb709e5dbc44fb0238c143acf14acdb87169b05b..bbae426cdfb19d67f573b2dd4502f8e9480a1e05 100644 (file)
@@ -18,6 +18,11 @@ used by the apr service device.
 = ADM routing
 "routing" subnode of the ADM node represents adm routing specific configuration
 
+- compatible:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "qcom,q6adm-routing".
+
 - #sound-dai-cells
        Usage: required
        Value type: <u32>
@@ -28,6 +33,7 @@ q6adm@8 {
        compatible = "qcom,q6adm";
        reg = <APR_SVC_ADM>;
        q6routing: routing {
+               compatible = "qcom,q6adm-routing";
                #sound-dai-cells = <0>;
        };
 };
index bdbf87df8c0be3933604ff177607b3ee314c3d70..a8179409c1945a58bebe84ee86ab858a1d927386 100644 (file)
@@ -17,6 +17,11 @@ used by all apr services. Must contain the following properties.
 subnode of "dais" representing board specific dai setup.
 "dais" node should have following properties followed by dai children.
 
+- compatible:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "qcom,q6afe-dais"
+
 - #sound-dai-cells
        Usage: required
        Value type: <u32>
@@ -100,6 +105,7 @@ q6afe@4 {
        reg = <APR_SVC_AFE>;
 
        dais {
+               compatible = "qcom,q6afe-dais";
                #sound-dai-cells = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
index 2178eb91146f84a8ade34294f535df5240c6b6c5..f9c7bd8c1bc0fa8f3bb61cbe95ec09639d66122d 100644 (file)
@@ -17,6 +17,11 @@ used by the apr service device.
 = ASM DAIs (Digial Audio Interface)
 "dais" subnode of the ASM node represents dai specific configuration
 
+- compatible:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "qcom,q6asm-dais".
+
 - #sound-dai-cells
        Usage: required
        Value type: <u32>
@@ -28,6 +33,7 @@ q6asm@7 {
        compatible = "qcom,q6asm";
        reg = <APR_SVC_ASM>;
        q6asmdai: dais {
+               compatible = "qcom,q6asm-dais";
                #sound-dai-cells = <1>;
        };
 };
diff --git a/Documentation/devicetree/bindings/sound/qcom,sdm845.txt b/Documentation/devicetree/bindings/sound/qcom,sdm845.txt
new file mode 100644 (file)
index 0000000..408c483
--- /dev/null
@@ -0,0 +1,80 @@
+* Qualcomm Technologies Inc. SDM845 ASoC sound card driver
+
+This binding describes the SDM845 sound card, which uses qdsp for audio.
+
+- compatible:
+       Usage: required
+       Value type: <stringlist>
+       Definition: must be "qcom,sdm845-sndcard"
+
+- audio-routing:
+       Usage: Optional
+       Value type: <stringlist>
+       Definition:  A list of the connections between audio components.
+                 Each entry is a pair of strings, the first being the
+                 connection's sink, the second being the connection's
+                 source. Valid names could be power supplies, MicBias
+                 of codec and the jacks on the board.
+
+- model:
+       Usage: required
+       Value type: <stringlist>
+       Definition: The user-visible name of this sound card.
+
+= dailinks
+Each subnode of sndcard represents either a dailink, and subnodes of each
+dailinks would be cpu/codec/platform dais.
+
+- link-name:
+       Usage: required
+       Value type: <string>
+       Definition: User friendly name for dai link
+
+= CPU, PLATFORM, CODEC dais subnodes
+- cpu:
+       Usage: required
+       Value type: <subnode>
+       Definition: cpu dai sub-node
+
+- codec:
+       Usage: required
+       Value type: <subnode>
+       Definition: codec dai sub-node
+
+- platform:
+       Usage: Optional
+       Value type: <subnode>
+       Definition: platform dai sub-node
+
+- sound-dai:
+       Usage: required
+       Value type: <phandle>
+       Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node.
+
+Example:
+
+audio {
+       compatible = "qcom,sdm845-sndcard";
+       model = "sdm845-snd-card";
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active>;
+       pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep>;
+
+       mm1-dai-link {
+               link-name = "MultiMedia1";
+               cpu {
+                       sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
+               };
+       };
+
+       pri-mi2s-dai-link {
+               link-name = "PRI MI2S Playback";
+               cpu {
+                       sound-dai = <&q6afedai PRIMARY_MI2S_RX>;
+               };
+
+               platform {
+                       sound-dai = <&q6routing>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
new file mode 100644 (file)
index 0000000..1d8d49e
--- /dev/null
@@ -0,0 +1,123 @@
+QCOM WCD9335 Codec
+
+Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, supports
+Qualcomm Technologies, Inc. (QTI) multimedia solutions, including
+the MSM8996, MSM8976, and MSM8956 chipsets. It has in-built
+Soundwire controller, interrupt mux. It supports both I2S/I2C and
+SLIMbus audio interfaces.
+
+Required properties with SLIMbus Interface:
+
+- compatible:
+       Usage: required
+       Value type: <stringlist>
+       Definition: For SLIMbus interface it should be "slimMID,PID",
+                   textual representation of Manufacturer ID, Product Code,
+                   shall be in lower case hexadecimal with leading zeroes
+                   suppressed.  Refer to slimbus/bus.txt for details.
+                   Should be:
+                   "slim217,1a0" for MSM8996 and APQ8096 SoCs with SLIMbus.
+
+- reg
+       Usage: required
+       Value type: <u32 u32>
+       Definition: Should be ('Device index', 'Instance ID')
+
+- interrupts
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: Interrupts via WCD INTR1 and INTR2 pins
+
+- interrupt-names:
+       Usage: required
+       Value type: <String array>
+       Definition: Interrupt names of WCD INTR1 and INTR2
+       Should be: "intr1", "intr2"
+
+- reset-gpio:
+       Usage: required
+       Value type: <String Array>
+       Definition: Reset gpio line
+
+- qcom,ifd:
+       Usage: required
+       Value type: <phandle>
+       Definition: SLIM interface device
+
+- clocks:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: See clock-bindings.txt section "consumers". List of
+                three clock specifiers for mclk, mclk2 and slimbus clock.
+
+- clock-names:
+       Usage: required
+       Value type: <string>
+       Definition: Must contain "mclk", "mclk2" and "slimbus" strings.
+
+- vdd-buck-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: Should contain a reference to the 1.8V buck supply
+
+- vdd-buck-sido-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: Should contain a reference to the 1.8V SIDO buck supply
+
+- vdd-rx-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: Should contain a reference to the 1.8V rx supply
+
+- vdd-tx-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: Should contain a reference to the 1.8V tx supply
+
+- vdd-vbat-supply:
+       Usage: Optional
+       Value type: <phandle>
+       Definition: Should contain a reference to the vbat supply
+
+- vdd-micbias-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: Should contain a reference to the micbias supply
+
+- vdd-io-supply:
+       Usage: required
+       Value type: <phandle>
+       Definition: Should contain a reference to the 1.8V io supply
+
+- interrupt-controller:
+       Usage: required
+       Definition: Indicating that this is a interrupt controller
+
+- #interrupt-cells:
+       Usage: required
+       Value type: <int>
+       Definition: should be 1
+
+#sound-dai-cells
+       Usage: required
+       Value type: <u32>
+       Definition: Must be 1
+
+codec@1{
+       compatible = "slim217,1a0";
+       reg  = <1 0>;
+       interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "intr2"
+       reset-gpio = <&msmgpio 64 0>;
+       qcom,ifd  = <&wc9335_ifd>;
+       clock-names = "mclk", "native";
+       clocks = <&rpmcc RPM_SMD_DIV_CLK1>,
+                <&rpmcc RPM_SMD_BB_CLK1>;
+       vdd-buck-supply = <&pm8994_s4>;
+       vdd-rx-supply = <&pm8994_s4>;
+       vdd-buck-sido-supply = <&pm8994_s4>;
+       vdd-tx-supply = <&pm8994_s4>;
+       vdd-io-supply = <&pm8994_s4>;
+       #sound-dai-cells = <1>;
+}
index b86d790f630ff79a390f6ef004c7fe595acf44e9..9e764270c36b869768429950b6fabcb88a3e6f7d 100644 (file)
@@ -352,6 +352,7 @@ Required properties:
                                    - "renesas,rcar_sound-r8a7794" (R-Car E2)
                                    - "renesas,rcar_sound-r8a7795" (R-Car H3)
                                    - "renesas,rcar_sound-r8a7796" (R-Car M3-W)
+                                   - "renesas,rcar_sound-r8a77965" (R-Car M3-N)
 - reg                          : Should contain the register physical address.
                                  required register is
                                   SRU/ADG/SSI      if generation1
index b208a752576c1173669d2d408b60101d05b361ac..54aefab71f2cb1b3c4e276ff905a4fed8d8ab568 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
 
 - compatible: should be one of the following:
    - "rockchip,rk3066-i2s": for rk3066
+   - "rockchip,px30-i2s", "rockchip,rk3066-i2s": for px30
    - "rockchip,rk3036-i2s", "rockchip,rk3066-i2s": for rk3036
    - "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188
    - "rockchip,rk3228-i2s", "rockchip,rk3066-i2s": for rk3228
diff --git a/Documentation/devicetree/bindings/sound/rt5682.txt b/Documentation/devicetree/bindings/sound/rt5682.txt
new file mode 100644 (file)
index 0000000..312e9a1
--- /dev/null
@@ -0,0 +1,50 @@
+RT5682 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5682" or "realtek,rt5682i"
+
+- reg : The I2C address of the device.
+
+Optional properties:
+
+- interrupts : The CODEC's interrupt output.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using GPIO2 pin as dmic1 data pin
+  2: using GPIO5 pin as dmic1 data pin
+
+- realtek,dmic1-clk-pin
+  0: using GPIO1 pin as dmic1 clock pin
+  1: using GPIO3 pin as dmic1 clock pin
+
+- realtek,jd-src
+  0: No JD is used
+  1: using JD1 as JD source
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+
+Pins on the device (for linking into audio routes) for RT5682:
+
+  * DMIC L1
+  * DMIC R1
+  * IN1P
+  * HPOL
+  * HPOR
+
+Example:
+
+rt5682 {
+       compatible = "realtek,rt5682i";
+       reg = <0x1a>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(U, 6) GPIO_ACTIVE_HIGH>;
+       realtek,ldo1-en-gpios =
+               <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
+       realtek,dmic1-data-pin = <1>;
+       realtek,dmic1-clk-pin = <1>;
+       realtek,jd-src = <1>;
+};
index 0f214457476f2aa399925720ee8b42c934b89568..9c58f724396ab0881e851eaef1ed3a5902c14115 100644 (file)
@@ -17,7 +17,7 @@ Optional properties:
 
 - VDDD-supply : the regulator provider of VDDD
 
-- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs
+- micbias-resistor-k-ohms : the bias resistor to be used in kOhms
        The resistor can take values of 2k, 4k or 8k.
        If set to 0 it will be off.
        If this node is not mentioned or if the value is unknown, then
diff --git a/Documentation/devicetree/bindings/sound/simple-amplifier.txt b/Documentation/devicetree/bindings/sound/simple-amplifier.txt
new file mode 100644 (file)
index 0000000..8647eda
--- /dev/null
@@ -0,0 +1,12 @@
+Simple Amplifier Audio Driver
+
+Required properties:
+- compatible : "dioo,dio2125" or "simple-audio-amplifier"
+- enable-gpios : the gpio connected to the enable pin of the simple amplifier
+
+Example:
+
+amp: analog-amplifier {
+       compatible = "simple-audio-amplifier";
+       enable-gpios = <&gpio GPIOH_3 0>;
+};
index b4959f10b74b0c7f05f1511dbc88ef183d2f2599..7c8fd37c2f9e9da14740f78ae8801a01d086ec46 100644 (file)
@@ -7,6 +7,7 @@ powerdown (optional).
 Required properties:
 
 - compatible: should be one of the following:
+  - "ti,tas5707"
   - "ti,tas5711",
   - "ti,tas5717",
   - "ti,tas5719",
index 395e5a5162820e709c7d01e81b06010adc6acf4f..fe61e02277f801058da3166b5c58d69872598ccd 100644 (file)
@@ -254,9 +254,7 @@ configuration.
        channels->min = channels->max = 2;
 
        /* set DAI0 to 16 bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S16_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
        return 0;
   }
 
index 7cebd5bba8a8eb15305966228440f77174744a97..cb044950be72c93c216af443723120486c83dfe7 100644 (file)
@@ -13575,6 +13575,13 @@ L:     linux-block@vger.kernel.org
 S:     Maintained
 F:     drivers/block/skd*[ch]
 
+STI AUDIO (ASoC) DRIVERS
+M:     Arnaud Pouliquen <arnaud.pouliquen@st.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
+F:     sound/soc/sti/
+
 STI CEC DRIVER
 M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 S:     Maintained
@@ -13588,6 +13595,14 @@ T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/stk1160/
 
+STM32 AUDIO (ASoC) DRIVERS
+M:     Olivier Moysan <olivier.moysan@st.com>
+M:     Arnaud Pouliquen <arnaud.pouliquen@st.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/st,stm32-*.txt
+F:     sound/soc/stm/
+
 STM32 TIMER/LPTIMER DRIVERS
 M:     Fabrice Gasnier <fabrice.gasnier@st.com>
 S:     Maintained
index d7c9a8476d5717950f893f2d1e419083e8b7da18..5a16ea74e28a00820e6d3b92b0c2c3c73ebaa784 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/platform_data/i2c-pxa.h>
 
@@ -59,16 +60,6 @@ static struct resource pxamci_resources[] = {
                .end    = IRQ_MMC,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               .start  = 21,
-               .end    = 21,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start  = 22,
-               .end    = 22,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 static u64 pxamci_dmamask = 0xffffffffUL;
@@ -406,16 +397,6 @@ static struct resource pxa_ir_resources[] = {
                .end    = 0x40700023,
                .flags  = IORESOURCE_MEM,
        },
-       [5] = {
-               .start  = 17,
-               .end    = 17,
-               .flags  = IORESOURCE_DMA,
-       },
-       [6] = {
-               .start  = 18,
-               .end    = 18,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa_device_ficp = {
@@ -544,18 +525,6 @@ static struct resource pxa25x_resource_ssp[] = {
                .end    = IRQ_SSP,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 13,
-               .end    = 13,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 14,
-               .end    = 14,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa25x_device_ssp = {
@@ -582,18 +551,6 @@ static struct resource pxa25x_resource_nssp[] = {
                .end    = IRQ_NSSP,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 15,
-               .end    = 15,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 16,
-               .end    = 16,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa25x_device_nssp = {
@@ -620,18 +577,6 @@ static struct resource pxa25x_resource_assp[] = {
                .end    = IRQ_ASSP,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 23,
-               .end    = 23,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 24,
-               .end    = 24,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa25x_device_assp = {
@@ -750,18 +695,6 @@ static struct resource pxa27x_resource_ssp1[] = {
                .end    = IRQ_SSP,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 13,
-               .end    = 13,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 14,
-               .end    = 14,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa27x_device_ssp1 = {
@@ -788,18 +721,6 @@ static struct resource pxa27x_resource_ssp2[] = {
                .end    = IRQ_SSP2,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 15,
-               .end    = 15,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 16,
-               .end    = 16,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa27x_device_ssp2 = {
@@ -826,18 +747,6 @@ static struct resource pxa27x_resource_ssp3[] = {
                .end    = IRQ_SSP3,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 66,
-               .end    = 66,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 67,
-               .end    = 67,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa27x_device_ssp3 = {
@@ -894,16 +803,6 @@ static struct resource pxa3xx_resources_mci2[] = {
                .end    = IRQ_MMC2,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               .start  = 93,
-               .end    = 93,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start  = 94,
-               .end    = 94,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa3xx_device_mci2 = {
@@ -933,16 +832,6 @@ static struct resource pxa3xx_resources_mci3[] = {
                .end    = IRQ_MMC3,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               .start  = 100,
-               .end    = 100,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start  = 101,
-               .end    = 101,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 struct platform_device pxa3xx_device_mci3 = {
@@ -1020,18 +909,6 @@ static struct resource pxa3xx_resources_nand[] = {
                .end    = IRQ_NAND,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for Data DMA */
-               .start  = 97,
-               .end    = 97,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for Command DMA */
-               .start  = 99,
-               .end    = 99,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 static u64 pxa3xx_nand_dma_mask = DMA_BIT_MASK(32);
@@ -1065,18 +942,6 @@ static struct resource pxa3xx_resource_ssp4[] = {
                .end    = IRQ_SSP4,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* DRCMR for RX */
-               .start  = 2,
-               .end    = 2,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               /* DRCMR for TX */
-               .start  = 3,
-               .end    = 3,
-               .flags  = IORESOURCE_DMA,
-       },
 };
 
 /*
@@ -1202,11 +1067,6 @@ void __init pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info)
        platform_device_add(pd);
 }
 
-static struct mmp_dma_platdata pxa_dma_pdata = {
-       .dma_channels   = 0,
-       .nb_requestors  = 0,
-};
-
 static struct resource pxa_dma_resource[] = {
        [0] = {
                .start  = 0x40000000,
@@ -1233,9 +1093,7 @@ static struct platform_device pxa2xx_pxa_dma = {
        .resource       = pxa_dma_resource,
 };
 
-void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors)
+void __init pxa2xx_set_dmac_info(struct mmp_dma_platdata *dma_pdata)
 {
-       pxa_dma_pdata.dma_channels = nb_channels;
-       pxa_dma_pdata.nb_requestors = nb_requestors;
-       pxa_register_device(&pxa2xx_pxa_dma, &pxa_dma_pdata);
+       pxa_register_device(&pxa2xx_pxa_dma, dma_pdata);
 }
index 11263f7c455bae2bbcd192dfcb3e3c444c632c1b..498b07bc6a3ea6323d0afb87e71ef6bb6cfd2472 100644 (file)
@@ -1,4 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 */
+#define PDMA_FILTER_PARAM(_prio, _requestor) (&(struct pxad_param) { \
+       .prio = PXAD_PRIO_##_prio, .drcmr = _requestor })
+struct mmp_dma_platdata;
+
 extern struct platform_device pxa_device_pmu;
 extern struct platform_device pxa_device_mci;
 extern struct platform_device pxa3xx_device_mci2;
@@ -55,7 +59,7 @@ extern struct platform_device pxa3xx_device_gpio;
 extern struct platform_device pxa93x_device_gpio;
 
 void __init pxa_register_device(struct platform_device *dev, void *data);
-void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors);
+void __init pxa2xx_set_dmac_info(struct mmp_dma_platdata *dma_pdata);
 
 struct i2c_pxa_platform_data;
 extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
index ba431fad5c47fd4456871083c5f81092da6814da..ab8808ce7e219cd5d5fd16963aa5e81f3498fe1d 100644 (file)
@@ -16,6 +16,8 @@
  * initialization stuff for PXA machines which can be overridden later if
  * need be.
  */
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/gpio.h>
 #include <linux/gpio-pxa.h>
 #include <linux/module.h>
@@ -26,6 +28,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
+#include <linux/platform_data/mmp_dma.h>
 
 #include <asm/mach/map.h>
 #include <asm/suspend.h>
@@ -201,6 +204,39 @@ static struct platform_device *pxa25x_devices[] __initdata = {
        &pxa_device_asoc_platform,
 };
 
+static const struct dma_slave_map pxa25x_slave_map[] = {
+       /* PXA25x, PXA27x and PXA3xx common entries */
+       { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
+       { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
+       { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
+         PDMA_FILTER_PARAM(LOWEST, 10) },
+       { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
+       { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
+       { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+       { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+       { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+       { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+       { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
+       { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
+       { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
+       { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
+
+       /* PXA25x specific map */
+       { "pxa25x-ssp.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+       { "pxa25x-ssp.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+       { "pxa25x-nssp.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+       { "pxa25x-nssp.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+       { "pxa25x-nssp.2", "rx", PDMA_FILTER_PARAM(LOWEST, 23) },
+       { "pxa25x-nssp.2", "tx", PDMA_FILTER_PARAM(LOWEST, 24) },
+};
+
+static struct mmp_dma_platdata pxa25x_dma_pdata = {
+       .dma_channels   = 16,
+       .nb_requestors  = 40,
+       .slave_map      = pxa25x_slave_map,
+       .slave_map_cnt  = ARRAY_SIZE(pxa25x_slave_map),
+};
+
 static int __init pxa25x_init(void)
 {
        int ret = 0;
@@ -215,7 +251,7 @@ static int __init pxa25x_init(void)
                register_syscore_ops(&pxa2xx_mfp_syscore_ops);
 
                if (!of_have_populated_dt()) {
-                       pxa2xx_set_dmac_info(16, 40);
+                       pxa2xx_set_dmac_info(&pxa25x_dma_pdata);
                        pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
                        ret = platform_add_devices(pxa25x_devices,
                                                   ARRAY_SIZE(pxa25x_devices));
index 0c06f383ad52afa0ac977b48944cedd9c996c942..5a8990a9313d193fc98baba0d46e5b37d8b87f32 100644 (file)
@@ -11,6 +11,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/gpio.h>
 #include <linux/gpio-pxa.h>
 #include <linux/module.h>
@@ -23,6 +25,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/platform_data/i2c-pxa.h>
+#include <linux/platform_data/mmp_dma.h>
 
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
@@ -297,6 +300,40 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_pwm1,
 };
 
+static const struct dma_slave_map pxa27x_slave_map[] = {
+       /* PXA25x, PXA27x and PXA3xx common entries */
+       { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
+       { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
+       { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
+         PDMA_FILTER_PARAM(LOWEST, 10) },
+       { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
+       { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
+       { "pxa-ssp-dai.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+       { "pxa-ssp-dai.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+       { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+       { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+       { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
+       { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
+       { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
+       { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
+       { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 66) },
+       { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 67) },
+
+       /* PXA27x specific map */
+       { "pxa2xx-i2s", "rx", PDMA_FILTER_PARAM(LOWEST, 2) },
+       { "pxa2xx-i2s", "tx", PDMA_FILTER_PARAM(LOWEST, 3) },
+       { "pxa27x-camera.0", "CI_Y", PDMA_FILTER_PARAM(HIGHEST, 68) },
+       { "pxa27x-camera.0", "CI_U", PDMA_FILTER_PARAM(HIGHEST, 69) },
+       { "pxa27x-camera.0", "CI_V", PDMA_FILTER_PARAM(HIGHEST, 70) },
+};
+
+static struct mmp_dma_platdata pxa27x_dma_pdata = {
+       .dma_channels   = 32,
+       .nb_requestors  = 75,
+       .slave_map      = pxa27x_slave_map,
+       .slave_map_cnt  = ARRAY_SIZE(pxa27x_slave_map),
+};
+
 static int __init pxa27x_init(void)
 {
        int ret = 0;
@@ -313,7 +350,7 @@ static int __init pxa27x_init(void)
                if (!of_have_populated_dt()) {
                        pxa_register_device(&pxa27x_device_gpio,
                                            &pxa27x_gpio_info);
-                       pxa2xx_set_dmac_info(32, 75);
+                       pxa2xx_set_dmac_info(&pxa27x_dma_pdata);
                        ret = platform_add_devices(devices,
                                                   ARRAY_SIZE(devices));
                }
index 8c64f93b669b9539dc691e325195740aac4d86d2..df9c8970adcf4a1edf98cc0f1856df9c2575ec67 100644 (file)
@@ -12,6 +12,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -24,6 +26,7 @@
 #include <linux/of.h>
 #include <linux/syscore_ops.h>
 #include <linux/platform_data/i2c-pxa.h>
+#include <linux/platform_data/mmp_dma.h>
 
 #include <asm/mach/map.h>
 #include <asm/suspend.h>
@@ -421,6 +424,42 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_pwm1,
 };
 
+static const struct dma_slave_map pxa3xx_slave_map[] = {
+       /* PXA25x, PXA27x and PXA3xx common entries */
+       { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
+       { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
+       { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
+         PDMA_FILTER_PARAM(LOWEST, 10) },
+       { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
+       { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
+       { "pxa-ssp-dai.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+       { "pxa-ssp-dai.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+       { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+       { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+       { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
+       { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
+       { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
+       { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
+       { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 66) },
+       { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 67) },
+
+       /* PXA3xx specific map */
+       { "pxa-ssp-dai.3", "rx", PDMA_FILTER_PARAM(LOWEST, 2) },
+       { "pxa-ssp-dai.3", "tx", PDMA_FILTER_PARAM(LOWEST, 3) },
+       { "pxa2xx-mci.1", "rx", PDMA_FILTER_PARAM(LOWEST, 93) },
+       { "pxa2xx-mci.1", "tx", PDMA_FILTER_PARAM(LOWEST, 94) },
+       { "pxa3xx-nand", "data", PDMA_FILTER_PARAM(LOWEST, 97) },
+       { "pxa2xx-mci.2", "rx", PDMA_FILTER_PARAM(LOWEST, 100) },
+       { "pxa2xx-mci.2", "tx", PDMA_FILTER_PARAM(LOWEST, 101) },
+};
+
+static struct mmp_dma_platdata pxa3xx_dma_pdata = {
+       .dma_channels   = 32,
+       .nb_requestors  = 100,
+       .slave_map      = pxa3xx_slave_map,
+       .slave_map_cnt  = ARRAY_SIZE(pxa3xx_slave_map),
+};
+
 static int __init pxa3xx_init(void)
 {
        int ret = 0;
@@ -456,7 +495,7 @@ static int __init pxa3xx_init(void)
                if (of_have_populated_dt())
                        return 0;
 
-               pxa2xx_set_dmac_info(32, 100);
+               pxa2xx_set_dmac_info(&pxa3xx_dma_pdata);
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
                if (ret)
                        return ret;
index ba13f793fbce45734b149e861481c0a33f996ac4..ed36dcab80f1e7fb1a89cb41bc05ed71a1afd66f 100644 (file)
@@ -127,53 +127,6 @@ static int pxa_ssp_probe(struct platform_device *pdev)
        if (IS_ERR(ssp->clk))
                return PTR_ERR(ssp->clk);
 
-       if (dev->of_node) {
-               struct of_phandle_args dma_spec;
-               struct device_node *np = dev->of_node;
-               int ret;
-
-               /*
-                * FIXME: we should allocate the DMA channel from this
-                * context and pass the channel down to the ssp users.
-                * For now, we lookup the rx and tx indices manually
-                */
-
-               /* rx */
-               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
-                                                0, &dma_spec);
-
-               if (ret) {
-                       dev_err(dev, "Can't parse dmas property\n");
-                       return -ENODEV;
-               }
-               ssp->drcmr_rx = dma_spec.args[0];
-               of_node_put(dma_spec.np);
-
-               /* tx */
-               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
-                                                1, &dma_spec);
-               if (ret) {
-                       dev_err(dev, "Can't parse dmas property\n");
-                       return -ENODEV;
-               }
-               ssp->drcmr_tx = dma_spec.args[0];
-               of_node_put(dma_spec.np);
-       } else {
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (res == NULL) {
-                       dev_err(dev, "no SSP RX DRCMR defined\n");
-                       return -ENODEV;
-               }
-               ssp->drcmr_rx = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (res == NULL) {
-                       dev_err(dev, "no SSP TX DRCMR defined\n");
-                       return -ENODEV;
-               }
-               ssp->drcmr_tx = res->start;
-       }
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(dev, "no memory resource defined\n");
index f6c46e9a4dc0f1425ae99b7fbf5dfa71d6a86eeb..e8b6a2e464c988e5eb5f586fa38fc426419b1678 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/libata.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
-#include <linux/dma/pxa-dma.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
@@ -180,8 +179,6 @@ static int pxa_ata_probe(struct platform_device *pdev)
        struct resource *irq_res;
        struct pata_pxa_pdata *pdata = dev_get_platdata(&pdev->dev);
        struct dma_slave_config config;
-       dma_cap_mask_t mask;
-       struct pxad_param param;
        int ret = 0;
 
        /*
@@ -278,10 +275,6 @@ static int pxa_ata_probe(struct platform_device *pdev)
 
        ap->private_data = data;
 
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       param.prio = PXAD_PRIO_LOWEST;
-       param.drcmr = pdata->dma_dreq;
        memset(&config, 0, sizeof(config));
        config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
        config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -294,8 +287,7 @@ static int pxa_ata_probe(struct platform_device *pdev)
         * Request the DMA channel
         */
        data->dma_chan =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &param, &pdev->dev, "data");
+               dma_request_slave_channel(&pdev->dev, "data");
        if (!data->dma_chan)
                return -EBUSY;
        ret = dmaengine_slave_config(data->dma_chan, &config);
index e2ed078abd90c7b0e775a4e8e510ab46151c82ef..976f59e11f9a65b8af5e8df3a85440a1a67dacc6 100644 (file)
@@ -67,6 +67,7 @@ struct clk_core {
        unsigned long           max_rate;
        unsigned long           accuracy;
        int                     phase;
+       struct clk_duty         duty;
        struct hlist_head       children;
        struct hlist_node       child_node;
        struct hlist_head       clks;
@@ -2401,6 +2402,172 @@ int clk_get_phase(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_get_phase);
 
+static void clk_core_reset_duty_cycle_nolock(struct clk_core *core)
+{
+       /* Assume a default value of 50% */
+       core->duty.num = 1;
+       core->duty.den = 2;
+}
+
+static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core);
+
+static int clk_core_update_duty_cycle_nolock(struct clk_core *core)
+{
+       struct clk_duty *duty = &core->duty;
+       int ret = 0;
+
+       if (!core->ops->get_duty_cycle)
+               return clk_core_update_duty_cycle_parent_nolock(core);
+
+       ret = core->ops->get_duty_cycle(core->hw, duty);
+       if (ret)
+               goto reset;
+
+       /* Don't trust the clock provider too much */
+       if (duty->den == 0 || duty->num > duty->den) {
+               ret = -EINVAL;
+               goto reset;
+       }
+
+       return 0;
+
+reset:
+       clk_core_reset_duty_cycle_nolock(core);
+       return ret;
+}
+
+static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core)
+{
+       int ret = 0;
+
+       if (core->parent &&
+           core->flags & CLK_DUTY_CYCLE_PARENT) {
+               ret = clk_core_update_duty_cycle_nolock(core->parent);
+               memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
+       } else {
+               clk_core_reset_duty_cycle_nolock(core);
+       }
+
+       return ret;
+}
+
+static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
+                                                struct clk_duty *duty);
+
+static int clk_core_set_duty_cycle_nolock(struct clk_core *core,
+                                         struct clk_duty *duty)
+{
+       int ret;
+
+       lockdep_assert_held(&prepare_lock);
+
+       if (clk_core_rate_is_protected(core))
+               return -EBUSY;
+
+       trace_clk_set_duty_cycle(core, duty);
+
+       if (!core->ops->set_duty_cycle)
+               return clk_core_set_duty_cycle_parent_nolock(core, duty);
+
+       ret = core->ops->set_duty_cycle(core->hw, duty);
+       if (!ret)
+               memcpy(&core->duty, duty, sizeof(*duty));
+
+       trace_clk_set_duty_cycle_complete(core, duty);
+
+       return ret;
+}
+
+static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
+                                                struct clk_duty *duty)
+{
+       int ret = 0;
+
+       if (core->parent &&
+           core->flags & (CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)) {
+               ret = clk_core_set_duty_cycle_nolock(core->parent, duty);
+               memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
+       }
+
+       return ret;
+}
+
+/**
+ * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
+ * @clk: clock signal source
+ * @num: numerator of the duty cycle ratio to be applied
+ * @den: denominator of the duty cycle ratio to be applied
+ *
+ * Apply the duty cycle ratio if the ratio is valid and the clock can
+ * perform this operation
+ *
+ * Returns (0) on success, a negative errno otherwise.
+ */
+int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den)
+{
+       int ret;
+       struct clk_duty duty;
+
+       if (!clk)
+               return 0;
+
+       /* sanity check the ratio */
+       if (den == 0 || num > den)
+               return -EINVAL;
+
+       duty.num = num;
+       duty.den = den;
+
+       clk_prepare_lock();
+
+       if (clk->exclusive_count)
+               clk_core_rate_unprotect(clk->core);
+
+       ret = clk_core_set_duty_cycle_nolock(clk->core, &duty);
+
+       if (clk->exclusive_count)
+               clk_core_rate_protect(clk->core);
+
+       clk_prepare_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_duty_cycle);
+
+static int clk_core_get_scaled_duty_cycle(struct clk_core *core,
+                                         unsigned int scale)
+{
+       struct clk_duty *duty = &core->duty;
+       int ret;
+
+       clk_prepare_lock();
+
+       ret = clk_core_update_duty_cycle_nolock(core);
+       if (!ret)
+               ret = mult_frac(scale, duty->num, duty->den);
+
+       clk_prepare_unlock();
+
+       return ret;
+}
+
+/**
+ * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal
+ * @clk: clock signal source
+ * @scale: scaling factor to be applied to represent the ratio as an integer
+ *
+ * Returns the duty cycle ratio of a clock node multiplied by the provided
+ * scaling factor, or negative errno on error.
+ */
+int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale)
+{
+       if (!clk)
+               return 0;
+
+       return clk_core_get_scaled_duty_cycle(clk->core, scale);
+}
+EXPORT_SYMBOL_GPL(clk_get_scaled_duty_cycle);
+
 /**
  * clk_is_match - check if two clk's point to the same hardware clock
  * @p: clk compared against q
@@ -2454,12 +2621,13 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
        if (!c)
                return;
 
-       seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n",
+       seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
                   level * 3 + 1, "",
                   30 - level * 3, c->name,
                   c->enable_count, c->prepare_count, c->protect_count,
                   clk_core_get_rate(c), clk_core_get_accuracy(c),
-                  clk_core_get_phase(c));
+                  clk_core_get_phase(c),
+                  clk_core_get_scaled_duty_cycle(c, 100000));
 }
 
 static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2481,9 +2649,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
        struct clk_core *c;
        struct hlist_head **lists = (struct hlist_head **)s->private;
 
-       seq_puts(s, "                                 enable  prepare  protect                               \n");
-       seq_puts(s, "   clock                          count    count    count        rate   accuracy   phase\n");
-       seq_puts(s, "----------------------------------------------------------------------------------------\n");
+       seq_puts(s, "                                 enable  prepare  protect                                duty\n");
+       seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle\n");
+       seq_puts(s, "---------------------------------------------------------------------------------------------\n");
 
        clk_prepare_lock();
 
@@ -2510,6 +2678,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
        seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
        seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
        seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
+       seq_printf(s, "\"duty_cycle\": %u",
+                  clk_core_get_scaled_duty_cycle(c, 100000));
 }
 
 static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
@@ -2571,6 +2741,7 @@ static const struct {
        ENTRY(CLK_SET_RATE_UNGATE),
        ENTRY(CLK_IS_CRITICAL),
        ENTRY(CLK_OPS_PARENT_ENABLE),
+       ENTRY(CLK_DUTY_CYCLE_PARENT),
 #undef ENTRY
 };
 
@@ -2609,6 +2780,17 @@ static int possible_parents_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(possible_parents);
 
+static int clk_duty_cycle_show(struct seq_file *s, void *data)
+{
+       struct clk_core *core = s->private;
+       struct clk_duty *duty = &core->duty;
+
+       seq_printf(s, "%u/%u\n", duty->num, duty->den);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle);
+
 static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
 {
        struct dentry *root;
@@ -2627,6 +2809,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
        debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
        debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
        debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
+       debugfs_create_file("clk_duty_cycle", 0444, root, core,
+                           &clk_duty_cycle_fops);
 
        if (core->num_parents > 1)
                debugfs_create_file("clk_possible_parents", 0444, root, core,
@@ -2844,6 +3028,11 @@ static int __clk_core_init(struct clk_core *core)
        else
                core->phase = 0;
 
+       /*
+        * Set clk's duty cycle.
+        */
+       clk_core_update_duty_cycle_nolock(core);
+
        /*
         * Set clk's rate.  The preferred method is to use .recalc_rate.  For
         * simple clocks and lazy developers the default fallback is to use the
index b53fb618bbf6b5a44043d470fe5ae3a55ddb4147..b31c28b67ad3ec6aef3babf5402defaac504f680 100644 (file)
@@ -179,6 +179,8 @@ static unsigned int pxad_drcmr(unsigned int line)
        return 0x1000 + line * 4;
 }
 
+bool pxad_filter_fn(struct dma_chan *chan, void *param);
+
 /*
  * Debug fs
  */
@@ -760,6 +762,8 @@ static void pxad_free_chan_resources(struct dma_chan *dchan)
        dma_pool_destroy(chan->desc_pool);
        chan->desc_pool = NULL;
 
+       chan->drcmr = U32_MAX;
+       chan->prio = PXAD_PRIO_LOWEST;
 }
 
 static void pxad_free_desc(struct virt_dma_desc *vd)
@@ -1384,6 +1388,9 @@ static int pxad_init_dmadev(struct platform_device *op,
                c = devm_kzalloc(&op->dev, sizeof(*c), GFP_KERNEL);
                if (!c)
                        return -ENOMEM;
+
+               c->drcmr = U32_MAX;
+               c->prio = PXAD_PRIO_LOWEST;
                c->vc.desc_free = pxad_free_desc;
                vchan_init(&c->vc, &pdev->slave);
                init_waitqueue_head(&c->wq_state);
@@ -1396,9 +1403,10 @@ static int pxad_probe(struct platform_device *op)
 {
        struct pxad_device *pdev;
        const struct of_device_id *of_id;
+       const struct dma_slave_map *slave_map = NULL;
        struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
        struct resource *iores;
-       int ret, dma_channels = 0, nb_requestors = 0;
+       int ret, dma_channels = 0, nb_requestors = 0, slave_map_cnt = 0;
        const enum dma_slave_buswidth widths =
                DMA_SLAVE_BUSWIDTH_1_BYTE   | DMA_SLAVE_BUSWIDTH_2_BYTES |
                DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1429,6 +1437,8 @@ static int pxad_probe(struct platform_device *op)
        } else if (pdata && pdata->dma_channels) {
                dma_channels = pdata->dma_channels;
                nb_requestors = pdata->nb_requestors;
+               slave_map = pdata->slave_map;
+               slave_map_cnt = pdata->slave_map_cnt;
        } else {
                dma_channels = 32;      /* default 32 channel */
        }
@@ -1440,6 +1450,9 @@ static int pxad_probe(struct platform_device *op)
        pdev->slave.device_prep_dma_memcpy = pxad_prep_memcpy;
        pdev->slave.device_prep_slave_sg = pxad_prep_slave_sg;
        pdev->slave.device_prep_dma_cyclic = pxad_prep_dma_cyclic;
+       pdev->slave.filter.map = slave_map;
+       pdev->slave.filter.mapcnt = slave_map_cnt;
+       pdev->slave.filter.fn = pxad_filter_fn;
 
        pdev->slave.copy_align = PDMA_ALIGNMENT;
        pdev->slave.src_addr_widths = widths;
index dfd95889f4b7ae1fa89366b766727c586b875d3f..5c607f2c707b6e0c4dab27d4bfcc052e1ca226d3 100644 (file)
@@ -23,6 +23,7 @@ config DRM_I915
        select SYNC_FILE
        select IOSF_MBI
        select CRC32
+       select SND_HDA_I915 if SND_HDA_CORE
        help
          Choose this option if you have a system that has "Intel Graphics
          Media Accelerator" or "HD Graphics" integrated graphics,
index 3ea566f99450e37f10317712b651b8104bda2a28..7dd5605d94ae8ae7a515e40ad056a2709d965a2d 100644 (file)
@@ -639,11 +639,12 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
        dev_priv->av_enc_map[pipe] = encoder;
        mutex_unlock(&dev_priv->av_mutex);
 
-       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+       if (acomp && acomp->base.audio_ops &&
+           acomp->base.audio_ops->pin_eld_notify) {
                /* audio drivers expect pipe = -1 to indicate Non-MST cases */
                if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
                        pipe = -1;
-               acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+               acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
                                                 (int) port, (int) pipe);
        }
 
@@ -681,11 +682,12 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
        dev_priv->av_enc_map[pipe] = NULL;
        mutex_unlock(&dev_priv->av_mutex);
 
-       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+       if (acomp && acomp->base.audio_ops &&
+           acomp->base.audio_ops->pin_eld_notify) {
                /* audio drivers expect pipe = -1 to indicate Non-MST cases */
                if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST))
                        pipe = -1;
-               acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+               acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
                                                 (int) port, (int) pipe);
        }
 
@@ -880,7 +882,7 @@ static int i915_audio_component_get_eld(struct device *kdev, int port,
        return ret;
 }
 
-static const struct i915_audio_component_ops i915_audio_component_ops = {
+static const struct drm_audio_component_ops i915_audio_component_ops = {
        .owner          = THIS_MODULE,
        .get_power      = i915_audio_component_get_power,
        .put_power      = i915_audio_component_put_power,
@@ -897,12 +899,12 @@ static int i915_audio_component_bind(struct device *i915_kdev,
        struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
        int i;
 
-       if (WARN_ON(acomp->ops || acomp->dev))
+       if (WARN_ON(acomp->base.ops || acomp->base.dev))
                return -EEXIST;
 
        drm_modeset_lock_all(&dev_priv->drm);
-       acomp->ops = &i915_audio_component_ops;
-       acomp->dev = i915_kdev;
+       acomp->base.ops = &i915_audio_component_ops;
+       acomp->base.dev = i915_kdev;
        BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
        for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
                acomp->aud_sample_rate[i] = 0;
@@ -919,8 +921,8 @@ static void i915_audio_component_unbind(struct device *i915_kdev,
        struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
 
        drm_modeset_lock_all(&dev_priv->drm);
-       acomp->ops = NULL;
-       acomp->dev = NULL;
+       acomp->base.ops = NULL;
+       acomp->base.dev = NULL;
        dev_priv->audio_component = NULL;
        drm_modeset_unlock_all(&dev_priv->drm);
 }
index d85ffbfb7c1fde9271f1e42ec28a31b205206a78..b6e9e93bde7a8ad635a32eab35fc4658610d571a 100644 (file)
@@ -2375,8 +2375,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
                .src_maxburst = 8,
                .direction = DMA_DEV_TO_MEM,
        };
-       dma_cap_mask_t mask;
-       struct pxad_param params;
        char clk_name[V4L2_CLK_NAME_SIZE];
        int irq;
        int err = 0, i;
@@ -2450,34 +2448,20 @@ static int pxa_camera_probe(struct platform_device *pdev)
        pcdev->base = base;
 
        /* request dma */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       dma_cap_set(DMA_PRIVATE, mask);
-
-       params.prio = 0;
-       params.drcmr = 68;
-       pcdev->dma_chans[0] =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &params, &pdev->dev, "CI_Y");
+       pcdev->dma_chans[0] = dma_request_slave_channel(&pdev->dev, "CI_Y");
        if (!pcdev->dma_chans[0]) {
                dev_err(&pdev->dev, "Can't request DMA for Y\n");
                return -ENODEV;
        }
 
-       params.drcmr = 69;
-       pcdev->dma_chans[1] =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &params, &pdev->dev, "CI_U");
+       pcdev->dma_chans[1] = dma_request_slave_channel(&pdev->dev, "CI_U");
        if (!pcdev->dma_chans[1]) {
                dev_err(&pdev->dev, "Can't request DMA for Y\n");
                err = -ENODEV;
                goto exit_free_dma_y;
        }
 
-       params.drcmr = 70;
-       pcdev->dma_chans[2] =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &params, &pdev->dev, "CI_V");
+       pcdev->dma_chans[2] = dma_request_slave_channel(&pdev->dev, "CI_V");
        if (!pcdev->dma_chans[2]) {
                dev_err(&pdev->dev, "Can't request DMA for V\n");
                err = -ENODEV;
index c763b404510f3a29d3864290297b22f596701cc3..6c94474e36f461eefac935c794879c297a62c94a 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/mmc/host.h>
@@ -637,10 +636,8 @@ static int pxamci_probe(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
        struct pxamci_host *host = NULL;
-       struct resource *r, *dmarx, *dmatx;
-       struct pxad_param param_rx, param_tx;
+       struct resource *r;
        int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
-       dma_cap_mask_t mask;
 
        ret = pxamci_of_init(pdev);
        if (ret)
@@ -739,34 +736,14 @@ static int pxamci_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, mmc);
 
-       if (!pdev->dev.of_node) {
-               dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (!dmarx || !dmatx) {
-                       ret = -ENXIO;
-                       goto out;
-               }
-               param_rx.prio = PXAD_PRIO_LOWEST;
-               param_rx.drcmr = dmarx->start;
-               param_tx.prio = PXAD_PRIO_LOWEST;
-               param_tx.drcmr = dmatx->start;
-       }
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       host->dma_chan_rx =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &param_rx, &pdev->dev, "rx");
+       host->dma_chan_rx = dma_request_slave_channel(&pdev->dev, "rx");
        if (host->dma_chan_rx == NULL) {
                dev_err(&pdev->dev, "unable to request rx dma channel\n");
                ret = -ENODEV;
                goto out;
        }
 
-       host->dma_chan_tx =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &param_tx,  &pdev->dev, "tx");
+       host->dma_chan_tx = dma_request_slave_channel(&pdev->dev, "tx");
        if (host->dma_chan_tx == NULL) {
                dev_err(&pdev->dev, "unable to request tx dma channel\n");
                ret = -ENODEV;
index ebb1d141b90000c069b0634fe0a3c4d5d5f842d4..00d9f29bbdb6148a1584d4d4c7d449c0066beee9 100644 (file)
@@ -2612,8 +2612,6 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
                                                    dev);
        struct dma_slave_config config = {};
        struct resource *r;
-       dma_cap_mask_t mask;
-       struct pxad_param param;
        int ret;
 
        if (!IS_ENABLED(CONFIG_PXA_DMA)) {
@@ -2626,20 +2624,7 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
        if (ret)
                return ret;
 
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!r) {
-               dev_err(nfc->dev, "No resource defined for data DMA\n");
-               return -ENXIO;
-       }
-
-       param.drcmr = r->start;
-       param.prio = PXAD_PRIO_LOWEST;
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       nfc->dma_chan =
-               dma_request_slave_channel_compat(mask, pxad_filter_fn,
-                                                &param, nfc->dev,
-                                                "data");
+       nfc->dma_chan = dma_request_slave_channel(nfc->dev, "data");
        if (!nfc->dma_chan) {
                dev_err(nfc->dev,
                        "Unable to request data DMA channel\n");
diff --git a/include/drm/drm_audio_component.h b/include/drm/drm_audio_component.h
new file mode 100644 (file)
index 0000000..4923b00
--- /dev/null
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: MIT
+// Copyright Â© 2014 Intel Corporation
+
+#ifndef _DRM_AUDIO_COMPONENT_H_
+#define _DRM_AUDIO_COMPONENT_H_
+
+struct drm_audio_component;
+
+/**
+ * struct drm_audio_component_ops - Ops implemented by DRM driver, called by hda driver
+ */
+struct drm_audio_component_ops {
+       /**
+        * @owner: drm module to pin down
+        */
+       struct module *owner;
+       /**
+        * @get_power: get the POWER_DOMAIN_AUDIO power well
+        *
+        * Request the power well to be turned on.
+        */
+       void (*get_power)(struct device *);
+       /**
+        * @put_power: put the POWER_DOMAIN_AUDIO power well
+        *
+        * Allow the power well to be turned off.
+        */
+       void (*put_power)(struct device *);
+       /**
+        * @codec_wake_override: Enable/disable codec wake signal
+        */
+       void (*codec_wake_override)(struct device *, bool enable);
+       /**
+        * @get_cdclk_freq: Get the Core Display Clock in kHz
+        */
+       int (*get_cdclk_freq)(struct device *);
+       /**
+        * @sync_audio_rate: set n/cts based on the sample rate
+        *
+        * Called from audio driver. After audio driver sets the
+        * sample rate, it will call this function to set n/cts
+        */
+       int (*sync_audio_rate)(struct device *, int port, int pipe, int rate);
+       /**
+        * @get_eld: fill the audio state and ELD bytes for the given port
+        *
+        * Called from audio driver to get the HDMI/DP audio state of the given
+        * digital port, and also fetch ELD bytes to the given pointer.
+        *
+        * It returns the byte size of the original ELD (not the actually
+        * copied size), zero for an invalid ELD, or a negative error code.
+        *
+        * Note that the returned size may be over @max_bytes.  Then it
+        * implies that only a part of ELD has been copied to the buffer.
+        */
+       int (*get_eld)(struct device *, int port, int pipe, bool *enabled,
+                      unsigned char *buf, int max_bytes);
+};
+
+/**
+ * struct drm_audio_component_audio_ops - Ops implemented by hda driver, called by DRM driver
+ */
+struct drm_audio_component_audio_ops {
+       /**
+        * @audio_ptr: Pointer to be used in call to pin_eld_notify
+        */
+       void *audio_ptr;
+       /**
+        * @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed
+        *
+        * Called when the DRM driver has set up audio pipeline or has just
+        * begun to tear it down. This allows the HDA driver to update its
+        * status accordingly (even when the HDA controller is in power save
+        * mode).
+        */
+       void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
+       /**
+        * @pin2port: Check and convert from pin node to port number
+        *
+        * Called by HDA driver to check and convert from the pin widget node
+        * number to a port number in the graphics side.
+        */
+       int (*pin2port)(void *audio_ptr, int pin);
+       /**
+        * @master_bind: (Optional) component master bind callback
+        *
+        * Called at binding master component, for HDA codec-specific
+        * handling of dynamic binding.
+        */
+       int (*master_bind)(struct device *dev, struct drm_audio_component *);
+       /**
+        * @master_unbind: (Optional) component master unbind callback
+        *
+        * Called at unbinding master component, for HDA codec-specific
+        * handling of dynamic unbinding.
+        */
+       void (*master_unbind)(struct device *dev, struct drm_audio_component *);
+};
+
+/**
+ * struct drm_audio_component - Used for direct communication between DRM and hda drivers
+ */
+struct drm_audio_component {
+       /**
+        * @dev: DRM device, used as parameter for ops
+        */
+       struct device *dev;
+       /**
+        * @ops: Ops implemented by DRM driver, called by hda driver
+        */
+       const struct drm_audio_component_ops *ops;
+       /**
+        * @audio_ops: Ops implemented by hda driver, called by DRM driver
+        */
+       const struct drm_audio_component_audio_ops *audio_ops;
+};
+
+#endif /* _DRM_AUDIO_COMPONENT_H_ */
index 346b1f5cb180c2618d3f9feb3b036d8e7bcdc55e..fca22d463e1bf707199bc0dbe8e77705c21c3a8b 100644 (file)
 #ifndef _I915_COMPONENT_H_
 #define _I915_COMPONENT_H_
 
+#include "drm_audio_component.h"
+
 /* MAX_PORT is the number of port
  * It must be sync with I915_MAX_PORTS defined i915_drv.h
  */
 #define MAX_PORTS 6
 
-/**
- * struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver
- */
-struct i915_audio_component_ops {
-       /**
-        * @owner: i915 module
-        */
-       struct module *owner;
-       /**
-        * @get_power: get the POWER_DOMAIN_AUDIO power well
-        *
-        * Request the power well to be turned on.
-        */
-       void (*get_power)(struct device *);
-       /**
-        * @put_power: put the POWER_DOMAIN_AUDIO power well
-        *
-        * Allow the power well to be turned off.
-        */
-       void (*put_power)(struct device *);
-       /**
-        * @codec_wake_override: Enable/disable codec wake signal
-        */
-       void (*codec_wake_override)(struct device *, bool enable);
-       /**
-        * @get_cdclk_freq: Get the Core Display Clock in kHz
-        */
-       int (*get_cdclk_freq)(struct device *);
-       /**
-        * @sync_audio_rate: set n/cts based on the sample rate
-        *
-        * Called from audio driver. After audio driver sets the
-        * sample rate, it will call this function to set n/cts
-        */
-       int (*sync_audio_rate)(struct device *, int port, int pipe, int rate);
-       /**
-        * @get_eld: fill the audio state and ELD bytes for the given port
-        *
-        * Called from audio driver to get the HDMI/DP audio state of the given
-        * digital port, and also fetch ELD bytes to the given pointer.
-        *
-        * It returns the byte size of the original ELD (not the actually
-        * copied size), zero for an invalid ELD, or a negative error code.
-        *
-        * Note that the returned size may be over @max_bytes.  Then it
-        * implies that only a part of ELD has been copied to the buffer.
-        */
-       int (*get_eld)(struct device *, int port, int pipe, bool *enabled,
-                      unsigned char *buf, int max_bytes);
-};
-
-/**
- * struct i915_audio_component_audio_ops - Ops implemented by hda driver, called by i915 driver
- */
-struct i915_audio_component_audio_ops {
-       /**
-        * @audio_ptr: Pointer to be used in call to pin_eld_notify
-        */
-       void *audio_ptr;
-       /**
-        * @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed
-        *
-        * Called when the i915 driver has set up audio pipeline or has just
-        * begun to tear it down. This allows the HDA driver to update its
-        * status accordingly (even when the HDA controller is in power save
-        * mode).
-        */
-       void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
-};
-
 /**
  * struct i915_audio_component - Used for direct communication between i915 and hda drivers
  */
 struct i915_audio_component {
        /**
-        * @dev: i915 device, used as parameter for ops
+        * @base: the drm_audio_component base class
         */
-       struct device *dev;
+       struct drm_audio_component      base;
+
        /**
         * @aud_sample_rate: the array of audio sample rate per port
         */
        int aud_sample_rate[MAX_PORTS];
-       /**
-        * @ops: Ops implemented by i915 driver, called by hda driver
-        */
-       const struct i915_audio_component_ops *ops;
-       /**
-        * @audio_ops: Ops implemented by hda driver, called by i915 driver
-        */
-       const struct i915_audio_component_audio_ops *audio_ops;
 };
 
 #endif /* _I915_COMPONENT_H_ */
index b7cfa037e593ef7b86048a5393d3cda6870e2c34..08b1aa70a38d30a30cb4ae0f58bf7a68be92b15b 100644 (file)
@@ -38,6 +38,8 @@
 #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
 /* parents need enable during gate/ungate, set rate and re-parent */
 #define CLK_OPS_PARENT_ENABLE  BIT(12)
+/* duty cycle call may be forwarded to the parent clock */
+#define CLK_DUTY_CYCLE_PARENT  BIT(13)
 
 struct clk;
 struct clk_hw;
@@ -66,6 +68,17 @@ struct clk_rate_request {
        struct clk_hw *best_parent_hw;
 };
 
+/**
+ * struct clk_duty - Struture encoding the duty cycle ratio of a clock
+ *
+ * @num:       Numerator of the duty cycle ratio
+ * @den:       Denominator of the duty cycle ratio
+ */
+struct clk_duty {
+       unsigned int num;
+       unsigned int den;
+};
+
 /**
  * struct clk_ops -  Callback operations for hardware clocks; these are to
  * be provided by the clock implementation, and will be called by drivers
@@ -169,6 +182,15 @@ struct clk_rate_request {
  *             by the second argument. Valid values for degrees are
  *             0-359. Return 0 on success, otherwise -EERROR.
  *
+ * @get_duty_cycle: Queries the hardware to get the current duty cycle ratio
+ *              of a clock. Returned values denominator cannot be 0 and must be
+ *              superior or equal to the numerator.
+ *
+ * @set_duty_cycle: Apply the duty cycle ratio to this clock signal specified by
+ *              the numerator (2nd argurment) and denominator (3rd  argument).
+ *              Argument must be a valid ratio (denominator > 0
+ *              and >= numerator) Return 0 on success, otherwise -EERROR.
+ *
  * @init:      Perform platform-specific initialization magic.
  *             This is not not used by any of the basic clock types.
  *             Please consider other ways of solving initialization problems
@@ -218,6 +240,10 @@ struct clk_ops {
                                           unsigned long parent_accuracy);
        int             (*get_phase)(struct clk_hw *hw);
        int             (*set_phase)(struct clk_hw *hw, int degrees);
+       int             (*get_duty_cycle)(struct clk_hw *hw,
+                                         struct clk_duty *duty);
+       int             (*set_duty_cycle)(struct clk_hw *hw,
+                                         struct clk_duty *duty);
        void            (*init)(struct clk_hw *hw);
        void            (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
 };
index 0dbd0885b2c238f88cb9f2243ff4ecf158113c23..4f750c481b82b29d05e136d9cea42e51e58199b9 100644 (file)
@@ -141,6 +141,27 @@ int clk_set_phase(struct clk *clk, int degrees);
  */
 int clk_get_phase(struct clk *clk);
 
+/**
+ * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
+ * @clk: clock signal source
+ * @num: numerator of the duty cycle ratio to be applied
+ * @den: denominator of the duty cycle ratio to be applied
+ *
+ * Adjust the duty cycle of a clock signal by the specified ratio. Returns 0 on
+ * success, -EERROR otherwise.
+ */
+int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den);
+
+/**
+ * clk_get_duty_cycle - return the duty cycle ratio of a clock signal
+ * @clk: clock signal source
+ * @scale: scaling factor to be applied to represent the ratio as an integer
+ *
+ * Returns the duty cycle ratio multiplied by the scale provided, otherwise
+ * returns -EERROR.
+ */
+int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale);
+
 /**
  * clk_is_match - check if two clk's point to the same hardware clock
  * @p: clk compared against q
@@ -183,6 +204,18 @@ static inline long clk_get_phase(struct clk *clk)
        return -ENOTSUPP;
 }
 
+static inline int clk_set_duty_cycle(struct clk *clk, unsigned int num,
+                                    unsigned int den)
+{
+       return -ENOTSUPP;
+}
+
+static inline unsigned int clk_get_scaled_duty_cycle(struct clk *clk,
+                                                    unsigned int scale)
+{
+       return 0;
+}
+
 static inline bool clk_is_match(const struct clk *p, const struct clk *q)
 {
        return p == q;
index e56ec7af4fd7ca1054dba37f0a1800c079d21d27..9fc594f69eff3e693cf4297fe33a1dd249048c94 100644 (file)
@@ -9,6 +9,15 @@ enum pxad_chan_prio {
        PXAD_PRIO_LOWEST,
 };
 
+/**
+ * struct pxad_param - dma channel request parameters
+ * @drcmr: requestor line number
+ * @prio: minimal mandatory priority of the channel
+ *
+ * If a requested channel is granted, its priority will be at least @prio,
+ * ie. if PXAD_PRIO_LOW is required, the requested channel will be either
+ * PXAD_PRIO_LOW, PXAD_PRIO_NORMAL or PXAD_PRIO_HIGHEST.
+ */
 struct pxad_param {
        unsigned int drcmr;
        enum pxad_chan_prio prio;
index d1397c8ed94eef8768fe096d1ef00cdf3d42e95e..6397b9c8149ae8d110e7c374a0257499914a3b2c 100644 (file)
 #ifndef MMP_DMA_H
 #define MMP_DMA_H
 
+struct dma_slave_map;
+
 struct mmp_dma_platdata {
        int dma_channels;
        int nb_requestors;
+       int slave_map_cnt;
+       const struct dma_slave_map *slave_map;
 };
 
 #endif /* MMP_DMA_H */
index 8461b18e4608f206b8982192e07760aadb739f42..13b4244d44c1f8ebf052a8f31f36671ca53a667d 100644 (file)
 #define SSACD_SCDB             (1 << 3)        /* SSPSYSCLK Divider Bypass */
 #define SSACD_ACPS(x)          ((x) << 4)      /* Audio clock PLL select */
 #define SSACD_ACDS(x)          ((x) << 0)      /* Audio clock divider select */
+#define SSACD_ACDS_1           (0)
+#define SSACD_ACDS_2           (1)
+#define SSACD_ACDS_4           (2)
+#define SSACD_ACDS_8           (3)
+#define SSACD_ACDS_16          (4)
+#define SSACD_ACDS_32          (5)
+#define SSACD_SCDB_4X          (0)
+#define SSACD_SCDB_1X          (1)
 #define SSACD_SCDX8            (1 << 7)        /* SYSCLK division ratio select */
 
 /* LPSS SSP */
@@ -212,8 +220,6 @@ struct ssp_device {
        int             type;
        int             use_count;
        int             irq;
-       int             drcmr_rx;
-       int             drcmr_tx;
 
        struct device_node      *of_node;
 };
index ec04be9ab119281b0b1f8f1dfdb9eedf6132448d..9792d25fa36928b8470bfd6891dbb98ebf401733 100644 (file)
@@ -1,10 +1,8 @@
-/*
- *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+/* SPDX-License-Identifier: GPL-2.0
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
  */
+
 #ifndef __SOUND_AC97_CODEC2_H
 #define __SOUND_AC97_CODEC2_H
 
index 1351cba40048e577ccfb19b7a7ee072b5690cd6f..57e19afa31ab5c63ab810ca94c6ec8627cfc911f 100644 (file)
@@ -1,14 +1,11 @@
-/*
- *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+/* SPDX-License-Identifier: GPL-2.0
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
  *
  * This file is for backward compatibility with snd_ac97 structure and its
  * multiple usages, such as the snd_ac97_bus and snd_ac97_build_ops.
- *
  */
+
 #ifndef AC97_COMPAT_H
 #define AC97_COMPAT_H
 
index b36ecdd64f14aca196dbb9a8791b751229c21ac9..06b5afb7fa6b9fedfd997a1e87634012470ce9c4 100644 (file)
@@ -1,10 +1,8 @@
-/*
- *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+/* SPDX-License-Identifier: GPL-2.0
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
  */
+
 #ifndef AC97_CONTROLLER_H
 #define AC97_CONTROLLER_H
 
index 9a4fa0c3264aac22ca794751e7144052e1fe0c35..843f73f3705aec45de3d007cf6ca449923e17274 100644 (file)
@@ -1,27 +1,11 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0+
+ *
  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *  Universal interface for Audio Codec '97
  *
  *  For more details look to AC '97 component specification revision 2.1
  *  by Intel Corporation (http://developer.intel.com).
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
  */
-
 /*
  *  AC'97 codec registers
  */
index 89d311a503d34802223b98dbb4e80c924afee0b8..cc383991c0fe59c774020c4bb4d487ca2e75bee8 100644 (file)
@@ -1,30 +1,15 @@
-#ifndef __SOUND_AC97_CODEC_H
-#define __SOUND_AC97_CODEC_H
-
-/*
+/* SPDX-License-Identifier: GPL-2.0+
+ *
  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *  Universal interface for Audio Codec '97
  *
  *  For more details look to AC '97 component specification revision 2.1
  *  by Intel Corporation (http://developer.intel.com).
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
  */
 
+#ifndef __SOUND_AC97_CODEC_H
+#define __SOUND_AC97_CODEC_H
+
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
index 9924bc9cbc7c26ea3cdb82478f66bad6ab45be18..ea8c93bbb0e05490b023fdf402e8aa1d2f76ceeb 100644 (file)
@@ -1,27 +1,12 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  *  compress_driver.h - compress offload driver definations
  *
  *  Copyright (C) 2011 Intel Corporation
  *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
  *             Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
  */
+
 #ifndef __COMPRESS_DRIVER_H
 #define __COMPRESS_DRIVER_H
 
index e3481eebdd98d860cebc21d462bdcd303fd4fdfc..2c4cfaa135a62eae880e7d7fd78eb611055a7bb5 100644 (file)
@@ -1,17 +1,9 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0+
+ *
  *  Copyright (C) 2012, Analog Devices Inc.
  *     Author: Lars-Peter Clausen <lars@metafoo.de>
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under  the terms of the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the License, or (at your
- *  option) any later version.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
  */
+
 #ifndef __SOUND_DMAENGINE_PCM_H__
 #define __SOUND_DMAENGINE_PCM_H__
 
diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h
new file mode 100644 (file)
index 0000000..78626cd
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+// HD-Audio helpers to sync with DRM driver
+
+#ifndef __SOUND_HDA_COMPONENT_H
+#define __SOUND_HDA_COMPONENT_H
+
+#include <drm/drm_audio_component.h>
+
+#ifdef CONFIG_SND_HDA_COMPONENT
+int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
+int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
+int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
+                            int dev_id, int rate);
+int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
+                          bool *audio_enabled, char *buffer, int max_bytes);
+int snd_hdac_acomp_init(struct hdac_bus *bus,
+                       const struct drm_audio_component_audio_ops *aops,
+                       int (*match_master)(struct device *, void *),
+                       size_t extra_size);
+int snd_hdac_acomp_exit(struct hdac_bus *bus);
+int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
+                                   const struct drm_audio_component_audio_ops *ops);
+#else
+static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
+{
+       return 0;
+}
+static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
+{
+       return 0;
+}
+static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
+                                          hda_nid_t nid, int dev_id, int rate)
+{
+       return 0;
+}
+static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
+                                        int dev_id, bool *audio_enabled,
+                                        char *buffer, int max_bytes)
+{
+       return -ENODEV;
+}
+static inline int snd_hdac_acomp_init(struct hdac_bus *bus,
+                                     const struct drm_audio_component_audio_ops *aops,
+                                     int (*match_master)(struct device *, void *),
+                                     size_t extra_size)
+{
+       return -ENODEV;
+}
+static inline int snd_hdac_acomp_exit(struct hdac_bus *bus)
+{
+       return 0;
+}
+static inline int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
+                                                 const struct drm_audio_component_audio_ops *ops)
+{
+       return -ENODEV;
+}
+#endif
+
+#endif /* __SOUND_HDA_COMPONENT_H */
index a94f5b6f92ac6bba9476b594d38da22a5a86a8a5..6b79614a893b90dceb92e3a2945af150ff234bea 100644 (file)
@@ -5,54 +5,23 @@
 #ifndef __SOUND_HDA_I915_H
 #define __SOUND_HDA_I915_H
 
-#include <drm/i915_component.h>
+#include "hda_component.h"
 
 #ifdef CONFIG_SND_HDA_I915
-int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
-int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
 void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
-int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
-                            int dev_id, int rate);
-int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
-                          bool *audio_enabled, char *buffer, int max_bytes);
 int snd_hdac_i915_init(struct hdac_bus *bus);
-int snd_hdac_i915_exit(struct hdac_bus *bus);
-int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *);
 #else
-static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
-{
-       return 0;
-}
-static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
-{
-       return 0;
-}
 static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
 {
 }
-static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
-                                          hda_nid_t nid, int dev_id, int rate)
-{
-       return 0;
-}
-static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
-                                        int dev_id, bool *audio_enabled,
-                                        char *buffer, int max_bytes)
-{
-       return -ENODEV;
-}
 static inline int snd_hdac_i915_init(struct hdac_bus *bus)
 {
        return -ENODEV;
 }
+#endif
 static inline int snd_hdac_i915_exit(struct hdac_bus *bus)
 {
-       return 0;
+       return snd_hdac_acomp_exit(bus);
 }
-static inline int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *ops)
-{
-       return -ENODEV;
-}
-#endif
 
 #endif /* __SOUND_HDA_I915_H */
index c052afc2754721a00e8afbc40fb73875e2962423..ab5ee3ef219852ca278d6db8fa6865dd8f80d16a 100644 (file)
@@ -188,6 +188,11 @@ struct hdac_driver {
        const struct hda_device_id *id_table;
        int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
        void (*unsol_event)(struct hdac_device *dev, unsigned int event);
+
+       /* fields used by ext bus APIs */
+       int (*probe)(struct hdac_device *dev);
+       int (*remove)(struct hdac_device *dev);
+       void (*shutdown)(struct hdac_device *dev);
 };
 
 #define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
@@ -208,6 +213,14 @@ struct hdac_bus_ops {
        int (*link_power)(struct hdac_bus *bus, bool enable);
 };
 
+/*
+ * ops used for ASoC HDA codec drivers
+ */
+struct hdac_ext_bus_ops {
+       int (*hdev_attach)(struct hdac_device *hdev);
+       int (*hdev_detach)(struct hdac_device *hdev);
+};
+
 /*
  * Lowlevel I/O operators
  */
@@ -250,11 +263,17 @@ struct hdac_rb {
  * @mlcap: MultiLink capabilities pointer
  * @gtscap: gts capabilities pointer
  * @drsmcap: dma resume capabilities pointer
+ * @num_streams: streams supported
+ * @idx: HDA link index
+ * @hlink_list: link list of HDA links
+ * @lock: lock for link mgmt
+ * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
  */
 struct hdac_bus {
        struct device *dev;
        const struct hdac_bus_ops *ops;
        const struct hdac_io_ops *io_ops;
+       const struct hdac_ext_bus_ops *ext_ops;
 
        /* h/w resources */
        unsigned long addr;
@@ -314,9 +333,19 @@ struct hdac_bus {
        spinlock_t reg_lock;
        struct mutex cmd_mutex;
 
-       /* i915 component interface */
-       struct i915_audio_component *audio_component;
-       int i915_power_refcount;
+       /* DRM component interface */
+       struct drm_audio_component *audio_component;
+       int drm_power_refcount;
+
+       /* parameters required for enhanced capabilities */
+       int num_streams;
+       int idx;
+
+       struct list_head hlink_list;
+
+       struct mutex lock;
+       bool cmd_dma_state;
+
 };
 
 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
index 9c14e21dda85cf94ee47e3faa9bef10a881dc650..f34aced69ca803207e2196d58fd8de70518a4534 100644 (file)
@@ -4,38 +4,16 @@
 
 #include <sound/hdaudio.h>
 
-/**
- * hdac_ext_bus: HDAC extended bus for extended HDA caps
- *
- * @bus: hdac bus
- * @num_streams: streams supported
- * @hlink_list: link list of HDA links
- * @lock: lock for link mgmt
- * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
- */
-struct hdac_ext_bus {
-       struct hdac_bus bus;
-       int num_streams;
-       int idx;
-
-       struct list_head hlink_list;
-
-       struct mutex lock;
-       bool cmd_dma_state;
-};
-
-int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
+int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
                      const struct hdac_bus_ops *ops,
-                     const struct hdac_io_ops *io_ops);
+                     const struct hdac_io_ops *io_ops,
+                     const struct hdac_ext_bus_ops *ext_ops);
 
-void snd_hdac_ext_bus_exit(struct hdac_ext_bus *sbus);
-int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *sbus, int addr);
+void snd_hdac_ext_bus_exit(struct hdac_bus *bus);
+int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
+                                               struct hdac_device *hdev);
 void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev);
-void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
-
-#define ebus_to_hbus(ebus)     (&(ebus)->bus)
-#define hbus_to_ebus(_bus) \
-       container_of(_bus, struct hdac_ext_bus, bus)
+void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus);
 
 #define HDA_CODEC_REV_EXT_ENTRY(_vid, _rev, _name, drv_data) \
        { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
@@ -44,14 +22,14 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
 #define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
        HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)
 
-void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
-void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);
+void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable);
+void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable);
 
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *chip,
+void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip,
                                 bool enable, int index);
 
-int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *bus);
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *bus,
+int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus);
+struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
                                                const char *codec_name);
 
 enum hdac_ext_stream_type {
@@ -100,28 +78,28 @@ struct hdac_ext_stream {
 #define stream_to_hdac_ext_stream(s) \
        container_of(s, struct hdac_ext_stream, hstream)
 
-void snd_hdac_ext_stream_init(struct hdac_ext_bus *bus,
+void snd_hdac_ext_stream_init(struct hdac_bus *bus,
                                struct hdac_ext_stream *stream, int idx,
                                int direction, int tag);
-int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
+int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
                int num_stream, int dir);
-void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus);
-void snd_hdac_link_free_all(struct hdac_ext_bus *ebus);
-struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_ext_bus *bus,
+void snd_hdac_stream_free_all(struct hdac_bus *bus);
+void snd_hdac_link_free_all(struct hdac_bus *bus);
+struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
                                           struct snd_pcm_substream *substream,
                                           int type);
 void snd_hdac_ext_stream_release(struct hdac_ext_stream *azx_dev, int type);
-void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *bus,
+void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
                                struct hdac_ext_stream *azx_dev, bool decouple);
-void snd_hdac_ext_stop_streams(struct hdac_ext_bus *sbus);
+void snd_hdac_ext_stop_streams(struct hdac_bus *bus);
 
-int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
                                 struct hdac_ext_stream *stream, u32 value);
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
                                 struct hdac_ext_stream *stream);
-void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
                                bool enable, int index);
-int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
                                struct hdac_ext_stream *stream, u32 value);
 int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);
 
@@ -144,17 +122,15 @@ struct hdac_ext_link {
 
 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
 int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
-int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus);
+int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus);
 void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
                                 int stream);
 void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
                                 int stream);
 
-int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
-                               struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
-                               struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);
 
 /* update register macro */
 #define snd_hdac_updatel(addr, reg, mask, val)         \
@@ -181,53 +157,12 @@ struct hda_dai_map {
        u32     maxbps;
 };
 
-#define HDA_MAX_NIDS 16
-
-/**
- * struct hdac_ext_device - HDAC Ext device
- *
- * @hdac: hdac core device
- * @nid_list - the dai map which matches the dai-name with the nid
- * @map_cur_idx - the idx in use in dai_map
- * @ops - the hda codec ops common to all codec drivers
- * @pvt_data - private data, for asoc contains asoc codec object
- */
-struct hdac_ext_device {
-       struct hdac_device hdev;
-       struct hdac_ext_bus *ebus;
-
-       /* soc-dai to nid map */
-       struct hda_dai_map nid_list[HDA_MAX_NIDS];
-       unsigned int map_cur_idx;
-
-       /* codec ops */
-       struct hdac_ext_codec_ops ops;
-
-       struct snd_card *card;
-       void *scodec;
-       void *private_data;
-};
-
 struct hdac_ext_dma_params {
        u32 format;
        u8 stream_tag;
 };
-#define to_ehdac_device(dev) (container_of((dev), \
-                                struct hdac_ext_device, hdev))
-/*
- * HD-audio codec base driver
- */
-struct hdac_ext_driver {
-       struct hdac_driver hdac;
-
-       int     (*probe)(struct hdac_ext_device *dev);
-       int     (*remove)(struct hdac_ext_device *dev);
-       void    (*shutdown)(struct hdac_ext_device *dev);
-};
-
-int snd_hda_ext_driver_register(struct hdac_ext_driver *drv);
-void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv);
 
-#define to_ehdac_driver(_drv) container_of(_drv, struct hdac_ext_driver, hdac)
+int snd_hda_ext_driver_register(struct hdac_driver *drv);
+void snd_hda_ext_driver_unregister(struct hdac_driver *drv);
 
 #endif /* __SOUND_HDAUDIO_EXT_H */
index 9c3db3dce32b4a5e3f0bd4a14d65eaa4556341bf..67561b9979150833b4b433a38a59aedc101df573 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef __SOUND_MEMALLOC_H
 #define __SOUND_MEMALLOC_H
 
+#include <asm/page.h>
+
 struct device;
 
 /*
@@ -67,6 +69,14 @@ struct snd_dma_buffer {
        void *private_data;     /* private for allocator; don't touch */
 };
 
+/*
+ * return the pages matching with the given byte size
+ */
+static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
+{
+       return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
 #ifdef CONFIG_SND_DMA_SGBUF
 /*
  * Scatter-Gather generic device pages
@@ -90,14 +100,6 @@ struct snd_sg_buf {
        struct device *dev;
 };
 
-/*
- * return the pages matching with the given byte size
- */
-static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
-{
-       return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-}
-
 /*
  * return the physical address at the corresponding offset
  */
index c704357775fc4ef077ef52fb27cfb97c75b378ee..2dd37cada7c088d7bd6c8b4bd35f18c28c63cc86 100644 (file)
@@ -87,6 +87,13 @@ static inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
        mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
 }
 
+/* Most of drivers need only this one */
+static inline void snd_mask_set_format(struct snd_mask *mask,
+                                      snd_pcm_format_t format)
+{
+       snd_mask_set(mask, (__force unsigned int)format);
+}
+
 static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
 {
        mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
@@ -369,8 +376,7 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
 static inline void
 params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
 {
-       snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT),
-               (__force int)fmt);
+       snd_mask_set_format(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
 }
 
 #endif /* __SOUND_PCM_PARAMS_H */
index 63f75450d3dbb9f09eb9c11a1984c6a1c8e8fea2..6758fc12fa84b4ada446868964ddc26ec77f3110 100644 (file)
@@ -8,20 +8,23 @@
 /* PCM */
 struct snd_pcm_substream;
 struct snd_pcm_hw_params;
+struct snd_soc_pcm_runtime;
 struct snd_pcm;
 
-extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+extern int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params);
-extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
 extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
 extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
-extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
-extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream);
-extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_open(struct snd_pcm_substream *substream);
+extern int pxa2xx_pcm_close(struct snd_pcm_substream *substream);
 extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
        struct vm_area_struct *vma);
 extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream);
 extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm);
+extern int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd);
+extern const struct snd_pcm_ops pxa2xx_pcm_ops;
 
 /* AC97 */
 
diff --git a/include/sound/rt5682.h b/include/sound/rt5682.h
new file mode 100644 (file)
index 0000000..0251797
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * linux/sound/rt5682.h -- Platform data for RT5682
+ *
+ * Copyright 2018 Realtek Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_RT5682_H
+#define __LINUX_SND_RT5682_H
+
+enum rt5682_dmic1_data_pin {
+       RT5682_DMIC1_NULL,
+       RT5682_DMIC1_DATA_GPIO2,
+       RT5682_DMIC1_DATA_GPIO5,
+};
+
+enum rt5682_dmic1_clk_pin {
+       RT5682_DMIC1_CLK_GPIO1,
+       RT5682_DMIC1_CLK_GPIO3,
+};
+
+enum rt5682_jd_src {
+       RT5682_JD_NULL,
+       RT5682_JD1,
+};
+
+struct rt5682_platform_data {
+
+       int ldo1_en; /* GPIO for LDO1_EN */
+
+       enum rt5682_dmic1_data_pin dmic1_data_pin;
+       enum rt5682_dmic1_clk_pin dmic1_clk_pin;
+       enum rt5682_jd_src jd_src;
+};
+
+#endif
+
index 7a9710b4b799cd057ec2319e16a9237586d1411a..89eafe23ef8871d742a001f29ec2bc670d42c041 100644 (file)
@@ -1,16 +1,13 @@
-#ifndef __SOUND_FSI_H
-#define __SOUND_FSI_H
-
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * Fifo-attached Serial Interface (FSI) support for SH7724
  *
  * Copyright (C) 2009 Renesas Solutions Corp.
  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
+#ifndef __SOUND_FSI_H
+#define __SOUND_FSI_H
+
 #include <linux/clk.h>
 #include <sound/soc.h>
 
index a6a2e1547092a8e232c27bf5a8778b4eaa63a1bb..d264e5463f22dfd62ac4add4a64f5a747e9d7729 100644 (file)
@@ -1,12 +1,9 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * ASoC simple sound card support
  *
  * Copyright (C) 2012 Renesas Solutions Corp.
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __SIMPLE_CARD_H
index 7e25afce6566fe315496979c9da9f6176d3fae20..8bc5e2d8b13c47e0512cc42fe8637735d06ef315 100644 (file)
@@ -1,17 +1,20 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * simple_card_utils.h
  *
  * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
+
 #ifndef __SIMPLE_CARD_UTILS_H
 #define __SIMPLE_CARD_UTILS_H
 
 #include <sound/soc.h>
 
+#define asoc_simple_card_init_hp(card, sjack, prefix) \
+       asoc_simple_card_init_jack(card, sjack, 1, prefix)
+#define asoc_simple_card_init_mic(card, sjack, prefix) \
+       asoc_simple_card_init_jack(card, sjack, 0, prefix)
+
 struct asoc_simple_dai {
        const char *name;
        unsigned int sysclk;
@@ -28,6 +31,12 @@ struct asoc_simple_card_data {
        u32 convert_channels;
 };
 
+struct asoc_simple_jack {
+       struct snd_soc_jack jack;
+       struct snd_soc_jack_pin pin;
+       struct snd_soc_jack_gpio gpio;
+};
+
 int asoc_simple_card_parse_daifmt(struct device *dev,
                                  struct device_node *node,
                                  struct device_node *codec,
@@ -107,4 +116,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
 int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
                                      char *prefix);
 
+int asoc_simple_card_init_jack(struct snd_soc_card *card,
+                              struct asoc_simple_jack *sjack,
+                              int is_hp, char *prefix);
+
 #endif /* __SIMPLE_CARD_UTILS_H */
index 9da6388c20a1cc6a5ab509b9800139583a495912..bb1d24b703fb05a09b751c1fa7d36177553250b8 100644 (file)
@@ -1,16 +1,6 @@
-
-/*
- * Copyright (C) 2017, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+/* SPDX-License-Identifier: GPL-2.0
  *
+ * Copyright (C) 2017, Intel Corporation. All rights reserved.
  */
 
 #ifndef __LINUX_SND_SOC_ACPI_INTEL_MATCH_H
@@ -29,5 +19,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_legacy_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
 
 #endif
index 082224275f5232256819f4f4316886e0965c5a79..e45b2330d16a458b638f08dcdcdd87a4f87f76b0 100644 (file)
@@ -1,15 +1,6 @@
-/*
- * Copyright (C) 2013-15, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+/* SPDX-License-Identifier: GPL-2.0
  *
+ * Copyright (C) 2013-15, Intel Corporation. All rights reserved.
  */
 
 #ifndef __LINUX_SND_SOC_ACPI_H
index e6f8c40ed43c3f1615aaad20af4e467a3bc937e5..f5d70041108f75d45098ca21b1a3c1ee9610ff98 100644 (file)
@@ -1,12 +1,9 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * linux/sound/soc-dai.h -- ALSA SoC Layer
  *
  * Copyright:  2005-2008 Wolfson Microelectronics. PLC.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
  * Digital Audio Interface (DAI) API.
  */
 
@@ -141,6 +138,11 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
                             int direction);
 
+
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+               unsigned int *tx_num, unsigned int *tx_slot,
+               unsigned int *rx_num, unsigned int *rx_slot);
+
 int snd_soc_dai_is_dummy(struct snd_soc_dai *dai);
 
 struct snd_soc_dai_ops {
@@ -168,6 +170,9 @@ struct snd_soc_dai_ops {
        int (*set_channel_map)(struct snd_soc_dai *dai,
                unsigned int tx_num, unsigned int *tx_slot,
                unsigned int rx_num, unsigned int *rx_slot);
+       int (*get_channel_map)(struct snd_soc_dai *dai,
+                       unsigned int *tx_num, unsigned int *tx_slot,
+                       unsigned int *rx_num, unsigned int *rx_slot);
        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
 
        int (*set_sdw_stream)(struct snd_soc_dai *dai,
index a6ce2de4e20a837c79745c79cc7559a517a157fb..af9ef16cc34d36f6fd314cc2522997a4b2dbc12f 100644 (file)
@@ -1,13 +1,10 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
  *
- * Author:             Liam Girdwood
- * Created:            Aug 11th 2005
+ * Author:     Liam Girdwood
+ * Created:    Aug 11th 2005
  * Copyright:  Wolfson Microelectronics. PLC.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __LINUX_SND_SOC_DAPM_H
index 806059052bfcca4aa9d46ff3b0f061442136e84f..9bb92f187af87a3f8d7196c7580320792af35137 100644 (file)
@@ -1,11 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * linux/sound/soc-dpcm.h -- ALSA SoC Dynamic PCM Support
  *
  * Author:             Liam Girdwood <lrg@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __LINUX_SND_SOC_DPCM_H
index f552c3f56368c48a524e8889f5dabbc09f45d509..fa4b8413d2e222dd51e884f69e563c010b854980 100644 (file)
@@ -1,13 +1,10 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * linux/sound/soc-topology.h -- ALSA SoC Firmware Controls and DAPM
  *
  * Copyright (C) 2012 Texas Instruments Inc.
  * Copyright (C) 2015 Intel Corporation.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
  * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
  * algorithms, equalisers, DAIs, widgets, FE caps, BE caps, codec link caps etc.
  */
@@ -30,6 +27,9 @@ struct snd_soc_dapm_context;
 struct snd_soc_card;
 struct snd_kcontrol_new;
 struct snd_soc_dai_link;
+struct snd_soc_dai_driver;
+struct snd_soc_dai;
+struct snd_soc_dapm_route;
 
 /* object scan be loaded and unloaded in groups with identfying indexes */
 #define SND_SOC_TPLG_INDEX_ALL 0       /* ID that matches all FW objects */
@@ -109,35 +109,44 @@ struct snd_soc_tplg_widget_events {
 struct snd_soc_tplg_ops {
 
        /* external kcontrol init - used for any driver specific init */
-       int (*control_load)(struct snd_soc_component *,
+       int (*control_load)(struct snd_soc_component *, int index,
                struct snd_kcontrol_new *, struct snd_soc_tplg_ctl_hdr *);
        int (*control_unload)(struct snd_soc_component *,
                struct snd_soc_dobj *);
 
+       /* DAPM graph route element loading and unloading */
+       int (*dapm_route_load)(struct snd_soc_component *, int index,
+               struct snd_soc_dapm_route *route);
+       int (*dapm_route_unload)(struct snd_soc_component *,
+               struct snd_soc_dobj *);
+
        /* external widget init - used for any driver specific init */
-       int (*widget_load)(struct snd_soc_component *,
+       int (*widget_load)(struct snd_soc_component *, int index,
                struct snd_soc_dapm_widget *,
                struct snd_soc_tplg_dapm_widget *);
-       int (*widget_ready)(struct snd_soc_component *,
+       int (*widget_ready)(struct snd_soc_component *, int index,
                struct snd_soc_dapm_widget *,
                struct snd_soc_tplg_dapm_widget *);
        int (*widget_unload)(struct snd_soc_component *,
                struct snd_soc_dobj *);
 
        /* FE DAI - used for any driver specific init */
-       int (*dai_load)(struct snd_soc_component *,
-               struct snd_soc_dai_driver *dai_drv);
+       int (*dai_load)(struct snd_soc_component *, int index,
+               struct snd_soc_dai_driver *dai_drv,
+               struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai);
+
        int (*dai_unload)(struct snd_soc_component *,
                struct snd_soc_dobj *);
 
        /* DAI link - used for any driver specific init */
-       int (*link_load)(struct snd_soc_component *,
-               struct snd_soc_dai_link *link);
+       int (*link_load)(struct snd_soc_component *, int index,
+               struct snd_soc_dai_link *link,
+               struct snd_soc_tplg_link_config *cfg);
        int (*link_unload)(struct snd_soc_component *,
                struct snd_soc_dobj *);
 
        /* callback to handle vendor bespoke data */
-       int (*vendor_load)(struct snd_soc_component *,
+       int (*vendor_load)(struct snd_soc_component *, int index,
                struct snd_soc_tplg_hdr *);
        int (*vendor_unload)(struct snd_soc_component *,
                struct snd_soc_tplg_hdr *);
@@ -146,7 +155,7 @@ struct snd_soc_tplg_ops {
        void (*complete)(struct snd_soc_component *);
 
        /* manifest - optional to inform component of manifest */
-       int (*manifest)(struct snd_soc_component *,
+       int (*manifest)(struct snd_soc_component *, int index,
                struct snd_soc_tplg_manifest *);
 
        /* vendor specific kcontrol handlers available for binding */
index 1378dcd2128aa34f9fdbf9197817760bb98e96df..41cec42fb456a5013a007036a11c7b542c84a50e 100644 (file)
@@ -1,13 +1,10 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * linux/sound/soc.h -- ALSA SoC Layer
  *
- * Author:             Liam Girdwood
- * Created:            Aug 11th 2005
+ * Author:     Liam Girdwood
+ * Created:    Aug 11th 2005
  * Copyright:  Wolfson Microelectronics. PLC.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __LINUX_SND_SOC_H
@@ -806,6 +803,14 @@ struct snd_soc_component_driver {
        unsigned int use_pmdown_time:1; /* care pmdown_time at stop */
        unsigned int endianness:1;
        unsigned int non_legacy_dai_naming:1;
+
+       /* this component uses topology and ignore machine driver FEs */
+       const char *ignore_machine;
+       const char *topology_name_prefix;
+       int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+                                 struct snd_pcm_hw_params *params);
+       bool use_dai_pcm_id;    /* use the DAI link PCM ID as PCM device number */
+       int be_pcm_base;        /* base device ID for all BE PCMs */
 };
 
 struct snd_soc_component {
@@ -957,10 +962,17 @@ struct snd_soc_dai_link {
 
        /* DPCM used FE & BE merged format */
        unsigned int dpcm_merged_format:1;
+       /* DPCM used FE & BE merged channel */
+       unsigned int dpcm_merged_chan:1;
+       /* DPCM used FE & BE merged rate */
+       unsigned int dpcm_merged_rate:1;
 
        /* pmdown_time is ignored at stop */
        unsigned int ignore_pmdown_time:1;
 
+       /* Do not create a PCM for this DAI link (Backend link) */
+       unsigned int ignore:1;
+
        struct list_head list; /* DAI link list of the soc card */
        struct snd_soc_dobj dobj; /* For topology */
 };
@@ -1000,6 +1012,7 @@ struct snd_soc_card {
        const char *long_name;
        const char *driver_name;
        char dmi_longname[80];
+       char topology_shortname[32];
 
        struct device *dev;
        struct snd_card *snd_card;
@@ -1009,6 +1022,7 @@ struct snd_soc_card {
        struct mutex dapm_mutex;
 
        bool instantiated;
+       bool topology_shortname_created;
 
        int (*probe)(struct snd_soc_card *card);
        int (*late_probe)(struct snd_soc_card *card);
@@ -1412,6 +1426,9 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
                               const char *propname);
 int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
                                          const char *propname);
+int snd_soc_of_get_slot_mask(struct device_node *np,
+                            const char *prop_name,
+                            unsigned int *mask);
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
                              unsigned int *tx_mask,
                              unsigned int *rx_mask,
index 2cd449328aee37e55de94633d803d73fe3057f9e..9004ffff7f3265be88ba5afe1b7890c31b0c529d 100644 (file)
@@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete,
        TP_ARGS(core, phase)
 );
 
+DECLARE_EVENT_CLASS(clk_duty_cycle,
+
+       TP_PROTO(struct clk_core *core, struct clk_duty *duty),
+
+       TP_ARGS(core, duty),
+
+       TP_STRUCT__entry(
+               __string(        name,           core->name              )
+               __field( unsigned int,           num                     )
+               __field( unsigned int,           den                     )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, core->name);
+               __entry->num = duty->num;
+               __entry->den = duty->den;
+       ),
+
+       TP_printk("%s %u/%u", __get_str(name), (unsigned int)__entry->num,
+                 (unsigned int)__entry->den)
+);
+
+DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle,
+
+       TP_PROTO(struct clk_core *core, struct clk_duty *duty),
+
+       TP_ARGS(core, duty)
+);
+
+DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle_complete,
+
+       TP_PROTO(struct clk_core *core, struct clk_duty *duty),
+
+       TP_ARGS(core, duty)
+);
+
 #endif /* _TRACE_CLK_H */
 
 /* This part must be outside protection */
index 65171f6657a2984ccc14ce907a4c7c87d77d196b..5fbd47a9177ee250a5f05eb6211e5a4424ad69fc 100644 (file)
@@ -17,14 +17,9 @@ config SND_ARMAACI
        select SND_PCM
        select SND_AC97_CODEC
 
-config SND_PXA2XX_PCM
-       tristate
-       select SND_PCM
-
 config SND_PXA2XX_AC97
        tristate "AC97 driver for the Intel PXA2xx chip"
        depends on ARCH_PXA
-       select SND_PXA2XX_PCM
        select SND_AC97_CODEC
        select SND_PXA2XX_LIB
        select SND_PXA2XX_LIB_AC97
index e10d5b1695658085ca50ed09b8763d8103bf337f..34c7694898779581e7ffeee20aaeef95eba6cea9 100644 (file)
@@ -6,9 +6,6 @@
 obj-$(CONFIG_SND_ARMAACI)      += snd-aaci.o
 snd-aaci-objs                  := aaci.o
 
-obj-$(CONFIG_SND_PXA2XX_PCM)   += snd-pxa2xx-pcm.o
-snd-pxa2xx-pcm-objs            := pxa2xx-pcm.o
-
 obj-$(CONFIG_SND_PXA2XX_LIB)   += snd-pxa2xx-lib.o
 snd-pxa2xx-lib-y               := pxa2xx-pcm-lib.o
 snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97)   += pxa2xx-ac97-lib.o
index 5950a9e218d962294b4e46f36e795e0af37b0250..8eafd3d3dff67324899cd5433cce91d6cbc28a23 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 
 #include <sound/pxa2xx-lib.h>
 
@@ -337,6 +338,17 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
                        dev_err(&dev->dev, "Invalid reset GPIO %d\n",
                                pdata->reset_gpio);
                }
+       } else if (!pdata && dev->dev.of_node) {
+               pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+               pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node,
+                                                     "reset-gpios", 0);
+               if (pdata->reset_gpio == -ENOENT)
+                       pdata->reset_gpio = -1;
+               else if (pdata->reset_gpio < 0)
+                       return pdata->reset_gpio;
+               reset_gpio = pdata->reset_gpio;
        } else {
                if (cpu_is_pxa27x())
                        reset_gpio = 113;
index 4bc244c40f80b45c223b8f186c7e694030734650..1f72672262d06406d21ea4fc00c400fac24fd94b 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
-#include <linux/dma/pxa-dma.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -27,8 +27,6 @@
 #include <mach/regs-ac97.h>
 #include <mach/audio.h>
 
-#include "pxa2xx-pcm.h"
-
 static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
 {
        if (!pxa2xx_ac97_try_cold_reset())
@@ -63,61 +61,46 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_legacy_reset,
 };
 
-static struct pxad_param pxa2xx_ac97_pcm_out_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 12,
-};
-
-static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
-       .addr           = __PREG(PCDR),
-       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
-       .maxburst       = 32,
-       .filter_data    = &pxa2xx_ac97_pcm_out_req,
-};
-
-static struct pxad_param pxa2xx_ac97_pcm_in_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 11,
-};
-
-static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
-       .addr           = __PREG(PCDR),
-       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
-       .maxburst       = 32,
-       .filter_data    = &pxa2xx_ac97_pcm_in_req,
-};
-
 static struct snd_pcm *pxa2xx_ac97_pcm;
 static struct snd_ac97 *pxa2xx_ac97_ac97;
 
-static int pxa2xx_ac97_pcm_startup(struct snd_pcm_substream *substream)
+static int pxa2xx_ac97_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        pxa2xx_audio_ops_t *platform_ops;
-       int r;
+       int ret, i;
+
+       ret = pxa2xx_pcm_open(substream);
+       if (ret)
+               return ret;
 
        runtime->hw.channels_min = 2;
        runtime->hw.channels_max = 2;
 
-       r = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-           AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
-       runtime->hw.rates = pxa2xx_ac97_ac97->rates[r];
+       i = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+               AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
+       runtime->hw.rates = pxa2xx_ac97_ac97->rates[i];
        snd_pcm_limit_hw_rates(runtime);
 
-               platform_ops = substream->pcm->card->dev->platform_data;
-       if (platform_ops && platform_ops->startup)
-               return platform_ops->startup(substream, platform_ops->priv);
-       else
-               return 0;
+       platform_ops = substream->pcm->card->dev->platform_data;
+       if (platform_ops && platform_ops->startup) {
+               ret = platform_ops->startup(substream, platform_ops->priv);
+               if (ret < 0)
+                       pxa2xx_pcm_close(substream);
+       }
+
+       return ret;
 }
 
-static void pxa2xx_ac97_pcm_shutdown(struct snd_pcm_substream *substream)
+static int pxa2xx_ac97_pcm_close(struct snd_pcm_substream *substream)
 {
        pxa2xx_audio_ops_t *platform_ops;
 
-               platform_ops = substream->pcm->card->dev->platform_data;
+       platform_ops = substream->pcm->card->dev->platform_data;
        if (platform_ops && platform_ops->shutdown)
                platform_ops->shutdown(substream, platform_ops->priv);
+
+       return 0;
 }
 
 static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
@@ -125,17 +108,15 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+       int ret;
+
+       ret = pxa2xx_pcm_prepare(substream);
+       if (ret < 0)
+               return ret;
+
        return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
 }
 
-static struct pxa2xx_pcm_client pxa2xx_ac97_pcm_client = {
-       .playback_params        = &pxa2xx_ac97_pcm_out,
-       .capture_params         = &pxa2xx_ac97_pcm_in,
-       .startup                = pxa2xx_ac97_pcm_startup,
-       .shutdown               = pxa2xx_ac97_pcm_shutdown,
-       .prepare                = pxa2xx_ac97_pcm_prepare,
-};
-
 #ifdef CONFIG_PM_SLEEP
 
 static int pxa2xx_ac97_do_suspend(struct snd_card *card)
@@ -193,6 +174,53 @@ static int pxa2xx_ac97_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
 #endif
 
+static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
+       .open           = pxa2xx_ac97_pcm_open,
+       .close          = pxa2xx_ac97_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = pxa2xx_pcm_hw_params,
+       .hw_free        = pxa2xx_pcm_hw_free,
+       .prepare        = pxa2xx_ac97_pcm_prepare,
+       .trigger        = pxa2xx_pcm_trigger,
+       .pointer        = pxa2xx_pcm_pointer,
+       .mmap           = pxa2xx_pcm_mmap,
+};
+
+
+static int pxa2xx_ac97_pcm_new(struct snd_card *card)
+{
+       struct snd_pcm *pcm;
+       int stream, ret;
+
+       ret = snd_pcm_new(card, "PXA2xx-PCM", 0, 1, 1, &pcm);
+       if (ret)
+               goto out;
+
+       pcm->private_free = pxa2xx_pcm_free_dma_buffers;
+
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               goto out;
+
+       stream = SNDRV_PCM_STREAM_PLAYBACK;
+       snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
+       ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+       if (ret)
+               goto out;
+
+       stream = SNDRV_PCM_STREAM_CAPTURE;
+       snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
+       ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+       if (ret)
+               goto out;
+
+       pxa2xx_ac97_pcm = pcm;
+       ret = 0;
+
+ out:
+       return ret;
+}
+
 static int pxa2xx_ac97_probe(struct platform_device *dev)
 {
        struct snd_card *card;
@@ -214,7 +242,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
 
        strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
 
-       ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
+       ret = pxa2xx_ac97_pcm_new(card);
        if (ret)
                goto err;
 
index e8da3b8ee7213352426023029fcff04e87659d50..7931789d4a9f588fb5f1a29e6f4d1aa929cfd380 100644 (file)
@@ -16,8 +16,6 @@
 #include <sound/pxa2xx-lib.h>
 #include <sound/dmaengine_pcm.h>
 
-#include "pxa2xx-pcm.h"
-
 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
@@ -25,8 +23,8 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
                                  SNDRV_PCM_INFO_PAUSE |
                                  SNDRV_PCM_INFO_RESUME,
        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                       SNDRV_PCM_FMTBIT_S24_LE |
-                                       SNDRV_PCM_FMTBIT_S32_LE,
+                                 SNDRV_PCM_FMTBIT_S24_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192 - 32,
        .periods_min            = 1,
@@ -35,8 +33,8 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
        .fifo_size              = 32,
 };
 
-int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
+int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
 {
        struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -64,14 +62,14 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
 
        return 0;
 }
-EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
+EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
 
-int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        snd_pcm_set_runtime_buffer(substream, NULL);
        return 0;
 }
-EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
+EXPORT_SYMBOL(pxa2xx_pcm_hw_free);
 
 int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
@@ -86,13 +84,13 @@ pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL(pxa2xx_pcm_pointer);
 
-int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
        return 0;
 }
-EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
+EXPORT_SYMBOL(pxa2xx_pcm_prepare);
 
-int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -125,17 +123,17 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
        if (ret < 0)
                return ret;
 
-       return snd_dmaengine_pcm_open_request_chan(substream,
-                                       pxad_filter_fn,
-                                       dma_params->filter_data);
+       return snd_dmaengine_pcm_open(
+               substream, dma_request_slave_channel(rtd->cpu_dai->dev,
+                                                    dma_params->chan_name));
 }
-EXPORT_SYMBOL(__pxa2xx_pcm_open);
+EXPORT_SYMBOL(pxa2xx_pcm_open);
 
-int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 {
        return snd_dmaengine_pcm_close_release_chan(substream);
 }
-EXPORT_SYMBOL(__pxa2xx_pcm_close);
+EXPORT_SYMBOL(pxa2xx_pcm_close);
 
 int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
        struct vm_area_struct *vma)
@@ -181,6 +179,47 @@ void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 }
 EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
 
+int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret;
+
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+               ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+ out:
+       return ret;
+}
+EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
+
+const struct snd_pcm_ops pxa2xx_pcm_ops = {
+       .open           = pxa2xx_pcm_open,
+       .close          = pxa2xx_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = pxa2xx_pcm_hw_params,
+       .hw_free        = pxa2xx_pcm_hw_free,
+       .prepare        = pxa2xx_pcm_prepare,
+       .trigger        = pxa2xx_pcm_trigger,
+       .pointer        = pxa2xx_pcm_pointer,
+       .mmap           = pxa2xx_pcm_mmap,
+};
+EXPORT_SYMBOL(pxa2xx_pcm_ops);
+
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("Intel PXA2xx sound library");
 MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
deleted file mode 100644 (file)
index 1c6f4b4..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  (C) 2004 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-
-#include <mach/dma.h>
-
-#include <sound/core.h>
-#include <sound/pxa2xx-lib.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "pxa2xx-pcm.h"
-
-static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct pxa2xx_pcm_client *client = substream->private_data;
-
-       __pxa2xx_pcm_prepare(substream);
-
-       return client->prepare(substream);
-}
-
-static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct pxa2xx_pcm_client *client = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd;
-       int ret;
-
-       ret = __pxa2xx_pcm_open(substream);
-       if (ret)
-               goto out;
-
-       rtd = runtime->private_data;
-
-       rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                     client->playback_params : client->capture_params;
-
-       ret = client->startup(substream);
-       if (!ret)
-               goto err2;
-
-       return 0;
-
- err2:
-       __pxa2xx_pcm_close(substream);
- out:
-       return ret;
-}
-
-static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct pxa2xx_pcm_client *client = substream->private_data;
-
-       client->shutdown(substream);
-
-       return __pxa2xx_pcm_close(substream);
-}
-
-static const struct snd_pcm_ops pxa2xx_pcm_ops = {
-       .open           = pxa2xx_pcm_open,
-       .close          = pxa2xx_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = __pxa2xx_pcm_hw_params,
-       .hw_free        = __pxa2xx_pcm_hw_free,
-       .prepare        = pxa2xx_pcm_prepare,
-       .trigger        = pxa2xx_pcm_trigger,
-       .pointer        = pxa2xx_pcm_pointer,
-       .mmap           = pxa2xx_pcm_mmap,
-};
-
-int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
-                  struct snd_pcm **rpcm)
-{
-       struct snd_pcm *pcm;
-       int play = client->playback_params ? 1 : 0;
-       int capt = client->capture_params ? 1 : 0;
-       int ret;
-
-       ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm);
-       if (ret)
-               goto out;
-
-       pcm->private_data = client;
-       pcm->private_free = pxa2xx_pcm_free_dma_buffers;
-
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               goto out;
-
-       if (play) {
-               int stream = SNDRV_PCM_STREAM_PLAYBACK;
-               snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
-               ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
-               if (ret)
-                       goto out;
-       }
-       if (capt) {
-               int stream = SNDRV_PCM_STREAM_CAPTURE;
-               snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
-               ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
-               if (ret)
-                       goto out;
-       }
-
-       if (rpcm)
-               *rpcm = pcm;
-       ret = 0;
-
- out:
-       return ret;
-}
-
-EXPORT_SYMBOL(pxa2xx_pcm_new);
-
-MODULE_AUTHOR("Nicolas Pitre");
-MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
deleted file mode 100644 (file)
index 8fa2b7c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-struct pxa2xx_runtime_data {
-       int dma_ch;
-       struct snd_dmaengine_dai_dma_data *params;
-};
-
-struct pxa2xx_pcm_client {
-       struct snd_dmaengine_dai_dma_data *playback_params;
-       struct snd_dmaengine_dai_dma_data *capture_params;
-       int (*startup)(struct snd_pcm_substream *);
-       void (*shutdown)(struct snd_pcm_substream *);
-       int (*prepare)(struct snd_pcm_substream *);
-};
-
-extern int pxa2xx_pcm_new(struct snd_card *, struct pxa2xx_pcm_client *, struct snd_pcm **);
-
index 3129546398d0c20a27652ec4373281b1d0299dc1..2d90e11b3eaa2355621947d7e330dde12df014d6 100644 (file)
@@ -5,11 +5,12 @@ config SND_HDA_CORE
 config SND_HDA_DSP_LOADER
        bool
 
+config SND_HDA_COMPONENT
+       bool
+
 config SND_HDA_I915
        bool
-       default y
-       depends on DRM_I915
-       depends on SND_HDA_CORE
+       select SND_HDA_COMPONENT
 
 config SND_HDA_EXT_CORE
        tristate
index e4e726f2ce98b69a75ed81f38293bf7ad65f1749..2160202e2dc1b86e37874fa5e1e943fd3687130f 100644 (file)
@@ -6,6 +6,7 @@ snd-hda-core-objs += trace.o
 CFLAGS_trace.o := -I$(src)
 
 # for sync with i915 gfx driver
+snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o
 snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o
 
 obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
index 0daf31383084d22a85553970b9480a4287515d5b..9c37d9af3023f67bdba2ba4a3d207580cd1f70c5 100644 (file)
@@ -87,9 +87,10 @@ static const struct hdac_io_ops hdac_ext_default_io = {
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
+int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
                        const struct hdac_bus_ops *ops,
-                       const struct hdac_io_ops *io_ops)
+                       const struct hdac_io_ops *io_ops,
+                       const struct hdac_ext_bus_ops *ext_ops)
 {
        int ret;
        static int idx;
@@ -98,15 +99,16 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
        if (io_ops == NULL)
                io_ops = &hdac_ext_default_io;
 
-       ret = snd_hdac_bus_init(&ebus->bus, dev, ops, io_ops);
+       ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
        if (ret < 0)
                return ret;
 
-       INIT_LIST_HEAD(&ebus->hlink_list);
-       ebus->idx = idx++;
+       bus->ext_ops = ext_ops;
+       INIT_LIST_HEAD(&bus->hlink_list);
+       bus->idx = idx++;
 
-       mutex_init(&ebus->lock);
-       ebus->cmd_dma_state = true;
+       mutex_init(&bus->lock);
+       bus->cmd_dma_state = true;
 
        return 0;
 }
@@ -116,10 +118,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
  * snd_hdac_ext_bus_exit - clean up a HD-audio extended bus
  * @ebus: the pointer to extended bus object
  */
-void snd_hdac_ext_bus_exit(struct hdac_ext_bus *ebus)
+void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
 {
-       snd_hdac_bus_exit(&ebus->bus);
-       WARN_ON(!list_empty(&ebus->hlink_list));
+       snd_hdac_bus_exit(bus);
+       WARN_ON(!list_empty(&bus->hlink_list));
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);
 
@@ -135,21 +137,15 @@ static void default_release(struct device *dev)
  *
  * Returns zero for success or a negative error code.
  */
-int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
+int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
+                                       struct hdac_device *hdev)
 {
-       struct hdac_ext_device *edev;
-       struct hdac_device *hdev = NULL;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
        char name[15];
        int ret;
 
-       edev = kzalloc(sizeof(*edev), GFP_KERNEL);
-       if (!edev)
-               return -ENOMEM;
-       hdev = &edev->hdev;
-       edev->ebus = ebus;
+       hdev->bus = bus;
 
-       snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
+       snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);
 
        ret  = snd_hdac_device_init(hdev, bus, name, addr);
        if (ret < 0) {
@@ -176,10 +172,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
  */
 void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
 {
-       struct hdac_ext_device *edev = to_ehdac_device(hdev);
-
        snd_hdac_device_exit(hdev);
-       kfree(edev);
+       kfree(hdev);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
 
@@ -188,14 +182,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
  *
  * @ebus: HD-audio extended bus
  */
-void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus)
+void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus)
 {
        struct hdac_device *codec, *__codec;
        /*
         * we need to remove all the codec devices objects created in the
         * snd_hdac_ext_bus_device_init
         */
-       list_for_each_entry_safe(codec, __codec, &ebus->bus.codec_list, list) {
+       list_for_each_entry_safe(codec, __codec, &bus->codec_list, list) {
                snd_hdac_device_unregister(codec);
                put_device(&codec->dev);
        }
@@ -204,35 +198,31 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
 #define dev_to_hdac(dev) (container_of((dev), \
                        struct hdac_device, dev))
 
-static inline struct hdac_ext_driver *get_edrv(struct device *dev)
+static inline struct hdac_driver *get_hdrv(struct device *dev)
 {
        struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
-       struct hdac_ext_driver *edrv = to_ehdac_driver(hdrv);
-
-       return edrv;
+       return hdrv;
 }
 
-static inline struct hdac_ext_device *get_edev(struct device *dev)
+static inline struct hdac_device *get_hdev(struct device *dev)
 {
        struct hdac_device *hdev = dev_to_hdac_dev(dev);
-       struct hdac_ext_device *edev = to_ehdac_device(hdev);
-
-       return edev;
+       return hdev;
 }
 
 static int hda_ext_drv_probe(struct device *dev)
 {
-       return (get_edrv(dev))->probe(get_edev(dev));
+       return (get_hdrv(dev))->probe(get_hdev(dev));
 }
 
 static int hdac_ext_drv_remove(struct device *dev)
 {
-       return (get_edrv(dev))->remove(get_edev(dev));
+       return (get_hdrv(dev))->remove(get_hdev(dev));
 }
 
 static void hdac_ext_drv_shutdown(struct device *dev)
 {
-       return (get_edrv(dev))->shutdown(get_edev(dev));
+       return (get_hdrv(dev))->shutdown(get_hdev(dev));
 }
 
 /**
@@ -240,20 +230,20 @@ static void hdac_ext_drv_shutdown(struct device *dev)
  *
  * @drv: ext hda driver structure
  */
-int snd_hda_ext_driver_register(struct hdac_ext_driver *drv)
+int snd_hda_ext_driver_register(struct hdac_driver *drv)
 {
-       drv->hdac.type = HDA_DEV_ASOC;
-       drv->hdac.driver.bus = &snd_hda_bus_type;
+       drv->type = HDA_DEV_ASOC;
+       drv->driver.bus = &snd_hda_bus_type;
        /* we use default match */
 
        if (drv->probe)
-               drv->hdac.driver.probe = hda_ext_drv_probe;
+               drv->driver.probe = hda_ext_drv_probe;
        if (drv->remove)
-               drv->hdac.driver.remove = hdac_ext_drv_remove;
+               drv->driver.remove = hdac_ext_drv_remove;
        if (drv->shutdown)
-               drv->hdac.driver.shutdown = hdac_ext_drv_shutdown;
+               drv->driver.shutdown = hdac_ext_drv_shutdown;
 
-       return driver_register(&drv->hdac.driver);
+       return driver_register(&drv->driver);
 }
 EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
 
@@ -262,8 +252,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
  *
  * @drv: ext hda driver structure
  */
-void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv)
+void snd_hda_ext_driver_unregister(struct hdac_driver *drv)
 {
-       driver_unregister(&drv->hdac.driver);
+       driver_unregister(&drv->driver);
 }
 EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
index 84f3b81687164d419b4cff063011d774790273f3..5bc4a1d587d4f13121ca82433aeafa4b6594576c 100644 (file)
@@ -39,9 +39,8 @@
  * @ebus: HD-audio extended core bus
  * @enable: flag to turn on/off the capability
  */
-void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
+void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
 {
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->ppcap) {
                dev_err(bus->dev, "Address of PP capability is NULL");
@@ -60,9 +59,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
  * @ebus: HD-audio extended core bus
  * @enable: flag to enable/disable interrupt
  */
-void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
+void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
 {
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->ppcap) {
                dev_err(bus->dev, "Address of PP capability is NULL\n");
@@ -89,12 +87,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
  * in hlink_list of extended hdac bus
  * Note: this will be freed on bus exit by driver
  */
-int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
+int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
 {
        int idx;
        u32 link_count;
        struct hdac_ext_link *hlink;
-       struct hdac_bus *bus = &ebus->bus;
 
        link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
 
@@ -114,7 +111,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
                /* since link in On, update the ref */
                hlink->ref_count = 1;
 
-               list_add_tail(&hlink->list, &ebus->hlink_list);
+               list_add_tail(&hlink->list, &bus->hlink_list);
        }
 
        return 0;
@@ -127,12 +124,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
  * @ebus: HD-audio ext core bus
  */
 
-void snd_hdac_link_free_all(struct hdac_ext_bus *ebus)
+void snd_hdac_link_free_all(struct hdac_bus *bus)
 {
        struct hdac_ext_link *l;
 
-       while (!list_empty(&ebus->hlink_list)) {
-               l = list_first_entry(&ebus->hlink_list, struct hdac_ext_link, list);
+       while (!list_empty(&bus->hlink_list)) {
+               l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
                list_del(&l->list);
                kfree(l);
        }
@@ -144,7 +141,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
  * @ebus: HD-audio extended core bus
  * @codec_name: codec name
  */
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
+struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
                                                 const char *codec_name)
 {
        int i;
@@ -153,10 +150,10 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
 
        if (sscanf(codec_name, "ehdaudio%dD%d", &bus_idx, &addr) != 2)
                return NULL;
-       if (ebus->idx != bus_idx)
+       if (bus->idx != bus_idx)
                return NULL;
 
-       list_for_each_entry(hlink, &ebus->hlink_list, list) {
+       list_for_each_entry(hlink, &bus->hlink_list, list) {
                for (i = 0; i < HDA_MAX_CODECS; i++) {
                        if (hlink->lsdiid & (0x1 << addr))
                                return hlink;
@@ -219,12 +216,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
  * snd_hdac_ext_bus_link_power_up_all -power up all hda link
  * @ebus: HD-audio extended bus
  */
-int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
 {
        struct hdac_ext_link *hlink = NULL;
        int ret;
 
-       list_for_each_entry(hlink, &ebus->hlink_list, list) {
+       list_for_each_entry(hlink, &bus->hlink_list, list) {
                snd_hdac_updatel(hlink->ml_addr,
                                AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
                ret = check_hdac_link_power_active(hlink, true);
@@ -240,12 +237,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
  * snd_hdac_ext_bus_link_power_down_all -power down all hda link
  * @ebus: HD-audio extended bus
  */
-int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
+int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
 {
        struct hdac_ext_link *hlink = NULL;
        int ret;
 
-       list_for_each_entry(hlink, &ebus->hlink_list, list) {
+       list_for_each_entry(hlink, &bus->hlink_list, list) {
                snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
                ret = check_hdac_link_power_active(hlink, false);
                if (ret < 0)
@@ -256,39 +253,48 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
 
-int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
                                struct hdac_ext_link *link)
 {
        int ret = 0;
 
-       mutex_lock(&ebus->lock);
+       mutex_lock(&bus->lock);
 
        /*
         * if we move from 0 to 1, count will be 1 so power up this link
         * as well, also check the dma status and trigger that
         */
        if (++link->ref_count == 1) {
-               if (!ebus->cmd_dma_state) {
-                       snd_hdac_bus_init_cmd_io(&ebus->bus);
-                       ebus->cmd_dma_state = true;
+               if (!bus->cmd_dma_state) {
+                       snd_hdac_bus_init_cmd_io(bus);
+                       bus->cmd_dma_state = true;
                }
 
                ret = snd_hdac_ext_bus_link_power_up(link);
+
+               /*
+                *  wait for 521usec for codec to report status
+                *  HDA spec section 4.3 - Codec Discovery
+                */
+               udelay(521);
+               bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+               dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
+               snd_hdac_chip_writew(bus, STATESTS, bus->codec_mask);
        }
 
-       mutex_unlock(&ebus->lock);
+       mutex_unlock(&bus->lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
 
-int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
                                struct hdac_ext_link *link)
 {
        int ret = 0;
        struct hdac_ext_link *hlink;
        bool link_up = false;
 
-       mutex_lock(&ebus->lock);
+       mutex_lock(&bus->lock);
 
        /*
         * if we move from 1 to 0, count will be 0
@@ -301,7 +307,7 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
                 * now check if all links are off, if so turn off
                 * cmd dma as well
                 */
-               list_for_each_entry(hlink, &ebus->hlink_list, list) {
+               list_for_each_entry(hlink, &bus->hlink_list, list) {
                        if (hlink->ref_count) {
                                link_up = true;
                                break;
@@ -309,12 +315,12 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
                }
 
                if (!link_up) {
-                       snd_hdac_bus_stop_cmd_io(&ebus->bus);
-                       ebus->cmd_dma_state = false;
+                       snd_hdac_bus_stop_cmd_io(bus);
+                       bus->cmd_dma_state = false;
                }
        }
 
-       mutex_unlock(&ebus->lock);
+       mutex_unlock(&bus->lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
index c96d7a7a36af033b0c8241e20538e7722828bc0e..1bd27576db98d50cc12382c209c3938fe9fe5e14 100644 (file)
@@ -25,7 +25,7 @@
 
 /**
  * snd_hdac_ext_stream_init - initialize each stream (aka device)
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @stream: HD-audio ext core stream object to initialize
  * @idx: stream index number
  * @direction: stream direction (SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE)
  * initialize the stream, if ppcap is enabled then init those and then
  * invoke hdac stream initialization routine
  */
-void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_init(struct hdac_bus *bus,
                                struct hdac_ext_stream *stream,
                                int idx, int direction, int tag)
 {
-       struct hdac_bus *bus = &ebus->bus;
-
        if (bus->ppcap) {
                stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
                                AZX_PPHC_INTERVAL * idx;
 
                stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
-                               AZX_PPLC_MULTI * ebus->num_streams +
+                               AZX_PPLC_MULTI * bus->num_streams +
                                AZX_PPLC_INTERVAL * idx;
        }
 
@@ -71,12 +69,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init);
 /**
  * snd_hdac_ext_stream_init_all - create and initialize the stream objects
  *   for an extended hda bus
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @start_idx: start index for streams
  * @num_stream: number of streams to initialize
  * @dir: direction of streams
  */
-int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
+int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
                int num_stream, int dir)
 {
        int stream_tag = 0;
@@ -88,7 +86,7 @@ int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
                if (!stream)
                        return -ENOMEM;
                tag = ++stream_tag;
-               snd_hdac_ext_stream_init(ebus, stream, idx, dir, tag);
+               snd_hdac_ext_stream_init(bus, stream, idx, dir, tag);
                idx++;
        }
 
@@ -100,17 +98,16 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
 /**
  * snd_hdac_stream_free_all - free hdac extended stream objects
  *
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  */
-void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus)
+void snd_hdac_stream_free_all(struct hdac_bus *bus)
 {
        struct hdac_stream *s, *_s;
        struct hdac_ext_stream *stream;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
 
        list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
                stream = stream_to_hdac_ext_stream(s);
-               snd_hdac_ext_stream_decouple(ebus, stream, false);
+               snd_hdac_ext_stream_decouple(bus, stream, false);
                list_del(&s->list);
                kfree(stream);
        }
@@ -119,15 +116,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
 
 /**
  * snd_hdac_ext_stream_decouple - decouple the hdac stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @stream: HD-audio ext core stream object to initialize
  * @decouple: flag to decouple
  */
-void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
                                struct hdac_ext_stream *stream, bool decouple)
 {
        struct hdac_stream *hstream = &stream->hstream;
-       struct hdac_bus *bus = &ebus->bus;
        u32 val;
        int mask = AZX_PPCTL_PROCEN(hstream->index);
 
@@ -251,19 +247,18 @@ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
 EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
 
 static struct hdac_ext_stream *
-hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
+hdac_ext_link_stream_assign(struct hdac_bus *bus,
                                struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *res = NULL;
        struct hdac_stream *stream = NULL;
-       struct hdac_bus *hbus = &ebus->bus;
 
-       if (!hbus->ppcap) {
-               dev_err(hbus->dev, "stream type not supported\n");
+       if (!bus->ppcap) {
+               dev_err(bus->dev, "stream type not supported\n");
                return NULL;
        }
 
-       list_for_each_entry(stream, &hbus->stream_list, list) {
+       list_for_each_entry(stream, &bus->stream_list, list) {
                struct hdac_ext_stream *hstream = container_of(stream,
                                                struct hdac_ext_stream,
                                                hstream);
@@ -277,34 +272,33 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
                }
 
                if (!hstream->link_locked) {
-                       snd_hdac_ext_stream_decouple(ebus, hstream, true);
+                       snd_hdac_ext_stream_decouple(bus, hstream, true);
                        res = hstream;
                        break;
                }
        }
        if (res) {
-               spin_lock_irq(&hbus->reg_lock);
+               spin_lock_irq(&bus->reg_lock);
                res->link_locked = 1;
                res->link_substream = substream;
-               spin_unlock_irq(&hbus->reg_lock);
+               spin_unlock_irq(&bus->reg_lock);
        }
        return res;
 }
 
 static struct hdac_ext_stream *
-hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
+hdac_ext_host_stream_assign(struct hdac_bus *bus,
                                struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *res = NULL;
        struct hdac_stream *stream = NULL;
-       struct hdac_bus *hbus = &ebus->bus;
 
-       if (!hbus->ppcap) {
-               dev_err(hbus->dev, "stream type not supported\n");
+       if (!bus->ppcap) {
+               dev_err(bus->dev, "stream type not supported\n");
                return NULL;
        }
 
-       list_for_each_entry(stream, &hbus->stream_list, list) {
+       list_for_each_entry(stream, &bus->stream_list, list) {
                struct hdac_ext_stream *hstream = container_of(stream,
                                                struct hdac_ext_stream,
                                                hstream);
@@ -313,17 +307,17 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
 
                if (!stream->opened) {
                        if (!hstream->decoupled)
-                               snd_hdac_ext_stream_decouple(ebus, hstream, true);
+                               snd_hdac_ext_stream_decouple(bus, hstream, true);
                        res = hstream;
                        break;
                }
        }
        if (res) {
-               spin_lock_irq(&hbus->reg_lock);
+               spin_lock_irq(&bus->reg_lock);
                res->hstream.opened = 1;
                res->hstream.running = 0;
                res->hstream.substream = substream;
-               spin_unlock_irq(&hbus->reg_lock);
+               spin_unlock_irq(&bus->reg_lock);
        }
 
        return res;
@@ -331,7 +325,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
 
 /**
  * snd_hdac_ext_stream_assign - assign a stream for the PCM
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @substream: PCM substream to assign
  * @type: type of stream (coupled, host or link stream)
  *
@@ -346,27 +340,26 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
  * the same stream object when it's used beforehand.  when a stream is
  * decoupled, it becomes a host stream and link stream.
  */
-struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_ext_bus *ebus,
+struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
                                           struct snd_pcm_substream *substream,
                                           int type)
 {
        struct hdac_ext_stream *hstream = NULL;
        struct hdac_stream *stream = NULL;
-       struct hdac_bus *hbus = &ebus->bus;
 
        switch (type) {
        case HDAC_EXT_STREAM_TYPE_COUPLED:
-               stream = snd_hdac_stream_assign(hbus, substream);
+               stream = snd_hdac_stream_assign(bus, substream);
                if (stream)
                        hstream = container_of(stream,
                                        struct hdac_ext_stream, hstream);
                return hstream;
 
        case HDAC_EXT_STREAM_TYPE_HOST:
-               return hdac_ext_host_stream_assign(ebus, substream);
+               return hdac_ext_host_stream_assign(bus, substream);
 
        case HDAC_EXT_STREAM_TYPE_LINK:
-               return hdac_ext_link_stream_assign(ebus, substream);
+               return hdac_ext_link_stream_assign(bus, substream);
 
        default:
                return NULL;
@@ -384,7 +377,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_assign);
 void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
 {
        struct hdac_bus *bus = stream->hstream.bus;
-       struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
 
        switch (type) {
        case HDAC_EXT_STREAM_TYPE_COUPLED:
@@ -393,13 +385,13 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
 
        case HDAC_EXT_STREAM_TYPE_HOST:
                if (stream->decoupled && !stream->link_locked)
-                       snd_hdac_ext_stream_decouple(ebus, stream, false);
+                       snd_hdac_ext_stream_decouple(bus, stream, false);
                snd_hdac_stream_release(&stream->hstream);
                break;
 
        case HDAC_EXT_STREAM_TYPE_LINK:
                if (stream->decoupled && !stream->hstream.opened)
-                       snd_hdac_ext_stream_decouple(ebus, stream, false);
+                       snd_hdac_ext_stream_decouple(bus, stream, false);
                spin_lock_irq(&bus->reg_lock);
                stream->link_locked = 0;
                stream->link_substream = NULL;
@@ -415,16 +407,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
 
 /**
  * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @enable: flag to enable/disable SPIB
  * @index: stream index for which SPIB need to be enabled
  */
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
                                 bool enable, int index)
 {
        u32 mask = 0;
        u32 register_mask = 0;
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->spbcap) {
                dev_err(bus->dev, "Address of SPB capability is NULL\n");
@@ -446,14 +437,13 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
 
 /**
  * snd_hdac_ext_stream_set_spib - sets the spib value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @stream: hdac_ext_stream
  * @value: spib value to set
  */
-int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
                                 struct hdac_ext_stream *stream, u32 value)
 {
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->spbcap) {
                dev_err(bus->dev, "Address of SPB capability is NULL\n");
@@ -468,15 +458,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
 
 /**
  * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @stream: hdac_ext_stream
  *
  * Return maxfifo for the stream
  */
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
                                 struct hdac_ext_stream *stream)
 {
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->spbcap) {
                dev_err(bus->dev, "Address of SPB capability is NULL\n");
@@ -490,11 +479,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
 
 /**
  * snd_hdac_ext_stop_streams - stop all stream if running
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  */
-void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
+void snd_hdac_ext_stop_streams(struct hdac_bus *bus)
 {
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
        struct hdac_stream *stream;
 
        if (bus->chip_init) {
@@ -507,16 +495,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
 
 /**
  * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @enable: flag to enable/disable DRSM
  * @index: stream index for which DRSM need to be enabled
  */
-void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
                                bool enable, int index)
 {
        u32 mask = 0;
        u32 register_mask = 0;
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->drsmcap) {
                dev_err(bus->dev, "Address of DRSM capability is NULL\n");
@@ -538,14 +525,13 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
 
 /**
  * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @stream: hdac_ext_stream
  * @value: dpib value to set
  */
-int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
                                 struct hdac_ext_stream *stream, u32 value)
 {
-       struct hdac_bus *bus = &ebus->bus;
 
        if (!bus->drsmcap) {
                dev_err(bus->dev, "Address of DRSM capability is NULL\n");
@@ -560,7 +546,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
 
 /**
  * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
  * @stream: hdac_ext_stream
  * @value: lpib value to set
  */
diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c
new file mode 100644 (file)
index 0000000..6e46a9c
--- /dev/null
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+// hdac_component.c - routines for sync between HD-A core and DRM driver
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/component.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_component.h>
+#include <sound/hda_register.h>
+
+static void hdac_acomp_release(struct device *dev, void *res)
+{
+}
+
+static struct drm_audio_component *hdac_get_acomp(struct device *dev)
+{
+       return devres_find(dev, hdac_acomp_release, NULL, NULL);
+}
+
+/**
+ * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
+ * @bus: HDA core bus
+ * @enable: enable or disable the wakeup
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function should be called during the chip reset, also called at
+ * resume for updating STATESTS register read.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
+{
+       struct drm_audio_component *acomp = bus->audio_component;
+
+       if (!acomp || !acomp->ops)
+               return -ENODEV;
+
+       if (!acomp->ops->codec_wake_override)
+               return 0;
+
+       dev_dbg(bus->dev, "%s codec wakeup\n",
+               enable ? "enable" : "disable");
+
+       acomp->ops->codec_wake_override(acomp->dev, enable);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
+
+/**
+ * snd_hdac_display_power - Power up / down the power refcount
+ * @bus: HDA core bus
+ * @enable: power up or down
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function manages a refcount and calls the get_power() and
+ * put_power() ops accordingly, toggling the codec wakeup, too.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
+{
+       struct drm_audio_component *acomp = bus->audio_component;
+
+       if (!acomp || !acomp->ops)
+               return -ENODEV;
+
+       dev_dbg(bus->dev, "display power %s\n",
+               enable ? "enable" : "disable");
+
+       if (enable) {
+               if (!bus->drm_power_refcount++) {
+                       if (acomp->ops->get_power)
+                               acomp->ops->get_power(acomp->dev);
+                       snd_hdac_set_codec_wakeup(bus, true);
+                       snd_hdac_set_codec_wakeup(bus, false);
+               }
+       } else {
+               WARN_ON(!bus->drm_power_refcount);
+               if (!--bus->drm_power_refcount)
+                       if (acomp->ops->put_power)
+                               acomp->ops->put_power(acomp->dev);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_display_power);
+
+/**
+ * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
+ * @codec: HDA codec
+ * @nid: the pin widget NID
+ * @dev_id: device identifier
+ * @rate: the sample rate to set
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function sets N/CTS value based on the given sample rate.
+ * Returns zero for success, or a negative error code.
+ */
+int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
+                            int dev_id, int rate)
+{
+       struct hdac_bus *bus = codec->bus;
+       struct drm_audio_component *acomp = bus->audio_component;
+       int port, pipe;
+
+       if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
+               return -ENODEV;
+       port = nid;
+       if (acomp->audio_ops && acomp->audio_ops->pin2port) {
+               port = acomp->audio_ops->pin2port(codec, nid);
+               if (port < 0)
+                       return -EINVAL;
+       }
+       pipe = dev_id;
+       return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
+
+/**
+ * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
+ * @codec: HDA codec
+ * @nid: the pin widget NID
+ * @dev_id: device identifier
+ * @audio_enabled: the pointer to store the current audio state
+ * @buffer: the buffer pointer to store ELD bytes
+ * @max_bytes: the max bytes to be stored on @buffer
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function queries the current state of the audio on the given
+ * digital port and fetches the ELD bytes onto the given buffer.
+ * It returns the number of bytes for the total ELD data, zero for
+ * invalid ELD, or a negative error code.
+ *
+ * The return size is the total bytes required for the whole ELD bytes,
+ * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
+ * that only a part of ELD bytes have been fetched.
+ */
+int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
+                          bool *audio_enabled, char *buffer, int max_bytes)
+{
+       struct hdac_bus *bus = codec->bus;
+       struct drm_audio_component *acomp = bus->audio_component;
+       int port, pipe;
+
+       if (!acomp || !acomp->ops || !acomp->ops->get_eld)
+               return -ENODEV;
+
+       port = nid;
+       if (acomp->audio_ops && acomp->audio_ops->pin2port) {
+               port = acomp->audio_ops->pin2port(codec, nid);
+               if (port < 0)
+                       return -EINVAL;
+       }
+       pipe = dev_id;
+       return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
+                                  buffer, max_bytes);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
+
+static int hdac_component_master_bind(struct device *dev)
+{
+       struct drm_audio_component *acomp = hdac_get_acomp(dev);
+       int ret;
+
+       if (WARN_ON(!acomp))
+               return -EINVAL;
+
+       ret = component_bind_all(dev, acomp);
+       if (ret < 0)
+               return ret;
+
+       if (WARN_ON(!(acomp->dev && acomp->ops))) {
+               ret = -EINVAL;
+               goto out_unbind;
+       }
+
+       /* pin the module to avoid dynamic unbinding, but only if given */
+       if (!try_module_get(acomp->ops->owner)) {
+               ret = -ENODEV;
+               goto out_unbind;
+       }
+
+       if (acomp->audio_ops && acomp->audio_ops->master_bind) {
+               ret = acomp->audio_ops->master_bind(dev, acomp);
+               if (ret < 0)
+                       goto module_put;
+       }
+
+       return 0;
+
+ module_put:
+       module_put(acomp->ops->owner);
+out_unbind:
+       component_unbind_all(dev, acomp);
+
+       return ret;
+}
+
+static void hdac_component_master_unbind(struct device *dev)
+{
+       struct drm_audio_component *acomp = hdac_get_acomp(dev);
+
+       if (acomp->audio_ops && acomp->audio_ops->master_unbind)
+               acomp->audio_ops->master_unbind(dev, acomp);
+       module_put(acomp->ops->owner);
+       component_unbind_all(dev, acomp);
+       WARN_ON(acomp->ops || acomp->dev);
+}
+
+static const struct component_master_ops hdac_component_master_ops = {
+       .bind = hdac_component_master_bind,
+       .unbind = hdac_component_master_unbind,
+};
+
+/**
+ * snd_hdac_acomp_register_notifier - Register audio component ops
+ * @bus: HDA core bus
+ * @aops: audio component ops
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function sets the given ops to be called by the graphics driver.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
+                                   const struct drm_audio_component_audio_ops *aops)
+{
+       if (!bus->audio_component)
+               return -ENODEV;
+
+       bus->audio_component->audio_ops = aops;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
+
+/**
+ * snd_hdac_acomp_init - Initialize audio component
+ * @bus: HDA core bus
+ * @match_master: match function for finding components
+ * @extra_size: Extra bytes to allocate
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function initializes and sets up the audio component to communicate
+ * with graphics driver.
+ *
+ * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
+ * binding with the DRM component.  Each caller needs to sync via master_bind
+ * audio_ops.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_acomp_init(struct hdac_bus *bus,
+                       const struct drm_audio_component_audio_ops *aops,
+                       int (*match_master)(struct device *, void *),
+                       size_t extra_size)
+{
+       struct component_match *match = NULL;
+       struct device *dev = bus->dev;
+       struct drm_audio_component *acomp;
+       int ret;
+
+       if (WARN_ON(hdac_get_acomp(dev)))
+               return -EBUSY;
+
+       acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
+                            GFP_KERNEL);
+       if (!acomp)
+               return -ENOMEM;
+       acomp->audio_ops = aops;
+       bus->audio_component = acomp;
+       devres_add(dev, acomp);
+
+       component_match_add(dev, &match, match_master, bus);
+       ret = component_master_add_with_match(dev, &hdac_component_master_ops,
+                                             match);
+       if (ret < 0)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       bus->audio_component = NULL;
+       devres_destroy(dev, hdac_acomp_release, NULL, NULL);
+       dev_info(dev, "failed to add audio component master (%d)\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
+
+/**
+ * snd_hdac_acomp_exit - Finalize audio component
+ * @bus: HDA core bus
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function releases the audio component that has been used.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_acomp_exit(struct hdac_bus *bus)
+{
+       struct device *dev = bus->dev;
+       struct drm_audio_component *acomp = bus->audio_component;
+
+       if (!acomp)
+               return 0;
+
+       WARN_ON(bus->drm_power_refcount);
+       if (bus->drm_power_refcount > 0 && acomp->ops)
+               acomp->ops->put_power(acomp->dev);
+
+       component_master_del(dev, &hdac_component_master_ops);
+
+       bus->audio_component = NULL;
+       devres_destroy(dev, hdac_acomp_release, NULL, NULL);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);
index cbe818eda3363c0f0595c3496e980f64343776d6..8f2aa8bc1185d964e71d1545910f10e01f332fd6 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/component.h>
-#include <drm/i915_component.h>
 #include <sound/core.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
 #include <sound/hda_register.h>
 
-static struct i915_audio_component *hdac_acomp;
-
-/**
- * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
- * @bus: HDA core bus
- * @enable: enable or disable the wakeup
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function should be called during the chip reset, also called at
- * resume for updating STATESTS register read.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
-{
-       struct i915_audio_component *acomp = bus->audio_component;
-
-       if (!acomp || !acomp->ops)
-               return -ENODEV;
-
-       if (!acomp->ops->codec_wake_override) {
-               dev_warn(bus->dev,
-                       "Invalid codec wake callback\n");
-               return 0;
-       }
-
-       dev_dbg(bus->dev, "%s codec wakeup\n",
-               enable ? "enable" : "disable");
-
-       acomp->ops->codec_wake_override(acomp->dev, enable);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
-
-/**
- * snd_hdac_display_power - Power up / down the power refcount
- * @bus: HDA core bus
- * @enable: power up or down
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function manages a refcount and calls the i915 get_power() and
- * put_power() ops accordingly, toggling the codec wakeup, too.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
-{
-       struct i915_audio_component *acomp = bus->audio_component;
-
-       if (!acomp || !acomp->ops)
-               return -ENODEV;
-
-       dev_dbg(bus->dev, "display power %s\n",
-               enable ? "enable" : "disable");
-
-       if (enable) {
-               if (!bus->i915_power_refcount++) {
-                       acomp->ops->get_power(acomp->dev);
-                       snd_hdac_set_codec_wakeup(bus, true);
-                       snd_hdac_set_codec_wakeup(bus, false);
-               }
-       } else {
-               WARN_ON(!bus->i915_power_refcount);
-               if (!--bus->i915_power_refcount)
-                       acomp->ops->put_power(acomp->dev);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_display_power);
-
 #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
                                ((pci)->device == 0x0c0c) || \
                                ((pci)->device == 0x0d0c) || \
@@ -119,7 +41,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_display_power);
  */
 void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
 {
-       struct i915_audio_component *acomp = bus->audio_component;
+       struct drm_audio_component *acomp = bus->audio_component;
        struct pci_dev *pci = to_pci_dev(bus->dev);
        int cdclk_freq;
        unsigned int bclk_m, bclk_n;
@@ -158,181 +80,11 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk);
 
-/* There is a fixed mapping between audio pin node and display port.
- * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- *
- * on VLV, ILK:
- * Pin Widget 4 - PORT B (port = 1 in i915 driver)
- * Pin Widget 5 - PORT C (port = 2 in i915 driver)
- * Pin Widget 6 - PORT D (port = 3 in i915 driver)
- */
-static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
+static int i915_component_master_match(struct device *dev, void *data)
 {
-       int base_nid;
-
-       switch (codec->vendor_id) {
-       case 0x80860054: /* ILK */
-       case 0x80862804: /* ILK */
-       case 0x80862882: /* VLV */
-               base_nid = 3;
-               break;
-       default:
-               base_nid = 4;
-               break;
-       }
-
-       if (WARN_ON(pin_nid <= base_nid || pin_nid > base_nid + 3))
-               return -1;
-       return pin_nid - base_nid;
-}
-
-/**
- * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
- * @codec: HDA codec
- * @nid: the pin widget NID
- * @dev_id: device identifier
- * @rate: the sample rate to set
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function sets N/CTS value based on the given sample rate.
- * Returns zero for success, or a negative error code.
- */
-int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
-                            int dev_id, int rate)
-{
-       struct hdac_bus *bus = codec->bus;
-       struct i915_audio_component *acomp = bus->audio_component;
-       int port, pipe;
-
-       if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
-               return -ENODEV;
-       port = pin2port(codec, nid);
-       if (port < 0)
-               return -EINVAL;
-       pipe = dev_id;
-       return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
-
-/**
- * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
- * @codec: HDA codec
- * @nid: the pin widget NID
- * @dev_id: device identifier
- * @audio_enabled: the pointer to store the current audio state
- * @buffer: the buffer pointer to store ELD bytes
- * @max_bytes: the max bytes to be stored on @buffer
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function queries the current state of the audio on the given
- * digital port and fetches the ELD bytes onto the given buffer.
- * It returns the number of bytes for the total ELD data, zero for
- * invalid ELD, or a negative error code.
- *
- * The return size is the total bytes required for the whole ELD bytes,
- * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
- * that only a part of ELD bytes have been fetched.
- */
-int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
-                          bool *audio_enabled, char *buffer, int max_bytes)
-{
-       struct hdac_bus *bus = codec->bus;
-       struct i915_audio_component *acomp = bus->audio_component;
-       int port, pipe;
-
-       if (!acomp || !acomp->ops || !acomp->ops->get_eld)
-               return -ENODEV;
-
-       port = pin2port(codec, nid);
-       if (port < 0)
-               return -EINVAL;
-
-       pipe = dev_id;
-       return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
-                                  buffer, max_bytes);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
-
-static int hdac_component_master_bind(struct device *dev)
-{
-       struct i915_audio_component *acomp = hdac_acomp;
-       int ret;
-
-       ret = component_bind_all(dev, acomp);
-       if (ret < 0)
-               return ret;
-
-       if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
-                     acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
-               ret = -EINVAL;
-               goto out_unbind;
-       }
-
-       /*
-        * Atm, we don't support dynamic unbinding initiated by the child
-        * component, so pin its containing module until we unbind.
-        */
-       if (!try_module_get(acomp->ops->owner)) {
-               ret = -ENODEV;
-               goto out_unbind;
-       }
-
-       return 0;
-
-out_unbind:
-       component_unbind_all(dev, acomp);
-
-       return ret;
-}
-
-static void hdac_component_master_unbind(struct device *dev)
-{
-       struct i915_audio_component *acomp = hdac_acomp;
-
-       module_put(acomp->ops->owner);
-       component_unbind_all(dev, acomp);
-       WARN_ON(acomp->ops || acomp->dev);
-}
-
-static const struct component_master_ops hdac_component_master_ops = {
-       .bind = hdac_component_master_bind,
-       .unbind = hdac_component_master_unbind,
-};
-
-static int hdac_component_master_match(struct device *dev, void *data)
-{
-       /* i915 is the only supported component */
        return !strcmp(dev->driver->name, "i915");
 }
 
-/**
- * snd_hdac_i915_register_notifier - Register i915 audio component ops
- * @aops: i915 audio component ops
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function sets the given ops to be called by the i915 graphics driver.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops)
-{
-       if (!hdac_acomp)
-               return -ENODEV;
-
-       hdac_acomp->audio_ops = aops;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier);
-
 /* check whether intel graphics is present */
 static bool i915_gfx_present(void)
 {
@@ -359,83 +111,26 @@ static bool i915_gfx_present(void)
  */
 int snd_hdac_i915_init(struct hdac_bus *bus)
 {
-       struct component_match *match = NULL;
-       struct device *dev = bus->dev;
-       struct i915_audio_component *acomp;
-       int ret;
-
-       if (WARN_ON(hdac_acomp))
-               return -EBUSY;
+       struct drm_audio_component *acomp;
+       int err;
 
        if (!i915_gfx_present())
                return -ENODEV;
 
-       acomp = kzalloc(sizeof(*acomp), GFP_KERNEL);
+       err = snd_hdac_acomp_init(bus, NULL,
+                                 i915_component_master_match,
+                                 sizeof(struct i915_audio_component) - sizeof(*acomp));
+       if (err < 0)
+               return err;
+       acomp = bus->audio_component;
        if (!acomp)
-               return -ENOMEM;
-       bus->audio_component = acomp;
-       hdac_acomp = acomp;
-
-       component_match_add(dev, &match, hdac_component_master_match, bus);
-       ret = component_master_add_with_match(dev, &hdac_component_master_ops,
-                                             match);
-       if (ret < 0)
-               goto out_err;
-
-       /*
-        * Atm, we don't support deferring the component binding, so make sure
-        * i915 is loaded and that the binding successfully completes.
-        */
-       request_module("i915");
-
+               return -ENODEV;
+       if (!acomp->ops)
+               request_module("i915");
        if (!acomp->ops) {
-               ret = -ENODEV;
-               goto out_master_del;
+               snd_hdac_acomp_exit(bus);
+               return -ENODEV;
        }
-       dev_dbg(dev, "bound to i915 component master\n");
-
        return 0;
-out_master_del:
-       component_master_del(dev, &hdac_component_master_ops);
-out_err:
-       kfree(acomp);
-       bus->audio_component = NULL;
-       hdac_acomp = NULL;
-       dev_info(dev, "failed to add i915 component master (%d)\n", ret);
-
-       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
-
-/**
- * snd_hdac_i915_exit - Finalize i915 audio component
- * @bus: HDA core bus
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function releases the i915 audio component that has been used.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_i915_exit(struct hdac_bus *bus)
-{
-       struct device *dev = bus->dev;
-       struct i915_audio_component *acomp = bus->audio_component;
-
-       if (!acomp)
-               return 0;
-
-       WARN_ON(bus->i915_power_refcount);
-       if (bus->i915_power_refcount > 0 && acomp->ops)
-               acomp->ops->put_power(acomp->dev);
-
-       component_master_del(dev, &hdac_component_master_ops);
-
-       kfree(acomp);
-       bus->audio_component = NULL;
-       hdac_acomp = NULL;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_i915_exit);
index 20a171ac4bb2f7cff9715122c4e959c60fc9b485..3fd0c16fa602de98d3d88993e0b8be32c5e36e14 100644 (file)
@@ -858,6 +858,39 @@ static void snd_hda_codec_dev_release(struct device *dev)
        kfree(codec);
 }
 
+#define DEV_NAME_LEN 31
+
+static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card,
+                       unsigned int codec_addr, struct hda_codec **codecp)
+{
+       char name[DEV_NAME_LEN];
+       struct hda_codec *codec;
+       int err;
+
+       dev_dbg(card->dev, "%s: entry\n", __func__);
+
+       if (snd_BUG_ON(!bus))
+               return -EINVAL;
+       if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
+               return -EINVAL;
+
+       codec = kzalloc(sizeof(*codec), GFP_KERNEL);
+       if (!codec)
+               return -ENOMEM;
+
+       sprintf(name, "hdaudioC%dD%d", card->number, codec_addr);
+       err = snd_hdac_device_init(&codec->core, &bus->core, name, codec_addr);
+       if (err < 0) {
+               kfree(codec);
+               return err;
+       }
+
+       codec->core.type = HDA_DEV_LEGACY;
+       *codecp = codec;
+
+       return err;
+}
+
 /**
  * snd_hda_codec_new - create a HDA codec
  * @bus: the bus to assign
@@ -869,7 +902,19 @@ static void snd_hda_codec_dev_release(struct device *dev)
 int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
                      unsigned int codec_addr, struct hda_codec **codecp)
 {
-       struct hda_codec *codec;
+       int ret;
+
+       ret = snd_hda_codec_device_init(bus, card, codec_addr, codecp);
+       if (ret < 0)
+               return ret;
+
+       return snd_hda_codec_device_new(bus, card, codec_addr, *codecp);
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+
+int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
+                       unsigned int codec_addr, struct hda_codec *codec)
+{
        char component[31];
        hda_nid_t fg;
        int err;
@@ -879,25 +924,14 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
                .dev_free = snd_hda_codec_dev_free,
        };
 
+       dev_dbg(card->dev, "%s: entry\n", __func__);
+
        if (snd_BUG_ON(!bus))
                return -EINVAL;
        if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
                return -EINVAL;
 
-       codec = kzalloc(sizeof(*codec), GFP_KERNEL);
-       if (!codec)
-               return -ENOMEM;
-
-       sprintf(component, "hdaudioC%dD%d", card->number, codec_addr);
-       err = snd_hdac_device_init(&codec->core, &bus->core, component,
-                                  codec_addr);
-       if (err < 0) {
-               kfree(codec);
-               return err;
-       }
-
        codec->core.dev.release = snd_hda_codec_dev_release;
-       codec->core.type = HDA_DEV_LEGACY;
        codec->core.exec_verb = codec_exec_verb;
 
        codec->bus = bus;
@@ -957,15 +991,13 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
        if (err < 0)
                goto error;
 
-       if (codecp)
-               *codecp = codec;
        return 0;
 
  error:
        put_device(hda_codec_dev(codec));
        return err;
 }
-EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+EXPORT_SYMBOL_GPL(snd_hda_codec_device_new);
 
 /**
  * snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
@@ -2992,6 +3024,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
        sync_power_up_states(codec);
        return 0;
 }
+EXPORT_SYMBOL_GPL(snd_hda_codec_build_controls);
 
 /*
  * PCM stuff
@@ -3197,6 +3230,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(snd_hda_codec_parse_pcms);
 
 /* assign all PCMs of the given codec */
 int snd_hda_codec_build_pcms(struct hda_codec *codec)
index a8b1b31f161c26f739892ea6b52e79ba2ebca291..e03b5c1ccc5cf5584c6a517b07b9820846d6b62d 100644 (file)
@@ -308,6 +308,8 @@ struct hda_codec {
  */
 int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
                      unsigned int codec_addr, struct hda_codec **codecp);
+int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
+                     unsigned int codec_addr, struct hda_codec *codec);
 int snd_hda_codec_configure(struct hda_codec *codec);
 int snd_hda_codec_update_widgets(struct hda_codec *codec);
 
index 8a49415aebacb79cd3da6b90b1a34e041da02bbd..1de5491fb9bf611f2d1dda1a4e2d7f44da0cf3d5 100644 (file)
@@ -177,13 +177,13 @@ struct hdmi_spec {
 
        /* i915/powerwell (Haswell+/Valleyview+) specific */
        bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */
-       struct i915_audio_component_audio_ops i915_audio_ops;
+       struct drm_audio_component_audio_ops drm_audio_ops;
 
        struct hdac_chmap chmap;
        hda_nid_t vendor_nid;
 };
 
-#ifdef CONFIG_SND_HDA_I915
+#ifdef CONFIG_SND_HDA_COMPONENT
 static inline bool codec_has_acomp(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -2288,7 +2288,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
        int pin_idx, pcm_idx;
 
        if (codec_has_acomp(codec))
-               snd_hdac_i915_register_notifier(NULL);
+               snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
                struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -2471,6 +2471,38 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        snd_hda_codec_set_power_to_all(codec, fg, power_state);
 }
 
+/* There is a fixed mapping between audio pin node and display port.
+ * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ *
+ * on VLV, ILK:
+ * Pin Widget 4 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 5 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 6 - PORT D (port = 3 in i915 driver)
+ */
+static int intel_base_nid(struct hda_codec *codec)
+{
+       switch (codec->core.vendor_id) {
+       case 0x80860054: /* ILK */
+       case 0x80862804: /* ILK */
+       case 0x80862882: /* VLV */
+               return 4;
+       default:
+               return 5;
+       }
+}
+
+static int intel_pin2port(void *audio_ptr, int pin_nid)
+{
+       int base_nid = intel_base_nid(audio_ptr);
+
+       if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
+               return -1;
+       return pin_nid - base_nid + 1; /* intel port is 1-based */
+}
+
 static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
 {
        struct hda_codec *codec = audio_ptr;
@@ -2481,16 +2513,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
        if (port < 1 || port > 3)
                return;
 
-       switch (codec->core.vendor_id) {
-       case 0x80860054: /* ILK */
-       case 0x80862804: /* ILK */
-       case 0x80862882: /* VLV */
-               pin_nid = port + 0x03;
-               break;
-       default:
-               pin_nid = port + 0x04;
-               break;
-       }
+       pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
 
        /* skip notification during system suspend (but not in runtime PM);
         * the state will be updated at resume
@@ -2511,14 +2534,16 @@ static void register_i915_notifier(struct hda_codec *codec)
        struct hdmi_spec *spec = codec->spec;
 
        spec->use_acomp_notifier = true;
-       spec->i915_audio_ops.audio_ptr = codec;
+       spec->drm_audio_ops.audio_ptr = codec;
        /* intel_audio_codec_enable() or intel_audio_codec_disable()
         * will call pin_eld_notify with using audio_ptr pointer
         * We need make sure audio_ptr is really setup
         */
        wmb();
-       spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
-       snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
+       spec->drm_audio_ops.pin2port = intel_pin2port;
+       spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
+       snd_hdac_acomp_register_notifier(&codec->bus->core,
+                                       &spec->drm_audio_ops);
 }
 
 /* setup_stream ops override for HSW+ */
index 41af6b9cc3500bead51340637e24f4288e135100..1cf11cf51e1dd6912c3bdce14c9e651b4fd955c2 100644 (file)
@@ -57,6 +57,7 @@ source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/img/Kconfig"
 source "sound/soc/intel/Kconfig"
 source "sound/soc/mediatek/Kconfig"
+source "sound/soc/meson/Kconfig"
 source "sound/soc/mxs/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/qcom/Kconfig"
index 06389a5385d71ac05806a9d1db7eab1678b2dc2a..62a5f87c3cfc435b4ff8b1984f77ec65b3e53578 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
 obj-$(CONFIG_SND_SOC)  += img/
 obj-$(CONFIG_SND_SOC)  += intel/
 obj-$(CONFIG_SND_SOC)  += mediatek/
+obj-$(CONFIG_SND_SOC)  += meson/
 obj-$(CONFIG_SND_SOC)  += mxs/
 obj-$(CONFIG_SND_SOC)  += nuc900/
 obj-$(CONFIG_SND_SOC)  += omap/
index 6cbf9cf4d1a4c2e451a5d0f434b806dfbc414a87..58c1dcb4d2550f0931b182129747b471e84a7562 100644 (file)
@@ -8,6 +8,7 @@ config SND_SOC_AMD_CZ_DA7219MX98357_MACH
        select SND_SOC_DA7219
        select SND_SOC_MAX98357A
        select SND_SOC_ADAU7002
+       select REGULATOR
        depends on SND_SOC_AMD_ACP && I2C
        help
         This option enables machine driver for DA7219 and MAX9835.
index ccddc6650b9c79a112791e3d5ecd2e11d77e8494..8e3275a96a82102be7da0d4d2dc6b694c01571fd 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/acpi.h>
@@ -148,7 +150,8 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                   &constraints_rates);
 
-       machine->i2s_instance = I2S_BT_INSTANCE;
+       machine->i2s_instance = I2S_SP_INSTANCE;
+       machine->capture_channel = CAP_CHANNEL1;
        return da7219_clk_enable(substream);
 }
 
@@ -163,7 +166,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream)
        struct snd_soc_card *card = rtd->card;
        struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 
-       machine->i2s_instance = I2S_SP_INSTANCE;
+       machine->i2s_instance = I2S_BT_INSTANCE;
        return da7219_clk_enable(substream);
 }
 
@@ -172,13 +175,24 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
        da7219_clk_disable();
 }
 
-static int cz_dmic_startup(struct snd_pcm_substream *substream)
+static int cz_dmic0_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+       struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
+
+       machine->i2s_instance = I2S_BT_INSTANCE;
+       return da7219_clk_enable(substream);
+}
+
+static int cz_dmic1_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_card *card = rtd->card;
        struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 
        machine->i2s_instance = I2S_SP_INSTANCE;
+       machine->capture_channel = CAP_CHANNEL0;
        return da7219_clk_enable(substream);
 }
 
@@ -197,23 +211,39 @@ static const struct snd_soc_ops cz_max_play_ops = {
        .shutdown = cz_max_shutdown,
 };
 
-static const struct snd_soc_ops cz_dmic_cap_ops = {
-       .startup = cz_dmic_startup,
+static const struct snd_soc_ops cz_dmic0_cap_ops = {
+       .startup = cz_dmic0_startup,
+       .shutdown = cz_dmic_shutdown,
+};
+
+static const struct snd_soc_ops cz_dmic1_cap_ops = {
+       .startup = cz_dmic1_startup,
        .shutdown = cz_dmic_shutdown,
 };
 
 static struct snd_soc_dai_link cz_dai_7219_98357[] = {
        {
-               .name = "amd-da7219-play-cap",
-               .stream_name = "Playback and Capture",
+               .name = "amd-da7219-play",
+               .stream_name = "Playback",
                .platform_name = "acp_audio_dma.0.auto",
-               .cpu_dai_name = "designware-i2s.3.auto",
+               .cpu_dai_name = "designware-i2s.1.auto",
                .codec_dai_name = "da7219-hifi",
                .codec_name = "i2c-DLGS7219:00",
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
                                | SND_SOC_DAIFMT_CBM_CFM,
                .init = cz_da7219_init,
                .dpcm_playback = 1,
+               .ops = &cz_da7219_cap_ops,
+       },
+       {
+               .name = "amd-da7219-cap",
+               .stream_name = "Capture",
+               .platform_name = "acp_audio_dma.0.auto",
+               .cpu_dai_name = "designware-i2s.2.auto",
+               .codec_dai_name = "da7219-hifi",
+               .codec_name = "i2c-DLGS7219:00",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
                .dpcm_capture = 1,
                .ops = &cz_da7219_cap_ops,
        },
@@ -221,7 +251,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
                .name = "amd-max98357-play",
                .stream_name = "HiFi Playback",
                .platform_name = "acp_audio_dma.0.auto",
-               .cpu_dai_name = "designware-i2s.1.auto",
+               .cpu_dai_name = "designware-i2s.3.auto",
                .codec_dai_name = "HiFi",
                .codec_name = "MX98357A:00",
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
@@ -230,8 +260,22 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
                .ops = &cz_max_play_ops,
        },
        {
-               .name = "dmic",
-               .stream_name = "DMIC Capture",
+               /* C panel DMIC */
+               .name = "dmic0",
+               .stream_name = "DMIC0 Capture",
+               .platform_name = "acp_audio_dma.0.auto",
+               .cpu_dai_name = "designware-i2s.3.auto",
+               .codec_dai_name = "adau7002-hifi",
+               .codec_name = "ADAU7002:00",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .dpcm_capture = 1,
+               .ops = &cz_dmic0_cap_ops,
+       },
+       {
+               /* A/B panel DMIC */
+               .name = "dmic1",
+               .stream_name = "DMIC1 Capture",
                .platform_name = "acp_audio_dma.0.auto",
                .cpu_dai_name = "designware-i2s.2.auto",
                .codec_dai_name = "adau7002-hifi",
@@ -239,7 +283,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
                                | SND_SOC_DAIFMT_CBM_CFM,
                .dpcm_capture = 1,
-               .ops = &cz_dmic_cap_ops,
+               .ops = &cz_dmic1_cap_ops,
        },
 };
 
@@ -278,11 +322,52 @@ static struct snd_soc_card cz_card = {
        .num_controls = ARRAY_SIZE(cz_mc_controls),
 };
 
+static struct regulator_consumer_supply acp_da7219_supplies[] = {
+       REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"),
+       REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"),
+       REGULATOR_SUPPLY("VDDIO", "i2c-DLGS7219:00"),
+       REGULATOR_SUPPLY("IOVDD", "ADAU7002:00"),
+};
+
+static struct regulator_init_data acp_da7219_data = {
+       .constraints = {
+               .always_on = 1,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(acp_da7219_supplies),
+       .consumer_supplies = acp_da7219_supplies,
+};
+
+static struct regulator_config acp_da7219_cfg = {
+       .init_data = &acp_da7219_data,
+};
+
+static struct regulator_ops acp_da7219_ops = {
+};
+
+static struct regulator_desc acp_da7219_desc = {
+       .name = "reg-fixed-1.8V",
+       .type = REGULATOR_VOLTAGE,
+       .owner = THIS_MODULE,
+       .ops = &acp_da7219_ops,
+       .fixed_uV = 1800000, /* 1.8V */
+       .n_voltages = 1,
+};
+
 static int cz_probe(struct platform_device *pdev)
 {
        int ret;
        struct snd_soc_card *card;
        struct acp_platform_info *machine;
+       struct regulator_dev *rdev;
+
+       acp_da7219_cfg.dev = &pdev->dev;
+       rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc,
+                                      &acp_da7219_cfg);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "Failed to register regulator: %d\n",
+                       (int)PTR_ERR(rdev));
+               return -EINVAL;
+       }
 
        machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
                               GFP_KERNEL);
index 1458b504849820187317d507834941f2da7f9acc..e359938e3d7e16bfd3995084be4e1b20d6b1989e 100644 (file)
@@ -224,13 +224,11 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
                        switch (asic_type) {
                        case CHIP_STONEY:
                                dmadscr[i].xfer_val |=
-                               BIT(22) |
                                (ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC << 16) |
                                (size / 2);
                                break;
                        default:
                                dmadscr[i].xfer_val |=
-                               BIT(22) |
                                (ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION << 16) |
                                (size / 2);
                        }
@@ -322,22 +320,87 @@ static void config_acp_dma(void __iomem *acp_mmio,
                           struct audio_substream_data *rtd,
                           u32 asic_type)
 {
+       u16 ch_acp_sysmem, ch_acp_i2s;
+
        acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
                       rtd->pte_offset);
+
+       if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+               ch_acp_sysmem = rtd->ch1;
+               ch_acp_i2s = rtd->ch2;
+       } else {
+               ch_acp_i2s = rtd->ch1;
+               ch_acp_sysmem = rtd->ch2;
+       }
        /* Configure System memory <-> ACP SRAM DMA descriptors */
        set_acp_sysmem_dma_descriptors(acp_mmio, rtd->size,
                                       rtd->direction, rtd->pte_offset,
-                                      rtd->ch1, rtd->sram_bank,
+                                      ch_acp_sysmem, rtd->sram_bank,
                                       rtd->dma_dscr_idx_1, asic_type);
        /* Configure ACP SRAM <-> I2S DMA descriptors */
        set_acp_to_i2s_dma_descriptors(acp_mmio, rtd->size,
                                       rtd->direction, rtd->sram_bank,
-                                      rtd->destination, rtd->ch2,
+                                      rtd->destination, ch_acp_i2s,
                                       rtd->dma_dscr_idx_2, asic_type);
 }
 
+static void acp_dma_cap_channel_enable(void __iomem *acp_mmio,
+                                      u16 cap_channel)
+{
+       u32 val, ch_reg, imr_reg, res_reg;
+
+       switch (cap_channel) {
+       case CAP_CHANNEL1:
+               ch_reg = mmACP_I2SMICSP_RER1;
+               res_reg = mmACP_I2SMICSP_RCR1;
+               imr_reg = mmACP_I2SMICSP_IMR1;
+               break;
+       case CAP_CHANNEL0:
+       default:
+               ch_reg = mmACP_I2SMICSP_RER0;
+               res_reg = mmACP_I2SMICSP_RCR0;
+               imr_reg = mmACP_I2SMICSP_IMR0;
+               break;
+       }
+       val = acp_reg_read(acp_mmio,
+                          mmACP_I2S_16BIT_RESOLUTION_EN);
+       if (val & ACP_I2S_MIC_16BIT_RESOLUTION_EN) {
+               acp_reg_write(0x0, acp_mmio, ch_reg);
+               /* Set 16bit resolution on capture */
+               acp_reg_write(0x2, acp_mmio, res_reg);
+       }
+       val = acp_reg_read(acp_mmio, imr_reg);
+       val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
+       val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
+       acp_reg_write(val, acp_mmio, imr_reg);
+       acp_reg_write(0x1, acp_mmio, ch_reg);
+}
+
+static void acp_dma_cap_channel_disable(void __iomem *acp_mmio,
+                                       u16 cap_channel)
+{
+       u32 val, ch_reg, imr_reg;
+
+       switch (cap_channel) {
+       case CAP_CHANNEL1:
+               imr_reg = mmACP_I2SMICSP_IMR1;
+               ch_reg = mmACP_I2SMICSP_RER1;
+               break;
+       case CAP_CHANNEL0:
+       default:
+               imr_reg = mmACP_I2SMICSP_IMR0;
+               ch_reg = mmACP_I2SMICSP_RER0;
+               break;
+       }
+       val = acp_reg_read(acp_mmio, imr_reg);
+       val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
+       val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
+       acp_reg_write(val, acp_mmio, imr_reg);
+       acp_reg_write(0x0, acp_mmio, ch_reg);
+}
+
 /* Start a given DMA channel transfer */
-static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
+static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular)
 {
        u32 dma_ctrl;
 
@@ -356,10 +419,8 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
 
        switch (ch_num) {
        case ACP_TO_I2S_DMA_CH_NUM:
-       case ACP_TO_SYSRAM_CH_NUM:
        case I2S_TO_ACP_DMA_CH_NUM:
        case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM:
-       case ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM:
        case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM:
                dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
                break;
@@ -368,8 +429,11 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
                break;
        }
 
-       /* circular for both DMA channel */
-       dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+       /* enable for ACP to SRAM DMA channel */
+       if (is_circular == true)
+               dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+       else
+               dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
 
        acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
 }
@@ -613,6 +677,7 @@ static int acp_deinit(void __iomem *acp_mmio)
 /* ACP DMA irq handler routine for playback, capture usecases */
 static irqreturn_t dma_irq_handler(int irq, void *arg)
 {
+       u16 dscr_idx;
        u32 intr_flag, ext_intr_status;
        struct audio_drv_data *irq_data;
        void __iomem *acp_mmio;
@@ -644,32 +709,39 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
 
        if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
                valid_irq = true;
+               if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_14) ==
+                               CAPTURE_START_DMA_DESCR_CH15)
+                       dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
+               else
+                       dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
+               config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
+                                      1, 0);
+               acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
+
                snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
                acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
                              acp_mmio, mmACP_EXTERNAL_INTR_STAT);
        }
 
-       if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
-               valid_irq = true;
-               acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
-                             acp_mmio, mmACP_EXTERNAL_INTR_STAT);
-       }
-
        if ((intr_flag & BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) != 0) {
                valid_irq = true;
+               if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_10) ==
+                       CAPTURE_START_DMA_DESCR_CH11)
+                       dscr_idx = CAPTURE_END_DMA_DESCR_CH10;
+               else
+                       dscr_idx = CAPTURE_START_DMA_DESCR_CH10;
+               config_acp_dma_channel(acp_mmio,
+                                      ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
+                                      dscr_idx, 1, 0);
+               acp_dma_start(acp_mmio, ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
+                             false);
+
                snd_pcm_period_elapsed(irq_data->capture_i2sbt_stream);
                acp_reg_write((intr_flag &
                              BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) << 16,
                              acp_mmio, mmACP_EXTERNAL_INTR_STAT);
        }
 
-       if ((intr_flag & BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) != 0) {
-               valid_irq = true;
-               acp_reg_write((intr_flag &
-                             BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) << 16,
-                             acp_mmio, mmACP_EXTERNAL_INTR_STAT);
-       }
-
        if (valid_irq)
                return IRQ_HANDLED;
        else
@@ -773,8 +845,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
        if (WARN_ON(!rtd))
                return -EINVAL;
 
-       if (pinfo)
+       if (pinfo) {
                rtd->i2s_instance = pinfo->i2s_instance;
+               rtd->capture_channel = pinfo->capture_channel;
+       }
        if (adata->asic_type == CHIP_STONEY) {
                val = acp_reg_read(adata->acp_mmio,
                                   mmACP_I2S_16BIT_RESOLUTION_EN);
@@ -842,8 +916,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
                switch (rtd->i2s_instance) {
                case I2S_BT_INSTANCE:
                        rtd->pte_offset = ACP_ST_BT_CAPTURE_PTE_OFFSET;
-                       rtd->ch1 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
-                       rtd->ch2 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
+                       rtd->ch1 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
+                       rtd->ch2 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
                        rtd->sram_bank = ACP_SRAM_BANK_4_ADDRESS;
                        rtd->destination = FROM_BLUETOOTH;
                        rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH10;
@@ -852,13 +926,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
                                        mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH;
                        rtd->byte_cnt_low_reg_offset =
                                        mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW;
+                       rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11;
                        adata->capture_i2sbt_stream = substream;
                        break;
                case I2S_SP_INSTANCE:
                default:
                        rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
-                       rtd->ch1 = ACP_TO_SYSRAM_CH_NUM;
-                       rtd->ch2 = I2S_TO_ACP_DMA_CH_NUM;
+                       rtd->ch1 = I2S_TO_ACP_DMA_CH_NUM;
+                       rtd->ch2 = ACP_TO_SYSRAM_CH_NUM;
                        switch (adata->asic_type) {
                        case CHIP_STONEY:
                                rtd->pte_offset = ACP_ST_CAPTURE_PTE_OFFSET;
@@ -875,6 +950,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
                                        mmACP_I2S_RECEIVED_BYTE_CNT_HIGH;
                        rtd->byte_cnt_low_reg_offset =
                                        mmACP_I2S_RECEIVED_BYTE_CNT_LOW;
+                       rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_15;
                        adata->capture_i2ssp_stream = substream;
                }
        }
@@ -928,6 +1004,8 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
        u32 buffersize;
        u32 pos = 0;
        u64 bytescount = 0;
+       u16 dscr;
+       u32 period_bytes, delay;
 
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct audio_substream_data *rtd = runtime->private_data;
@@ -935,12 +1013,25 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
        if (!rtd)
                return -EINVAL;
 
-       buffersize = frames_to_bytes(runtime, runtime->buffer_size);
-       bytescount = acp_get_byte_count(rtd);
-
-       if (bytescount > rtd->bytescount)
-               bytescount -= rtd->bytescount;
-       pos = do_div(bytescount, buffersize);
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               period_bytes = frames_to_bytes(runtime, runtime->period_size);
+               dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
+               if (dscr == rtd->dma_dscr_idx_1)
+                       pos = period_bytes;
+               else
+                       pos = 0;
+               bytescount = acp_get_byte_count(rtd);
+               if (bytescount > rtd->bytescount)
+                       bytescount -= rtd->bytescount;
+               delay = do_div(bytescount, period_bytes);
+               runtime->delay = bytes_to_frames(runtime, delay);
+       } else {
+               buffersize = frames_to_bytes(runtime, runtime->buffer_size);
+               bytescount = acp_get_byte_count(rtd);
+               if (bytescount > rtd->bytescount)
+                       bytescount -= rtd->bytescount;
+               pos = do_div(bytescount, buffersize);
+       }
        return bytes_to_frames(runtime, pos);
 }
 
@@ -954,16 +1045,24 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct audio_substream_data *rtd = runtime->private_data;
+       u16 ch_acp_sysmem, ch_acp_i2s;
 
        if (!rtd)
                return -EINVAL;
 
+       if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+               ch_acp_sysmem = rtd->ch1;
+               ch_acp_i2s = rtd->ch2;
+       } else {
+               ch_acp_i2s = rtd->ch1;
+               ch_acp_sysmem = rtd->ch2;
+       }
        config_acp_dma_channel(rtd->acp_mmio,
-                              rtd->ch1,
+                              ch_acp_sysmem,
                               rtd->dma_dscr_idx_1,
                               NUM_DSCRS_PER_CHANNEL, 0);
        config_acp_dma_channel(rtd->acp_mmio,
-                              rtd->ch2,
+                              ch_acp_i2s,
                               rtd->dma_dscr_idx_2,
                               NUM_DSCRS_PER_CHANNEL, 0);
        return 0;
@@ -972,7 +1071,6 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
 static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        int ret;
-       u64 bytescount = 0;
 
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct audio_substream_data *rtd = runtime->private_data;
@@ -983,37 +1081,32 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_RESUME:
-               bytescount = acp_get_byte_count(rtd);
-               if (rtd->bytescount == 0)
-                       rtd->bytescount = bytescount;
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       acp_dma_start(rtd->acp_mmio, rtd->ch1);
-                       acp_dma_start(rtd->acp_mmio, rtd->ch2);
+               rtd->bytescount = acp_get_byte_count(rtd);
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       if (rtd->capture_channel == CAP_CHANNEL0) {
+                               acp_dma_cap_channel_disable(rtd->acp_mmio,
+                                                           CAP_CHANNEL1);
+                               acp_dma_cap_channel_enable(rtd->acp_mmio,
+                                                          CAP_CHANNEL0);
+                       }
+                       if (rtd->capture_channel == CAP_CHANNEL1) {
+                               acp_dma_cap_channel_disable(rtd->acp_mmio,
+                                                           CAP_CHANNEL0);
+                               acp_dma_cap_channel_enable(rtd->acp_mmio,
+                                                          CAP_CHANNEL1);
+                       }
+                       acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
                } else {
-                       acp_dma_start(rtd->acp_mmio, rtd->ch2);
-                       acp_dma_start(rtd->acp_mmio, rtd->ch1);
+                       acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
+                       acp_dma_start(rtd->acp_mmio, rtd->ch2, true);
                }
                ret = 0;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               /* For playback, non circular dma should be stopped first
-                * i.e Sysram to acp dma transfer channel(rtd->ch1) should be
-                * stopped before stopping cirular dma which is acp sram to i2s
-                * fifo dma transfer channel(rtd->ch2). Where as in Capture
-                * scenario, i2s fifo to acp sram dma channel(rtd->ch2) stopped
-                * first before stopping acp sram to sysram which is circular
-                * dma(rtd->ch1).
-                */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       acp_dma_stop(rtd->acp_mmio, rtd->ch1);
-                       ret =  acp_dma_stop(rtd->acp_mmio, rtd->ch2);
-               } else {
-                       acp_dma_stop(rtd->acp_mmio, rtd->ch2);
-                       ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
-               }
-               rtd->bytescount = 0;
+               acp_dma_stop(rtd->acp_mmio, rtd->ch2);
+               ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
                break;
        default:
                ret = -EINVAL;
index 9cd3e96c84d473ef39bef686ecf16cd9411c18f1..be3963e8f4fac527c2f048f595575c5b88397517 100644 (file)
@@ -55,6 +55,8 @@
 
 #define I2S_SP_INSTANCE                 0x01
 #define I2S_BT_INSTANCE                 0x02
+#define CAP_CHANNEL0                   0x00
+#define CAP_CHANNEL1                   0x01
 
 #define ACP_TILE_ON_MASK                0x03
 #define ACP_TILE_OFF_MASK               0x02
 #define ACP_TO_I2S_DMA_CH_NUM 13
 
 /* Capture DMA channels */
-#define ACP_TO_SYSRAM_CH_NUM 14
-#define I2S_TO_ACP_DMA_CH_NUM 15
+#define I2S_TO_ACP_DMA_CH_NUM 14
+#define ACP_TO_SYSRAM_CH_NUM 15
 
 /* Playback DMA Channels for I2S BT instance */
 #define SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM  8
 #define ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM 9
 
 /* Capture DMA Channels for I2S BT Instance */
-#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 10
-#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 11
+#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 10
+#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 11
 
 #define NUM_DSCRS_PER_CHANNEL 2
 
@@ -125,6 +127,7 @@ struct audio_substream_data {
        unsigned int order;
        u16 num_of_pages;
        u16 i2s_instance;
+       u16 capture_channel;
        u16 direction;
        u16 ch1;
        u16 ch2;
@@ -135,6 +138,7 @@ struct audio_substream_data {
        u32 sram_bank;
        u32 byte_cnt_high_reg_offset;
        u32 byte_cnt_low_reg_offset;
+       u32 dma_curr_dscr;
        uint64_t size;
        u64 bytescount;
        void __iomem *acp_mmio;
@@ -155,6 +159,7 @@ struct audio_drv_data {
  */
 struct acp_platform_info {
        u16 i2s_instance;
+       u16 capture_channel;
 };
 
 union acp_dma_count {
index 5d3b5af9fd92ff37d0bd585e6569002fd1c5d740..d88c1d995036c53922e5defc6d112e918a6062bd 100644 (file)
@@ -206,7 +206,6 @@ struct atmel_i2s_dev {
        struct regmap                           *regmap;
        struct clk                              *pclk;
        struct clk                              *gclk;
-       struct clk                              *aclk;
        struct snd_dmaengine_dai_dma_data       playback;
        struct snd_dmaengine_dai_dma_data       capture;
        unsigned int                            fmt;
@@ -303,7 +302,7 @@ static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
 {
        int i, best;
 
-       if (!dev->gclk || !dev->aclk) {
+       if (!dev->gclk) {
                dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
                return -EINVAL;
        }
@@ -421,7 +420,7 @@ static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
                                          bool enabled)
 {
        unsigned int mr, mr_mask;
-       unsigned long aclk_rate;
+       unsigned long gclk_rate;
        int ret;
 
        mr = 0;
@@ -445,35 +444,18 @@ static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
                /* Disable/unprepare the PMC generated clock. */
                clk_disable_unprepare(dev->gclk);
 
-               /* Disable/unprepare the PLL audio clock. */
-               clk_disable_unprepare(dev->aclk);
                return 0;
        }
 
        if (!dev->gck_param)
                return -EINVAL;
 
-       aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
+       gclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
 
-       /* Fist change the PLL audio clock frequency ... */
-       ret = clk_set_rate(dev->aclk, aclk_rate);
+       ret = clk_set_rate(dev->gclk, gclk_rate);
        if (ret)
                return ret;
 
-       /*
-        * ... then set the PMC generated clock rate to the very same frequency
-        * to set the gclk parent to aclk.
-        */
-       ret = clk_set_rate(dev->gclk, aclk_rate);
-       if (ret)
-               return ret;
-
-       /* Prepare and enable the PLL audio clock first ... */
-       ret = clk_prepare_enable(dev->aclk);
-       if (ret)
-               return ret;
-
-       /* ... then prepare and enable the PMC generated clock. */
        ret = clk_prepare_enable(dev->gclk);
        if (ret)
                return ret;
@@ -668,28 +650,14 @@ static int atmel_i2s_probe(struct platform_device *pdev)
                return err;
        }
 
-       /* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
-       dev->aclk = devm_clk_get(&pdev->dev, "aclk");
+       /* Get audio clock to generate the I2S Master Clock (I2S_MCK) */
        dev->gclk = devm_clk_get(&pdev->dev, "gclk");
-       if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
-               if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
-                   PTR_ERR(dev->gclk) == -EPROBE_DEFER)
+       if (IS_ERR(dev->gclk)) {
+               if (PTR_ERR(dev->gclk) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
                /* Master Mode not supported */
-               dev->aclk = NULL;
                dev->gclk = NULL;
-       } else if (IS_ERR(dev->gclk)) {
-               err = PTR_ERR(dev->gclk);
-               dev_err(&pdev->dev,
-                       "failed to get the PMC generated clock: %d\n", err);
-               return err;
-       } else if (IS_ERR(dev->aclk)) {
-               err = PTR_ERR(dev->aclk);
-               dev_err(&pdev->dev,
-                       "failed to get the PLL audio clock: %d\n", err);
-               return err;
        }
-
        dev->dev = &pdev->dev;
        dev->regmap = regmap;
        platform_set_drvdata(pdev, dev);
index 63cf62e9c9aa67733908f4011c30482b09e72457..efb095dbcd7145a5267bb7bda73552be43324095 100644 (file)
@@ -74,12 +74,12 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_DA7219 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
-       select SND_SOC_DIO2125
        select SND_SOC_DMIC if GPIOLIB
        select SND_SOC_ES8316 if I2C
        select SND_SOC_ES8328_SPI if SPI_MASTER
        select SND_SOC_ES8328_I2C if I2C
        select SND_SOC_ES7134
+       select SND_SOC_ES7241
        select SND_SOC_GTM601
        select SND_SOC_HDAC_HDMI
        select SND_SOC_ICS43432
@@ -141,8 +141,10 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_RT5668 if I2C
        select SND_SOC_RT5670 if I2C
        select SND_SOC_RT5677 if I2C && SPI_MASTER
+       select SND_SOC_RT5682 if I2C
        select SND_SOC_SGTL5000 if I2C
        select SND_SOC_SI476X if MFD_SI476X_CORE
+       select SND_SOC_SIMPLE_AMPLIFIER
        select SND_SOC_SIRF_AUDIO_CODEC
        select SND_SOC_SPDIF
        select SND_SOC_SSM2305
@@ -572,10 +574,6 @@ config SND_SOC_DA732X
 config SND_SOC_DA9055
        tristate
 
-config SND_SOC_DIO2125
-       tristate "Dioo DIO2125 Amplifier"
-       select GPIOLIB
-
 config SND_SOC_DMIC
        tristate
 
@@ -588,6 +586,9 @@ config SND_SOC_HDMI_CODEC
 config SND_SOC_ES7134
        tristate "Everest Semi ES7134 CODEC"
 
+config SND_SOC_ES7241
+       tristate "Everest Semi ES7241 CODEC"
+
 config SND_SOC_ES8316
        tristate "Everest Semi ES8316 CODEC"
        depends on I2C
@@ -778,6 +779,7 @@ config SND_SOC_RL6231
        default y if SND_SOC_RT5668=y
        default y if SND_SOC_RT5670=y
        default y if SND_SOC_RT5677=y
+       default y if SND_SOC_RT5682=y
        default y if SND_SOC_RT1305=y
        default m if SND_SOC_RT5514=m
        default m if SND_SOC_RT5616=m
@@ -791,6 +793,7 @@ config SND_SOC_RL6231
        default m if SND_SOC_RT5668=m
        default m if SND_SOC_RT5670=m
        default m if SND_SOC_RT5677=m
+       default m if SND_SOC_RT5682=m
        default m if SND_SOC_RT1305=m
 
 config SND_SOC_RL6347A
@@ -871,6 +874,9 @@ config SND_SOC_RT5677_SPI
        tristate
        default SND_SOC_RT5677 && SPI
 
+config SND_SOC_RT5682
+       tristate
+
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
        tristate "Freescale SGTL5000 CODEC"
@@ -891,6 +897,10 @@ config SND_SOC_SIGMADSP_REGMAP
        tristate
        select SND_SOC_SIGMADSP
 
+config SND_SOC_SIMPLE_AMPLIFIER
+       tristate "Simple Audio Amplifier"
+       select GPIOLIB
+
 config SND_SOC_SIRF_AUDIO_CODEC
        tristate "SiRF SoC internal audio codec"
        select REGMAP_MMIO
@@ -953,8 +963,11 @@ config SND_SOC_TAS5086
        depends on I2C
 
 config SND_SOC_TAS571X
-       tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers"
+       tristate "Texas Instruments TAS571x power amplifiers"
        depends on I2C
+       help
+         Enable support for Texas Instruments TAS5707, TAS5711, TAS5717,
+         TAS5719 and TAS5721 power amplifiers
 
 config SND_SOC_TAS5720
        tristate "Texas Instruments TAS5720 Mono Audio amplifier"
index e023fdf852215dea0e27bb5a9e2f7ac97e26a003..7ae7c85e8219f5ff035dacaea3abc4b831296056 100644 (file)
@@ -71,6 +71,7 @@ snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-es7134-objs := es7134.o
+snd-soc-es7241-objs := es7241.o
 snd-soc-es8316-objs := es8316.o
 snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
@@ -146,6 +147,7 @@ snd-soc-rt5668-objs := rt5668.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-spi-objs := rt5677-spi.o
+snd-soc-rt5682-objs := rt5682.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
@@ -249,9 +251,9 @@ snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-zx-aud96p22-objs := zx_aud96p22.o
 # Amp
-snd-soc-dio2125-objs := dio2125.o
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
+snd-soc-simple-amplifier-objs := simple-amplifier.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-tas2552-objs := tas2552.o
 
@@ -329,6 +331,7 @@ obj-$(CONFIG_SND_SOC_DA732X)        += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)   += snd-soc-es7134.o
+obj-$(CONFIG_SND_SOC_ES7241)   += snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
 obj-$(CONFIG_SND_SOC_ES8328)   += snd-soc-es8328.o
 obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
@@ -405,6 +408,7 @@ obj-$(CONFIG_SND_SOC_RT5668)        += snd-soc-rt5668.o
 obj-$(CONFIG_SND_SOC_RT5670)   += snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)   += snd-soc-rt5677.o
 obj-$(CONFIG_SND_SOC_RT5677_SPI)       += snd-soc-rt5677-spi.o
+obj-$(CONFIG_SND_SOC_RT5682)   += snd-soc-rt5682.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)     += snd-soc-sigmadsp-i2c.o
@@ -507,7 +511,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS)       += snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
 
 # Amp
-obj-$(CONFIG_SND_SOC_DIO2125)  += snd-soc-dio2125.o
 obj-$(CONFIG_SND_SOC_MAX9877)  += snd-soc-max9877.o
 obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
+obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)        += snd-soc-tpa6130a2.o
index ae41edd1c406b4fa38d1aed55670cfd227ee660a..57169b8ff14e3f4d02871ccbc074eb14fec5d5e5 100644 (file)
@@ -299,6 +299,7 @@ static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
 
        { "DSP", NULL, "Left Decimator" },
        { "DSP", NULL, "Right Decimator" },
+       { "DSP", NULL, "Playback" },
 };
 
 static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
index db21ecbe07625b5f972797de08ff51694f98c2df..8b9ca7e7a68242b5d2a632f6586fafe9b13e55a6 100644 (file)
@@ -648,6 +648,7 @@ static int adav80x_set_pll(struct snd_soc_component *component, int pll_id,
                        pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV;
                        break;
                }
+               /* fall through */
        default:
                return -EINVAL;
        }
index 31ec0ba2e639f2179c7574176f138c6e1cf106ea..299ada4dfaa009f7cdc1d04f6b02ac13987597ae 100644 (file)
@@ -558,7 +558,7 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
 }
 #endif /* CONFIG_PM */
 
-struct snd_soc_component_driver soc_codec_dev_ak4458 = {
+static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
        .probe                  = ak4458_probe,
        .remove                 = ak4458_remove,
        .controls               = ak4458_snd_controls,
index b7ee13406d93b0a6b4967a920dc02a6f1f3d399b..2fa83a1a84cf126f7b37b8da00fd46d4fd45548b 100644 (file)
@@ -1,13 +1,8 @@
-/*
- * ak4554.c
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+// ak4554.c
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
 #include <linux/module.h>
 #include <sound/soc.h>
@@ -97,6 +92,6 @@ static struct platform_driver ak4554_driver = {
 };
 module_platform_driver(ak4554_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("SoC AK4554 driver");
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 8523ff9351cf59a61bcf48517fc7cc08484fdbec..c1181a20714ddeaa8c634fa8cff119c1d52079d0 100644 (file)
@@ -1,18 +1,14 @@
-/*
- * ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
- *
- * Copyright (C) 2015 Renesas Electronics Corporation
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on ak4642.c by Kuninori Morimoto
- * Based on wm8731.c by Richard Purdie
- * Based on ak4535.c by Richard Purdie
- * Based on wm8753.c by Liam Girdwood
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
+//
+// Copyright (C) 2015 Renesas Electronics Corporation
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on ak4642.c by Kuninori Morimoto
+// Based on wm8731.c by Richard Purdie
+// Based on ak4535.c by Richard Purdie
+// Based on wm8753.c by Liam Girdwood
 
 #include <linux/clk.h>
 #include <linux/delay.h>
index 605055964529880b9c8589c49837460bcc5bb681..3532370255140e03f2f91289b871ff59e98762ee 100644 (file)
@@ -1,17 +1,13 @@
-/*
- * ak4642.c  --  AK4642/AK4643 ALSA Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on wm8731.c by Richard Purdie
- * Based on ak4535.c by Richard Purdie
- * Based on wm8753.c by Liam Girdwood
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ak4642.c  --  AK4642/AK4643 ALSA Soc Audio driver
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Based on wm8731.c by Richard Purdie
+// Based on ak4535.c by Richard Purdie
+// Based on wm8753.c by Liam Girdwood
 
 /* ** CAUTION **
  *
@@ -709,4 +705,4 @@ module_i2c_driver(ak4642_i2c_driver);
 
 MODULE_DESCRIPTION("Soc AK4642 driver");
 MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index f4ed5cc40661bd96af4a0c898a5ff26d4b16a664..448bb90c9c8e0aa7cac5df5b596b526c286ace04 100644 (file)
@@ -322,13 +322,13 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev)
        return regcache_sync(ak5558->regmap);
 }
 
-const struct dev_pm_ops ak5558_pm = {
+static const struct dev_pm_ops ak5558_pm = {
        SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
                                pm_runtime_force_resume)
 };
 
-struct snd_soc_component_driver soc_codec_dev_ak5558 = {
+static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
        .probe                  = ak5558_probe,
        .remove                 = ak5558_remove,
        .controls               = ak5558_snd_controls,
index 2a7a4168c072a0112939c2a8cd2440bf1fffa481..3c266eeb89bfb2eaec708783b4974a2d72e1b6a2 100644 (file)
@@ -219,7 +219,7 @@ static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
 {
        /* Unreadable registers are considered volatile */
        if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
-               return 1;
+               return true;
 
        return reg == CS4270_CHIPID;
 }
index 0da52ead91e0ed42aea0cd2ee8bc27da5f23b5df..45e50fe3bf25ddd15dbff93bd17855dc7f9629d5 100644 (file)
@@ -235,6 +235,9 @@ ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP2", 1),
+WM_ADSP_FW_CONTROL("DSP3", 2),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
index 07dd33b095967d6fd7aebf999068eff0f496d72e..ab174b5114dcf10a7d513b0eaab6f0afa66c9436 100644 (file)
@@ -362,8 +362,27 @@ static int cx20442_component_probe(struct snd_soc_component *component)
                return -ENOMEM;
 
        cx20442->por = regulator_get(component->dev, "POR");
-       if (IS_ERR(cx20442->por))
-               dev_warn(component->dev, "failed to get the regulator");
+       if (IS_ERR(cx20442->por)) {
+               int err = PTR_ERR(cx20442->por);
+
+               dev_warn(component->dev, "failed to get POR supply (%d)", err);
+               /*
+                * When running on a non-dt platform and requested regulator
+                * is not available, regulator_get() never returns
+                * -EPROBE_DEFER as it is not able to justify if the regulator
+                * may still appear later.  On the other hand, the board can
+                * still set full constraints flag at late_initcall in order
+                * to instruct regulator_get() to return a dummy one if
+                * sufficient.  Hence, if we get -ENODEV here, let's convert
+                * it to -EPROBE_DEFER and wait for the board to decide or
+                * let Deferred Probe infrastructure handle this error.
+                */
+               if (err == -ENODEV)
+                       err = -EPROBE_DEFER;
+               kfree(cx20442);
+               return err;
+       }
+
        cx20442->tty = NULL;
 
        snd_soc_component_set_drvdata(component, cx20442);
index a664111b71844eeafa256b71af510a0acd682c2a..e172913d04a4a2b7d86aaafa046d30011a5e4539 100644 (file)
@@ -1,19 +1,14 @@
-/*
- * DA7210 ALSA Soc codec driver
- *
- * Copyright (c) 2009 Dialog Semiconductor
- * Written by David Chen <Dajun.chen@diasemi.com>
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// DA7210 ALSA Soc codec driver
+//
+// Copyright (c) 2009 Dialog Semiconductor
+// Written by David Chen <Dajun.chen@diasemi.com>
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
index 54cb5f24969f3137ff3bfc2c2de16bb07499cae1..92d006a5283ed71d74f4f8047509218fcc7d162f 100644 (file)
@@ -1140,9 +1140,9 @@ static bool da7213_volatile_register(struct device *dev, unsigned int reg)
        case DA7213_ALC_OFFSET_AUTO_M_R:
        case DA7213_ALC_OFFSET_AUTO_U_R:
        case DA7213_ALC_CIC_OP_LVL_DATA:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
index a49ab751a036c26ee89b414be0ba69f8b22db7aa..2c7d5088e6f2759aba90e469be2b3b8eb8b07dcb 100644 (file)
@@ -59,6 +59,7 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
                container_of(work, struct da7219_aad_priv, btn_det_work);
        struct snd_soc_component *component = da7219_aad->component;
        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+       struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
        u8 statusa, micbias_ctrl;
        bool micbias_up = false;
        int retries = 0;
@@ -86,6 +87,8 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
        if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
                dev_warn(component->dev, "Mic bias status check timed out");
 
+       da7219->micbias_on_event = true;
+
        /*
         * Mic bias pulse required to enable mic, must be done before enabling
         * button detection to prevent erroneous button readings.
@@ -439,6 +442,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
                        snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
                                            DA7219_BUTTON_CONFIG_MASK, 0);
 
+                       da7219->micbias_on_event = false;
+
                        /* Disable mic bias */
                        snd_soc_dapm_disable_pin(dapm, "Mic Bias");
                        snd_soc_dapm_sync(dapm);
index 980a6a8bf56d38c2c54d928d3b901c76e20c66db..e46e9f4bc994681615b25066054d20867d3507cb 100644 (file)
@@ -768,6 +768,30 @@ static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = {
  * DAPM Events
  */
 
+static int da7219_mic_pga_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (da7219->micbias_on_event) {
+                       /*
+                        * Delay only for first capture after bias enabled to
+                        * avoid possible DC offset related noise.
+                        */
+                       da7219->micbias_on_event = false;
+                       msleep(da7219->mic_pga_delay);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static int da7219_dai_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
@@ -937,12 +961,12 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("MIC"),
 
        /* Input PGAs */
-       SND_SOC_DAPM_PGA("Mic PGA", DA7219_MIC_1_CTRL,
-                        DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
-                        NULL, 0),
-       SND_SOC_DAPM_PGA("Mixin PGA", DA7219_MIXIN_L_CTRL,
-                        DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
-                        NULL, 0),
+       SND_SOC_DAPM_PGA_E("Mic PGA", DA7219_MIC_1_CTRL,
+                          DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                          NULL, 0, da7219_mic_pga_event, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_E("Mixin PGA", DA7219_MIXIN_L_CTRL,
+                          DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                          NULL, 0, da7219_settling_event, SND_SOC_DAPM_POST_PMU),
 
        /* Input Filters */
        SND_SOC_DAPM_ADC("ADC", NULL, DA7219_ADC_L_CTRL, DA7219_ADC_L_EN_SHIFT,
@@ -1847,6 +1871,14 @@ static void da7219_handle_pdata(struct snd_soc_component *component)
 
                snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_lvl);
 
+               /*
+                * Calculate delay required to compensate for DC offset in
+                * Mic PGA, based on Mic Bias voltage.
+                */
+               da7219->mic_pga_delay =  DA7219_MIC_PGA_BASE_DELAY +
+                                       (pdata->micbias_lvl *
+                                        DA7219_MIC_PGA_OFFSET_DELAY);
+
                /* Mic */
                switch (pdata->mic_amp_in_sel) {
                case DA7219_MIC_AMP_IN_SEL_DIFF:
@@ -2143,9 +2175,9 @@ static bool da7219_volatile_register(struct device *dev, unsigned int reg)
        case DA7219_ACCDET_IRQ_EVENT_B:
        case DA7219_ACCDET_CONFIG_8:
        case DA7219_SYSTEM_STATUS:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
index 1b00023e33cd6761c2fac0c851eb040933c4ce74..3a006862f0e791b486ad009a83b1335a0a779c29 100644 (file)
 #define DA7219_SYS_STAT_CHECK_DELAY    50
 
 /* Power up/down Delays */
-#define DA7219_SETTLING_DELAY  40
-#define DA7219_MIN_GAIN_DELAY  30
+#define DA7219_SETTLING_DELAY          40
+#define DA7219_MIN_GAIN_DELAY          30
+#define DA7219_MIC_PGA_BASE_DELAY      100
+#define DA7219_MIC_PGA_OFFSET_DELAY    40
 
 enum da7219_clk_src {
        DA7219_CLKSRC_MCLK = 0,
@@ -828,6 +830,8 @@ struct da7219_priv {
 
        bool master;
        bool alc_en;
+       bool micbias_on_event;
+       unsigned int mic_pga_delay;
        u8 gain_ramp_ctrl;
 };
 
index afdf90c78884d222eb9089bb8bf70b0819bf414d..f6a7bf9560e7e0ec70785de8fc69af93d2c2da4f 100644 (file)
@@ -1041,9 +1041,9 @@ static bool da9055_volatile_register(struct device *dev,
        case DA9055_HP_R_GAIN_STATUS:
        case DA9055_LINE_GAIN_STATUS:
        case DA9055_ALC_CIC_OP_LVL_DATA:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
index 58515bb1a303655525ec2c259f4370f0868a0096..6d7bca7b78ca7dbcede3be58a5973ccd2a79cb05 100644 (file)
@@ -17,6 +17,7 @@
  * in the file called COPYING.
  */
 
+#include <linux/of_platform.h>
 #include <linux/module.h>
 #include <sound/soc.h>
 
  * The everest 7134 is a very simple DA converter with no register
  */
 
+struct es7134_clock_mode {
+       unsigned int rate_min;
+       unsigned int rate_max;
+       unsigned int *mclk_fs;
+       unsigned int mclk_fs_num;
+};
+
+struct es7134_chip {
+       struct snd_soc_dai_driver *dai_drv;
+       const struct es7134_clock_mode *modes;
+       unsigned int mode_num;
+       const struct snd_soc_dapm_widget *extra_widgets;
+       unsigned int extra_widget_num;
+       const struct snd_soc_dapm_route *extra_routes;
+       unsigned int extra_route_num;
+};
+
+struct es7134_data {
+       unsigned int mclk;
+       const struct es7134_chip *chip;
+};
+
+static int es7134_check_mclk(struct snd_soc_dai *dai,
+                            struct es7134_data *priv,
+                            unsigned int rate)
+{
+       unsigned int mfs = priv->mclk / rate;
+       int i, j;
+
+       for (i = 0; i < priv->chip->mode_num; i++) {
+               const struct es7134_clock_mode *mode = &priv->chip->modes[i];
+
+               if (rate < mode->rate_min || rate > mode->rate_max)
+                       continue;
+
+               for (j = 0; j < mode->mclk_fs_num; j++) {
+                       if (mode->mclk_fs[j] == mfs)
+                               return 0;
+               }
+
+               dev_err(dai->dev, "unsupported mclk_fs %u for rate %u\n",
+                       mfs, rate);
+               return -EINVAL;
+       }
+
+       /* should not happen */
+       dev_err(dai->dev, "unsupported rate: %u\n", rate);
+       return -EINVAL;
+}
+
+static int es7134_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
+
+       /* mclk has not been provided, assume it is OK */
+       if (!priv->mclk)
+               return 0;
+
+       return es7134_check_mclk(dai, priv, params_rate(params));
+}
+
+static int es7134_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
+
+       if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
+               priv->mclk = freq;
+               return 0;
+       }
+
+       return -ENOTSUPP;
+}
+
 static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
@@ -38,8 +115,38 @@ static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        return 0;
 }
 
+static int es7134_component_probe(struct snd_soc_component *c)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(c);
+       struct es7134_data *priv = snd_soc_component_get_drvdata(c);
+       const struct es7134_chip *chip = priv->chip;
+       int ret;
+
+       if (chip->extra_widget_num) {
+               ret = snd_soc_dapm_new_controls(dapm, chip->extra_widgets,
+                                               chip->extra_widget_num);
+               if (ret) {
+                       dev_err(c->dev, "failed to add extra widgets\n");
+                       return ret;
+               }
+       }
+
+       if (chip->extra_route_num) {
+               ret = snd_soc_dapm_add_routes(dapm, chip->extra_routes,
+                                             chip->extra_route_num);
+               if (ret) {
+                       dev_err(c->dev, "failed to add extra routes\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops es7134_dai_ops = {
        .set_fmt        = es7134_set_fmt,
+       .hw_params      = es7134_hw_params,
+       .set_sysclk     = es7134_set_sysclk,
 };
 
 static struct snd_soc_dai_driver es7134_dai = {
@@ -48,7 +155,11 @@ static struct snd_soc_dai_driver es7134_dai = {
                .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
+               .rates = (SNDRV_PCM_RATE_8000_48000 |
+                         SNDRV_PCM_RATE_88200      |
+                         SNDRV_PCM_RATE_96000      |
+                         SNDRV_PCM_RATE_176400     |
+                         SNDRV_PCM_RATE_192000),
                .formats = (SNDRV_PCM_FMTBIT_S16_LE  |
                            SNDRV_PCM_FMTBIT_S18_3LE |
                            SNDRV_PCM_FMTBIT_S20_3LE |
@@ -58,18 +169,56 @@ static struct snd_soc_dai_driver es7134_dai = {
        .ops = &es7134_dai_ops,
 };
 
+static const struct es7134_clock_mode es7134_modes[] = {
+       {
+               /* Single speed mode */
+               .rate_min = 8000,
+               .rate_max = 50000,
+               .mclk_fs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
+               .mclk_fs_num = 5,
+       }, {
+               /* Double speed mode */
+               .rate_min = 84000,
+               .rate_max = 100000,
+               .mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512 },
+               .mclk_fs_num = 5,
+       }, {
+               /* Quad speed mode */
+               .rate_min = 167000,
+               .rate_max = 192000,
+               .mclk_fs = (unsigned int[]) { 128, 192, 256 },
+               .mclk_fs_num = 3,
+       },
+};
+
+/* Digital I/O are also supplied by VDD on the es7134 */
+static const struct snd_soc_dapm_route es7134_extra_routes[] = {
+       { "Playback", NULL, "VDD", }
+};
+
+static const struct es7134_chip es7134_chip = {
+       .dai_drv = &es7134_dai,
+       .modes = es7134_modes,
+       .mode_num = ARRAY_SIZE(es7134_modes),
+       .extra_routes = es7134_extra_routes,
+       .extra_route_num = ARRAY_SIZE(es7134_extra_routes),
+};
+
 static const struct snd_soc_dapm_widget es7134_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("AOUTL"),
        SND_SOC_DAPM_OUTPUT("AOUTR"),
        SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("VDD", 0, 0),
 };
 
 static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
        { "AOUTL", NULL, "DAC" },
        { "AOUTR", NULL, "DAC" },
+       { "DAC", NULL, "VDD" },
 };
 
 static const struct snd_soc_component_driver es7134_component_driver = {
+       .probe                  = es7134_component_probe,
        .dapm_widgets           = es7134_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(es7134_dapm_widgets),
        .dapm_routes            = es7134_dapm_routes,
@@ -80,17 +229,87 @@ static const struct snd_soc_component_driver es7134_component_driver = {
        .non_legacy_dai_naming  = 1,
 };
 
+static struct snd_soc_dai_driver es7154_dai = {
+       .name = "es7154-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = (SNDRV_PCM_RATE_8000_48000 |
+                         SNDRV_PCM_RATE_88200      |
+                         SNDRV_PCM_RATE_96000),
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE  |
+                           SNDRV_PCM_FMTBIT_S18_3LE |
+                           SNDRV_PCM_FMTBIT_S20_3LE |
+                           SNDRV_PCM_FMTBIT_S24_3LE |
+                           SNDRV_PCM_FMTBIT_S24_LE),
+       },
+       .ops = &es7134_dai_ops,
+};
+
+static const struct es7134_clock_mode es7154_modes[] = {
+       {
+               /* Single speed mode */
+               .rate_min = 8000,
+               .rate_max = 50000,
+               .mclk_fs = (unsigned int[]) { 32, 64, 128, 192, 256,
+                                             384, 512, 768, 1024 },
+               .mclk_fs_num = 9,
+       }, {
+               /* Double speed mode */
+               .rate_min = 84000,
+               .rate_max = 100000,
+               .mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512,
+                                             768, 1024},
+               .mclk_fs_num = 7,
+       }
+};
+
+/* Es7154 has a separate supply for digital I/O  */
+static const struct snd_soc_dapm_widget es7154_extra_widgets[] = {
+       SND_SOC_DAPM_REGULATOR_SUPPLY("PVDD", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7154_extra_routes[] = {
+       { "Playback", NULL, "PVDD", }
+};
+
+static const struct es7134_chip es7154_chip = {
+       .dai_drv = &es7154_dai,
+       .modes = es7154_modes,
+       .mode_num = ARRAY_SIZE(es7154_modes),
+       .extra_routes = es7154_extra_routes,
+       .extra_route_num = ARRAY_SIZE(es7154_extra_routes),
+       .extra_widgets = es7154_extra_widgets,
+       .extra_widget_num = ARRAY_SIZE(es7154_extra_widgets),
+};
+
 static int es7134_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
+       struct es7134_data *priv;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, priv);
+
+       priv->chip = of_device_get_match_data(dev);
+       if (!priv->chip) {
+               dev_err(dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
        return devm_snd_soc_register_component(&pdev->dev,
                                      &es7134_component_driver,
-                                     &es7134_dai, 1);
+                                     priv->chip->dai_drv, 1);
 }
 
 #ifdef CONFIG_OF
 static const struct of_device_id es7134_ids[] = {
-       { .compatible = "everest,es7134", },
-       { .compatible = "everest,es7144", },
+       { .compatible = "everest,es7134", .data = &es7134_chip },
+       { .compatible = "everest,es7144", .data = &es7134_chip },
+       { .compatible = "everest,es7154", .data = &es7154_chip },
        { }
 };
 MODULE_DEVICE_TABLE(of, es7134_ids);
diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c
new file mode 100644 (file)
index 0000000..87991bd
--- /dev/null
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+struct es7241_clock_mode {
+       unsigned int rate_min;
+       unsigned int rate_max;
+       unsigned int *slv_mfs;
+       unsigned int slv_mfs_num;
+       unsigned int mst_mfs;
+       unsigned int mst_m0:1;
+       unsigned int mst_m1:1;
+};
+
+struct es7241_chip {
+       const struct es7241_clock_mode *modes;
+       unsigned int mode_num;
+};
+
+struct es7241_data {
+       struct gpio_desc *reset;
+       struct gpio_desc *m0;
+       struct gpio_desc *m1;
+       unsigned int fmt;
+       unsigned int mclk;
+       bool is_slave;
+       const struct es7241_chip *chip;
+};
+
+static void es7241_set_mode(struct es7241_data *priv,  int m0, int m1)
+{
+       /* put the device in reset */
+       gpiod_set_value_cansleep(priv->reset, 0);
+
+       /* set the mode */
+       gpiod_set_value_cansleep(priv->m0, m0);
+       gpiod_set_value_cansleep(priv->m1, m1);
+
+       /* take the device out of reset - datasheet does not specify a delay */
+       gpiod_set_value_cansleep(priv->reset, 1);
+}
+
+static int es7241_set_slave_mode(struct es7241_data *priv,
+                                const struct es7241_clock_mode *mode,
+                                unsigned int mfs)
+{
+       int j;
+
+       if (!mfs)
+               goto out_ok;
+
+       for (j = 0; j < mode->slv_mfs_num; j++) {
+               if (mode->slv_mfs[j] == mfs)
+                       goto out_ok;
+       }
+
+       return -EINVAL;
+
+out_ok:
+       es7241_set_mode(priv, 1, 1);
+       return 0;
+}
+
+static int es7241_set_master_mode(struct es7241_data *priv,
+                                 const struct es7241_clock_mode *mode,
+                                 unsigned int mfs)
+{
+       /*
+        * We can't really set clock ratio, if the mclk/lrclk is different
+        * from what we provide, then error out
+        */
+       if (mfs && mfs != mode->mst_mfs)
+               return -EINVAL;
+
+       es7241_set_mode(priv, mode->mst_m0, mode->mst_m1);
+
+       return 0;
+}
+
+static int es7241_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       unsigned int mfs = priv->mclk / rate;
+       int i;
+
+       for (i = 0; i < priv->chip->mode_num; i++) {
+               const struct es7241_clock_mode *mode = &priv->chip->modes[i];
+
+               if (rate < mode->rate_min || rate >= mode->rate_max)
+                       continue;
+
+               if (priv->is_slave)
+                       return es7241_set_slave_mode(priv, mode, mfs);
+               else
+                       return es7241_set_master_mode(priv, mode, mfs);
+       }
+
+       /* should not happen */
+       dev_err(dai->dev, "unsupported rate: %u\n", rate);
+       return -EINVAL;
+}
+
+static int es7241_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+
+       if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
+               priv->mclk = freq;
+               return 0;
+       }
+
+       return -ENOTSUPP;
+}
+
+static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+
+       if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+               dev_err(dai->dev, "Unsupported dai clock inversion\n");
+               return -EINVAL;
+       }
+
+       if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != priv->fmt) {
+               dev_err(dai->dev, "Invalid dai format\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               priv->is_slave = true;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               priv->is_slave = false;
+               break;
+
+       default:
+               dev_err(dai->dev, "Unsupported clock configuration\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops es7241_dai_ops = {
+       .set_fmt        = es7241_set_fmt,
+       .hw_params      = es7241_hw_params,
+       .set_sysclk     = es7241_set_sysclk,
+};
+
+static struct snd_soc_dai_driver es7241_dai = {
+       .name = "es7241-hifi",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE  |
+                           SNDRV_PCM_FMTBIT_S24_3LE |
+                           SNDRV_PCM_FMTBIT_S24_LE),
+       },
+       .ops = &es7241_dai_ops,
+};
+
+static const struct es7241_clock_mode es7241_modes[] = {
+       {
+               /* Single speed mode */
+               .rate_min = 8000,
+               .rate_max = 50000,
+               .slv_mfs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
+               .slv_mfs_num = 5,
+               .mst_mfs = 256,
+               .mst_m0 = 0,
+               .mst_m1 = 0,
+       }, {
+               /* Double speed mode */
+               .rate_min = 50000,
+               .rate_max = 100000,
+               .slv_mfs = (unsigned int[]) { 128, 192 },
+               .slv_mfs_num = 2,
+               .mst_mfs = 128,
+               .mst_m0 = 1,
+               .mst_m1 = 0,
+       }, {
+               /* Quad speed mode */
+               .rate_min = 100000,
+               .rate_max = 200000,
+               .slv_mfs = (unsigned int[]) { 64 },
+               .slv_mfs_num = 1,
+               .mst_mfs = 64,
+               .mst_m0 = 0,
+               .mst_m1 = 1,
+       },
+};
+
+static const struct es7241_chip es7241_chip = {
+       .modes = es7241_modes,
+       .mode_num = ARRAY_SIZE(es7241_modes),
+};
+
+static const struct snd_soc_dapm_widget es7241_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("AINL"),
+       SND_SOC_DAPM_INPUT("AINR"),
+       SND_SOC_DAPM_DAC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("VDDP", 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("VDDD", 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("VDDA", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7241_dapm_routes[] = {
+       { "ADC", NULL, "AINL", },
+       { "ADC", NULL, "AINR", },
+       { "ADC", NULL, "VDDA", },
+       { "Capture", NULL, "VDDP", },
+       { "Capture", NULL, "VDDD", },
+};
+
+static const struct snd_soc_component_driver es7241_component_driver = {
+       .dapm_widgets           = es7241_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(es7241_dapm_widgets),
+       .dapm_routes            = es7241_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(es7241_dapm_routes),
+       .idle_bias_on           = 1,
+       .endianness             = 1,
+       .non_legacy_dai_naming  = 1,
+};
+
+static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv)
+{
+       bool is_leftj;
+
+       /*
+        * The format is given by a pull resistor on the SDOUT pin:
+        * pull-up for i2s, pull-down for left justified.
+        */
+       is_leftj = of_property_read_bool(dev->of_node,
+                                        "everest,sdout-pull-down");
+       if (is_leftj)
+               priv->fmt = SND_SOC_DAIFMT_LEFT_J;
+       else
+               priv->fmt = SND_SOC_DAIFMT_I2S;
+}
+
+static int es7241_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct es7241_data *priv;
+       int err;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, priv);
+
+       priv->chip = of_device_get_match_data(dev);
+       if (!priv->chip) {
+               dev_err(dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
+       es7241_parse_fmt(dev, priv);
+
+       priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->reset)) {
+               err = PTR_ERR(priv->reset);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get 'reset' gpio: %d", err);
+               return err;
+       }
+
+       priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->m0)) {
+               err = PTR_ERR(priv->m0);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get 'm0' gpio: %d", err);
+               return err;
+       }
+
+       priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->m1)) {
+               err = PTR_ERR(priv->m1);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get 'm1' gpio: %d", err);
+               return err;
+       }
+
+       return devm_snd_soc_register_component(&pdev->dev,
+                                     &es7241_component_driver,
+                                     &es7241_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es7241_ids[] = {
+       { .compatible = "everest,es7241", .data = &es7241_chip },
+       { }
+};
+MODULE_DEVICE_TABLE(of, es7241_ids);
+#endif
+
+static struct platform_driver es7241_driver = {
+       .driver = {
+               .name = "es7241",
+               .of_match_table = of_match_ptr(es7241_ids),
+       },
+       .probe = es7241_probe,
+};
+
+module_platform_driver(es7241_driver);
+
+MODULE_DESCRIPTION("ASoC ES7241 audio codec driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
index 84f7a7a36e4b56a7e413699e517f7287368fc179..7b8533abf637319e56de6f68a37e88912d7a0c2f 100644 (file)
@@ -85,7 +85,7 @@ struct hdac_hdmi_pin {
        bool mst_capable;
        struct hdac_hdmi_port *ports;
        int num_ports;
-       struct hdac_ext_device *edev;
+       struct hdac_device *hdev;
 };
 
 struct hdac_hdmi_port {
@@ -126,6 +126,9 @@ struct hdac_hdmi_drv_data {
 };
 
 struct hdac_hdmi_priv {
+       struct hdac_device *hdev;
+       struct snd_soc_component *component;
+       struct snd_card *card;
        struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
        struct list_head pin_list;
        struct list_head cvt_list;
@@ -139,7 +142,7 @@ struct hdac_hdmi_priv {
        struct snd_soc_dai_driver *dai_drv;
 };
 
-#define hdev_to_hdmi_priv(_hdev) ((to_ehdac_device(_hdev))->private_data)
+#define hdev_to_hdmi_priv(_hdev) dev_get_drvdata(&(_hdev)->dev)
 
 static struct hdac_hdmi_pcm *
 hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
@@ -158,7 +161,7 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
 static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
                struct hdac_hdmi_port *port, bool is_connect)
 {
-       struct hdac_ext_device *edev = port->pin->edev;
+       struct hdac_device *hdev = port->pin->hdev;
 
        if (is_connect)
                snd_soc_dapm_enable_pin(port->dapm, port->jack_pin);
@@ -172,7 +175,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
                 * ports.
                 */
                if (pcm->jack_event == 0) {
-                       dev_dbg(&edev->hdev.dev,
+                       dev_dbg(&hdev->dev,
                                        "jack report for pcm=%d\n",
                                        pcm->pcm_id);
                        snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT,
@@ -198,19 +201,18 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
 /*
  * Get the no devices that can be connected to a port on the Pin widget.
  */
-static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid)
+static int hdac_hdmi_get_port_len(struct hdac_device *hdev, hda_nid_t nid)
 {
        unsigned int caps;
        unsigned int type, param;
 
-       caps = get_wcaps(&edev->hdev, nid);
+       caps = get_wcaps(hdev, nid);
        type = get_wcaps_type(caps);
 
        if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
                return 0;
 
-       param = snd_hdac_read_parm_uncached(&edev->hdev, nid,
-                                       AC_PAR_DEVLIST_LEN);
+       param = snd_hdac_read_parm_uncached(hdev, nid, AC_PAR_DEVLIST_LEN);
        if (param == -1)
                return param;
 
@@ -222,10 +224,10 @@ static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid)
  * id selected on the pin. Return 0 means the first port entry
  * is selected or MST is not supported.
  */
-static int hdac_hdmi_port_select_get(struct hdac_ext_device *edev,
+static int hdac_hdmi_port_select_get(struct hdac_device *hdev,
                                        struct hdac_hdmi_port *port)
 {
-       return snd_hdac_codec_read(&edev->hdev, port->pin->nid,
+       return snd_hdac_codec_read(hdev, port->pin->nid,
                                0, AC_VERB_GET_DEVICE_SEL, 0);
 }
 
@@ -233,7 +235,7 @@ static int hdac_hdmi_port_select_get(struct hdac_ext_device *edev,
  * Sets the selected port entry for the configuring Pin widget verb.
  * returns error if port set is not equal to port get otherwise success
  */
-static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev,
+static int hdac_hdmi_port_select_set(struct hdac_device *hdev,
                                        struct hdac_hdmi_port *port)
 {
        int num_ports;
@@ -242,8 +244,7 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev,
                return 0;
 
        /* AC_PAR_DEVLIST_LEN is 0 based. */
-       num_ports = hdac_hdmi_get_port_len(edev, port->pin->nid);
-
+       num_ports = hdac_hdmi_get_port_len(hdev, port->pin->nid);
        if (num_ports < 0)
                return -EIO;
        /*
@@ -253,13 +254,13 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev,
        if (num_ports + 1  < port->id)
                return 0;
 
-       snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+       snd_hdac_codec_write(hdev, port->pin->nid, 0,
                        AC_VERB_SET_DEVICE_SEL, port->id);
 
-       if (port->id != hdac_hdmi_port_select_get(edev, port))
+       if (port->id != hdac_hdmi_port_select_get(hdev, port))
                return -EIO;
 
-       dev_dbg(&edev->hdev.dev, "Selected the port=%d\n", port->id);
+       dev_dbg(&hdev->dev, "Selected the port=%d\n", port->id);
 
        return 0;
 }
@@ -277,13 +278,6 @@ static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
        return NULL;
 }
 
-static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
-{
-       struct hdac_device *hdev = dev_to_hdac_dev(dev);
-
-       return to_ehdac_device(hdev);
-}
-
 static unsigned int sad_format(const u8 *sad)
 {
        return ((sad[0] >> 0x3) & 0x1f);
@@ -324,15 +318,13 @@ format_constraint:
 }
 
 static void
-hdac_hdmi_set_dip_index(struct hdac_ext_device *edev, hda_nid_t pin_nid,
+hdac_hdmi_set_dip_index(struct hdac_device *hdev, hda_nid_t pin_nid,
                                int packet_index, int byte_index)
 {
        int val;
 
        val = (packet_index << 5) | (byte_index & 0x1f);
-
-       snd_hdac_codec_write(&edev->hdev, pin_nid, 0,
-                               AC_VERB_SET_HDMI_DIP_INDEX, val);
+       snd_hdac_codec_write(hdev, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
 }
 
 struct dp_audio_infoframe {
@@ -347,14 +339,14 @@ struct dp_audio_infoframe {
        u8 LFEPBL01_LSV36_DM_INH7;
 };
 
-static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_device *hdev,
                   struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port)
 {
        uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
        struct hdmi_audio_infoframe frame;
        struct hdac_hdmi_pin *pin = port->pin;
        struct dp_audio_infoframe dp_ai;
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_cvt *cvt = pcm->cvt;
        u8 *dip;
        int ret;
@@ -363,11 +355,11 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
        u8 conn_type;
        int channels, ca;
 
-       ca = snd_hdac_channel_allocation(&edev->hdev, port->eld.info.spk_alloc,
+       ca = snd_hdac_channel_allocation(hdev, port->eld.info.spk_alloc,
                        pcm->channels, pcm->chmap_set, true, pcm->chmap);
 
        channels = snd_hdac_get_active_channels(ca);
-       hdmi->chmap.ops.set_channel_count(&edev->hdev, cvt->nid, channels);
+       hdmi->chmap.ops.set_channel_count(hdev, cvt->nid, channels);
 
        snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
                                pcm->channels, pcm->chmap, pcm->chmap_set);
@@ -400,32 +392,31 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
                break;
 
        default:
-               dev_err(&edev->hdev.dev, "Invalid connection type: %d\n",
-                                               conn_type);
+               dev_err(&hdev->dev, "Invalid connection type: %d\n", conn_type);
                return -EIO;
        }
 
        /* stop infoframe transmission */
-       hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
-       snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+       hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+       snd_hdac_codec_write(hdev, pin->nid, 0,
                        AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
 
 
        /*  Fill infoframe. Index auto-incremented */
-       hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
+       hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
        if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
                for (i = 0; i < sizeof(buffer); i++)
-                       snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+                       snd_hdac_codec_write(hdev, pin->nid, 0,
                                AC_VERB_SET_HDMI_DIP_DATA, buffer[i]);
        } else {
                for (i = 0; i < sizeof(dp_ai); i++)
-                       snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+                       snd_hdac_codec_write(hdev, pin->nid, 0,
                                AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
        }
 
        /* Start infoframe */
-       hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
-       snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+       hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+       snd_hdac_codec_write(hdev, pin->nid, 0,
                        AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
 
        return 0;
@@ -435,12 +426,12 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
                unsigned int tx_mask, unsigned int rx_mask,
                int slots, int slot_width)
 {
-       struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+       struct hdac_device *hdev = hdmi->hdev;
        struct hdac_hdmi_dai_port_map *dai_map;
        struct hdac_hdmi_pcm *pcm;
 
-       dev_dbg(&edev->hdev.dev, "%s: strm_tag: %d\n", __func__, tx_mask);
+       dev_dbg(&hdev->dev, "%s: strm_tag: %d\n", __func__, tx_mask);
 
        dai_map = &hdmi->dai_map[dai->id];
 
@@ -455,8 +446,8 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
 static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
 {
-       struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+       struct hdac_device *hdev = hdmi->hdev;
        struct hdac_hdmi_dai_port_map *dai_map;
        struct hdac_hdmi_port *port;
        struct hdac_hdmi_pcm *pcm;
@@ -469,7 +460,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
                return -ENODEV;
 
        if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
-               dev_err(&edev->hdev.dev,
+               dev_err(&hdev->dev,
                        "device is not configured for this pin:port%d:%d\n",
                                        port->pin->nid, port->id);
                return -ENODEV;
@@ -489,28 +480,28 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev,
+static int hdac_hdmi_query_port_connlist(struct hdac_device *hdev,
                                        struct hdac_hdmi_pin *pin,
                                        struct hdac_hdmi_port *port)
 {
-       if (!(get_wcaps(&edev->hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
-               dev_warn(&edev->hdev.dev,
+       if (!(get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
+               dev_warn(&hdev->dev,
                        "HDMI: pin %d wcaps %#x does not support connection list\n",
-                       pin->nid, get_wcaps(&edev->hdev, pin->nid));
+                       pin->nid, get_wcaps(hdev, pin->nid));
                return -EINVAL;
        }
 
-       if (hdac_hdmi_port_select_set(edev, port) < 0)
+       if (hdac_hdmi_port_select_set(hdev, port) < 0)
                return -EIO;
 
-       port->num_mux_nids = snd_hdac_get_connections(&edev->hdev, pin->nid,
+       port->num_mux_nids = snd_hdac_get_connections(hdev, pin->nid,
                        port->mux_nids, HDA_MAX_CONNECTIONS);
        if (port->num_mux_nids == 0)
-               dev_warn(&edev->hdev.dev,
+               dev_warn(&hdev->dev,
                        "No connections found for pin:port %d:%d\n",
                                                pin->nid, port->id);
 
-       dev_dbg(&edev->hdev.dev, "num_mux_nids %d for pin:port %d:%d\n",
+       dev_dbg(&hdev->dev, "num_mux_nids %d for pin:port %d:%d\n",
                        port->num_mux_nids, pin->nid, port->id);
 
        return port->num_mux_nids;
@@ -526,7 +517,7 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev,
  * connected.
  */
 static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
-                       struct hdac_ext_device *edev,
+                       struct hdac_device *hdev,
                        struct hdac_hdmi_priv *hdmi,
                        struct hdac_hdmi_cvt *cvt)
 {
@@ -541,7 +532,7 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
 
                        list_for_each_entry(port, &pcm->port_list, head) {
                                mutex_lock(&pcm->lock);
-                               ret = hdac_hdmi_query_port_connlist(edev,
+                               ret = hdac_hdmi_query_port_connlist(hdev,
                                                        port->pin, port);
                                mutex_unlock(&pcm->lock);
                                if (ret < 0)
@@ -568,8 +559,8 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
 static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+       struct hdac_device *hdev = hdmi->hdev;
        struct hdac_hdmi_dai_port_map *dai_map;
        struct hdac_hdmi_cvt *cvt;
        struct hdac_hdmi_port *port;
@@ -578,7 +569,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
        dai_map = &hdmi->dai_map[dai->id];
 
        cvt = dai_map->cvt;
-       port = hdac_hdmi_get_port_from_cvt(edev, hdmi, cvt);
+       port = hdac_hdmi_get_port_from_cvt(hdev, hdmi, cvt);
 
        /*
         * To make PA and other userland happy.
@@ -589,7 +580,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
        if ((!port->eld.monitor_present) ||
                        (!port->eld.eld_valid)) {
 
-               dev_warn(&edev->hdev.dev,
+               dev_warn(&hdev->dev,
                        "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n",
                        port->eld.monitor_present, port->eld.eld_valid,
                        port->pin->nid, port->id);
@@ -611,8 +602,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
 static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
        struct hdac_hdmi_dai_port_map *dai_map;
        struct hdac_hdmi_pcm *pcm;
 
@@ -695,10 +685,10 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
        route->connected = handler;
 }
 
-static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
+static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_device *hdev,
                                        struct hdac_hdmi_port *port)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pcm *pcm = NULL;
        struct hdac_hdmi_port *p;
 
@@ -715,33 +705,32 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
        return NULL;
 }
 
-static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
+static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
                             hda_nid_t nid, unsigned int pwr_state)
 {
        int count;
        unsigned int state;
 
-       if (get_wcaps(&edev->hdev, nid) & AC_WCAP_POWER) {
-               if (!snd_hdac_check_power_state(&edev->hdev, nid, pwr_state)) {
+       if (get_wcaps(hdev, nid) & AC_WCAP_POWER) {
+               if (!snd_hdac_check_power_state(hdev, nid, pwr_state)) {
                        for (count = 0; count < 10; count++) {
-                               snd_hdac_codec_read(&edev->hdev, nid, 0,
+                               snd_hdac_codec_read(hdev, nid, 0,
                                                AC_VERB_SET_POWER_STATE,
                                                pwr_state);
-                               state = snd_hdac_sync_power_state(&edev->hdev,
+                               state = snd_hdac_sync_power_state(hdev,
                                                nid, pwr_state);
                                if (!(state & AC_PWRST_ERROR))
                                        break;
                        }
                }
-
        }
 }
 
-static void hdac_hdmi_set_amp(struct hdac_ext_device *edev,
+static void hdac_hdmi_set_amp(struct hdac_device *hdev,
                                   hda_nid_t nid, int val)
 {
-       if (get_wcaps(&edev->hdev, nid) & AC_WCAP_OUT_AMP)
-               snd_hdac_codec_write(&edev->hdev, nid, 0,
+       if (get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
+               snd_hdac_codec_write(hdev, nid, 0,
                                        AC_VERB_SET_AMP_GAIN_MUTE, val);
 }
 
@@ -750,40 +739,40 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
                                        struct snd_kcontrol *kc, int event)
 {
        struct hdac_hdmi_port *port = w->priv;
-       struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+       struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
        struct hdac_hdmi_pcm *pcm;
 
-       dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
+       dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
                        __func__, w->name, event);
 
-       pcm = hdac_hdmi_get_pcm(edev, port);
+       pcm = hdac_hdmi_get_pcm(hdev, port);
        if (!pcm)
                return -EIO;
 
        /* set the device if pin is mst_capable */
-       if (hdac_hdmi_port_select_set(edev, port) < 0)
+       if (hdac_hdmi_port_select_set(hdev, port) < 0)
                return -EIO;
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0);
+               hdac_hdmi_set_power_state(hdev, port->pin->nid, AC_PWRST_D0);
 
                /* Enable out path for this pin widget */
-               snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+               snd_hdac_codec_write(hdev, port->pin->nid, 0,
                                AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 
-               hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE);
+               hdac_hdmi_set_amp(hdev, port->pin->nid, AMP_OUT_UNMUTE);
 
-               return hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
+               return hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
 
        case SND_SOC_DAPM_POST_PMD:
-               hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE);
+               hdac_hdmi_set_amp(hdev, port->pin->nid, AMP_OUT_MUTE);
 
                /* Disable out path for this pin widget */
-               snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+               snd_hdac_codec_write(hdev, port->pin->nid, 0,
                                AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 
-               hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3);
+               hdac_hdmi_set_power_state(hdev, port->pin->nid, AC_PWRST_D3);
                break;
 
        }
@@ -795,11 +784,11 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
                                        struct snd_kcontrol *kc, int event)
 {
        struct hdac_hdmi_cvt *cvt = w->priv;
-       struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pcm *pcm;
 
-       dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
+       dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
                        __func__, w->name, event);
 
        pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt);
@@ -808,29 +797,29 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0);
+               hdac_hdmi_set_power_state(hdev, cvt->nid, AC_PWRST_D0);
 
                /* Enable transmission */
-               snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+               snd_hdac_codec_write(hdev, cvt->nid, 0,
                        AC_VERB_SET_DIGI_CONVERT_1, 1);
 
                /* Category Code (CC) to zero */
-               snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+               snd_hdac_codec_write(hdev, cvt->nid, 0,
                        AC_VERB_SET_DIGI_CONVERT_2, 0);
 
-               snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+               snd_hdac_codec_write(hdev, cvt->nid, 0,
                                AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
-               snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+               snd_hdac_codec_write(hdev, cvt->nid, 0,
                                AC_VERB_SET_STREAM_FORMAT, pcm->format);
                break;
 
        case SND_SOC_DAPM_POST_PMD:
-               snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+               snd_hdac_codec_write(hdev, cvt->nid, 0,
                                AC_VERB_SET_CHANNEL_STREAMID, 0);
-               snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+               snd_hdac_codec_write(hdev, cvt->nid, 0,
                                AC_VERB_SET_STREAM_FORMAT, 0);
 
-               hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3);
+               hdac_hdmi_set_power_state(hdev, cvt->nid, AC_PWRST_D3);
                break;
 
        }
@@ -842,10 +831,10 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
                                        struct snd_kcontrol *kc, int event)
 {
        struct hdac_hdmi_port *port = w->priv;
-       struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+       struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
        int mux_idx;
 
-       dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
+       dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
                        __func__, w->name, event);
 
        if (!kc)
@@ -854,11 +843,11 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
        mux_idx = dapm_kcontrol_get_value(kc);
 
        /* set the device if pin is mst_capable */
-       if (hdac_hdmi_port_select_set(edev, port) < 0)
+       if (hdac_hdmi_port_select_set(hdev, port) < 0)
                return -EIO;
 
        if (mux_idx > 0) {
-               snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+               snd_hdac_codec_write(hdev, port->pin->nid, 0,
                        AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
        }
 
@@ -877,8 +866,8 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct hdac_hdmi_port *port = w->priv;
-       struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pcm *pcm = NULL;
        const char *cvt_name =  e->texts[ucontrol->value.enumerated.item[0]];
 
@@ -931,12 +920,12 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
  * care of selecting the right one and leaving all other inputs selected to
  * "NONE"
  */
-static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
+static int hdac_hdmi_create_pin_port_muxs(struct hdac_device *hdev,
                                struct hdac_hdmi_port *port,
                                struct snd_soc_dapm_widget *widget,
                                const char *widget_name)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pin *pin = port->pin;
        struct snd_kcontrol_new *kc;
        struct hdac_hdmi_cvt *cvt;
@@ -948,17 +937,17 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
        int i = 0;
        int num_items = hdmi->num_cvt + 1;
 
-       kc = devm_kzalloc(&edev->hdev.dev, sizeof(*kc), GFP_KERNEL);
+       kc = devm_kzalloc(&hdev->dev, sizeof(*kc), GFP_KERNEL);
        if (!kc)
                return -ENOMEM;
 
-       se = devm_kzalloc(&edev->hdev.dev, sizeof(*se), GFP_KERNEL);
+       se = devm_kzalloc(&hdev->dev, sizeof(*se), GFP_KERNEL);
        if (!se)
                return -ENOMEM;
 
        snprintf(kc_name, NAME_SIZE, "Pin %d port %d Input",
                                                pin->nid, port->id);
-       kc->name = devm_kstrdup(&edev->hdev.dev, kc_name, GFP_KERNEL);
+       kc->name = devm_kstrdup(&hdev->dev, kc_name, GFP_KERNEL);
        if (!kc->name)
                return -ENOMEM;
 
@@ -976,35 +965,35 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
        se->mask = roundup_pow_of_two(se->items) - 1;
 
        sprintf(mux_items, "NONE");
-       items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL);
+       items[i] = devm_kstrdup(&hdev->dev, mux_items, GFP_KERNEL);
        if (!items[i])
                return -ENOMEM;
 
        list_for_each_entry(cvt, &hdmi->cvt_list, head) {
                i++;
                sprintf(mux_items, "cvt %d", cvt->nid);
-               items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL);
+               items[i] = devm_kstrdup(&hdev->dev, mux_items, GFP_KERNEL);
                if (!items[i])
                        return -ENOMEM;
        }
 
-       se->texts = devm_kmemdup(&edev->hdev.dev, items,
+       se->texts = devm_kmemdup(&hdev->dev, items,
                        (num_items  * sizeof(char *)), GFP_KERNEL);
        if (!se->texts)
                return -ENOMEM;
 
-       return hdac_hdmi_fill_widget_info(&edev->hdev.dev, widget,
+       return hdac_hdmi_fill_widget_info(&hdev->dev, widget,
                        snd_soc_dapm_mux, port, widget_name, NULL, kc, 1,
                        hdac_hdmi_pin_mux_widget_event,
                        SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG);
 }
 
 /* Add cvt <- input <- mux route map */
-static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
+static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_device *hdev,
                        struct snd_soc_dapm_widget *widgets,
                        struct snd_soc_dapm_route *route, int rindex)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        const struct snd_kcontrol_new *kc;
        struct soc_enum *se;
        int mux_index = hdmi->num_cvt + hdmi->num_ports;
@@ -1046,8 +1035,8 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_widget *widgets;
        struct snd_soc_dapm_route *route;
-       struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct snd_soc_dai_driver *dai_drv = hdmi->dai_drv;
        char widget_name[NAME_SIZE];
        struct hdac_hdmi_cvt *cvt;
@@ -1099,7 +1088,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
                for (j = 0; j < pin->num_ports; j++) {
                        sprintf(widget_name, "Pin%d-Port%d Mux",
                                pin->nid, pin->ports[j].id);
-                       ret = hdac_hdmi_create_pin_port_muxs(edev,
+                       ret = hdac_hdmi_create_pin_port_muxs(hdev,
                                                &pin->ports[j], &widgets[i],
                                                widget_name);
                        if (ret < 0)
@@ -1134,7 +1123,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
                }
        }
 
-       hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
+       hdac_hdmi_add_pinmux_cvt_route(hdev, widgets, route, i);
 
        snd_soc_dapm_new_controls(dapm, widgets,
                ((2 * hdmi->num_ports) + hdmi->num_cvt));
@@ -1146,9 +1135,9 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
 
 }
 
-static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
+static int hdac_hdmi_init_dai_map(struct hdac_device *hdev)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_dai_port_map *dai_map;
        struct hdac_hdmi_cvt *cvt;
        int dai_id = 0;
@@ -1164,7 +1153,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
                dai_id++;
 
                if (dai_id == HDA_MAX_CVTS) {
-                       dev_warn(&edev->hdev.dev,
+                       dev_warn(&hdev->dev,
                                "Max dais supported: %d\n", dai_id);
                        break;
                }
@@ -1173,9 +1162,9 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
        return 0;
 }
 
-static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
+static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_cvt *cvt;
        char name[NAME_SIZE];
 
@@ -1190,10 +1179,10 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
        list_add_tail(&cvt->head, &hdmi->cvt_list);
        hdmi->num_cvt++;
 
-       return hdac_hdmi_query_cvt_params(&edev->hdev, cvt);
+       return hdac_hdmi_query_cvt_params(hdev, cvt);
 }
 
-static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
+static int hdac_hdmi_parse_eld(struct hdac_device *hdev,
                        struct hdac_hdmi_port *port)
 {
        unsigned int ver, mnl;
@@ -1202,7 +1191,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
                                                >> DRM_ELD_VER_SHIFT;
 
        if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
-               dev_err(&edev->hdev.dev, "HDMI: Unknown ELD version %d\n", ver);
+               dev_err(&hdev->dev, "HDMI: Unknown ELD version %d\n", ver);
                return -EINVAL;
        }
 
@@ -1210,7 +1199,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
                DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
 
        if (mnl > ELD_MAX_MNL) {
-               dev_err(&edev->hdev.dev, "HDMI: MNL Invalid %d\n", mnl);
+               dev_err(&hdev->dev, "HDMI: MNL Invalid %d\n", mnl);
                return -EINVAL;
        }
 
@@ -1222,8 +1211,8 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
 static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
                                    struct hdac_hdmi_port *port)
 {
-       struct hdac_ext_device *edev = pin->edev;
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_device *hdev = pin->hdev;
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pcm *pcm;
        int size = 0;
        int port_id = -1;
@@ -1241,14 +1230,14 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
        if (pin->mst_capable)
                port_id = port->id;
 
-       size = snd_hdac_acomp_get_eld(&edev->hdev, pin->nid, port_id,
+       size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id,
                                &port->eld.monitor_present,
                                port->eld.eld_buffer,
                                ELD_MAX_SIZE);
 
        if (size > 0) {
                size = min(size, ELD_MAX_SIZE);
-               if (hdac_hdmi_parse_eld(edev, port) < 0)
+               if (hdac_hdmi_parse_eld(hdev, port) < 0)
                        size = -EINVAL;
        }
 
@@ -1260,11 +1249,11 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
                port->eld.eld_size = 0;
        }
 
-       pcm = hdac_hdmi_get_pcm(edev, port);
+       pcm = hdac_hdmi_get_pcm(hdev, port);
 
        if (!port->eld.monitor_present || !port->eld.eld_valid) {
 
-               dev_err(&edev->hdev.dev, "%s: disconnect for pin:port %d:%d\n",
+               dev_err(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
                                                __func__, pin->nid, port->id);
 
                /*
@@ -1316,9 +1305,9 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi,
        return 0;
 }
 
-static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
+static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pin *pin;
        int ret;
 
@@ -1328,7 +1317,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
 
        pin->nid = nid;
        pin->mst_capable = false;
-       pin->edev = edev;
+       pin->hdev = hdev;
        ret = hdac_hdmi_add_ports(hdmi, pin);
        if (ret < 0)
                return ret;
@@ -1459,15 +1448,14 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
  * Parse all nodes and store the cvt/pin nids in array
  * Add one time initialization for pin and cvt widgets
  */
-static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
+static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
                struct snd_soc_dai_driver **dais, int *num_dais)
 {
        hda_nid_t nid;
        int i, num_nodes;
        struct hdac_hdmi_cvt *temp_cvt, *cvt_next;
        struct hdac_hdmi_pin *temp_pin, *pin_next;
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
-       struct hdac_device *hdev = &edev->hdev;
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        int ret;
 
        hdac_hdmi_skl_enable_all_pins(hdev);
@@ -1492,13 +1480,13 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
                switch (type) {
 
                case AC_WID_AUD_OUT:
-                       ret = hdac_hdmi_add_cvt(edev, nid);
+                       ret = hdac_hdmi_add_cvt(hdev, nid);
                        if (ret < 0)
                                goto free_widgets;
                        break;
 
                case AC_WID_PIN:
-                       ret = hdac_hdmi_add_pin(edev, nid);
+                       ret = hdac_hdmi_add_pin(hdev, nid);
                        if (ret < 0)
                                goto free_widgets;
                        break;
@@ -1518,7 +1506,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
        }
 
        *num_dais = hdmi->num_cvt;
-       ret = hdac_hdmi_init_dai_map(edev);
+       ret = hdac_hdmi_init_dai_map(hdev);
        if (ret < 0)
                goto free_widgets;
 
@@ -1542,19 +1530,24 @@ free_widgets:
        return ret;
 }
 
+static int hdac_hdmi_pin2port(void *aptr, int pin)
+{
+       return pin - 4; /* map NID 0x05 -> port #1 */
+}
+
 static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
 {
-       struct hdac_ext_device *edev = aptr;
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_device *hdev = aptr;
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pin *pin = NULL;
        struct hdac_hdmi_port *hport = NULL;
-       struct snd_soc_component *component = edev->scodec;
+       struct snd_soc_component *component = hdmi->component;
        int i;
 
        /* Don't know how this mapping is derived */
        hda_nid_t pin_nid = port + 0x04;
 
-       dev_dbg(&edev->hdev.dev, "%s: for pin:%d port=%d\n", __func__,
+       dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
                                                        pin_nid, pipe);
 
        /*
@@ -1567,7 +1560,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
                        SNDRV_CTL_POWER_D0)
                return;
 
-       if (atomic_read(&edev->hdev.in_pm))
+       if (atomic_read(&hdev->in_pm))
                return;
 
        list_for_each_entry(pin, &hdmi->pin_list, head) {
@@ -1595,7 +1588,8 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
 
 }
 
-static struct i915_audio_component_audio_ops aops = {
+static struct drm_audio_component_audio_ops aops = {
+       .pin2port       = hdac_hdmi_pin2port,
        .pin_eld_notify = hdac_hdmi_eld_notify_cb,
 };
 
@@ -1614,15 +1608,15 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
 
 /* create jack pin kcontrols */
 static int create_fill_jack_kcontrols(struct snd_soc_card *card,
-                                   struct hdac_ext_device *edev)
+                                   struct hdac_device *hdev)
 {
        struct hdac_hdmi_pin *pin;
        struct snd_kcontrol_new *kc;
        char kc_name[NAME_SIZE], xname[NAME_SIZE];
        char *name;
        int i = 0, j;
-       struct snd_soc_component *component = edev->scodec;
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+       struct snd_soc_component *component = hdmi->component;
 
        kc = devm_kcalloc(component->dev, hdmi->num_ports,
                                sizeof(*kc), GFP_KERNEL);
@@ -1659,8 +1653,8 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card,
 int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
                        struct snd_soc_dapm_context *dapm)
 {
-       struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+       struct hdac_device *hdev = hdmi->hdev;
        struct hdac_hdmi_pin *pin;
        struct snd_soc_dapm_widget *widgets;
        struct snd_soc_dapm_route *route;
@@ -1715,7 +1709,7 @@ int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
                return ret;
 
        /* Add Jack Pin switch Kcontrol */
-       ret = create_fill_jack_kcontrols(dapm->card, edev);
+       ret = create_fill_jack_kcontrols(dapm->card, hdev);
 
        if (ret < 0)
                return ret;
@@ -1735,8 +1729,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
                                struct snd_soc_jack *jack)
 {
        struct snd_soc_component *component = dai->component;
-       struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+       struct hdac_device *hdev = hdmi->hdev;
        struct hdac_hdmi_pcm *pcm;
        struct snd_pcm *snd_pcm;
        int err;
@@ -1758,7 +1752,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
        if (snd_pcm) {
                err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
                if (err < 0) {
-                       dev_err(&edev->hdev.dev,
+                       dev_err(&hdev->dev,
                                "chmap control add failed with err: %d for pcm: %d\n",
                                err, device);
                        kfree(pcm);
@@ -1772,7 +1766,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
 }
 EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
 
-static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
+static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev,
                        struct hdac_hdmi_priv *hdmi, bool detect_pin_caps)
 {
        int i;
@@ -1781,7 +1775,7 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
        list_for_each_entry(pin, &hdmi->pin_list, head) {
                if (detect_pin_caps) {
 
-                       if (hdac_hdmi_get_port_len(edev, pin->nid)  == 0)
+                       if (hdac_hdmi_get_port_len(hdev, pin->nid)  == 0)
                                pin->mst_capable = false;
                        else
                                pin->mst_capable = true;
@@ -1798,68 +1792,67 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
 
 static int hdmi_codec_probe(struct snd_soc_component *component)
 {
-       struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+       struct hdac_device *hdev = hdmi->hdev;
        struct snd_soc_dapm_context *dapm =
                snd_soc_component_get_dapm(component);
        struct hdac_ext_link *hlink = NULL;
        int ret;
 
-       edev->scodec = component;
+       hdmi->component = component;
 
        /*
         * hold the ref while we probe, also no need to drop the ref on
         * exit, we call pm_runtime_suspend() so that will do for us
         */
-       hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev));
+       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
        if (!hlink) {
-               dev_err(&edev->hdev.dev, "hdac link not found\n");
+               dev_err(&hdev->dev, "hdac link not found\n");
                return -EIO;
        }
 
-       snd_hdac_ext_bus_link_get(edev->ebus, hlink);
+       snd_hdac_ext_bus_link_get(hdev->bus, hlink);
 
        ret = create_fill_widget_route_map(dapm);
        if (ret < 0)
                return ret;
 
-       aops.audio_ptr = edev;
-       ret = snd_hdac_i915_register_notifier(&aops);
+       aops.audio_ptr = hdev;
+       ret = snd_hdac_acomp_register_notifier(hdev->bus, &aops);
        if (ret < 0) {
-               dev_err(&edev->hdev.dev, "notifier register failed: err: %d\n",
-                               ret);
+               dev_err(&hdev->dev, "notifier register failed: err: %d\n", ret);
                return ret;
        }
 
-       hdac_hdmi_present_sense_all_pins(edev, hdmi, true);
+       hdac_hdmi_present_sense_all_pins(hdev, hdmi, true);
        /* Imp: Store the card pointer in hda_codec */
-       edev->card = dapm->card->snd_card;
+       hdmi->card = dapm->card->snd_card;
 
        /*
         * hdac_device core already sets the state to active and calls
         * get_noresume. So enable runtime and set the device to suspend.
         */
-       pm_runtime_enable(&edev->hdev.dev);
-       pm_runtime_put(&edev->hdev.dev);
-       pm_runtime_suspend(&edev->hdev.dev);
+       pm_runtime_enable(&hdev->dev);
+       pm_runtime_put(&hdev->dev);
+       pm_runtime_suspend(&hdev->dev);
 
        return 0;
 }
 
 static void hdmi_codec_remove(struct snd_soc_component *component)
 {
-       struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
+       struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+       struct hdac_device *hdev = hdmi->hdev;
 
-       pm_runtime_disable(&edev->hdev.dev);
+       pm_runtime_disable(&hdev->dev);
 }
 
 #ifdef CONFIG_PM
 static int hdmi_codec_prepare(struct device *dev)
 {
-       struct hdac_ext_device *edev = to_hda_ext_device(dev);
-       struct hdac_device *hdev = &edev->hdev;
+       struct hdac_device *hdev = dev_to_hdac_dev(dev);
 
-       pm_runtime_get_sync(&edev->hdev.dev);
+       pm_runtime_get_sync(&hdev->dev);
 
        /*
         * Power down afg.
@@ -1876,16 +1869,15 @@ static int hdmi_codec_prepare(struct device *dev)
 
 static void hdmi_codec_complete(struct device *dev)
 {
-       struct hdac_ext_device *edev = to_hda_ext_device(dev);
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
-       struct hdac_device *hdev = &edev->hdev;
+       struct hdac_device *hdev = dev_to_hdac_dev(dev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
 
        /* Power up afg */
        snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
                                                        AC_PWRST_D0);
 
-       hdac_hdmi_skl_enable_all_pins(&edev->hdev);
-       hdac_hdmi_skl_enable_dp12(&edev->hdev);
+       hdac_hdmi_skl_enable_all_pins(hdev);
+       hdac_hdmi_skl_enable_dp12(hdev);
 
        /*
         * As the ELD notify callback request is not entertained while the
@@ -1893,9 +1885,9 @@ static void hdmi_codec_complete(struct device *dev)
         * all pins here. pin capablity change is not support, so use the
         * already set pin caps.
         */
-       hdac_hdmi_present_sense_all_pins(edev, hdmi, false);
+       hdac_hdmi_present_sense_all_pins(hdev, hdmi, false);
 
-       pm_runtime_put_sync(&edev->hdev.dev);
+       pm_runtime_put_sync(&hdev->dev);
 }
 #else
 #define hdmi_codec_prepare NULL
@@ -1922,7 +1914,6 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx,
 static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
                                unsigned char *chmap, int prepared)
 {
-       struct hdac_ext_device *edev = to_ehdac_device(hdev);
        struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
        struct hdac_hdmi_port *port;
@@ -1938,7 +1929,7 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
        memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap));
        list_for_each_entry(port, &pcm->port_list, head)
                if (prepared)
-                       hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
+                       hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
        mutex_unlock(&pcm->lock);
 }
 
@@ -1987,10 +1978,9 @@ static struct hdac_hdmi_drv_data intel_drv_data  = {
        .vendor_nid = INTEL_VENDOR_NID,
 };
 
-static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
+static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
 {
-       struct hdac_device *hdev = &edev->hdev;
-       struct hdac_hdmi_priv *hdmi_priv;
+       struct hdac_hdmi_priv *hdmi_priv = NULL;
        struct snd_soc_dai_driver *hdmi_dais = NULL;
        struct hdac_ext_link *hlink = NULL;
        int num_dais = 0;
@@ -1999,24 +1989,24 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
 
        /* hold the ref while we probe */
-       hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev));
+       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
        if (!hlink) {
-               dev_err(&edev->hdev.dev, "hdac link not found\n");
+               dev_err(&hdev->dev, "hdac link not found\n");
                return -EIO;
        }
 
-       snd_hdac_ext_bus_link_get(edev->ebus, hlink);
+       snd_hdac_ext_bus_link_get(hdev->bus, hlink);
 
        hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
        if (hdmi_priv == NULL)
                return -ENOMEM;
 
-       edev->private_data = hdmi_priv;
        snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
        hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
        hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
        hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
        hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
+       hdmi_priv->hdev = hdev;
 
        if (!hdac_id)
                return -ENODEV;
@@ -2027,7 +2017,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        else
                hdmi_priv->drv_data = &intel_drv_data;
 
-       dev_set_drvdata(&hdev->dev, edev);
+       dev_set_drvdata(&hdev->dev, hdmi_priv);
 
        INIT_LIST_HEAD(&hdmi_priv->pin_list);
        INIT_LIST_HEAD(&hdmi_priv->cvt_list);
@@ -2038,15 +2028,15 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
         * Turned off in the runtime_suspend during the first explicit
         * pm_runtime_suspend call.
         */
-       ret = snd_hdac_display_power(edev->hdev.bus, true);
+       ret = snd_hdac_display_power(hdev->bus, true);
        if (ret < 0) {
-               dev_err(&edev->hdev.dev,
+               dev_err(&hdev->dev,
                        "Cannot turn on display power on i915 err: %d\n",
                        ret);
                return ret;
        }
 
-       ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
+       ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais);
        if (ret < 0) {
                dev_err(&hdev->dev,
                        "Failed in parse and map nid with err: %d\n", ret);
@@ -2058,14 +2048,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
        ret = devm_snd_soc_register_component(&hdev->dev, &hdmi_hda_codec,
                                        hdmi_dais, num_dais);
 
-       snd_hdac_ext_bus_link_put(edev->ebus, hlink);
+       snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 
        return ret;
 }
 
-static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
+static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
 {
-       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
        struct hdac_hdmi_pin *pin, *pin_next;
        struct hdac_hdmi_cvt *cvt, *cvt_next;
        struct hdac_hdmi_pcm *pcm, *pcm_next;
@@ -2103,12 +2093,79 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
 }
 
 #ifdef CONFIG_PM
+/*
+ * Power management sequences
+ * ==========================
+ *
+ * The following explains the PM handling of HDAC HDMI with its parent
+ * device SKL and display power usage
+ *
+ * Probe
+ * -----
+ * In SKL probe,
+ * 1. skl_probe_work() powers up the display (refcount++ -> 1)
+ * 2. enumerates the codecs on the link
+ * 3. powers down the display  (refcount-- -> 0)
+ *
+ * In HDAC HDMI probe,
+ * 1. hdac_hdmi_dev_probe() powers up the display (refcount++ -> 1)
+ * 2. probe the codec
+ * 3. put the HDAC HDMI device to runtime suspend
+ * 4. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Once children are runtime suspended, SKL device also goes to runtime
+ * suspend
+ *
+ * HDMI Playback
+ * -------------
+ * Open HDMI device,
+ * 1. skl_runtime_resume() invoked
+ * 2. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
+ *
+ * Close HDMI device,
+ * 1. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ * 2. skl_runtime_suspend() invoked
+ *
+ * S0/S3 Cycle with playback in progress
+ * -------------------------------------
+ * When the device is opened for playback, the device is runtime active
+ * already and the display refcount is 1 as explained above.
+ *
+ * Entering to S3,
+ * 1. hdmi_codec_prepare() invoke the runtime resume of codec which just
+ *    increments the PM runtime usage count of the codec since the device
+ *    is in use already
+ * 2. skl_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Wakeup from S3,
+ * 1. skl_resume() powers up the display (refcount++ -> 1)
+ * 2. hdmi_codec_complete() invokes the runtime suspend of codec which just
+ *    decrements the PM runtime usage count of the codec since the device
+ *    is in use already
+ *
+ * Once playback is stopped, the display refcount is set to 0 as explained
+ * above in the HDMI playback sequence. The PM handlings are designed in
+ * such way that to balance the refcount of display power when the codec
+ * device put to S3 while playback is going on.
+ *
+ * S0/S3 Cycle without playback in progress
+ * ----------------------------------------
+ * Entering to S3,
+ * 1. hdmi_codec_prepare() invoke the runtime resume of codec
+ * 2. skl_runtime_resume() invoked
+ * 3. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
+ * 4. skl_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Wakeup from S3,
+ * 1. skl_resume() powers up the display (refcount++ -> 1)
+ * 2. hdmi_codec_complete() invokes the runtime suspend of codec
+ * 3. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ * 4. skl_runtime_suspend() invoked
+ */
 static int hdac_hdmi_runtime_suspend(struct device *dev)
 {
-       struct hdac_ext_device *edev = to_hda_ext_device(dev);
-       struct hdac_device *hdev = &edev->hdev;
+       struct hdac_device *hdev = dev_to_hdac_dev(dev);
        struct hdac_bus *bus = hdev->bus;
-       struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
        struct hdac_ext_link *hlink = NULL;
        int err;
 
@@ -2129,27 +2186,25 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
                                                        AC_PWRST_D3);
        err = snd_hdac_display_power(bus, false);
        if (err < 0) {
-               dev_err(bus->dev, "Cannot turn on display power on i915\n");
+               dev_err(dev, "Cannot turn on display power on i915\n");
                return err;
        }
 
-       hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
+       hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
        if (!hlink) {
                dev_err(dev, "hdac link not found\n");
                return -EIO;
        }
 
-       snd_hdac_ext_bus_link_put(ebus, hlink);
+       snd_hdac_ext_bus_link_put(bus, hlink);
 
        return 0;
 }
 
 static int hdac_hdmi_runtime_resume(struct device *dev)
 {
-       struct hdac_ext_device *edev = to_hda_ext_device(dev);
-       struct hdac_device *hdev = &edev->hdev;
+       struct hdac_device *hdev = dev_to_hdac_dev(dev);
        struct hdac_bus *bus = hdev->bus;
-       struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
        struct hdac_ext_link *hlink = NULL;
        int err;
 
@@ -2159,22 +2214,22 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
        if (!bus)
                return 0;
 
-       hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
+       hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
        if (!hlink) {
                dev_err(dev, "hdac link not found\n");
                return -EIO;
        }
 
-       snd_hdac_ext_bus_link_get(ebus, hlink);
+       snd_hdac_ext_bus_link_get(bus, hlink);
 
        err = snd_hdac_display_power(bus, true);
        if (err < 0) {
-               dev_err(bus->dev, "Cannot turn on display power on i915\n");
+               dev_err(dev, "Cannot turn on display power on i915\n");
                return err;
        }
 
-       hdac_hdmi_skl_enable_all_pins(&edev->hdev);
-       hdac_hdmi_skl_enable_dp12(&edev->hdev);
+       hdac_hdmi_skl_enable_all_pins(hdev);
+       hdac_hdmi_skl_enable_dp12(hdev);
 
        /* Power up afg */
        snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
@@ -2206,14 +2261,12 @@ static const struct hda_device_id hdmi_list[] = {
 
 MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
 
-static struct hdac_ext_driver hdmi_driver = {
-       . hdac = {
-               .driver = {
-                       .name   = "HDMI HDA Codec",
-                       .pm = &hdac_hdmi_pm,
-               },
-               .id_table       = hdmi_list,
+static struct hdac_driver hdmi_driver = {
+       .driver = {
+               .name   = "HDMI HDA Codec",
+               .pm = &hdac_hdmi_pm,
        },
+       .id_table       = hdmi_list,
        .probe          = hdac_hdmi_dev_probe,
        .remove         = hdac_hdmi_dev_remove,
 };
index 74d7f52c7e73b21f5293e942573037ff75c61160..6e6134589588e2a16e9e5e738e99ac3c81b00836 100644 (file)
@@ -52,9 +52,9 @@ static bool max9850_volatile_register(struct device *dev, unsigned int reg)
        switch (reg) {
        case MAX9850_STATUSA:
        case MAX9850_STATUSB:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
index 17104f8dc1a9ef0db2e7321b23ec196b4400ba5a..e3c8cd17daf2dab0afd66d8b18d2462818e164de 100644 (file)
@@ -362,11 +362,8 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
 
 static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
 {
-       int osrate;
-
        if (osr >= ARRAY_SIZE(osr_adc_sel))
                return -EINVAL;
-       osrate = osr_adc_sel[osr].osr;
 
        if (rate * osr > CLK_ADC_MAX) {
                dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
index 6bd14453f06ec4849628b90a5448bdaa6081d3ed..468d5143e2c4f700e2f6e7b519e8ad485fb7aa7d 100644 (file)
@@ -1274,7 +1274,7 @@ static int nau8824_calc_fll_param(unsigned int fll_in,
        fvco_max = 0;
        fvco_sel = ARRAY_SIZE(mclk_src_scaling);
        for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
-               fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+               fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
                if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
                        fvco_max < fvco) {
                        fvco_max = fvco;
index dc6ea4987b7d9a4fb132d41902dd6c0bf75e39f8..b9fed99d8b5ed389d15d41af269f79d3f6ae0ce3 100644 (file)
@@ -2016,7 +2016,7 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
        fvco_max = 0;
        fvco_sel = ARRAY_SIZE(mclk_src_scaling);
        for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
-               fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+               fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
                if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
                        fvco_max < fvco) {
                        fvco_max = fvco;
index 21f15219b3ad825ebaae5f0db7b45cc59e756765..8df6447c76a668d9c301f41303fae9e86cd4c5e7 100644 (file)
@@ -262,8 +262,7 @@ int pcm1789_common_exit(struct device *dev)
 {
        struct pcm1789_private *priv = dev_get_drvdata(dev);
 
-       if (&priv->work)
-               flush_work(&priv->work);
+       flush_work(&priv->work);
 
        return 0;
 }
index 88fde70b1e9ef775c1c263fe36c5a613a93546c0..690c26e7389e527567169464f47461b6a2f60e07 100644 (file)
@@ -265,7 +265,7 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_component *component = dai->component;
        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
        unsigned int rate = params_rate(params);
-       unsigned int format = params_format(params);
+       snd_pcm_format_t format = params_format(params);
        unsigned int width = params_width(params);
        unsigned int channels = params_channels(params);
        unsigned int div_lrck;
index f4c8c45f40103cf82f5450b93da3b7e446db3878..c4452efc79700a1e62f260f8362dec175e447294 100644 (file)
@@ -1066,7 +1066,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305)
        pr_debug("Left_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
        pr_info("Left channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
 
-       r0l = 562949953421312;
+       r0l = 562949953421312ULL;
        if (rhl != 0)
                do_div(r0l, rhl);
        pr_debug("Left_r0 = 0x%llx\n", r0l);
@@ -1083,7 +1083,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305)
        pr_debug("Right_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
        pr_info("Right channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
 
-       r0r = 562949953421312;
+       r0r = 562949953421312ULL;
        if (rhl != 0)
                do_div(r0r, rhl);
        pr_debug("Right_r0 = 0x%llx\n", r0r);
@@ -1150,17 +1150,11 @@ static int rt1305_i2c_probe(struct i2c_client *i2c,
        rt1305_reset(rt1305->regmap);
        rt1305_calibrate(rt1305);
 
-       return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt1305,
+       return devm_snd_soc_register_component(&i2c->dev,
+                       &soc_component_dev_rt1305,
                        rt1305_dai, ARRAY_SIZE(rt1305_dai));
 }
 
-static int rt1305_i2c_remove(struct i2c_client *i2c)
-{
-       snd_soc_unregister_component(&i2c->dev);
-
-       return 0;
-}
-
 static void rt1305_i2c_shutdown(struct i2c_client *client)
 {
        struct rt1305_priv *rt1305 = i2c_get_clientdata(client);
@@ -1180,7 +1174,6 @@ static struct i2c_driver rt1305_i2c_driver = {
 #endif
        },
        .probe = rt1305_i2c_probe,
-       .remove   = rt1305_i2c_remove,
        .shutdown = rt1305_i2c_shutdown,
        .id_table = rt1305_i2c_id,
 };
index cf6dce69eb2ad0bfe22c43236f80ffc228a9be46..865f49ac38dd1c372873fe45b242df050f2f7ffd 100644 (file)
@@ -105,9 +105,9 @@ static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
        case RT5631_INDEX_ADD:
        case RT5631_INDEX_DATA:
        case RT5631_EQ_CTRL:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
@@ -164,9 +164,9 @@ static bool rt5631_readable_register(struct device *dev, unsigned int reg)
        case RT5631_VENDOR_ID:
        case RT5631_VENDOR_ID1:
        case RT5631_VENDOR_ID2:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
@@ -229,10 +229,10 @@ static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
 static const struct snd_kcontrol_new rt5631_snd_controls[] = {
        /* MIC */
        SOC_ENUM("MIC1 Mode Control",  rt5631_mic1_mode_enum),
-       SOC_SINGLE_TLV("MIC1 Boost", RT5631_MIC_CTRL_2,
+       SOC_SINGLE_TLV("MIC1 Boost Volume", RT5631_MIC_CTRL_2,
                RT5631_MIC1_BOOST_SHIFT, 8, 0, mic_bst_tlv),
        SOC_ENUM("MIC2 Mode Control", rt5631_mic2_mode_enum),
-       SOC_SINGLE_TLV("MIC2 Boost", RT5631_MIC_CTRL_2,
+       SOC_SINGLE_TLV("MIC2 Boost Volume", RT5631_MIC_CTRL_2,
                RT5631_MIC2_BOOST_SHIFT, 8, 0, mic_bst_tlv),
        /* MONO IN */
        SOC_ENUM("MONOIN Mode Control", rt5631_monoin_mode_enum),
index 8bf8d360c25f921c8b86155eb903ec651c25bc75..27770143ae8f2210b6461dff39ef90cf2b690f86 100644 (file)
@@ -1665,6 +1665,7 @@ static int get_sdp_info(struct snd_soc_component *component, int dai_id)
                        break;
                case RT5640_IF_113:
                        ret |= RT5640_U_IF1;
+                       /* fall through */
                case RT5640_IF_312:
                case RT5640_IF_213:
                        ret |= RT5640_U_IF2;
@@ -1680,6 +1681,7 @@ static int get_sdp_info(struct snd_soc_component *component, int dai_id)
                        break;
                case RT5640_IF_223:
                        ret |= RT5640_U_IF1;
+                       /* fall through */
                case RT5640_IF_123:
                case RT5640_IF_321:
                        ret |= RT5640_U_IF2;
index 6b5669f3e85d740d3c088ac17f87074af352afd0..985852fd972387025e46a418d2081c24de218892 100644 (file)
@@ -331,11 +331,13 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
        SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
                        RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
                        175, 0, dac_vol_tlv),
-       /* IN1/IN2 Control */
+       /* IN1/IN2/IN3 Control */
        SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
                RT5651_BST_SFT1, 8, 0, bst_tlv),
        SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
                RT5651_BST_SFT2, 8, 0, bst_tlv),
+       SOC_SINGLE_TLV("IN3 Boost", RT5651_IN3,
+               RT5651_BST_SFT1, 8, 0, bst_tlv),
        /* INL/INR Volume Control */
        SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
                        RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
@@ -1581,6 +1583,24 @@ static void rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *component
        snd_soc_dapm_mutex_unlock(dapm);
 }
 
+static void rt5651_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+       struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+       snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+               RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_NOR);
+       rt5651->ovcd_irq_enabled = true;
+}
+
+static void rt5651_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+       struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+       snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+               RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_BP);
+       rt5651->ovcd_irq_enabled = false;
+}
+
 static void rt5651_clear_micbias1_ovcd(struct snd_soc_component *component)
 {
        snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
@@ -1622,10 +1642,80 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
        return val == 0;
 }
 
-/* Jack detect timings */
+/* Jack detect and button-press timings */
 #define JACK_SETTLE_TIME       100 /* milli seconds */
 #define JACK_DETECT_COUNT      5
 #define JACK_DETECT_MAXCOUNT   20  /* Aprox. 2 seconds worth of tries */
+#define JACK_UNPLUG_TIME       80  /* milli seconds */
+#define BP_POLL_TIME           10  /* milli seconds */
+#define BP_POLL_MAXCOUNT       200 /* assume something is wrong after this */
+#define BP_THRESHOLD           3
+
+static void rt5651_start_button_press_work(struct snd_soc_component *component)
+{
+       struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+       rt5651->poll_count = 0;
+       rt5651->press_count = 0;
+       rt5651->release_count = 0;
+       rt5651->pressed = false;
+       rt5651->press_reported = false;
+       rt5651_clear_micbias1_ovcd(component);
+       schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static void rt5651_button_press_work(struct work_struct *work)
+{
+       struct rt5651_priv *rt5651 =
+               container_of(work, struct rt5651_priv, bp_work.work);
+       struct snd_soc_component *component = rt5651->component;
+
+       /* Check the jack was not removed underneath us */
+       if (!rt5651_jack_inserted(component))
+               return;
+
+       if (rt5651_micbias1_ovcd(component)) {
+               rt5651->release_count = 0;
+               rt5651->press_count++;
+               /* Remember till after JACK_UNPLUG_TIME wait */
+               if (rt5651->press_count >= BP_THRESHOLD)
+                       rt5651->pressed = true;
+               rt5651_clear_micbias1_ovcd(component);
+       } else {
+               rt5651->press_count = 0;
+               rt5651->release_count++;
+       }
+
+       /*
+        * The pins get temporarily shorted on jack unplug, so we poll for
+        * at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
+        */
+       rt5651->poll_count++;
+       if (rt5651->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
+               schedule_delayed_work(&rt5651->bp_work,
+                                     msecs_to_jiffies(BP_POLL_TIME));
+               return;
+       }
+
+       if (rt5651->pressed && !rt5651->press_reported) {
+               dev_dbg(component->dev, "headset button press\n");
+               snd_soc_jack_report(rt5651->hp_jack, SND_JACK_BTN_0,
+                                   SND_JACK_BTN_0);
+               rt5651->press_reported = true;
+       }
+
+       if (rt5651->release_count >= BP_THRESHOLD) {
+               if (rt5651->press_reported) {
+                       dev_dbg(component->dev, "headset button release\n");
+                       snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+               }
+               /* Re-enable OVCD IRQ to detect next press */
+               rt5651_enable_micbias1_ovcd_irq(component);
+               return; /* Stop polling */
+       }
+
+       schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
 
 static int rt5651_detect_headset(struct snd_soc_component *component)
 {
@@ -1676,15 +1766,58 @@ static void rt5651_jack_detect_work(struct work_struct *work)
 {
        struct rt5651_priv *rt5651 =
                container_of(work, struct rt5651_priv, jack_detect_work);
+       struct snd_soc_component *component = rt5651->component;
        int report = 0;
 
-       if (rt5651_jack_inserted(rt5651->component)) {
-               rt5651_enable_micbias1_for_ovcd(rt5651->component);
-               report = rt5651_detect_headset(rt5651->component);
-               rt5651_disable_micbias1_for_ovcd(rt5651->component);
+       if (!rt5651_jack_inserted(component)) {
+               /* Jack removed, or spurious IRQ? */
+               if (rt5651->hp_jack->status & SND_JACK_HEADPHONE) {
+                       if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+                               cancel_delayed_work_sync(&rt5651->bp_work);
+                               rt5651_disable_micbias1_ovcd_irq(component);
+                               rt5651_disable_micbias1_for_ovcd(component);
+                       }
+                       snd_soc_jack_report(rt5651->hp_jack, 0,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0);
+                       dev_dbg(component->dev, "jack unplugged\n");
+               }
+       } else if (!(rt5651->hp_jack->status & SND_JACK_HEADPHONE)) {
+               /* Jack inserted */
+               WARN_ON(rt5651->ovcd_irq_enabled);
+               rt5651_enable_micbias1_for_ovcd(component);
+               report = rt5651_detect_headset(component);
+               if (report == SND_JACK_HEADSET) {
+                       /* Enable ovcd IRQ for button press detect. */
+                       rt5651_enable_micbias1_ovcd_irq(component);
+               } else {
+                       /* No more need for overcurrent detect. */
+                       rt5651_disable_micbias1_for_ovcd(component);
+               }
+               dev_dbg(component->dev, "detect report %#02x\n", report);
+               snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
+       } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) {
+               dev_dbg(component->dev, "OVCD IRQ\n");
+
+               /*
+                * The ovcd IRQ keeps firing while the button is pressed, so
+                * we disable it and start polling the button until released.
+                *
+                * The disable will make the IRQ pin 0 again and since we get
+                * IRQs on both edges (so as to detect both jack plugin and
+                * unplug) this means we will immediately get another IRQ.
+                * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
+                */
+               rt5651_disable_micbias1_ovcd_irq(component);
+               rt5651_start_button_press_work(component);
+
+               /*
+                * If the jack-detect IRQ flag goes high (unplug) after our
+                * above rt5651_jack_inserted() check and before we have
+                * disabled the OVCD IRQ, the IRQ pin will stay high and as
+                * we react to edges, we miss the unplug event -> recheck.
+                */
+               queue_work(system_long_wq, &rt5651->jack_detect_work);
        }
-
-       snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
 }
 
 static irqreturn_t rt5651_irq(int irq, void *data)
@@ -1696,14 +1829,18 @@ static irqreturn_t rt5651_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int rt5651_set_jack(struct snd_soc_component *component,
-                          struct snd_soc_jack *hp_jack, void *data)
+static void rt5651_cancel_work(void *data)
 {
-       struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
-       int ret;
+       struct rt5651_priv *rt5651 = data;
 
-       if (!rt5651->irq)
-               return -EINVAL;
+       cancel_work_sync(&rt5651->jack_detect_work);
+       cancel_delayed_work_sync(&rt5651->bp_work);
+}
+
+static void rt5651_enable_jack_detect(struct snd_soc_component *component,
+                                     struct snd_soc_jack *hp_jack)
+{
+       struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
        /* IRQ output on GPIO1 */
        snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
@@ -1730,10 +1867,10 @@ static int rt5651_set_jack(struct snd_soc_component *component,
                        RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
                break;
        case RT5651_JD_NULL:
-               return 0;
+               return;
        default:
                dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
-               return -EINVAL;
+               return;
        }
 
        /* Enable jack detect power */
@@ -1767,19 +1904,39 @@ static int rt5651_set_jack(struct snd_soc_component *component,
                RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
 
        rt5651->hp_jack = hp_jack;
-
-       ret = devm_request_threaded_irq(component->dev, rt5651->irq, NULL,
-                                       rt5651_irq,
-                                       IRQF_TRIGGER_RISING |
-                                       IRQF_TRIGGER_FALLING |
-                                       IRQF_ONESHOT, "rt5651", rt5651);
-       if (ret) {
-               dev_err(component->dev, "Failed to reguest IRQ: %d\n", ret);
-               return ret;
+       if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+               rt5651_enable_micbias1_for_ovcd(component);
+               rt5651_enable_micbias1_ovcd_irq(component);
        }
 
+       enable_irq(rt5651->irq);
        /* sync initial jack state */
        queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
+}
+
+static void rt5651_disable_jack_detect(struct snd_soc_component *component)
+{
+       struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+       disable_irq(rt5651->irq);
+       rt5651_cancel_work(rt5651);
+
+       if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+               rt5651_disable_micbias1_ovcd_irq(component);
+               rt5651_disable_micbias1_for_ovcd(component);
+               snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+       }
+
+       rt5651->hp_jack = NULL;
+}
+
+static int rt5651_set_jack(struct snd_soc_component *component,
+                          struct snd_soc_jack *jack, void *data)
+{
+       if (jack)
+               rt5651_enable_jack_detect(component, jack);
+       else
+               rt5651_disable_jack_detect(component);
 
        return 0;
 }
@@ -2034,8 +2191,26 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
        rt5651->irq = i2c->irq;
        rt5651->hp_mute = 1;
 
+       INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work);
        INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
 
+       /* Make sure work is stopped on probe-error / remove */
+       ret = devm_add_action_or_reset(&i2c->dev, rt5651_cancel_work, rt5651);
+       if (ret)
+               return ret;
+
+       ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq,
+                              IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                              | IRQF_ONESHOT, "rt5651", rt5651);
+       if (ret == 0) {
+               /* Gets re-enabled by rt5651_set_jack() */
+               disable_irq(rt5651->irq);
+       } else {
+               dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+                        rt5651->irq, ret);
+               rt5651->irq = -ENXIO;
+       }
+
        ret = devm_snd_soc_register_component(&i2c->dev,
                                &soc_component_dev_rt5651,
                                rt5651_dai, ARRAY_SIZE(rt5651_dai));
@@ -2043,15 +2218,6 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
        return ret;
 }
 
-static int rt5651_i2c_remove(struct i2c_client *i2c)
-{
-       struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c);
-
-       cancel_work_sync(&rt5651->jack_detect_work);
-
-       return 0;
-}
-
 static struct i2c_driver rt5651_i2c_driver = {
        .driver = {
                .name = "rt5651",
@@ -2059,7 +2225,6 @@ static struct i2c_driver rt5651_i2c_driver = {
                .of_match_table = of_match_ptr(rt5651_of_match),
        },
        .probe = rt5651_i2c_probe,
-       .remove   = rt5651_i2c_remove,
        .id_table = rt5651_i2c_id,
 };
 module_i2c_driver(rt5651_i2c_driver);
index 3a0968c53fde8ef5c5040d56c4621d4842af768e..ac6de6fb541498dfd18614a9321070d790fb5b2f 100644 (file)
@@ -2071,8 +2071,16 @@ struct rt5651_pll_code {
 struct rt5651_priv {
        struct snd_soc_component *component;
        struct regmap *regmap;
+       /* Jack and button detect data */
        struct snd_soc_jack *hp_jack;
        struct work_struct jack_detect_work;
+       struct delayed_work bp_work;
+       bool ovcd_irq_enabled;
+       bool pressed;
+       bool press_reported;
+       int press_count;
+       int release_count;
+       int poll_count;
        unsigned int jd_src;
        unsigned int ovcd_th;
        unsigned int ovcd_sf;
index 8a0181a2db085459cb974d30d81f0d100880490b..9b7a1833d3316c28d2872294e629664c6e59e4f2 100644 (file)
@@ -4417,6 +4417,7 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
                break;
        case 25:
                slot_width_25 = 0x8080;
+               /* fall through */
        case 24:
                val |= (2 << 8);
                break;
@@ -5007,7 +5008,7 @@ static const struct regmap_config rt5677_regmap = {
 };
 
 static const struct of_device_id rt5677_of_match[] = {
-       { .compatible = "realtek,rt5677", RT5677 },
+       { .compatible = "realtek,rt5677", .data = (const void *)RT5677 },
        { }
 };
 MODULE_DEVICE_TABLE(of, rt5677_of_match);
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
new file mode 100644 (file)
index 0000000..640d400
--- /dev/null
@@ -0,0 +1,2681 @@
+/*
+ * rt5682.c  --  RT5682 ALSA SoC audio component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5682.h>
+
+#include "rl6231.h"
+#include "rt5682.h"
+
+#define RT5682_NUM_SUPPLIES 3
+
+static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
+       "AVDD",
+       "MICVDD",
+       "VBAT",
+};
+
+struct rt5682_priv {
+       struct snd_soc_component *component;
+       struct rt5682_platform_data pdata;
+       struct regmap *regmap;
+       struct snd_soc_jack *hs_jack;
+       struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES];
+       struct delayed_work jack_detect_work;
+       struct delayed_work jd_check_work;
+       struct mutex calibrate_mutex;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5682_AIFS];
+       int bclk[RT5682_AIFS];
+       int master[RT5682_AIFS];
+
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+       int jack_type;
+};
+
+static const struct reg_sequence patch_list[] = {
+       {0x01c1, 0x1000},
+};
+
+static const struct reg_default rt5682_reg[] = {
+       {0x0002, 0x8080},
+       {0x0003, 0x8000},
+       {0x0005, 0x0000},
+       {0x0006, 0x0000},
+       {0x0008, 0x800f},
+       {0x000b, 0x0000},
+       {0x0010, 0x4040},
+       {0x0011, 0x0000},
+       {0x0012, 0x1404},
+       {0x0013, 0x1000},
+       {0x0014, 0xa00a},
+       {0x0015, 0x0404},
+       {0x0016, 0x0404},
+       {0x0019, 0xafaf},
+       {0x001c, 0x2f2f},
+       {0x001f, 0x0000},
+       {0x0022, 0x5757},
+       {0x0023, 0x0039},
+       {0x0024, 0x000b},
+       {0x0026, 0xc0c4},
+       {0x0029, 0x8080},
+       {0x002a, 0xa0a0},
+       {0x002b, 0x0300},
+       {0x0030, 0x0000},
+       {0x003c, 0x0080},
+       {0x0044, 0x0c0c},
+       {0x0049, 0x0000},
+       {0x0061, 0x0000},
+       {0x0062, 0x0000},
+       {0x0063, 0x003f},
+       {0x0064, 0x0000},
+       {0x0065, 0x0000},
+       {0x0066, 0x0030},
+       {0x0067, 0x0000},
+       {0x006b, 0x0000},
+       {0x006c, 0x0000},
+       {0x006d, 0x2200},
+       {0x006e, 0x0a10},
+       {0x0070, 0x8000},
+       {0x0071, 0x8000},
+       {0x0073, 0x0000},
+       {0x0074, 0x0000},
+       {0x0075, 0x0002},
+       {0x0076, 0x0001},
+       {0x0079, 0x0000},
+       {0x007a, 0x0000},
+       {0x007b, 0x0000},
+       {0x007c, 0x0100},
+       {0x007e, 0x0000},
+       {0x0080, 0x0000},
+       {0x0081, 0x0000},
+       {0x0082, 0x0000},
+       {0x0083, 0x0000},
+       {0x0084, 0x0000},
+       {0x0085, 0x0000},
+       {0x0086, 0x0005},
+       {0x0087, 0x0000},
+       {0x0088, 0x0000},
+       {0x008c, 0x0003},
+       {0x008d, 0x0000},
+       {0x008e, 0x0060},
+       {0x008f, 0x1000},
+       {0x0091, 0x0c26},
+       {0x0092, 0x0073},
+       {0x0093, 0x0000},
+       {0x0094, 0x0080},
+       {0x0098, 0x0000},
+       {0x009a, 0x0000},
+       {0x009b, 0x0000},
+       {0x009c, 0x0000},
+       {0x009d, 0x0000},
+       {0x009e, 0x100c},
+       {0x009f, 0x0000},
+       {0x00a0, 0x0000},
+       {0x00a3, 0x0002},
+       {0x00a4, 0x0001},
+       {0x00ae, 0x2040},
+       {0x00af, 0x0000},
+       {0x00b6, 0x0000},
+       {0x00b7, 0x0000},
+       {0x00b8, 0x0000},
+       {0x00b9, 0x0002},
+       {0x00be, 0x0000},
+       {0x00c0, 0x0160},
+       {0x00c1, 0x82a0},
+       {0x00c2, 0x0000},
+       {0x00d0, 0x0000},
+       {0x00d1, 0x2244},
+       {0x00d2, 0x3300},
+       {0x00d3, 0x2200},
+       {0x00d4, 0x0000},
+       {0x00d9, 0x0009},
+       {0x00da, 0x0000},
+       {0x00db, 0x0000},
+       {0x00dc, 0x00c0},
+       {0x00dd, 0x2220},
+       {0x00de, 0x3131},
+       {0x00df, 0x3131},
+       {0x00e0, 0x3131},
+       {0x00e2, 0x0000},
+       {0x00e3, 0x4000},
+       {0x00e4, 0x0aa0},
+       {0x00e5, 0x3131},
+       {0x00e6, 0x3131},
+       {0x00e7, 0x3131},
+       {0x00e8, 0x3131},
+       {0x00ea, 0xb320},
+       {0x00eb, 0x0000},
+       {0x00f0, 0x0000},
+       {0x00f1, 0x00d0},
+       {0x00f2, 0x00d0},
+       {0x00f6, 0x0000},
+       {0x00fa, 0x0000},
+       {0x00fb, 0x0000},
+       {0x00fc, 0x0000},
+       {0x00fd, 0x0000},
+       {0x00fe, 0x10ec},
+       {0x00ff, 0x6530},
+       {0x0100, 0xa0a0},
+       {0x010b, 0x0000},
+       {0x010c, 0xae00},
+       {0x010d, 0xaaa0},
+       {0x010e, 0x8aa2},
+       {0x010f, 0x02a2},
+       {0x0110, 0xc000},
+       {0x0111, 0x04a2},
+       {0x0112, 0x2800},
+       {0x0113, 0x0000},
+       {0x0117, 0x0100},
+       {0x0125, 0x0410},
+       {0x0132, 0x6026},
+       {0x0136, 0x5555},
+       {0x0138, 0x3700},
+       {0x013a, 0x2000},
+       {0x013b, 0x2000},
+       {0x013c, 0x2005},
+       {0x013f, 0x0000},
+       {0x0142, 0x0000},
+       {0x0145, 0x0002},
+       {0x0146, 0x0000},
+       {0x0147, 0x0000},
+       {0x0148, 0x0000},
+       {0x0149, 0x0000},
+       {0x0150, 0x79a1},
+       {0x0151, 0x0000},
+       {0x0160, 0x4ec0},
+       {0x0161, 0x0080},
+       {0x0162, 0x0200},
+       {0x0163, 0x0800},
+       {0x0164, 0x0000},
+       {0x0165, 0x0000},
+       {0x0166, 0x0000},
+       {0x0167, 0x000f},
+       {0x0168, 0x000f},
+       {0x0169, 0x0021},
+       {0x0190, 0x413d},
+       {0x0194, 0x0000},
+       {0x0195, 0x0000},
+       {0x0197, 0x0022},
+       {0x0198, 0x0000},
+       {0x0199, 0x0000},
+       {0x01af, 0x0000},
+       {0x01b0, 0x0400},
+       {0x01b1, 0x0000},
+       {0x01b2, 0x0000},
+       {0x01b3, 0x0000},
+       {0x01b4, 0x0000},
+       {0x01b5, 0x0000},
+       {0x01b6, 0x01c3},
+       {0x01b7, 0x02a0},
+       {0x01b8, 0x03e9},
+       {0x01b9, 0x1389},
+       {0x01ba, 0xc351},
+       {0x01bb, 0x0009},
+       {0x01bc, 0x0018},
+       {0x01bd, 0x002a},
+       {0x01be, 0x004c},
+       {0x01bf, 0x0097},
+       {0x01c0, 0x433d},
+       {0x01c2, 0x0000},
+       {0x01c3, 0x0000},
+       {0x01c4, 0x0000},
+       {0x01c5, 0x0000},
+       {0x01c6, 0x0000},
+       {0x01c7, 0x0000},
+       {0x01c8, 0x40af},
+       {0x01c9, 0x0702},
+       {0x01ca, 0x0000},
+       {0x01cb, 0x0000},
+       {0x01cc, 0x5757},
+       {0x01cd, 0x5757},
+       {0x01ce, 0x5757},
+       {0x01cf, 0x5757},
+       {0x01d0, 0x5757},
+       {0x01d1, 0x5757},
+       {0x01d2, 0x5757},
+       {0x01d3, 0x5757},
+       {0x01d4, 0x5757},
+       {0x01d5, 0x5757},
+       {0x01d6, 0x0000},
+       {0x01d7, 0x0008},
+       {0x01d8, 0x0029},
+       {0x01d9, 0x3333},
+       {0x01da, 0x0000},
+       {0x01db, 0x0004},
+       {0x01dc, 0x0000},
+       {0x01de, 0x7c00},
+       {0x01df, 0x0320},
+       {0x01e0, 0x06a1},
+       {0x01e1, 0x0000},
+       {0x01e2, 0x0000},
+       {0x01e3, 0x0000},
+       {0x01e4, 0x0000},
+       {0x01e6, 0x0001},
+       {0x01e7, 0x0000},
+       {0x01e8, 0x0000},
+       {0x01ea, 0x0000},
+       {0x01eb, 0x0000},
+       {0x01ec, 0x0000},
+       {0x01ed, 0x0000},
+       {0x01ee, 0x0000},
+       {0x01ef, 0x0000},
+       {0x01f0, 0x0000},
+       {0x01f1, 0x0000},
+       {0x01f2, 0x0000},
+       {0x01f3, 0x0000},
+       {0x01f4, 0x0000},
+       {0x0210, 0x6297},
+       {0x0211, 0xa005},
+       {0x0212, 0x824c},
+       {0x0213, 0xf7ff},
+       {0x0214, 0xf24c},
+       {0x0215, 0x0102},
+       {0x0216, 0x00a3},
+       {0x0217, 0x0048},
+       {0x0218, 0xa2c0},
+       {0x0219, 0x0400},
+       {0x021a, 0x00c8},
+       {0x021b, 0x00c0},
+       {0x021c, 0x0000},
+       {0x0250, 0x4500},
+       {0x0251, 0x40b3},
+       {0x0252, 0x0000},
+       {0x0253, 0x0000},
+       {0x0254, 0x0000},
+       {0x0255, 0x0000},
+       {0x0256, 0x0000},
+       {0x0257, 0x0000},
+       {0x0258, 0x0000},
+       {0x0259, 0x0000},
+       {0x025a, 0x0005},
+       {0x0270, 0x0000},
+       {0x02ff, 0x0110},
+       {0x0300, 0x001f},
+       {0x0301, 0x032c},
+       {0x0302, 0x5f21},
+       {0x0303, 0x4000},
+       {0x0304, 0x4000},
+       {0x0305, 0x06d5},
+       {0x0306, 0x8000},
+       {0x0307, 0x0700},
+       {0x0310, 0x4560},
+       {0x0311, 0xa4a8},
+       {0x0312, 0x7418},
+       {0x0313, 0x0000},
+       {0x0314, 0x0006},
+       {0x0315, 0xffff},
+       {0x0316, 0xc400},
+       {0x0317, 0x0000},
+       {0x03c0, 0x7e00},
+       {0x03c1, 0x8000},
+       {0x03c2, 0x8000},
+       {0x03c3, 0x8000},
+       {0x03c4, 0x8000},
+       {0x03c5, 0x8000},
+       {0x03c6, 0x8000},
+       {0x03c7, 0x8000},
+       {0x03c8, 0x8000},
+       {0x03c9, 0x8000},
+       {0x03ca, 0x8000},
+       {0x03cb, 0x8000},
+       {0x03cc, 0x8000},
+       {0x03d0, 0x0000},
+       {0x03d1, 0x0000},
+       {0x03d2, 0x0000},
+       {0x03d3, 0x0000},
+       {0x03d4, 0x2000},
+       {0x03d5, 0x2000},
+       {0x03d6, 0x0000},
+       {0x03d7, 0x0000},
+       {0x03d8, 0x2000},
+       {0x03d9, 0x2000},
+       {0x03da, 0x2000},
+       {0x03db, 0x2000},
+       {0x03dc, 0x0000},
+       {0x03dd, 0x0000},
+       {0x03de, 0x0000},
+       {0x03df, 0x2000},
+       {0x03e0, 0x0000},
+       {0x03e1, 0x0000},
+       {0x03e2, 0x0000},
+       {0x03e3, 0x0000},
+       {0x03e4, 0x0000},
+       {0x03e5, 0x0000},
+       {0x03e6, 0x0000},
+       {0x03e7, 0x0000},
+       {0x03e8, 0x0000},
+       {0x03e9, 0x0000},
+       {0x03ea, 0x0000},
+       {0x03eb, 0x0000},
+       {0x03ec, 0x0000},
+       {0x03ed, 0x0000},
+       {0x03ee, 0x0000},
+       {0x03ef, 0x0000},
+       {0x03f0, 0x0800},
+       {0x03f1, 0x0800},
+       {0x03f2, 0x0800},
+       {0x03f3, 0x0800},
+};
+
+static bool rt5682_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case RT5682_RESET:
+       case RT5682_CBJ_CTRL_2:
+       case RT5682_INT_ST_1:
+       case RT5682_4BTN_IL_CMD_1:
+       case RT5682_AJD1_CTRL:
+       case RT5682_HP_CALIB_CTRL_1:
+       case RT5682_DEVICE_ID:
+       case RT5682_I2C_MODE:
+       case RT5682_HP_CALIB_CTRL_10:
+       case RT5682_EFUSE_CTRL_2:
+       case RT5682_JD_TOP_VC_VTRL:
+       case RT5682_HP_IMP_SENS_CTRL_19:
+       case RT5682_IL_CMD_1:
+       case RT5682_SAR_IL_CMD_2:
+       case RT5682_SAR_IL_CMD_4:
+       case RT5682_SAR_IL_CMD_10:
+       case RT5682_SAR_IL_CMD_11:
+       case RT5682_EFUSE_CTRL_6...RT5682_EFUSE_CTRL_11:
+       case RT5682_HP_CALIB_STA_1...RT5682_HP_CALIB_STA_11:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5682_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case RT5682_RESET:
+       case RT5682_VERSION_ID:
+       case RT5682_VENDOR_ID:
+       case RT5682_DEVICE_ID:
+       case RT5682_HP_CTRL_1:
+       case RT5682_HP_CTRL_2:
+       case RT5682_HPL_GAIN:
+       case RT5682_HPR_GAIN:
+       case RT5682_I2C_CTRL:
+       case RT5682_CBJ_BST_CTRL:
+       case RT5682_CBJ_CTRL_1:
+       case RT5682_CBJ_CTRL_2:
+       case RT5682_CBJ_CTRL_3:
+       case RT5682_CBJ_CTRL_4:
+       case RT5682_CBJ_CTRL_5:
+       case RT5682_CBJ_CTRL_6:
+       case RT5682_CBJ_CTRL_7:
+       case RT5682_DAC1_DIG_VOL:
+       case RT5682_STO1_ADC_DIG_VOL:
+       case RT5682_STO1_ADC_BOOST:
+       case RT5682_HP_IMP_GAIN_1:
+       case RT5682_HP_IMP_GAIN_2:
+       case RT5682_SIDETONE_CTRL:
+       case RT5682_STO1_ADC_MIXER:
+       case RT5682_AD_DA_MIXER:
+       case RT5682_STO1_DAC_MIXER:
+       case RT5682_A_DAC1_MUX:
+       case RT5682_DIG_INF2_DATA:
+       case RT5682_REC_MIXER:
+       case RT5682_CAL_REC:
+       case RT5682_ALC_BACK_GAIN:
+       case RT5682_PWR_DIG_1:
+       case RT5682_PWR_DIG_2:
+       case RT5682_PWR_ANLG_1:
+       case RT5682_PWR_ANLG_2:
+       case RT5682_PWR_ANLG_3:
+       case RT5682_PWR_MIXER:
+       case RT5682_PWR_VOL:
+       case RT5682_CLK_DET:
+       case RT5682_RESET_LPF_CTRL:
+       case RT5682_RESET_HPF_CTRL:
+       case RT5682_DMIC_CTRL_1:
+       case RT5682_I2S1_SDP:
+       case RT5682_I2S2_SDP:
+       case RT5682_ADDA_CLK_1:
+       case RT5682_ADDA_CLK_2:
+       case RT5682_I2S1_F_DIV_CTRL_1:
+       case RT5682_I2S1_F_DIV_CTRL_2:
+       case RT5682_TDM_CTRL:
+       case RT5682_TDM_ADDA_CTRL_1:
+       case RT5682_TDM_ADDA_CTRL_2:
+       case RT5682_DATA_SEL_CTRL_1:
+       case RT5682_TDM_TCON_CTRL:
+       case RT5682_GLB_CLK:
+       case RT5682_PLL_CTRL_1:
+       case RT5682_PLL_CTRL_2:
+       case RT5682_PLL_TRACK_1:
+       case RT5682_PLL_TRACK_2:
+       case RT5682_PLL_TRACK_3:
+       case RT5682_PLL_TRACK_4:
+       case RT5682_PLL_TRACK_5:
+       case RT5682_PLL_TRACK_6:
+       case RT5682_PLL_TRACK_11:
+       case RT5682_SDW_REF_CLK:
+       case RT5682_DEPOP_1:
+       case RT5682_DEPOP_2:
+       case RT5682_HP_CHARGE_PUMP_1:
+       case RT5682_HP_CHARGE_PUMP_2:
+       case RT5682_MICBIAS_1:
+       case RT5682_MICBIAS_2:
+       case RT5682_PLL_TRACK_12:
+       case RT5682_PLL_TRACK_14:
+       case RT5682_PLL2_CTRL_1:
+       case RT5682_PLL2_CTRL_2:
+       case RT5682_PLL2_CTRL_3:
+       case RT5682_PLL2_CTRL_4:
+       case RT5682_RC_CLK_CTRL:
+       case RT5682_I2S_M_CLK_CTRL_1:
+       case RT5682_I2S2_F_DIV_CTRL_1:
+       case RT5682_I2S2_F_DIV_CTRL_2:
+       case RT5682_EQ_CTRL_1:
+       case RT5682_EQ_CTRL_2:
+       case RT5682_IRQ_CTRL_1:
+       case RT5682_IRQ_CTRL_2:
+       case RT5682_IRQ_CTRL_3:
+       case RT5682_IRQ_CTRL_4:
+       case RT5682_INT_ST_1:
+       case RT5682_GPIO_CTRL_1:
+       case RT5682_GPIO_CTRL_2:
+       case RT5682_GPIO_CTRL_3:
+       case RT5682_HP_AMP_DET_CTRL_1:
+       case RT5682_HP_AMP_DET_CTRL_2:
+       case RT5682_MID_HP_AMP_DET:
+       case RT5682_LOW_HP_AMP_DET:
+       case RT5682_DELAY_BUF_CTRL:
+       case RT5682_SV_ZCD_1:
+       case RT5682_SV_ZCD_2:
+       case RT5682_IL_CMD_1:
+       case RT5682_IL_CMD_2:
+       case RT5682_IL_CMD_3:
+       case RT5682_IL_CMD_4:
+       case RT5682_IL_CMD_5:
+       case RT5682_IL_CMD_6:
+       case RT5682_4BTN_IL_CMD_1:
+       case RT5682_4BTN_IL_CMD_2:
+       case RT5682_4BTN_IL_CMD_3:
+       case RT5682_4BTN_IL_CMD_4:
+       case RT5682_4BTN_IL_CMD_5:
+       case RT5682_4BTN_IL_CMD_6:
+       case RT5682_4BTN_IL_CMD_7:
+       case RT5682_ADC_STO1_HP_CTRL_1:
+       case RT5682_ADC_STO1_HP_CTRL_2:
+       case RT5682_AJD1_CTRL:
+       case RT5682_JD1_THD:
+       case RT5682_JD2_THD:
+       case RT5682_JD_CTRL_1:
+       case RT5682_DUMMY_1:
+       case RT5682_DUMMY_2:
+       case RT5682_DUMMY_3:
+       case RT5682_DAC_ADC_DIG_VOL1:
+       case RT5682_BIAS_CUR_CTRL_2:
+       case RT5682_BIAS_CUR_CTRL_3:
+       case RT5682_BIAS_CUR_CTRL_4:
+       case RT5682_BIAS_CUR_CTRL_5:
+       case RT5682_BIAS_CUR_CTRL_6:
+       case RT5682_BIAS_CUR_CTRL_7:
+       case RT5682_BIAS_CUR_CTRL_8:
+       case RT5682_BIAS_CUR_CTRL_9:
+       case RT5682_BIAS_CUR_CTRL_10:
+       case RT5682_VREF_REC_OP_FB_CAP_CTRL:
+       case RT5682_CHARGE_PUMP_1:
+       case RT5682_DIG_IN_CTRL_1:
+       case RT5682_PAD_DRIVING_CTRL:
+       case RT5682_SOFT_RAMP_DEPOP:
+       case RT5682_CHOP_DAC:
+       case RT5682_CHOP_ADC:
+       case RT5682_CALIB_ADC_CTRL:
+       case RT5682_VOL_TEST:
+       case RT5682_SPKVDD_DET_STA:
+       case RT5682_TEST_MODE_CTRL_1:
+       case RT5682_TEST_MODE_CTRL_2:
+       case RT5682_TEST_MODE_CTRL_3:
+       case RT5682_TEST_MODE_CTRL_4:
+       case RT5682_TEST_MODE_CTRL_5:
+       case RT5682_PLL1_INTERNAL:
+       case RT5682_PLL2_INTERNAL:
+       case RT5682_STO_NG2_CTRL_1:
+       case RT5682_STO_NG2_CTRL_2:
+       case RT5682_STO_NG2_CTRL_3:
+       case RT5682_STO_NG2_CTRL_4:
+       case RT5682_STO_NG2_CTRL_5:
+       case RT5682_STO_NG2_CTRL_6:
+       case RT5682_STO_NG2_CTRL_7:
+       case RT5682_STO_NG2_CTRL_8:
+       case RT5682_STO_NG2_CTRL_9:
+       case RT5682_STO_NG2_CTRL_10:
+       case RT5682_STO1_DAC_SIL_DET:
+       case RT5682_SIL_PSV_CTRL1:
+       case RT5682_SIL_PSV_CTRL2:
+       case RT5682_SIL_PSV_CTRL3:
+       case RT5682_SIL_PSV_CTRL4:
+       case RT5682_SIL_PSV_CTRL5:
+       case RT5682_HP_IMP_SENS_CTRL_01:
+       case RT5682_HP_IMP_SENS_CTRL_02:
+       case RT5682_HP_IMP_SENS_CTRL_03:
+       case RT5682_HP_IMP_SENS_CTRL_04:
+       case RT5682_HP_IMP_SENS_CTRL_05:
+       case RT5682_HP_IMP_SENS_CTRL_06:
+       case RT5682_HP_IMP_SENS_CTRL_07:
+       case RT5682_HP_IMP_SENS_CTRL_08:
+       case RT5682_HP_IMP_SENS_CTRL_09:
+       case RT5682_HP_IMP_SENS_CTRL_10:
+       case RT5682_HP_IMP_SENS_CTRL_11:
+       case RT5682_HP_IMP_SENS_CTRL_12:
+       case RT5682_HP_IMP_SENS_CTRL_13:
+       case RT5682_HP_IMP_SENS_CTRL_14:
+       case RT5682_HP_IMP_SENS_CTRL_15:
+       case RT5682_HP_IMP_SENS_CTRL_16:
+       case RT5682_HP_IMP_SENS_CTRL_17:
+       case RT5682_HP_IMP_SENS_CTRL_18:
+       case RT5682_HP_IMP_SENS_CTRL_19:
+       case RT5682_HP_IMP_SENS_CTRL_20:
+       case RT5682_HP_IMP_SENS_CTRL_21:
+       case RT5682_HP_IMP_SENS_CTRL_22:
+       case RT5682_HP_IMP_SENS_CTRL_23:
+       case RT5682_HP_IMP_SENS_CTRL_24:
+       case RT5682_HP_IMP_SENS_CTRL_25:
+       case RT5682_HP_IMP_SENS_CTRL_26:
+       case RT5682_HP_IMP_SENS_CTRL_27:
+       case RT5682_HP_IMP_SENS_CTRL_28:
+       case RT5682_HP_IMP_SENS_CTRL_29:
+       case RT5682_HP_IMP_SENS_CTRL_30:
+       case RT5682_HP_IMP_SENS_CTRL_31:
+       case RT5682_HP_IMP_SENS_CTRL_32:
+       case RT5682_HP_IMP_SENS_CTRL_33:
+       case RT5682_HP_IMP_SENS_CTRL_34:
+       case RT5682_HP_IMP_SENS_CTRL_35:
+       case RT5682_HP_IMP_SENS_CTRL_36:
+       case RT5682_HP_IMP_SENS_CTRL_37:
+       case RT5682_HP_IMP_SENS_CTRL_38:
+       case RT5682_HP_IMP_SENS_CTRL_39:
+       case RT5682_HP_IMP_SENS_CTRL_40:
+       case RT5682_HP_IMP_SENS_CTRL_41:
+       case RT5682_HP_IMP_SENS_CTRL_42:
+       case RT5682_HP_IMP_SENS_CTRL_43:
+       case RT5682_HP_LOGIC_CTRL_1:
+       case RT5682_HP_LOGIC_CTRL_2:
+       case RT5682_HP_LOGIC_CTRL_3:
+       case RT5682_HP_CALIB_CTRL_1:
+       case RT5682_HP_CALIB_CTRL_2:
+       case RT5682_HP_CALIB_CTRL_3:
+       case RT5682_HP_CALIB_CTRL_4:
+       case RT5682_HP_CALIB_CTRL_5:
+       case RT5682_HP_CALIB_CTRL_6:
+       case RT5682_HP_CALIB_CTRL_7:
+       case RT5682_HP_CALIB_CTRL_9:
+       case RT5682_HP_CALIB_CTRL_10:
+       case RT5682_HP_CALIB_CTRL_11:
+       case RT5682_HP_CALIB_STA_1:
+       case RT5682_HP_CALIB_STA_2:
+       case RT5682_HP_CALIB_STA_3:
+       case RT5682_HP_CALIB_STA_4:
+       case RT5682_HP_CALIB_STA_5:
+       case RT5682_HP_CALIB_STA_6:
+       case RT5682_HP_CALIB_STA_7:
+       case RT5682_HP_CALIB_STA_8:
+       case RT5682_HP_CALIB_STA_9:
+       case RT5682_HP_CALIB_STA_10:
+       case RT5682_HP_CALIB_STA_11:
+       case RT5682_SAR_IL_CMD_1:
+       case RT5682_SAR_IL_CMD_2:
+       case RT5682_SAR_IL_CMD_3:
+       case RT5682_SAR_IL_CMD_4:
+       case RT5682_SAR_IL_CMD_5:
+       case RT5682_SAR_IL_CMD_6:
+       case RT5682_SAR_IL_CMD_7:
+       case RT5682_SAR_IL_CMD_8:
+       case RT5682_SAR_IL_CMD_9:
+       case RT5682_SAR_IL_CMD_10:
+       case RT5682_SAR_IL_CMD_11:
+       case RT5682_SAR_IL_CMD_12:
+       case RT5682_SAR_IL_CMD_13:
+       case RT5682_EFUSE_CTRL_1:
+       case RT5682_EFUSE_CTRL_2:
+       case RT5682_EFUSE_CTRL_3:
+       case RT5682_EFUSE_CTRL_4:
+       case RT5682_EFUSE_CTRL_5:
+       case RT5682_EFUSE_CTRL_6:
+       case RT5682_EFUSE_CTRL_7:
+       case RT5682_EFUSE_CTRL_8:
+       case RT5682_EFUSE_CTRL_9:
+       case RT5682_EFUSE_CTRL_10:
+       case RT5682_EFUSE_CTRL_11:
+       case RT5682_JD_TOP_VC_VTRL:
+       case RT5682_DRC1_CTRL_0:
+       case RT5682_DRC1_CTRL_1:
+       case RT5682_DRC1_CTRL_2:
+       case RT5682_DRC1_CTRL_3:
+       case RT5682_DRC1_CTRL_4:
+       case RT5682_DRC1_CTRL_5:
+       case RT5682_DRC1_CTRL_6:
+       case RT5682_DRC1_HARD_LMT_CTRL_1:
+       case RT5682_DRC1_HARD_LMT_CTRL_2:
+       case RT5682_DRC1_PRIV_1:
+       case RT5682_DRC1_PRIV_2:
+       case RT5682_DRC1_PRIV_3:
+       case RT5682_DRC1_PRIV_4:
+       case RT5682_DRC1_PRIV_5:
+       case RT5682_DRC1_PRIV_6:
+       case RT5682_DRC1_PRIV_7:
+       case RT5682_DRC1_PRIV_8:
+       case RT5682_EQ_AUTO_RCV_CTRL1:
+       case RT5682_EQ_AUTO_RCV_CTRL2:
+       case RT5682_EQ_AUTO_RCV_CTRL3:
+       case RT5682_EQ_AUTO_RCV_CTRL4:
+       case RT5682_EQ_AUTO_RCV_CTRL5:
+       case RT5682_EQ_AUTO_RCV_CTRL6:
+       case RT5682_EQ_AUTO_RCV_CTRL7:
+       case RT5682_EQ_AUTO_RCV_CTRL8:
+       case RT5682_EQ_AUTO_RCV_CTRL9:
+       case RT5682_EQ_AUTO_RCV_CTRL10:
+       case RT5682_EQ_AUTO_RCV_CTRL11:
+       case RT5682_EQ_AUTO_RCV_CTRL12:
+       case RT5682_EQ_AUTO_RCV_CTRL13:
+       case RT5682_ADC_L_EQ_LPF1_A1:
+       case RT5682_R_EQ_LPF1_A1:
+       case RT5682_L_EQ_LPF1_H0:
+       case RT5682_R_EQ_LPF1_H0:
+       case RT5682_L_EQ_BPF1_A1:
+       case RT5682_R_EQ_BPF1_A1:
+       case RT5682_L_EQ_BPF1_A2:
+       case RT5682_R_EQ_BPF1_A2:
+       case RT5682_L_EQ_BPF1_H0:
+       case RT5682_R_EQ_BPF1_H0:
+       case RT5682_L_EQ_BPF2_A1:
+       case RT5682_R_EQ_BPF2_A1:
+       case RT5682_L_EQ_BPF2_A2:
+       case RT5682_R_EQ_BPF2_A2:
+       case RT5682_L_EQ_BPF2_H0:
+       case RT5682_R_EQ_BPF2_H0:
+       case RT5682_L_EQ_BPF3_A1:
+       case RT5682_R_EQ_BPF3_A1:
+       case RT5682_L_EQ_BPF3_A2:
+       case RT5682_R_EQ_BPF3_A2:
+       case RT5682_L_EQ_BPF3_H0:
+       case RT5682_R_EQ_BPF3_H0:
+       case RT5682_L_EQ_BPF4_A1:
+       case RT5682_R_EQ_BPF4_A1:
+       case RT5682_L_EQ_BPF4_A2:
+       case RT5682_R_EQ_BPF4_A2:
+       case RT5682_L_EQ_BPF4_H0:
+       case RT5682_R_EQ_BPF4_H0:
+       case RT5682_L_EQ_HPF1_A1:
+       case RT5682_R_EQ_HPF1_A1:
+       case RT5682_L_EQ_HPF1_H0:
+       case RT5682_R_EQ_HPF1_H0:
+       case RT5682_L_EQ_PRE_VOL:
+       case RT5682_R_EQ_PRE_VOL:
+       case RT5682_L_EQ_POST_VOL:
+       case RT5682_R_EQ_POST_VOL:
+       case RT5682_I2C_MODE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+       6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+       8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5682_data_select[] = {
+       "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if2_adc_enum,
+       RT5682_DIG_INF2_DATA, RT5682_IF2_ADC_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_01_adc_enum,
+       RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC1_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_23_adc_enum,
+       RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC2_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_45_adc_enum,
+       RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC3_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_67_adc_enum,
+       RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC4_SEL_SFT, rt5682_data_select);
+
+static const struct snd_kcontrol_new rt5682_if2_adc_swap_mux =
+       SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5682_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_01_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5682_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_23_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5682_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_45_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5682_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_67_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682_if1_67_adc_enum);
+
+static void rt5682_reset(struct regmap *regmap)
+{
+       regmap_write(regmap, RT5682_RESET, 0);
+       regmap_write(regmap, RT5682_I2C_MODE, 1);
+}
+/**
+ * rt5682_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5682 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the component driver will turn on
+ * ASRC for these filters if ASRC is selected as their clock source.
+ */
+int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+               unsigned int filter_mask, unsigned int clk_src)
+{
+
+       switch (clk_src) {
+       case RT5682_CLK_SEL_SYS:
+       case RT5682_CLK_SEL_I2S1_ASRC:
+       case RT5682_CLK_SEL_I2S2_ASRC:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (filter_mask & RT5682_DA_STEREO1_FILTER) {
+               snd_soc_component_update_bits(component, RT5682_PLL_TRACK_2,
+                       RT5682_FILTER_CLK_SEL_MASK,
+                       clk_src << RT5682_FILTER_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5682_AD_STEREO1_FILTER) {
+               snd_soc_component_update_bits(component, RT5682_PLL_TRACK_3,
+                       RT5682_FILTER_CLK_SEL_MASK,
+                       clk_src << RT5682_FILTER_CLK_SEL_SFT);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5682_sel_asrc_clk_src);
+
+static int rt5682_button_detect(struct snd_soc_component *component)
+{
+       int btn_type, val;
+
+       val = snd_soc_component_read32(component, RT5682_4BTN_IL_CMD_1);
+       btn_type = val & 0xfff0;
+       snd_soc_component_write(component, RT5682_4BTN_IL_CMD_1, val);
+       pr_debug("%s btn_type=%x\n", __func__, btn_type);
+       snd_soc_component_update_bits(component,
+               RT5682_SAR_IL_CMD_2, 0x10, 0x10);
+
+       return btn_type;
+}
+
+static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
+               bool enable)
+{
+       if (enable) {
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+                       RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_EN);
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_13,
+                       RT5682_SAR_SOUR_MASK, RT5682_SAR_SOUR_BTN);
+               snd_soc_component_write(component, RT5682_IL_CMD_1, 0x0040);
+               snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+                       RT5682_4BTN_IL_MASK | RT5682_4BTN_IL_RST_MASK,
+                       RT5682_4BTN_IL_EN | RT5682_4BTN_IL_NOR);
+               snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3,
+                       RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_EN);
+       } else {
+               snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3,
+                       RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_DIS);
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+                       RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_DIS);
+               snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+                       RT5682_4BTN_IL_MASK, RT5682_4BTN_IL_DIS);
+               snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+                       RT5682_4BTN_IL_RST_MASK, RT5682_4BTN_IL_RST);
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_13,
+                       RT5682_SAR_SOUR_MASK, RT5682_SAR_SOUR_TYPE);
+       }
+}
+
+/**
+ * rt5682_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5682_headset_detect(struct snd_soc_component *component,
+               int jack_insert)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       unsigned int val, count;
+
+       if (jack_insert) {
+               snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+               snd_soc_dapm_sync(dapm);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
+
+               count = 0;
+               val = snd_soc_component_read32(component, RT5682_CBJ_CTRL_2)
+                       & RT5682_JACK_TYPE_MASK;
+               while (val == 0 && count < 50) {
+                       usleep_range(10000, 15000);
+                       val = snd_soc_component_read32(component,
+                               RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+                       count++;
+               }
+
+               switch (val) {
+               case 0x1:
+               case 0x2:
+                       rt5682->jack_type = SND_JACK_HEADSET;
+                       rt5682_enable_push_button_irq(component, true);
+                       break;
+               default:
+                       rt5682->jack_type = SND_JACK_HEADPHONE;
+               }
+
+       } else {
+               rt5682_enable_push_button_irq(component, false);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW);
+               snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+               snd_soc_dapm_sync(dapm);
+
+               rt5682->jack_type = 0;
+       }
+
+       dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
+       return rt5682->jack_type;
+}
+
+static irqreturn_t rt5682_irq(int irq, void *data)
+{
+       struct rt5682_priv *rt5682 = data;
+
+       mod_delayed_work(system_power_efficient_wq,
+                       &rt5682->jack_detect_work, msecs_to_jiffies(250));
+
+       return IRQ_HANDLED;
+}
+
+static void rt5682_jd_check_handler(struct work_struct *work)
+{
+       struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
+               jd_check_work.work);
+
+       if (snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
+               & RT5682_JDH_RS_MASK) {
+               /* jack out */
+               rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+
+               snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+                               SND_JACK_HEADSET |
+                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                               SND_JACK_BTN_2 | SND_JACK_BTN_3);
+       } else {
+               schedule_delayed_work(&rt5682->jd_check_work, 500);
+       }
+}
+
+static int rt5682_set_jack_detect(struct snd_soc_component *component,
+       struct snd_soc_jack *hs_jack, void *data)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       switch (rt5682->pdata.jd_src) {
+       case RT5682_JD1:
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2,
+                       RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
+               snd_soc_component_write(component, RT5682_CBJ_CTRL_1, 0xd042);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_3,
+                       RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN);
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+                       RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN);
+               regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+                       RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_IRQ);
+               regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+                               RT5682_POW_IRQ | RT5682_POW_JDH |
+                               RT5682_POW_ANA, RT5682_POW_IRQ |
+                               RT5682_POW_JDH | RT5682_POW_ANA);
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2,
+                       RT5682_PWR_JDH | RT5682_PWR_JDL,
+                       RT5682_PWR_JDH | RT5682_PWR_JDL);
+               regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+                       RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK,
+                       RT5682_JD1_EN | RT5682_JD1_POL_NOR);
+               mod_delayed_work(system_power_efficient_wq,
+                          &rt5682->jack_detect_work, msecs_to_jiffies(250));
+               break;
+
+       case RT5682_JD_NULL:
+               regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+                       RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
+               regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+                               RT5682_POW_JDH | RT5682_POW_JDL, 0);
+               break;
+
+       default:
+               dev_warn(component->dev, "Wrong JD source\n");
+               break;
+       }
+
+       rt5682->hs_jack = hs_jack;
+
+       return 0;
+}
+
+static void rt5682_jack_detect_handler(struct work_struct *work)
+{
+       struct rt5682_priv *rt5682 =
+               container_of(work, struct rt5682_priv, jack_detect_work.work);
+       int val, btn_type;
+
+       while (!rt5682->component)
+               usleep_range(10000, 15000);
+
+       while (!rt5682->component->card->instantiated)
+               usleep_range(10000, 15000);
+
+       mutex_lock(&rt5682->calibrate_mutex);
+
+       val = snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
+               & RT5682_JDH_RS_MASK;
+       if (!val) {
+               /* jack in */
+               if (rt5682->jack_type == 0) {
+                       /* jack was out, report jack type */
+                       rt5682->jack_type =
+                               rt5682_headset_detect(rt5682->component, 1);
+               } else {
+                       /* jack is already in, report button event */
+                       rt5682->jack_type = SND_JACK_HEADSET;
+                       btn_type = rt5682_button_detect(rt5682->component);
+                       /**
+                        * rt5682 can report three kinds of button behavior,
+                        * one click, double click and hold. However,
+                        * currently we will report button pressed/released
+                        * event. So all the three button behaviors are
+                        * treated as button pressed.
+                        */
+                       switch (btn_type) {
+                       case 0x8000:
+                       case 0x4000:
+                       case 0x2000:
+                               rt5682->jack_type |= SND_JACK_BTN_0;
+                               break;
+                       case 0x1000:
+                       case 0x0800:
+                       case 0x0400:
+                               rt5682->jack_type |= SND_JACK_BTN_1;
+                               break;
+                       case 0x0200:
+                       case 0x0100:
+                       case 0x0080:
+                               rt5682->jack_type |= SND_JACK_BTN_2;
+                               break;
+                       case 0x0040:
+                       case 0x0020:
+                       case 0x0010:
+                               rt5682->jack_type |= SND_JACK_BTN_3;
+                               break;
+                       case 0x0000: /* unpressed */
+                               break;
+                       default:
+                               btn_type = 0;
+                               dev_err(rt5682->component->dev,
+                                       "Unexpected button code 0x%04x\n",
+                                       btn_type);
+                               break;
+                       }
+               }
+       } else {
+               /* jack out */
+               rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+       }
+
+       snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+                       SND_JACK_HEADSET |
+                           SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                           SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+       if (rt5682->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+               SND_JACK_BTN_2 | SND_JACK_BTN_3))
+               schedule_delayed_work(&rt5682->jd_check_work, 0);
+       else
+               cancel_delayed_work_sync(&rt5682->jd_check_work);
+
+       mutex_unlock(&rt5682->calibrate_mutex);
+}
+
+static const struct snd_kcontrol_new rt5682_snd_controls[] = {
+       /* Headphone Output Volume */
+       SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5682_HPL_GAIN,
+               RT5682_HPR_GAIN, RT5682_G_HP_SFT, 15, 1, hp_vol_tlv),
+
+       /* DAC Digital Volume */
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682_DAC1_DIG_VOL,
+               RT5682_L_VOL_SFT, RT5682_R_VOL_SFT, 175, 0, dac_vol_tlv),
+
+       /* IN Boost Volume */
+       SOC_SINGLE_TLV("CBJ Boost Volume", RT5682_CBJ_BST_CTRL,
+               RT5682_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("STO1 ADC Capture Switch", RT5682_STO1_ADC_DIG_VOL,
+               RT5682_L_MUTE_SFT, RT5682_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5682_STO1_ADC_DIG_VOL,
+               RT5682_L_VOL_SFT, RT5682_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5682_STO1_ADC_BOOST,
+               RT5682_STO1_ADC_L_BST_SFT, RT5682_STO1_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+};
+
+
+static int rt5682_div_sel(struct rt5682_priv *rt5682,
+                         int target, const int div[], int size)
+{
+       int i;
+
+       if (rt5682->sysclk < target) {
+               pr_err("sysclk rate %d is too low\n",
+                       rt5682->sysclk);
+               return 0;
+       }
+
+       for (i = 0; i < size - 1; i++) {
+               pr_info("div[%d]=%d\n", i, div[i]);
+               if (target * div[i] == rt5682->sysclk)
+                       return i;
+               if (target * div[i + 1] > rt5682->sysclk) {
+                       pr_err("can't find div for sysclk %d\n",
+                               rt5682->sysclk);
+                       return i;
+               }
+       }
+
+       if (target * div[i] < rt5682->sysclk)
+               pr_err("sysclk rate %d is too high\n",
+                       rt5682->sysclk);
+
+       return size - 1;
+
+}
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       int idx = -EINVAL;
+       static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
+
+       idx = rt5682_div_sel(rt5682, 1500000, div, ARRAY_SIZE(div));
+
+       snd_soc_component_update_bits(component, RT5682_DMIC_CTRL_1,
+               RT5682_DMIC_CLK_MASK, idx << RT5682_DMIC_CLK_SFT);
+
+       return 0;
+}
+
+static int set_filter_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       int ref, val, reg, sft, mask, idx = -EINVAL;
+       static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+       static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+
+       val = snd_soc_component_read32(component, RT5682_GPIO_CTRL_1) &
+               RT5682_GP4_PIN_MASK;
+       if (w->shift == RT5682_PWR_ADC_S1F_BIT &&
+               val == RT5682_GP4_PIN_ADCDAT2)
+               ref = 256 * rt5682->lrck[RT5682_AIF2];
+       else
+               ref = 256 * rt5682->lrck[RT5682_AIF1];
+
+       idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f));
+
+       if (w->shift == RT5682_PWR_ADC_S1F_BIT) {
+               reg = RT5682_PLL_TRACK_3;
+               sft = RT5682_ADC_OSR_SFT;
+               mask = RT5682_ADC_OSR_MASK;
+       } else {
+               reg = RT5682_PLL_TRACK_2;
+               sft = RT5682_DAC_OSR_SFT;
+               mask = RT5682_DAC_OSR_MASK;
+       }
+
+       snd_soc_component_update_bits(component, reg,
+               RT5682_FILTER_CLK_DIV_MASK, idx << RT5682_FILTER_CLK_DIV_SFT);
+
+       /* select over sample rate */
+       for (idx = 0; idx < ARRAY_SIZE(div_o); idx++) {
+               if (rt5682->sysclk <= 12288000 * div_o[idx])
+                       break;
+       }
+
+       snd_soc_component_update_bits(component, RT5682_ADDA_CLK_1,
+               mask, idx << sft);
+
+       return 0;
+}
+
+static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+
+       val = snd_soc_component_read32(component, RT5682_GLB_CLK);
+       val &= RT5682_SCLK_SRC_MASK;
+       if (val == RT5682_SCLK_SRC_PLL1)
+               return 1;
+       else
+               return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int reg, shift, val;
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+
+       switch (w->shift) {
+       case RT5682_ADC_STO1_ASRC_SFT:
+               reg = RT5682_PLL_TRACK_3;
+               shift = RT5682_FILTER_CLK_SEL_SFT;
+               break;
+       case RT5682_DAC_STO1_ASRC_SFT:
+               reg = RT5682_PLL_TRACK_2;
+               shift = RT5682_FILTER_CLK_SEL_SFT;
+               break;
+       default:
+               return 0;
+       }
+
+       val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+       switch (val) {
+       case RT5682_CLK_SEL_I2S1_ASRC:
+       case RT5682_CLK_SEL_I2S2_ASRC:
+               return 1;
+       default:
+               return 0;
+       }
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5682_sto1_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5682_STO1_ADC_MIXER,
+                       RT5682_M_STO1_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5682_STO1_ADC_MIXER,
+                       RT5682_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5682_STO1_ADC_MIXER,
+                       RT5682_M_STO1_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5682_STO1_ADC_MIXER,
+                       RT5682_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682_AD_DA_MIXER,
+                       RT5682_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5682_AD_DA_MIXER,
+                       RT5682_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682_AD_DA_MIXER,
+                       RT5682_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5682_AD_DA_MIXER,
+                       RT5682_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5682_STO1_DAC_MIXER,
+                       RT5682_M_DAC_L1_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5682_STO1_DAC_MIXER,
+                       RT5682_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5682_STO1_DAC_MIXER,
+                       RT5682_M_DAC_L1_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5682_STO1_DAC_MIXER,
+                       RT5682_M_DAC_R1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5682_rec1_l_mix[] = {
+       SOC_DAPM_SINGLE("CBJ Switch", RT5682_REC_MIXER,
+                       RT5682_M_CBJ_RM1_L_SFT, 1, 1),
+};
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5682_sto1_adc1_src[] = {
+       "DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_sto1_adc1l_enum, RT5682_STO1_ADC_MIXER,
+       RT5682_STO1_ADC1L_SRC_SFT, rt5682_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc1l_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682_sto1_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_sto1_adc1r_enum, RT5682_STO1_ADC_MIXER,
+       RT5682_STO1_ADC1R_SRC_SFT, rt5682_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc1r_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5682_sto1_adc_src[] = {
+       "ADC1 L", "ADC1 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_sto1_adcl_enum, RT5682_STO1_ADC_MIXER,
+       RT5682_STO1_ADCL_SRC_SFT, rt5682_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adcl_mux =
+       SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5682_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_sto1_adcr_enum, RT5682_STO1_ADC_MIXER,
+       RT5682_STO1_ADCR_SRC_SFT, rt5682_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adcr_mux =
+       SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5682_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5682_sto1_adc2_src[] = {
+       "DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_sto1_adc2l_enum, RT5682_STO1_ADC_MIXER,
+       RT5682_STO1_ADC2L_SRC_SFT, rt5682_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc2l_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5682_sto1_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_sto1_adc2r_enum, RT5682_STO1_ADC_MIXER,
+       RT5682_STO1_ADC2R_SRC_SFT, rt5682_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc2r_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5682_sto1_adc2r_enum);
+
+/* MX-79 [6:4] I2S1 ADC data location */
+static const unsigned int rt5682_if1_adc_slot_values[] = {
+       0,
+       2,
+       4,
+       6,
+};
+
+static const char * const rt5682_if1_adc_slot_src[] = {
+       "Slot 0", "Slot 2", "Slot 4", "Slot 6"
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_if1_adc_slot_enum,
+       RT5682_TDM_CTRL, RT5682_TDM_ADC_LCA_SFT, RT5682_TDM_ADC_LCA_MASK,
+       rt5682_if1_adc_slot_src, rt5682_if1_adc_slot_values);
+
+static const struct snd_kcontrol_new rt5682_if1_adc_slot_mux =
+       SOC_DAPM_ENUM("IF1 ADC Slot location", rt5682_if1_adc_slot_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2B [4], MX-2B [0]*/
+static const char * const rt5682_alg_dac1_src[] = {
+       "Stereo1 DAC Mixer", "DAC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_alg_dac_l1_enum, RT5682_A_DAC1_MUX,
+       RT5682_A_DACL1_SFT, rt5682_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5682_alg_dac_l1_mux =
+       SOC_DAPM_ENUM("Analog DAC L1 Source", rt5682_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5682_alg_dac_r1_enum, RT5682_A_DAC1_MUX,
+       RT5682_A_DACR1_SFT, rt5682_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5682_alg_dac_r1_mux =
+       SOC_DAPM_ENUM("Analog DAC R1 Source", rt5682_alg_dac_r1_enum);
+
+/* Out Switch */
+static const struct snd_kcontrol_new hpol_switch =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
+                                       RT5682_L_MUTE_SFT, 1, 1);
+static const struct snd_kcontrol_new hpor_switch =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
+                                       RT5682_R_MUTE_SFT, 1, 1);
+
+static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_component_write(component,
+                       RT5682_HP_LOGIC_CTRL_2, 0x0012);
+               snd_soc_component_write(component,
+                       RT5682_HP_CTRL_2, 0x6000);
+               snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1,
+                       RT5682_NG2_EN_MASK, RT5682_NG2_EN);
+               snd_soc_component_update_bits(component,
+                       RT5682_DEPOP_1, 0x60, 0x60);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component,
+                       RT5682_DEPOP_1, 0x60, 0x0);
+               snd_soc_component_write(component,
+                       RT5682_HP_CTRL_2, 0x0000);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /*Add delay to avoid pop noise*/
+               msleep(150);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               switch (w->shift) {
+               case RT5682_PWR_VREF1_BIT:
+                       snd_soc_component_update_bits(component,
+                               RT5682_PWR_ANLG_1, RT5682_PWR_FV1, 0);
+                       break;
+
+               case RT5682_PWR_VREF2_BIT:
+                       snd_soc_component_update_bits(component,
+                               RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               usleep_range(15000, 20000);
+               switch (w->shift) {
+               case RT5682_PWR_VREF1_BIT:
+                       snd_soc_component_update_bits(component,
+                               RT5682_PWR_ANLG_1, RT5682_PWR_FV1,
+                               RT5682_PWR_FV1);
+                       break;
+
+               case RT5682_PWR_VREF2_BIT:
+                       snd_soc_component_update_bits(component,
+                               RT5682_PWR_ANLG_1, RT5682_PWR_FV2,
+                               RT5682_PWR_FV2);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static const unsigned int rt5682_adcdat_pin_values[] = {
+       1,
+       3,
+};
+
+static const char * const rt5682_adcdat_pin_select[] = {
+       "ADCDAT1",
+       "ADCDAT2",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_adcdat_pin_enum,
+       RT5682_GPIO_CTRL_1, RT5682_GP4_PIN_SFT, RT5682_GP4_PIN_MASK,
+       rt5682_adcdat_pin_select, rt5682_adcdat_pin_values);
+
+static const struct snd_kcontrol_new rt5682_adcdat_pin_ctrl =
+       SOC_DAPM_ENUM("ADCDAT", rt5682_adcdat_pin_enum);
+
+static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("LDO2", RT5682_PWR_ANLG_3, RT5682_PWR_LDO2_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL1", RT5682_PWR_ANLG_3, RT5682_PWR_PLL_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL2B", RT5682_PWR_ANLG_3, RT5682_PWR_PLL2B_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL2F", RT5682_PWR_ANLG_3, RT5682_PWR_PLL2F_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Vref1", RT5682_PWR_ANLG_1, RT5682_PWR_VREF1_BIT, 0,
+               rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SUPPLY("Vref2", RT5682_PWR_ANLG_1, RT5682_PWR_VREF2_BIT, 0,
+               rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682_PLL_TRACK_1,
+               RT5682_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5682_PLL_TRACK_1,
+               RT5682_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5682_PLL_TRACK_1,
+               RT5682_AD_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5682_PLL_TRACK_1,
+               RT5682_DA_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5682_PLL_TRACK_1,
+               RT5682_DMIC_ASRC_SFT, 0, NULL, 0),
+
+       /* Input Side */
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5682_PWR_ANLG_2, RT5682_PWR_MB1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5682_PWR_ANLG_2, RT5682_PWR_MB2_BIT,
+               0, NULL, 0),
+
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("DMIC L1"),
+       SND_SOC_DAPM_INPUT("DMIC R1"),
+
+       SND_SOC_DAPM_INPUT("IN1P"),
+
+       SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+               set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5682_DMIC_CTRL_1,
+               RT5682_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+       /* Boost */
+       SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("CBJ Power", RT5682_PWR_ANLG_3,
+               RT5682_PWR_CBJ_BIT, 0, NULL, 0),
+
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682_rec1_l_mix,
+               ARRAY_SIZE(rt5682_rec1_l_mix)),
+       SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5682_PWR_ANLG_2,
+               RT5682_PWR_RM1_L_BIT, 0, NULL, 0),
+
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5682_PWR_DIG_1,
+               RT5682_PWR_ADC_L1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5682_PWR_DIG_1,
+               RT5682_PWR_ADC_R1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5682_CHOP_ADC,
+               RT5682_CKGEN_ADC1_SFT, 0, NULL, 0),
+
+       /* ADC Mux */
+       SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_sto1_adc1l_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_sto1_adc1r_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_sto1_adc2l_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_sto1_adc2r_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_sto1_adcl_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_sto1_adcr_mux),
+       SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0,
+               &rt5682_if1_adc_slot_mux),
+
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682_PWR_DIG_2,
+               RT5682_PWR_ADC_S1F_BIT, 0, set_filter_clk,
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682_STO1_ADC_DIG_VOL,
+               RT5682_L_MUTE_SFT, 1, rt5682_sto1_adc_l_mix,
+               ARRAY_SIZE(rt5682_sto1_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682_STO1_ADC_DIG_VOL,
+               RT5682_R_MUTE_SFT, 1, rt5682_sto1_adc_r_mix,
+               ARRAY_SIZE(rt5682_sto1_adc_r_mix)),
+       SND_SOC_DAPM_SUPPLY("BTN Detection Mode", RT5682_SAR_IL_CMD_1,
+               14, 1, NULL, 0),
+
+       /* ADC PGA */
+       SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1", RT5682_PWR_DIG_1, RT5682_PWR_I2S1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2", RT5682_PWR_DIG_1, RT5682_PWR_I2S2_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Digital Interface Select */
+       SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5682_if1_01_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5682_if1_23_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5682_if1_45_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5682_if1_67_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5682_if2_adc_swap_mux),
+
+       SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5682_adcdat_pin_ctrl),
+
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0,
+               RT5682_I2S1_SDP, RT5682_SEL_ADCDAT_SFT, 1),
+       SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0,
+               RT5682_I2S2_SDP, RT5682_I2S2_PIN_CFG_SFT, 1),
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+               rt5682_dac_l_mix, ARRAY_SIZE(rt5682_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+               rt5682_dac_r_mix, ARRAY_SIZE(rt5682_dac_r_mix)),
+
+       /* DAC channel Mux */
+       SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+               &rt5682_alg_dac_l1_mux),
+       SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+               &rt5682_alg_dac_r1_mux),
+
+       /* DAC Mixer */
+       SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5682_PWR_DIG_2,
+               RT5682_PWR_DAC_S1F_BIT, 0, set_filter_clk,
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5682_sto1_dac_l_mix, ARRAY_SIZE(rt5682_sto1_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5682_sto1_dac_r_mix, ARRAY_SIZE(rt5682_sto1_dac_r_mix)),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC L1", NULL, RT5682_PWR_DIG_1,
+               RT5682_PWR_DAC_L1_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, RT5682_PWR_DIG_1,
+               RT5682_PWR_DAC_R1_BIT, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 3, RT5682_CHOP_DAC,
+               RT5682_CKGEN_DAC1_SFT, 0, NULL, 0),
+
+       /* HPO */
+       SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5682_hp_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_SUPPLY("HP Amp L", RT5682_PWR_ANLG_1,
+               RT5682_PWR_HA_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1,
+               RT5682_PWR_HA_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1,
+               RT5682_PUMP_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1,
+               RT5682_CAPLESS_EN_SFT, 0, NULL, 0),
+
+       SND_SOC_DAPM_SWITCH("HPOL Playback", SND_SOC_NOPM, 0, 0,
+               &hpol_switch),
+       SND_SOC_DAPM_SWITCH("HPOR Playback", SND_SOC_NOPM, 0, 0,
+               &hpor_switch),
+
+       /* CLK DET */
+       SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682_CLK_DET,
+               RT5682_SYS_CLK_DET_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5682_CLK_DET,
+               RT5682_PLL1_CLK_DET_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET PLL2", RT5682_CLK_DET,
+               RT5682_PLL2_CLK_DET_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET", RT5682_CLK_DET,
+               RT5682_POW_CLK_DET_SFT, 0, NULL, 0),
+
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+
+};
+
+static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
+       /*PLL*/
+       {"ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+       {"DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+
+       /*ASRC*/
+       {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+       {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+       {"ADC STO1 ASRC", NULL, "AD ASRC"},
+       {"ADC STO1 ASRC", NULL, "CLKDET"},
+       {"DAC STO1 ASRC", NULL, "DA ASRC"},
+       {"DAC STO1 ASRC", NULL, "CLKDET"},
+
+       /*Vref*/
+       {"MICBIAS1", NULL, "Vref1"},
+       {"MICBIAS1", NULL, "Vref2"},
+       {"MICBIAS2", NULL, "Vref1"},
+       {"MICBIAS2", NULL, "Vref2"},
+
+       {"CLKDET SYS", NULL, "CLKDET"},
+
+       {"IN1P", NULL, "LDO2"},
+
+       {"BST1 CBJ", NULL, "IN1P"},
+       {"BST1 CBJ", NULL, "CBJ Power"},
+       {"CBJ Power", NULL, "Vref2"},
+
+       {"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+       {"RECMIX1L", NULL, "RECMIX1L Power"},
+
+       {"ADC1 L", NULL, "RECMIX1L"},
+       {"ADC1 L", NULL, "ADC1 L Power"},
+       {"ADC1 L", NULL, "ADC1 clock"},
+
+       {"DMIC L1", NULL, "DMIC CLK"},
+       {"DMIC L1", NULL, "DMIC1 Power"},
+       {"DMIC R1", NULL, "DMIC CLK"},
+       {"DMIC R1", NULL, "DMIC1 Power"},
+       {"DMIC CLK", NULL, "DMIC ASRC"},
+
+       {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+       {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+       {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+       {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+       {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+       {"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+       {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+       {"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+
+       {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+       {"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+       {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+       {"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+
+       {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+       {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+       {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+       {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+       {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+       {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+       {"ADC Stereo1 Filter", NULL, "BTN Detection Mode"},
+
+       {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+       {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+
+       {"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+       {"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+       {"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+       {"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+       {"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+       {"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+       {"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+       {"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+       {"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+       {"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+       {"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+       {"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+       {"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+       {"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+       {"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+       {"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+
+       {"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"},
+       {"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"},
+       {"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"},
+       {"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"},
+       {"IF1_ADC Mux", NULL, "I2S1"},
+       {"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"},
+       {"AIF1TX", NULL, "ADCDAT Mux"},
+       {"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+       {"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+       {"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+       {"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+       {"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"},
+       {"AIF2TX", NULL, "ADCDAT Mux"},
+
+       {"IF1 DAC1 L", NULL, "AIF1RX"},
+       {"IF1 DAC1 L", NULL, "I2S1"},
+       {"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"},
+       {"IF1 DAC1 R", NULL, "AIF1RX"},
+       {"IF1 DAC1 R", NULL, "I2S1"},
+       {"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"},
+
+       {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+       {"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"},
+       {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+       {"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"},
+
+       {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+       {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+
+       {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+       {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+
+       {"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+       {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+       {"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+       {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+
+       {"DAC L1", NULL, "DAC L1 Source"},
+       {"DAC R1", NULL, "DAC R1 Source"},
+
+       {"DAC L1", NULL, "DAC 1 Clock"},
+       {"DAC R1", NULL, "DAC 1 Clock"},
+
+       {"HP Amp", NULL, "DAC L1"},
+       {"HP Amp", NULL, "DAC R1"},
+       {"HP Amp", NULL, "HP Amp L"},
+       {"HP Amp", NULL, "HP Amp R"},
+       {"HP Amp", NULL, "Capless"},
+       {"HP Amp", NULL, "Charge Pump"},
+       {"HP Amp", NULL, "CLKDET SYS"},
+       {"HP Amp", NULL, "CBJ Power"},
+       {"HP Amp", NULL, "Vref2"},
+       {"HPOL Playback", "Switch", "HP Amp"},
+       {"HPOR Playback", "Switch", "HP Amp"},
+       {"HPOL", NULL, "HPOL Playback"},
+       {"HPOR", NULL, "HPOR Playback"},
+};
+
+static int rt5682_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                       unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_component *component = dai->component;
+       unsigned int cl, val = 0;
+
+       if (tx_mask || rx_mask)
+               snd_soc_component_update_bits(component, RT5682_TDM_ADDA_CTRL_2,
+                       RT5682_TDM_EN, RT5682_TDM_EN);
+       else
+               snd_soc_component_update_bits(component, RT5682_TDM_ADDA_CTRL_2,
+                       RT5682_TDM_EN, 0);
+
+       switch (slots) {
+       case 4:
+               val |= RT5682_TDM_TX_CH_4;
+               val |= RT5682_TDM_RX_CH_4;
+               break;
+       case 6:
+               val |= RT5682_TDM_TX_CH_6;
+               val |= RT5682_TDM_RX_CH_6;
+               break;
+       case 8:
+               val |= RT5682_TDM_TX_CH_8;
+               val |= RT5682_TDM_RX_CH_8;
+               break;
+       case 2:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_component_update_bits(component, RT5682_TDM_CTRL,
+               RT5682_TDM_TX_CH_MASK | RT5682_TDM_RX_CH_MASK, val);
+
+       switch (slot_width) {
+       case 8:
+               if (tx_mask || rx_mask)
+                       return -EINVAL;
+               cl = RT5682_I2S1_TX_CHL_8 | RT5682_I2S1_RX_CHL_8;
+               break;
+       case 16:
+               val = RT5682_TDM_CL_16;
+               cl = RT5682_I2S1_TX_CHL_16 | RT5682_I2S1_RX_CHL_16;
+               break;
+       case 20:
+               val = RT5682_TDM_CL_20;
+               cl = RT5682_I2S1_TX_CHL_20 | RT5682_I2S1_RX_CHL_20;
+               break;
+       case 24:
+               val = RT5682_TDM_CL_24;
+               cl = RT5682_I2S1_TX_CHL_24 | RT5682_I2S1_RX_CHL_24;
+               break;
+       case 32:
+               val = RT5682_TDM_CL_32;
+               cl = RT5682_I2S1_TX_CHL_32 | RT5682_I2S1_RX_CHL_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_component_update_bits(component, RT5682_TDM_TCON_CTRL,
+               RT5682_TDM_CL_MASK, val);
+       snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+               RT5682_I2S1_TX_CHL_MASK | RT5682_I2S1_RX_CHL_MASK, cl);
+
+       return 0;
+}
+
+
+static int rt5682_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       unsigned int len_1 = 0, len_2 = 0;
+       int pre_div, frame_size;
+
+       rt5682->lrck[dai->id] = params_rate(params);
+       pre_div = rl6231_get_clk_info(rt5682->sysclk, rt5682->lrck[dai->id]);
+
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(component->dev, "Unsupported frame size: %d\n",
+                       frame_size);
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+                               rt5682->lrck[dai->id], pre_div, dai->id);
+
+       switch (params_width(params)) {
+       case 16:
+               break;
+       case 20:
+               len_1 |= RT5682_I2S1_DL_20;
+               len_2 |= RT5682_I2S2_DL_20;
+               break;
+       case 24:
+               len_1 |= RT5682_I2S1_DL_24;
+               len_2 |= RT5682_I2S2_DL_24;
+               break;
+       case 32:
+               len_1 |= RT5682_I2S1_DL_32;
+               len_2 |= RT5682_I2S2_DL_24;
+               break;
+       case 8:
+               len_1 |= RT5682_I2S2_DL_8;
+               len_2 |= RT5682_I2S2_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5682_AIF1:
+               snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+                       RT5682_I2S1_DL_MASK, len_1);
+               if (rt5682->master[RT5682_AIF1]) {
+                       snd_soc_component_update_bits(component,
+                               RT5682_ADDA_CLK_1, RT5682_I2S_M_DIV_MASK,
+                               pre_div << RT5682_I2S_M_DIV_SFT);
+               }
+               if (params_channels(params) == 1) /* mono mode */
+                       snd_soc_component_update_bits(component,
+                               RT5682_I2S1_SDP, RT5682_I2S1_MONO_MASK,
+                               RT5682_I2S1_MONO_EN);
+               else
+                       snd_soc_component_update_bits(component,
+                               RT5682_I2S1_SDP, RT5682_I2S1_MONO_MASK,
+                               RT5682_I2S1_MONO_DIS);
+               break;
+       case RT5682_AIF2:
+               snd_soc_component_update_bits(component, RT5682_I2S2_SDP,
+                       RT5682_I2S2_DL_MASK, len_2);
+               if (rt5682->master[RT5682_AIF2]) {
+                       snd_soc_component_update_bits(component,
+                               RT5682_I2S_M_CLK_CTRL_1, RT5682_I2S2_M_PD_MASK,
+                               pre_div << RT5682_I2S2_M_PD_SFT);
+               }
+               if (params_channels(params) == 1) /* mono mode */
+                       snd_soc_component_update_bits(component,
+                               RT5682_I2S2_SDP, RT5682_I2S2_MONO_MASK,
+                               RT5682_I2S2_MONO_EN);
+               else
+                       snd_soc_component_update_bits(component,
+                               RT5682_I2S2_SDP, RT5682_I2S2_MONO_MASK,
+                               RT5682_I2S2_MONO_DIS);
+               break;
+       default:
+               dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rt5682_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       unsigned int reg_val = 0, tdm_ctrl = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5682->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               rt5682->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5682_I2S_BP_INV;
+               tdm_ctrl |= RT5682_TDM_S_BP_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               if (dai->id == RT5682_AIF1)
+                       tdm_ctrl |= RT5682_TDM_S_LP_INV | RT5682_TDM_M_BP_INV;
+               else
+                       return -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               if (dai->id == RT5682_AIF1)
+                       tdm_ctrl |= RT5682_TDM_S_BP_INV | RT5682_TDM_S_LP_INV |
+                                   RT5682_TDM_M_BP_INV | RT5682_TDM_M_LP_INV;
+               else
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5682_I2S_DF_LEFT;
+               tdm_ctrl |= RT5682_TDM_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5682_I2S_DF_PCM_A;
+               tdm_ctrl |= RT5682_TDM_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val |= RT5682_I2S_DF_PCM_B;
+               tdm_ctrl |= RT5682_TDM_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5682_AIF1:
+               snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+                       RT5682_I2S_DF_MASK, reg_val);
+               snd_soc_component_update_bits(component, RT5682_TDM_TCON_CTRL,
+                       RT5682_TDM_MS_MASK | RT5682_TDM_S_BP_MASK |
+                       RT5682_TDM_DF_MASK | RT5682_TDM_M_BP_MASK |
+                       RT5682_TDM_M_LP_MASK | RT5682_TDM_S_LP_MASK,
+                       tdm_ctrl | rt5682->master[dai->id]);
+               break;
+       case RT5682_AIF2:
+               if (rt5682->master[dai->id] == 0)
+                       reg_val |= RT5682_I2S2_MS_S;
+               snd_soc_component_update_bits(component, RT5682_I2S2_SDP,
+                       RT5682_I2S2_MS_MASK | RT5682_I2S_BP_MASK |
+                       RT5682_I2S_DF_MASK, reg_val);
+               break;
+       default:
+               dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int rt5682_set_component_sysclk(struct snd_soc_component *component,
+               int clk_id, int source, unsigned int freq, int dir)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       unsigned int reg_val = 0, src = 0;
+
+       if (freq == rt5682->sysclk && clk_id == rt5682->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5682_SCLK_S_MCLK:
+               reg_val |= RT5682_SCLK_SRC_MCLK;
+               src = RT5682_CLK_SRC_MCLK;
+               break;
+       case RT5682_SCLK_S_PLL1:
+               reg_val |= RT5682_SCLK_SRC_PLL1;
+               src = RT5682_CLK_SRC_PLL1;
+               break;
+       case RT5682_SCLK_S_PLL2:
+               reg_val |= RT5682_SCLK_SRC_PLL2;
+               src = RT5682_CLK_SRC_PLL2;
+               break;
+       case RT5682_SCLK_S_RCCLK:
+               reg_val |= RT5682_SCLK_SRC_RCCLK;
+               src = RT5682_CLK_SRC_RCCLK;
+               break;
+       default:
+               dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+               RT5682_SCLK_SRC_MASK, reg_val);
+
+       if (rt5682->master[RT5682_AIF2]) {
+               snd_soc_component_update_bits(component,
+                       RT5682_I2S_M_CLK_CTRL_1, RT5682_I2S2_SRC_MASK,
+                       src << RT5682_I2S2_SRC_SFT);
+       }
+
+       rt5682->sysclk = freq;
+       rt5682->sysclk_src = clk_id;
+
+       dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+               freq, clk_id);
+
+       return 0;
+}
+
+static int rt5682_set_component_pll(struct snd_soc_component *component,
+               int pll_id, int source, unsigned int freq_in,
+               unsigned int freq_out)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       struct rl6231_pll_code pll_code;
+       int ret;
+
+       if (source == rt5682->pll_src && freq_in == rt5682->pll_in &&
+           freq_out == rt5682->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(component->dev, "PLL disabled\n");
+
+               rt5682->pll_in = 0;
+               rt5682->pll_out = 0;
+               snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+                       RT5682_SCLK_SRC_MASK, RT5682_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (source) {
+       case RT5682_PLL1_S_MCLK:
+               snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+                       RT5682_PLL1_SRC_MASK, RT5682_PLL1_SRC_MCLK);
+               break;
+       case RT5682_PLL1_S_BCLK1:
+               snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+                               RT5682_PLL1_SRC_MASK, RT5682_PLL1_SRC_BCLK1);
+               break;
+       default:
+               dev_err(component->dev, "Unknown PLL Source %d\n", source);
+               return -EINVAL;
+       }
+
+       ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+       if (ret < 0) {
+               dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+               pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+               pll_code.n_code, pll_code.k_code);
+
+       snd_soc_component_write(component, RT5682_PLL_CTRL_1,
+               pll_code.n_code << RT5682_PLL_N_SFT | pll_code.k_code);
+       snd_soc_component_write(component, RT5682_PLL_CTRL_2,
+               (pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT |
+               pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST);
+
+       rt5682->pll_in = freq_in;
+       rt5682->pll_out = freq_out;
+       rt5682->pll_src = source;
+
+       return 0;
+}
+
+static int rt5682_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       rt5682->bclk[dai->id] = ratio;
+
+       switch (ratio) {
+       case 64:
+               snd_soc_component_update_bits(component, RT5682_ADDA_CLK_2,
+                       RT5682_I2S2_BCLK_MS2_MASK,
+                       RT5682_I2S2_BCLK_MS2_64);
+               break;
+       case 32:
+               snd_soc_component_update_bits(component, RT5682_ADDA_CLK_2,
+                       RT5682_I2S2_BCLK_MS2_MASK,
+                       RT5682_I2S2_BCLK_MS2_32);
+               break;
+       default:
+               dev_err(dai->dev, "Invalid bclk ratio %d\n", ratio);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rt5682_set_bias_level(struct snd_soc_component *component,
+                       enum snd_soc_bias_level level)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+                       RT5682_PWR_MB | RT5682_PWR_BG,
+                       RT5682_PWR_MB | RT5682_PWR_BG);
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+                       RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO,
+                       RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+                       RT5682_PWR_MB, RT5682_PWR_MB);
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+                       RT5682_DIG_GATE_CTRL, RT5682_DIG_GATE_CTRL);
+               break;
+       case SND_SOC_BIAS_OFF:
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+                       RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, 0);
+               regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+                       RT5682_PWR_MB | RT5682_PWR_BG, 0);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5682_probe(struct snd_soc_component *component)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       rt5682->component = component;
+
+       return 0;
+}
+
+static void rt5682_remove(struct snd_soc_component *component)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       rt5682_reset(rt5682->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt5682_suspend(struct snd_soc_component *component)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       regcache_cache_only(rt5682->regmap, true);
+       regcache_mark_dirty(rt5682->regmap);
+       return 0;
+}
+
+static int rt5682_resume(struct snd_soc_component *component)
+{
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+       regcache_cache_only(rt5682->regmap, false);
+       regcache_sync(rt5682->regmap);
+
+       return 0;
+}
+#else
+#define rt5682_suspend NULL
+#define rt5682_resume NULL
+#endif
+
+#define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5682_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5682_aif1_dai_ops = {
+       .hw_params = rt5682_hw_params,
+       .set_fmt = rt5682_set_dai_fmt,
+       .set_tdm_slot = rt5682_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops rt5682_aif2_dai_ops = {
+       .hw_params = rt5682_hw_params,
+       .set_fmt = rt5682_set_dai_fmt,
+       .set_bclk_ratio = rt5682_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5682_dai[] = {
+       {
+               .name = "rt5682-aif1",
+               .id = RT5682_AIF1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5682_STEREO_RATES,
+                       .formats = RT5682_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5682_STEREO_RATES,
+                       .formats = RT5682_FORMATS,
+               },
+               .ops = &rt5682_aif1_dai_ops,
+       },
+       {
+               .name = "rt5682-aif2",
+               .id = RT5682_AIF2,
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5682_STEREO_RATES,
+                       .formats = RT5682_FORMATS,
+               },
+               .ops = &rt5682_aif2_dai_ops,
+       },
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5682 = {
+       .probe = rt5682_probe,
+       .remove = rt5682_remove,
+       .suspend = rt5682_suspend,
+       .resume = rt5682_resume,
+       .set_bias_level = rt5682_set_bias_level,
+       .controls = rt5682_snd_controls,
+       .num_controls = ARRAY_SIZE(rt5682_snd_controls),
+       .dapm_widgets = rt5682_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt5682_dapm_widgets),
+       .dapm_routes = rt5682_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt5682_dapm_routes),
+       .set_sysclk = rt5682_set_component_sysclk,
+       .set_pll = rt5682_set_component_pll,
+       .set_jack = rt5682_set_jack_detect,
+       .use_pmdown_time        = 1,
+       .endianness             = 1,
+       .non_legacy_dai_naming  = 1,
+};
+
+static const struct regmap_config rt5682_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+       .max_register = RT5682_I2C_MODE,
+       .volatile_reg = rt5682_volatile_register,
+       .readable_reg = rt5682_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5682_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5682_reg),
+       .use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5682_i2c_id[] = {
+       {"rt5682", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, rt5682_i2c_id);
+
+static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
+{
+
+       device_property_read_u32(dev, "realtek,dmic1-data-pin",
+               &rt5682->pdata.dmic1_data_pin);
+       device_property_read_u32(dev, "realtek,dmic1-clk-pin",
+               &rt5682->pdata.dmic1_clk_pin);
+       device_property_read_u32(dev, "realtek,jd-src",
+               &rt5682->pdata.jd_src);
+
+       rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+               "realtek,ldo1-en-gpios", 0);
+
+       return 0;
+}
+
+static void rt5682_calibrate(struct rt5682_priv *rt5682)
+{
+       int value, count;
+
+       mutex_lock(&rt5682->calibrate_mutex);
+
+       rt5682_reset(rt5682->regmap);
+       regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf);
+       usleep_range(15000, 20000);
+       regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf);
+       regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
+       regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001);
+       regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
+       regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080);
+       regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040);
+       regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069);
+       regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
+       regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000);
+       regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26);
+       regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05);
+       regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
+       regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
+       regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f);
+       regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01);
+       regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
+       regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004);
+       regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
+       regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1);
+       regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311);
+       regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000);
+       regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320);
+
+       regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00);
+
+       for (count = 0; count < 60; count++) {
+               regmap_read(rt5682->regmap, RT5682_HP_CALIB_STA_1, &value);
+               if (!(value & 0x8000))
+                       break;
+
+               usleep_range(10000, 10005);
+       }
+
+       if (count >= 60)
+               pr_err("HP Calibration Failure\n");
+
+       /* restore settings */
+       regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
+       regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
+
+       mutex_unlock(&rt5682->calibrate_mutex);
+
+}
+
+static int rt5682_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       struct rt5682_priv *rt5682;
+       int i, ret;
+       unsigned int val;
+
+       rt5682 = devm_kzalloc(&i2c->dev, sizeof(struct rt5682_priv),
+               GFP_KERNEL);
+
+       if (rt5682 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, rt5682);
+
+       if (pdata)
+               rt5682->pdata = *pdata;
+       else
+               rt5682_parse_dt(rt5682, &i2c->dev);
+
+       rt5682->regmap = devm_regmap_init_i2c(i2c, &rt5682_regmap);
+       if (IS_ERR(rt5682->regmap)) {
+               ret = PTR_ERR(rt5682->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(rt5682->supplies); i++)
+               rt5682->supplies[i].supply = rt5682_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5682->supplies),
+                                     rt5682->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
+                                   rt5682->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
+               if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
+                                         GPIOF_OUT_INIT_HIGH, "rt5682"))
+                       dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+       }
+
+       /* Sleep for 300 ms miniumum */
+       usleep_range(300000, 350000);
+
+       regmap_write(rt5682->regmap, RT5682_I2C_MODE, 0x1);
+       usleep_range(10000, 15000);
+
+       regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
+       if (val != DEVICE_ID) {
+               pr_err("Device with ID register %x is not rt5682\n", val);
+               return -ENODEV;
+       }
+
+       rt5682_reset(rt5682->regmap);
+
+       rt5682_calibrate(rt5682);
+
+       ret = regmap_register_patch(rt5682->regmap, patch_list,
+                                   ARRAY_SIZE(patch_list));
+       if (ret != 0)
+               dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+       regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
+
+       /* DMIC pin*/
+       if (rt5682->pdata.dmic1_data_pin != RT5682_DMIC1_NULL) {
+               switch (rt5682->pdata.dmic1_data_pin) {
+               case RT5682_DMIC1_DATA_GPIO2: /* share with LRCK2 */
+                       regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
+                               RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO2);
+                       regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+                               RT5682_GP2_PIN_MASK, RT5682_GP2_PIN_DMIC_SDA);
+                       break;
+
+               case RT5682_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
+                       regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
+                               RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO5);
+                       regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+                               RT5682_GP5_PIN_MASK, RT5682_GP5_PIN_DMIC_SDA);
+                       break;
+
+               default:
+                       dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n");
+                       break;
+               }
+
+               switch (rt5682->pdata.dmic1_clk_pin) {
+               case RT5682_DMIC1_CLK_GPIO1: /* share with IRQ */
+                       regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+                               RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_DMIC_CLK);
+                       break;
+
+               case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
+                       regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+                               RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
+                       break;
+
+               default:
+                       dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n");
+                       break;
+               }
+       }
+
+       regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+                       RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
+                       RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
+       regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
+       regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+                       RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
+                       RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
+       regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
+
+       INIT_DELAYED_WORK(&rt5682->jack_detect_work,
+                               rt5682_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt5682->jd_check_work,
+                               rt5682_jd_check_handler);
+
+       mutex_init(&rt5682->calibrate_mutex);
+
+       if (i2c->irq) {
+               ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+                       rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                       | IRQF_ONESHOT, "rt5682", rt5682);
+               if (ret)
+                       dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+       }
+
+       return devm_snd_soc_register_component(&i2c->dev,
+                       &soc_component_dev_rt5682,
+                       rt5682_dai, ARRAY_SIZE(rt5682_dai));
+}
+
+static void rt5682_i2c_shutdown(struct i2c_client *client)
+{
+       struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
+
+       rt5682_reset(rt5682->regmap);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5682_of_match[] = {
+       {.compatible = "realtek,rt5682i"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, rt5682_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5682_acpi_match[] = {
+       {"10EC5682", 0,},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
+#endif
+
+static struct i2c_driver rt5682_i2c_driver = {
+       .driver = {
+               .name = "rt5682",
+               .of_match_table = of_match_ptr(rt5682_of_match),
+               .acpi_match_table = ACPI_PTR(rt5682_acpi_match),
+       },
+       .probe = rt5682_i2c_probe,
+       .shutdown = rt5682_i2c_shutdown,
+       .id_table = rt5682_i2c_id,
+};
+module_i2c_driver(rt5682_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5682 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
new file mode 100644 (file)
index 0000000..8068140
--- /dev/null
@@ -0,0 +1,1324 @@
+/*
+ * rt5682.h  --  RT5682/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2018 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5682_H__
+#define __RT5682_H__
+
+#include <sound/rt5682.h>
+
+#define DEVICE_ID 0x6530
+
+/* Info */
+#define RT5682_RESET                           0x0000
+#define RT5682_VERSION_ID                      0x00fd
+#define RT5682_VENDOR_ID                       0x00fe
+#define RT5682_DEVICE_ID                       0x00ff
+/*  I/O - Output */
+#define RT5682_HP_CTRL_1                       0x0002
+#define RT5682_HP_CTRL_2                       0x0003
+#define RT5682_HPL_GAIN                                0x0005
+#define RT5682_HPR_GAIN                                0x0006
+
+#define RT5682_I2C_CTRL                                0x0008
+
+/* I/O - Input */
+#define RT5682_CBJ_BST_CTRL                    0x000b
+#define RT5682_CBJ_CTRL_1                      0x0010
+#define RT5682_CBJ_CTRL_2                      0x0011
+#define RT5682_CBJ_CTRL_3                      0x0012
+#define RT5682_CBJ_CTRL_4                      0x0013
+#define RT5682_CBJ_CTRL_5                      0x0014
+#define RT5682_CBJ_CTRL_6                      0x0015
+#define RT5682_CBJ_CTRL_7                      0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5682_DAC1_DIG_VOL                    0x0019
+#define RT5682_STO1_ADC_DIG_VOL                        0x001c
+#define RT5682_STO1_ADC_BOOST                  0x001f
+#define RT5682_HP_IMP_GAIN_1                   0x0022
+#define RT5682_HP_IMP_GAIN_2                   0x0023
+/* Mixer - D-D */
+#define RT5682_SIDETONE_CTRL                   0x0024
+#define RT5682_STO1_ADC_MIXER                  0x0026
+#define RT5682_AD_DA_MIXER                     0x0029
+#define RT5682_STO1_DAC_MIXER                  0x002a
+#define RT5682_A_DAC1_MUX                      0x002b
+#define RT5682_DIG_INF2_DATA                   0x0030
+/* Mixer - ADC */
+#define RT5682_REC_MIXER                       0x003c
+#define RT5682_CAL_REC                         0x0044
+#define RT5682_ALC_BACK_GAIN                   0x0049
+/* Power */
+#define RT5682_PWR_DIG_1                       0x0061
+#define RT5682_PWR_DIG_2                       0x0062
+#define RT5682_PWR_ANLG_1                      0x0063
+#define RT5682_PWR_ANLG_2                      0x0064
+#define RT5682_PWR_ANLG_3                      0x0065
+#define RT5682_PWR_MIXER                       0x0066
+#define RT5682_PWR_VOL                         0x0067
+/* Clock Detect */
+#define RT5682_CLK_DET                         0x006b
+/* Filter Auto Reset */
+#define RT5682_RESET_LPF_CTRL                  0x006c
+#define RT5682_RESET_HPF_CTRL                  0x006d
+/* DMIC */
+#define RT5682_DMIC_CTRL_1                     0x006e
+/* Format - ADC/DAC */
+#define RT5682_I2S1_SDP                                0x0070
+#define RT5682_I2S2_SDP                                0x0071
+#define RT5682_ADDA_CLK_1                      0x0073
+#define RT5682_ADDA_CLK_2                      0x0074
+#define RT5682_I2S1_F_DIV_CTRL_1               0x0075
+#define RT5682_I2S1_F_DIV_CTRL_2               0x0076
+/* Format - TDM Control */
+#define RT5682_TDM_CTRL                                0x0079
+#define RT5682_TDM_ADDA_CTRL_1                 0x007a
+#define RT5682_TDM_ADDA_CTRL_2                 0x007b
+#define RT5682_DATA_SEL_CTRL_1                 0x007c
+#define RT5682_TDM_TCON_CTRL                   0x007e
+/* Function - Analog */
+#define RT5682_GLB_CLK                         0x0080
+#define RT5682_PLL_CTRL_1                      0x0081
+#define RT5682_PLL_CTRL_2                      0x0082
+#define RT5682_PLL_TRACK_1                     0x0083
+#define RT5682_PLL_TRACK_2                     0x0084
+#define RT5682_PLL_TRACK_3                     0x0085
+#define RT5682_PLL_TRACK_4                     0x0086
+#define RT5682_PLL_TRACK_5                     0x0087
+#define RT5682_PLL_TRACK_6                     0x0088
+#define RT5682_PLL_TRACK_11                    0x008c
+#define RT5682_SDW_REF_CLK                     0x008d
+#define RT5682_DEPOP_1                         0x008e
+#define RT5682_DEPOP_2                         0x008f
+#define RT5682_HP_CHARGE_PUMP_1                        0x0091
+#define RT5682_HP_CHARGE_PUMP_2                        0x0092
+#define RT5682_MICBIAS_1                       0x0093
+#define RT5682_MICBIAS_2                       0x0094
+#define RT5682_PLL_TRACK_12                    0x0098
+#define RT5682_PLL_TRACK_14                    0x009a
+#define RT5682_PLL2_CTRL_1                     0x009b
+#define RT5682_PLL2_CTRL_2                     0x009c
+#define RT5682_PLL2_CTRL_3                     0x009d
+#define RT5682_PLL2_CTRL_4                     0x009e
+#define RT5682_RC_CLK_CTRL                     0x009f
+#define RT5682_I2S_M_CLK_CTRL_1                        0x00a0
+#define RT5682_I2S2_F_DIV_CTRL_1               0x00a3
+#define RT5682_I2S2_F_DIV_CTRL_2               0x00a4
+/* Function - Digital */
+#define RT5682_EQ_CTRL_1                       0x00ae
+#define RT5682_EQ_CTRL_2                       0x00af
+#define RT5682_IRQ_CTRL_1                      0x00b6
+#define RT5682_IRQ_CTRL_2                      0x00b7
+#define RT5682_IRQ_CTRL_3                      0x00b8
+#define RT5682_IRQ_CTRL_4                      0x00b9
+#define RT5682_INT_ST_1                                0x00be
+#define RT5682_GPIO_CTRL_1                     0x00c0
+#define RT5682_GPIO_CTRL_2                     0x00c1
+#define RT5682_GPIO_CTRL_3                     0x00c2
+#define RT5682_HP_AMP_DET_CTRL_1               0x00d0
+#define RT5682_HP_AMP_DET_CTRL_2               0x00d1
+#define RT5682_MID_HP_AMP_DET                  0x00d2
+#define RT5682_LOW_HP_AMP_DET                  0x00d3
+#define RT5682_DELAY_BUF_CTRL                  0x00d4
+#define RT5682_SV_ZCD_1                                0x00d9
+#define RT5682_SV_ZCD_2                                0x00da
+#define RT5682_IL_CMD_1                                0x00db
+#define RT5682_IL_CMD_2                                0x00dc
+#define RT5682_IL_CMD_3                                0x00dd
+#define RT5682_IL_CMD_4                                0x00de
+#define RT5682_IL_CMD_5                                0x00df
+#define RT5682_IL_CMD_6                                0x00e0
+#define RT5682_4BTN_IL_CMD_1                   0x00e2
+#define RT5682_4BTN_IL_CMD_2                   0x00e3
+#define RT5682_4BTN_IL_CMD_3                   0x00e4
+#define RT5682_4BTN_IL_CMD_4                   0x00e5
+#define RT5682_4BTN_IL_CMD_5                   0x00e6
+#define RT5682_4BTN_IL_CMD_6                   0x00e7
+#define RT5682_4BTN_IL_CMD_7                   0x00e8
+
+#define RT5682_ADC_STO1_HP_CTRL_1              0x00ea
+#define RT5682_ADC_STO1_HP_CTRL_2              0x00eb
+#define RT5682_AJD1_CTRL                       0x00f0
+#define RT5682_JD1_THD                         0x00f1
+#define RT5682_JD2_THD                         0x00f2
+#define RT5682_JD_CTRL_1                       0x00f6
+/* General Control */
+#define RT5682_DUMMY_1                         0x00fa
+#define RT5682_DUMMY_2                         0x00fb
+#define RT5682_DUMMY_3                         0x00fc
+
+#define RT5682_DAC_ADC_DIG_VOL1                        0x0100
+#define RT5682_BIAS_CUR_CTRL_2                 0x010b
+#define RT5682_BIAS_CUR_CTRL_3                 0x010c
+#define RT5682_BIAS_CUR_CTRL_4                 0x010d
+#define RT5682_BIAS_CUR_CTRL_5                 0x010e
+#define RT5682_BIAS_CUR_CTRL_6                 0x010f
+#define RT5682_BIAS_CUR_CTRL_7                 0x0110
+#define RT5682_BIAS_CUR_CTRL_8                 0x0111
+#define RT5682_BIAS_CUR_CTRL_9                 0x0112
+#define RT5682_BIAS_CUR_CTRL_10                        0x0113
+#define RT5682_VREF_REC_OP_FB_CAP_CTRL         0x0117
+#define RT5682_CHARGE_PUMP_1                   0x0125
+#define RT5682_DIG_IN_CTRL_1                   0x0132
+#define RT5682_PAD_DRIVING_CTRL                        0x0136
+#define RT5682_SOFT_RAMP_DEPOP                 0x0138
+#define RT5682_CHOP_DAC                                0x013a
+#define RT5682_CHOP_ADC                                0x013b
+#define RT5682_CALIB_ADC_CTRL                  0x013c
+#define RT5682_VOL_TEST                                0x013f
+#define RT5682_SPKVDD_DET_STA                  0x0142
+#define RT5682_TEST_MODE_CTRL_1                        0x0145
+#define RT5682_TEST_MODE_CTRL_2                        0x0146
+#define RT5682_TEST_MODE_CTRL_3                        0x0147
+#define RT5682_TEST_MODE_CTRL_4                        0x0148
+#define RT5682_TEST_MODE_CTRL_5                        0x0149
+#define RT5682_PLL1_INTERNAL                   0x0150
+#define RT5682_PLL2_INTERNAL                   0x0151
+#define RT5682_STO_NG2_CTRL_1                  0x0160
+#define RT5682_STO_NG2_CTRL_2                  0x0161
+#define RT5682_STO_NG2_CTRL_3                  0x0162
+#define RT5682_STO_NG2_CTRL_4                  0x0163
+#define RT5682_STO_NG2_CTRL_5                  0x0164
+#define RT5682_STO_NG2_CTRL_6                  0x0165
+#define RT5682_STO_NG2_CTRL_7                  0x0166
+#define RT5682_STO_NG2_CTRL_8                  0x0167
+#define RT5682_STO_NG2_CTRL_9                  0x0168
+#define RT5682_STO_NG2_CTRL_10                 0x0169
+#define RT5682_STO1_DAC_SIL_DET                        0x0190
+#define RT5682_SIL_PSV_CTRL1                   0x0194
+#define RT5682_SIL_PSV_CTRL2                   0x0195
+#define RT5682_SIL_PSV_CTRL3                   0x0197
+#define RT5682_SIL_PSV_CTRL4                   0x0198
+#define RT5682_SIL_PSV_CTRL5                   0x0199
+#define RT5682_HP_IMP_SENS_CTRL_01             0x01af
+#define RT5682_HP_IMP_SENS_CTRL_02             0x01b0
+#define RT5682_HP_IMP_SENS_CTRL_03             0x01b1
+#define RT5682_HP_IMP_SENS_CTRL_04             0x01b2
+#define RT5682_HP_IMP_SENS_CTRL_05             0x01b3
+#define RT5682_HP_IMP_SENS_CTRL_06             0x01b4
+#define RT5682_HP_IMP_SENS_CTRL_07             0x01b5
+#define RT5682_HP_IMP_SENS_CTRL_08             0x01b6
+#define RT5682_HP_IMP_SENS_CTRL_09             0x01b7
+#define RT5682_HP_IMP_SENS_CTRL_10             0x01b8
+#define RT5682_HP_IMP_SENS_CTRL_11             0x01b9
+#define RT5682_HP_IMP_SENS_CTRL_12             0x01ba
+#define RT5682_HP_IMP_SENS_CTRL_13             0x01bb
+#define RT5682_HP_IMP_SENS_CTRL_14             0x01bc
+#define RT5682_HP_IMP_SENS_CTRL_15             0x01bd
+#define RT5682_HP_IMP_SENS_CTRL_16             0x01be
+#define RT5682_HP_IMP_SENS_CTRL_17             0x01bf
+#define RT5682_HP_IMP_SENS_CTRL_18             0x01c0
+#define RT5682_HP_IMP_SENS_CTRL_19             0x01c1
+#define RT5682_HP_IMP_SENS_CTRL_20             0x01c2
+#define RT5682_HP_IMP_SENS_CTRL_21             0x01c3
+#define RT5682_HP_IMP_SENS_CTRL_22             0x01c4
+#define RT5682_HP_IMP_SENS_CTRL_23             0x01c5
+#define RT5682_HP_IMP_SENS_CTRL_24             0x01c6
+#define RT5682_HP_IMP_SENS_CTRL_25             0x01c7
+#define RT5682_HP_IMP_SENS_CTRL_26             0x01c8
+#define RT5682_HP_IMP_SENS_CTRL_27             0x01c9
+#define RT5682_HP_IMP_SENS_CTRL_28             0x01ca
+#define RT5682_HP_IMP_SENS_CTRL_29             0x01cb
+#define RT5682_HP_IMP_SENS_CTRL_30             0x01cc
+#define RT5682_HP_IMP_SENS_CTRL_31             0x01cd
+#define RT5682_HP_IMP_SENS_CTRL_32             0x01ce
+#define RT5682_HP_IMP_SENS_CTRL_33             0x01cf
+#define RT5682_HP_IMP_SENS_CTRL_34             0x01d0
+#define RT5682_HP_IMP_SENS_CTRL_35             0x01d1
+#define RT5682_HP_IMP_SENS_CTRL_36             0x01d2
+#define RT5682_HP_IMP_SENS_CTRL_37             0x01d3
+#define RT5682_HP_IMP_SENS_CTRL_38             0x01d4
+#define RT5682_HP_IMP_SENS_CTRL_39             0x01d5
+#define RT5682_HP_IMP_SENS_CTRL_40             0x01d6
+#define RT5682_HP_IMP_SENS_CTRL_41             0x01d7
+#define RT5682_HP_IMP_SENS_CTRL_42             0x01d8
+#define RT5682_HP_IMP_SENS_CTRL_43             0x01d9
+#define RT5682_HP_LOGIC_CTRL_1                 0x01da
+#define RT5682_HP_LOGIC_CTRL_2                 0x01db
+#define RT5682_HP_LOGIC_CTRL_3                 0x01dc
+#define RT5682_HP_CALIB_CTRL_1                 0x01de
+#define RT5682_HP_CALIB_CTRL_2                 0x01df
+#define RT5682_HP_CALIB_CTRL_3                 0x01e0
+#define RT5682_HP_CALIB_CTRL_4                 0x01e1
+#define RT5682_HP_CALIB_CTRL_5                 0x01e2
+#define RT5682_HP_CALIB_CTRL_6                 0x01e3
+#define RT5682_HP_CALIB_CTRL_7                 0x01e4
+#define RT5682_HP_CALIB_CTRL_9                 0x01e6
+#define RT5682_HP_CALIB_CTRL_10                        0x01e7
+#define RT5682_HP_CALIB_CTRL_11                        0x01e8
+#define RT5682_HP_CALIB_STA_1                  0x01ea
+#define RT5682_HP_CALIB_STA_2                  0x01eb
+#define RT5682_HP_CALIB_STA_3                  0x01ec
+#define RT5682_HP_CALIB_STA_4                  0x01ed
+#define RT5682_HP_CALIB_STA_5                  0x01ee
+#define RT5682_HP_CALIB_STA_6                  0x01ef
+#define RT5682_HP_CALIB_STA_7                  0x01f0
+#define RT5682_HP_CALIB_STA_8                  0x01f1
+#define RT5682_HP_CALIB_STA_9                  0x01f2
+#define RT5682_HP_CALIB_STA_10                 0x01f3
+#define RT5682_HP_CALIB_STA_11                 0x01f4
+#define RT5682_SAR_IL_CMD_1                    0x0210
+#define RT5682_SAR_IL_CMD_2                    0x0211
+#define RT5682_SAR_IL_CMD_3                    0x0212
+#define RT5682_SAR_IL_CMD_4                    0x0213
+#define RT5682_SAR_IL_CMD_5                    0x0214
+#define RT5682_SAR_IL_CMD_6                    0x0215
+#define RT5682_SAR_IL_CMD_7                    0x0216
+#define RT5682_SAR_IL_CMD_8                    0x0217
+#define RT5682_SAR_IL_CMD_9                    0x0218
+#define RT5682_SAR_IL_CMD_10                   0x0219
+#define RT5682_SAR_IL_CMD_11                   0x021a
+#define RT5682_SAR_IL_CMD_12                   0x021b
+#define RT5682_SAR_IL_CMD_13                   0x021c
+#define RT5682_EFUSE_CTRL_1                    0x0250
+#define RT5682_EFUSE_CTRL_2                    0x0251
+#define RT5682_EFUSE_CTRL_3                    0x0252
+#define RT5682_EFUSE_CTRL_4                    0x0253
+#define RT5682_EFUSE_CTRL_5                    0x0254
+#define RT5682_EFUSE_CTRL_6                    0x0255
+#define RT5682_EFUSE_CTRL_7                    0x0256
+#define RT5682_EFUSE_CTRL_8                    0x0257
+#define RT5682_EFUSE_CTRL_9                    0x0258
+#define RT5682_EFUSE_CTRL_10                   0x0259
+#define RT5682_EFUSE_CTRL_11                   0x025a
+#define RT5682_JD_TOP_VC_VTRL                  0x0270
+#define RT5682_DRC1_CTRL_0                     0x02ff
+#define RT5682_DRC1_CTRL_1                     0x0300
+#define RT5682_DRC1_CTRL_2                     0x0301
+#define RT5682_DRC1_CTRL_3                     0x0302
+#define RT5682_DRC1_CTRL_4                     0x0303
+#define RT5682_DRC1_CTRL_5                     0x0304
+#define RT5682_DRC1_CTRL_6                     0x0305
+#define RT5682_DRC1_HARD_LMT_CTRL_1            0x0306
+#define RT5682_DRC1_HARD_LMT_CTRL_2            0x0307
+#define RT5682_DRC1_PRIV_1                     0x0310
+#define RT5682_DRC1_PRIV_2                     0x0311
+#define RT5682_DRC1_PRIV_3                     0x0312
+#define RT5682_DRC1_PRIV_4                     0x0313
+#define RT5682_DRC1_PRIV_5                     0x0314
+#define RT5682_DRC1_PRIV_6                     0x0315
+#define RT5682_DRC1_PRIV_7                     0x0316
+#define RT5682_DRC1_PRIV_8                     0x0317
+#define RT5682_EQ_AUTO_RCV_CTRL1               0x03c0
+#define RT5682_EQ_AUTO_RCV_CTRL2               0x03c1
+#define RT5682_EQ_AUTO_RCV_CTRL3               0x03c2
+#define RT5682_EQ_AUTO_RCV_CTRL4               0x03c3
+#define RT5682_EQ_AUTO_RCV_CTRL5               0x03c4
+#define RT5682_EQ_AUTO_RCV_CTRL6               0x03c5
+#define RT5682_EQ_AUTO_RCV_CTRL7               0x03c6
+#define RT5682_EQ_AUTO_RCV_CTRL8               0x03c7
+#define RT5682_EQ_AUTO_RCV_CTRL9               0x03c8
+#define RT5682_EQ_AUTO_RCV_CTRL10              0x03c9
+#define RT5682_EQ_AUTO_RCV_CTRL11              0x03ca
+#define RT5682_EQ_AUTO_RCV_CTRL12              0x03cb
+#define RT5682_EQ_AUTO_RCV_CTRL13              0x03cc
+#define RT5682_ADC_L_EQ_LPF1_A1                        0x03d0
+#define RT5682_R_EQ_LPF1_A1                    0x03d1
+#define RT5682_L_EQ_LPF1_H0                    0x03d2
+#define RT5682_R_EQ_LPF1_H0                    0x03d3
+#define RT5682_L_EQ_BPF1_A1                    0x03d4
+#define RT5682_R_EQ_BPF1_A1                    0x03d5
+#define RT5682_L_EQ_BPF1_A2                    0x03d6
+#define RT5682_R_EQ_BPF1_A2                    0x03d7
+#define RT5682_L_EQ_BPF1_H0                    0x03d8
+#define RT5682_R_EQ_BPF1_H0                    0x03d9
+#define RT5682_L_EQ_BPF2_A1                    0x03da
+#define RT5682_R_EQ_BPF2_A1                    0x03db
+#define RT5682_L_EQ_BPF2_A2                    0x03dc
+#define RT5682_R_EQ_BPF2_A2                    0x03dd
+#define RT5682_L_EQ_BPF2_H0                    0x03de
+#define RT5682_R_EQ_BPF2_H0                    0x03df
+#define RT5682_L_EQ_BPF3_A1                    0x03e0
+#define RT5682_R_EQ_BPF3_A1                    0x03e1
+#define RT5682_L_EQ_BPF3_A2                    0x03e2
+#define RT5682_R_EQ_BPF3_A2                    0x03e3
+#define RT5682_L_EQ_BPF3_H0                    0x03e4
+#define RT5682_R_EQ_BPF3_H0                    0x03e5
+#define RT5682_L_EQ_BPF4_A1                    0x03e6
+#define RT5682_R_EQ_BPF4_A1                    0x03e7
+#define RT5682_L_EQ_BPF4_A2                    0x03e8
+#define RT5682_R_EQ_BPF4_A2                    0x03e9
+#define RT5682_L_EQ_BPF4_H0                    0x03ea
+#define RT5682_R_EQ_BPF4_H0                    0x03eb
+#define RT5682_L_EQ_HPF1_A1                    0x03ec
+#define RT5682_R_EQ_HPF1_A1                    0x03ed
+#define RT5682_L_EQ_HPF1_H0                    0x03ee
+#define RT5682_R_EQ_HPF1_H0                    0x03ef
+#define RT5682_L_EQ_PRE_VOL                    0x03f0
+#define RT5682_R_EQ_PRE_VOL                    0x03f1
+#define RT5682_L_EQ_POST_VOL                   0x03f2
+#define RT5682_R_EQ_POST_VOL                   0x03f3
+#define RT5682_I2C_MODE                                0xffff
+
+
+/* global definition */
+#define RT5682_L_MUTE                          (0x1 << 15)
+#define RT5682_L_MUTE_SFT                      15
+#define RT5682_VOL_L_MUTE                      (0x1 << 14)
+#define RT5682_VOL_L_SFT                       14
+#define RT5682_R_MUTE                          (0x1 << 7)
+#define RT5682_R_MUTE_SFT                      7
+#define RT5682_VOL_R_MUTE                      (0x1 << 6)
+#define RT5682_VOL_R_SFT                       6
+#define RT5682_L_VOL_MASK                      (0x3f << 8)
+#define RT5682_L_VOL_SFT                       8
+#define RT5682_R_VOL_MASK                      (0x3f)
+#define RT5682_R_VOL_SFT                       0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5682_G_HP                            (0xf << 8)
+#define RT5682_G_HP_SFT                                8
+#define RT5682_G_STO_DA_DMIX                   (0xf)
+#define RT5682_G_STO_DA_SFT                    0
+
+/* CBJ Control (0x000b) */
+#define RT5682_BST_CBJ_MASK                    (0xf << 8)
+#define RT5682_BST_CBJ_SFT                     8
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5682_EMB_JD_EN                       (0x1 << 15)
+#define RT5682_EMB_JD_EN_SFT                   15
+#define RT5682_EMB_JD_RST                      (0x1 << 14)
+#define RT5682_JD_MODE                         (0x1 << 13)
+#define RT5682_JD_MODE_SFT                     13
+#define RT5682_DET_TYPE                                (0x1 << 12)
+#define RT5682_DET_TYPE_SFT                    12
+#define RT5682_POLA_EXT_JD_MASK                        (0x1 << 11)
+#define RT5682_POLA_EXT_JD_LOW                 (0x1 << 11)
+#define RT5682_POLA_EXT_JD_HIGH                        (0x0 << 11)
+#define RT5682_EXT_JD_DIG                      (0x1 << 9)
+#define RT5682_POL_FAST_OFF_MASK               (0x1 << 8)
+#define RT5682_POL_FAST_OFF_HIGH               (0x1 << 8)
+#define RT5682_POL_FAST_OFF_LOW                        (0x0 << 8)
+#define RT5682_FAST_OFF_MASK                   (0x1 << 7)
+#define RT5682_FAST_OFF_EN                     (0x1 << 7)
+#define RT5682_FAST_OFF_DIS                    (0x0 << 7)
+#define RT5682_VREF_POW_MASK                   (0x1 << 6)
+#define RT5682_VREF_POW_FSM                    (0x0 << 6)
+#define RT5682_VREF_POW_REG                    (0x1 << 6)
+#define RT5682_MB1_PATH_MASK                   (0x1 << 5)
+#define RT5682_CTRL_MB1_REG                    (0x1 << 5)
+#define RT5682_CTRL_MB1_FSM                    (0x0 << 5)
+#define RT5682_MB2_PATH_MASK                   (0x1 << 4)
+#define RT5682_CTRL_MB2_REG                    (0x1 << 4)
+#define RT5682_CTRL_MB2_FSM                    (0x0 << 4)
+#define RT5682_TRIG_JD_MASK                    (0x1 << 3)
+#define RT5682_TRIG_JD_HIGH                    (0x1 << 3)
+#define RT5682_TRIG_JD_LOW                     (0x0 << 3)
+#define RT5682_MIC_CAP_MASK                    (0x1 << 1)
+#define RT5682_MIC_CAP_HS                      (0x1 << 1)
+#define RT5682_MIC_CAP_HP                      (0x0 << 1)
+#define RT5682_MIC_CAP_SRC_MASK                        (0x1)
+#define RT5682_MIC_CAP_SRC_REG                 (0x1)
+#define RT5682_MIC_CAP_SRC_ANA                 (0x0)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5682_EXT_JD_SRC                      (0x7 << 4)
+#define RT5682_EXT_JD_SRC_SFT                  4
+#define RT5682_EXT_JD_SRC_GPIO_JD1             (0x0 << 4)
+#define RT5682_EXT_JD_SRC_GPIO_JD2             (0x1 << 4)
+#define RT5682_EXT_JD_SRC_JDH                  (0x2 << 4)
+#define RT5682_EXT_JD_SRC_JDL                  (0x3 << 4)
+#define RT5682_EXT_JD_SRC_MANUAL               (0x4 << 4)
+#define RT5682_JACK_TYPE_MASK                  (0x3)
+
+/* Combo Jack and Type Detection Control 3 (0x0012) */
+#define RT5682_CBJ_IN_BUF_EN                   (0x1 << 7)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5682_SEL_SHT_MID_TON_MASK            (0x3 << 12)
+#define RT5682_SEL_SHT_MID_TON_2               (0x0 << 12)
+#define RT5682_SEL_SHT_MID_TON_3               (0x1 << 12)
+#define RT5682_CBJ_JD_TEST_MASK                        (0x1 << 6)
+#define RT5682_CBJ_JD_TEST_NORM                        (0x0 << 6)
+#define RT5682_CBJ_JD_TEST_MODE                        (0x1 << 6)
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5682_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5682_DAC_L1_VOL_SFT                  8
+#define RT5682_DAC_R1_VOL_MASK                 (0xff)
+#define RT5682_DAC_R1_VOL_SFT                  0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5682_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5682_ADC_L_VOL_SFT                   8
+#define RT5682_ADC_R_VOL_MASK                  (0x7f)
+#define RT5682_ADC_R_VOL_SFT                   0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5682_STO1_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5682_STO1_ADC_L_BST_SFT              14
+#define RT5682_STO1_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5682_STO1_ADC_R_BST_SFT              12
+
+/* Sidetone Control (0x0024) */
+#define RT5682_ST_SRC_SEL                      (0x1 << 8)
+#define RT5682_ST_SRC_SFT                      8
+#define RT5682_ST_EN_MASK                      (0x1 << 6)
+#define RT5682_ST_DIS                          (0x0 << 6)
+#define RT5682_ST_EN                           (0x1 << 6)
+#define RT5682_ST_EN_SFT                       6
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5682_M_STO1_ADC_L1                   (0x1 << 15)
+#define RT5682_M_STO1_ADC_L1_SFT               15
+#define RT5682_M_STO1_ADC_L2                   (0x1 << 14)
+#define RT5682_M_STO1_ADC_L2_SFT               14
+#define RT5682_STO1_ADC1L_SRC_MASK             (0x1 << 13)
+#define RT5682_STO1_ADC1L_SRC_SFT              13
+#define RT5682_STO1_ADC1_SRC_ADC               (0x1 << 13)
+#define RT5682_STO1_ADC1_SRC_DACMIX            (0x0 << 13)
+#define RT5682_STO1_ADC2L_SRC_MASK             (0x1 << 12)
+#define RT5682_STO1_ADC2L_SRC_SFT              12
+#define RT5682_STO1_ADCL_SRC_MASK              (0x3 << 10)
+#define RT5682_STO1_ADCL_SRC_SFT               10
+#define RT5682_STO1_DD_L_SRC_MASK              (0x1 << 9)
+#define RT5682_STO1_DD_L_SRC_SFT               9
+#define RT5682_STO1_DMIC_SRC_MASK              (0x1 << 8)
+#define RT5682_STO1_DMIC_SRC_SFT               8
+#define RT5682_STO1_DMIC_SRC_DMIC2             (0x1 << 8)
+#define RT5682_STO1_DMIC_SRC_DMIC1             (0x0 << 8)
+#define RT5682_M_STO1_ADC_R1                   (0x1 << 7)
+#define RT5682_M_STO1_ADC_R1_SFT               7
+#define RT5682_M_STO1_ADC_R2                   (0x1 << 6)
+#define RT5682_M_STO1_ADC_R2_SFT               6
+#define RT5682_STO1_ADC1R_SRC_MASK             (0x1 << 5)
+#define RT5682_STO1_ADC1R_SRC_SFT              5
+#define RT5682_STO1_ADC2R_SRC_MASK             (0x1 << 4)
+#define RT5682_STO1_ADC2R_SRC_SFT              4
+#define RT5682_STO1_ADCR_SRC_MASK              (0x3 << 2)
+#define RT5682_STO1_ADCR_SRC_SFT               2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5682_M_ADCMIX_L                      (0x1 << 15)
+#define RT5682_M_ADCMIX_L_SFT                  15
+#define RT5682_M_DAC1_L                                (0x1 << 14)
+#define RT5682_M_DAC1_L_SFT                    14
+#define RT5682_DAC1_R_SEL_MASK                 (0x1 << 10)
+#define RT5682_DAC1_R_SEL_SFT                  10
+#define RT5682_DAC1_L_SEL_MASK                 (0x1 << 8)
+#define RT5682_DAC1_L_SEL_SFT                  8
+#define RT5682_M_ADCMIX_R                      (0x1 << 7)
+#define RT5682_M_ADCMIX_R_SFT                  7
+#define RT5682_M_DAC1_R                                (0x1 << 6)
+#define RT5682_M_DAC1_R_SFT                    6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5682_M_DAC_L1_STO_L                  (0x1 << 15)
+#define RT5682_M_DAC_L1_STO_L_SFT              15
+#define RT5682_G_DAC_L1_STO_L_MASK             (0x1 << 14)
+#define RT5682_G_DAC_L1_STO_L_SFT              14
+#define RT5682_M_DAC_R1_STO_L                  (0x1 << 13)
+#define RT5682_M_DAC_R1_STO_L_SFT              13
+#define RT5682_G_DAC_R1_STO_L_MASK             (0x1 << 12)
+#define RT5682_G_DAC_R1_STO_L_SFT              12
+#define RT5682_M_DAC_L1_STO_R                  (0x1 << 7)
+#define RT5682_M_DAC_L1_STO_R_SFT              7
+#define RT5682_G_DAC_L1_STO_R_MASK             (0x1 << 6)
+#define RT5682_G_DAC_L1_STO_R_SFT              6
+#define RT5682_M_DAC_R1_STO_R                  (0x1 << 5)
+#define RT5682_M_DAC_R1_STO_R_SFT              5
+#define RT5682_G_DAC_R1_STO_R_MASK             (0x1 << 4)
+#define RT5682_G_DAC_R1_STO_R_SFT              4
+
+/* Analog DAC1 Input Source Control (0x002b) */
+#define RT5682_M_ST_STO_L                      (0x1 << 9)
+#define RT5682_M_ST_STO_L_SFT                  9
+#define RT5682_M_ST_STO_R                      (0x1 << 8)
+#define RT5682_M_ST_STO_R_SFT                  8
+#define RT5682_DAC_L1_SRC_MASK                 (0x3 << 4)
+#define RT5682_A_DACL1_SFT                     4
+#define RT5682_DAC_R1_SRC_MASK                 (0x3)
+#define RT5682_A_DACR1_SFT                     0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5682_IF2_ADC_SEL_MASK                        (0x3 << 0)
+#define RT5682_IF2_ADC_SEL_SFT                 0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5682_G_CBJ_RM1_L                     (0x7 << 10)
+#define RT5682_G_CBJ_RM1_L_SFT                 10
+#define RT5682_M_CBJ_RM1_L                     (0x1 << 7)
+#define RT5682_M_CBJ_RM1_L_SFT                 7
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5682_PWR_I2S1                                (0x1 << 15)
+#define RT5682_PWR_I2S1_BIT                    15
+#define RT5682_PWR_I2S2                                (0x1 << 14)
+#define RT5682_PWR_I2S2_BIT                    14
+#define RT5682_PWR_DAC_L1                      (0x1 << 11)
+#define RT5682_PWR_DAC_L1_BIT                  11
+#define RT5682_PWR_DAC_R1                      (0x1 << 10)
+#define RT5682_PWR_DAC_R1_BIT                  10
+#define RT5682_PWR_LDO                         (0x1 << 8)
+#define RT5682_PWR_LDO_BIT                     8
+#define RT5682_PWR_ADC_L1                      (0x1 << 4)
+#define RT5682_PWR_ADC_L1_BIT                  4
+#define RT5682_PWR_ADC_R1                      (0x1 << 3)
+#define RT5682_PWR_ADC_R1_BIT                  3
+#define RT5682_DIG_GATE_CTRL                   (0x1 << 0)
+#define RT5682_DIG_GATE_CTRL_SFT               0
+
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5682_PWR_ADC_S1F                     (0x1 << 15)
+#define RT5682_PWR_ADC_S1F_BIT                 15
+#define RT5682_PWR_DAC_S1F                     (0x1 << 10)
+#define RT5682_PWR_DAC_S1F_BIT                 10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5682_PWR_VREF1                       (0x1 << 15)
+#define RT5682_PWR_VREF1_BIT                   15
+#define RT5682_PWR_FV1                         (0x1 << 14)
+#define RT5682_PWR_FV1_BIT                     14
+#define RT5682_PWR_VREF2                       (0x1 << 13)
+#define RT5682_PWR_VREF2_BIT                   13
+#define RT5682_PWR_FV2                         (0x1 << 12)
+#define RT5682_PWR_FV2_BIT                     12
+#define RT5682_LDO1_DBG_MASK                   (0x3 << 10)
+#define RT5682_PWR_MB                          (0x1 << 9)
+#define RT5682_PWR_MB_BIT                      9
+#define RT5682_PWR_BG                          (0x1 << 7)
+#define RT5682_PWR_BG_BIT                      7
+#define RT5682_LDO1_BYPASS_MASK                        (0x1 << 6)
+#define RT5682_LDO1_BYPASS                     (0x1 << 6)
+#define RT5682_LDO1_NOT_BYPASS                 (0x0 << 6)
+#define RT5682_PWR_MA_BIT                      6
+#define RT5682_LDO1_DVO_MASK                   (0x3 << 4)
+#define RT5682_LDO1_DVO_09                     (0x0 << 4)
+#define RT5682_LDO1_DVO_10                     (0x1 << 4)
+#define RT5682_LDO1_DVO_12                     (0x2 << 4)
+#define RT5682_LDO1_DVO_14                     (0x3 << 4)
+#define RT5682_HP_DRIVER_MASK                  (0x3 << 2)
+#define RT5682_HP_DRIVER_1X                    (0x0 << 2)
+#define RT5682_HP_DRIVER_3X                    (0x1 << 2)
+#define RT5682_HP_DRIVER_5X                    (0x3 << 2)
+#define RT5682_PWR_HA_L                                (0x1 << 1)
+#define RT5682_PWR_HA_L_BIT                    1
+#define RT5682_PWR_HA_R                                (0x1 << 0)
+#define RT5682_PWR_HA_R_BIT                    0
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5682_PWR_MB1                         (0x1 << 11)
+#define RT5682_PWR_MB1_PWR_DOWN                        (0x0 << 11)
+#define RT5682_PWR_MB1_BIT                     11
+#define RT5682_PWR_MB2                         (0x1 << 10)
+#define RT5682_PWR_MB2_PWR_DOWN                        (0x0 << 10)
+#define RT5682_PWR_MB2_BIT                     10
+#define RT5682_PWR_JDH                         (0x1 << 3)
+#define RT5682_PWR_JDH_BIT                     3
+#define RT5682_PWR_JDL                         (0x1 << 2)
+#define RT5682_PWR_JDL_BIT                     2
+#define RT5682_PWR_RM1_L                       (0x1 << 1)
+#define RT5682_PWR_RM1_L_BIT                   1
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5682_PWR_CBJ                         (0x1 << 9)
+#define RT5682_PWR_CBJ_BIT                     9
+#define RT5682_PWR_PLL                         (0x1 << 6)
+#define RT5682_PWR_PLL_BIT                     6
+#define RT5682_PWR_PLL2B                       (0x1 << 5)
+#define RT5682_PWR_PLL2B_BIT                   5
+#define RT5682_PWR_PLL2F                       (0x1 << 4)
+#define RT5682_PWR_PLL2F_BIT                   4
+#define RT5682_PWR_LDO2                                (0x1 << 2)
+#define RT5682_PWR_LDO2_BIT                    2
+#define RT5682_PWR_DET_SPKVDD                  (0x1 << 1)
+#define RT5682_PWR_DET_SPKVDD_BIT              1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5682_PWR_STO1_DAC_L                  (0x1 << 5)
+#define RT5682_PWR_STO1_DAC_L_BIT              5
+#define RT5682_PWR_STO1_DAC_R                  (0x1 << 4)
+#define RT5682_PWR_STO1_DAC_R_BIT              4
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5682_SYS_CLK_DET                     (0x1 << 15)
+#define RT5682_SYS_CLK_DET_SFT                 15
+#define RT5682_PLL1_CLK_DET                    (0x1 << 14)
+#define RT5682_PLL1_CLK_DET_SFT                        14
+#define RT5682_PLL2_CLK_DET                    (0x1 << 13)
+#define RT5682_PLL2_CLK_DET_SFT                        13
+#define RT5682_POW_CLK_DET2_SFT                        8
+#define RT5682_POW_CLK_DET_SFT                 0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5682_DMIC_1_EN_MASK                  (0x1 << 15)
+#define RT5682_DMIC_1_EN_SFT                   15
+#define RT5682_DMIC_1_DIS                      (0x0 << 15)
+#define RT5682_DMIC_1_EN                       (0x1 << 15)
+#define RT5682_DMIC_1_DP_MASK                  (0x3 << 4)
+#define RT5682_DMIC_1_DP_SFT                   4
+#define RT5682_DMIC_1_DP_GPIO2                 (0x0 << 4)
+#define RT5682_DMIC_1_DP_GPIO5                 (0x1 << 4)
+#define RT5682_DMIC_CLK_MASK                   (0xf << 0)
+#define RT5682_DMIC_CLK_SFT                    0
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5682_SEL_ADCDAT_MASK                 (0x1 << 15)
+#define RT5682_SEL_ADCDAT_OUT                  (0x0 << 15)
+#define RT5682_SEL_ADCDAT_IN                   (0x1 << 15)
+#define RT5682_SEL_ADCDAT_SFT                  15
+#define RT5682_I2S1_TX_CHL_MASK                        (0x7 << 12)
+#define RT5682_I2S1_TX_CHL_SFT                 12
+#define RT5682_I2S1_TX_CHL_16                  (0x0 << 12)
+#define RT5682_I2S1_TX_CHL_20                  (0x1 << 12)
+#define RT5682_I2S1_TX_CHL_24                  (0x2 << 12)
+#define RT5682_I2S1_TX_CHL_32                  (0x3 << 12)
+#define RT5682_I2S1_TX_CHL_8                   (0x4 << 12)
+#define RT5682_I2S1_RX_CHL_MASK                        (0x7 << 8)
+#define RT5682_I2S1_RX_CHL_SFT                 8
+#define RT5682_I2S1_RX_CHL_16                  (0x0 << 8)
+#define RT5682_I2S1_RX_CHL_20                  (0x1 << 8)
+#define RT5682_I2S1_RX_CHL_24                  (0x2 << 8)
+#define RT5682_I2S1_RX_CHL_32                  (0x3 << 8)
+#define RT5682_I2S1_RX_CHL_8                   (0x4 << 8)
+#define RT5682_I2S1_MONO_MASK                  (0x1 << 7)
+#define RT5682_I2S1_MONO_EN                    (0x1 << 7)
+#define RT5682_I2S1_MONO_DIS                   (0x0 << 7)
+#define RT5682_I2S2_MONO_MASK                  (0x1 << 6)
+#define RT5682_I2S2_MONO_EN                    (0x1 << 6)
+#define RT5682_I2S2_MONO_DIS                   (0x0 << 6)
+#define RT5682_I2S1_DL_MASK                    (0x7 << 4)
+#define RT5682_I2S1_DL_SFT                     4
+#define RT5682_I2S1_DL_16                      (0x0 << 4)
+#define RT5682_I2S1_DL_20                      (0x1 << 4)
+#define RT5682_I2S1_DL_24                      (0x2 << 4)
+#define RT5682_I2S1_DL_32                      (0x3 << 4)
+#define RT5682_I2S1_DL_8                       (0x4 << 4)
+
+/* I2S1/2 Audio Serial Data Port Control (0x0070)(0x0071) */
+#define RT5682_I2S2_MS_MASK                    (0x1 << 15)
+#define RT5682_I2S2_MS_SFT                     15
+#define RT5682_I2S2_MS_M                       (0x0 << 15)
+#define RT5682_I2S2_MS_S                       (0x1 << 15)
+#define RT5682_I2S2_PIN_CFG_MASK               (0x1 << 14)
+#define RT5682_I2S2_PIN_CFG_SFT                        14
+#define RT5682_I2S2_CLK_SEL_MASK               (0x1 << 11)
+#define RT5682_I2S2_CLK_SEL_SFT                        11
+#define RT5682_I2S2_OUT_MASK                   (0x1 << 9)
+#define RT5682_I2S2_OUT_SFT                    9
+#define RT5682_I2S2_OUT_UM                     (0x0 << 9)
+#define RT5682_I2S2_OUT_M                      (0x1 << 9)
+#define RT5682_I2S_BP_MASK                     (0x1 << 8)
+#define RT5682_I2S_BP_SFT                      8
+#define RT5682_I2S_BP_NOR                      (0x0 << 8)
+#define RT5682_I2S_BP_INV                      (0x1 << 8)
+#define RT5682_I2S2_MONO_EN                    (0x1 << 6)
+#define RT5682_I2S2_MONO_DIS                   (0x0 << 6)
+#define RT5682_I2S2_DL_MASK                    (0x3 << 4)
+#define RT5682_I2S2_DL_SFT                     4
+#define RT5682_I2S2_DL_16                      (0x0 << 4)
+#define RT5682_I2S2_DL_20                      (0x1 << 4)
+#define RT5682_I2S2_DL_24                      (0x2 << 4)
+#define RT5682_I2S2_DL_8                       (0x3 << 4)
+#define RT5682_I2S_DF_MASK                     (0x7)
+#define RT5682_I2S_DF_SFT                      0
+#define RT5682_I2S_DF_I2S                      (0x0)
+#define RT5682_I2S_DF_LEFT                     (0x1)
+#define RT5682_I2S_DF_PCM_A                    (0x2)
+#define RT5682_I2S_DF_PCM_B                    (0x3)
+#define RT5682_I2S_DF_PCM_A_N                  (0x6)
+#define RT5682_I2S_DF_PCM_B_N                  (0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5682_ADC_OSR_MASK                    (0xf << 12)
+#define RT5682_ADC_OSR_SFT                     12
+#define RT5682_ADC_OSR_D_1                     (0x0 << 12)
+#define RT5682_ADC_OSR_D_2                     (0x1 << 12)
+#define RT5682_ADC_OSR_D_4                     (0x2 << 12)
+#define RT5682_ADC_OSR_D_6                     (0x3 << 12)
+#define RT5682_ADC_OSR_D_8                     (0x4 << 12)
+#define RT5682_ADC_OSR_D_12                    (0x5 << 12)
+#define RT5682_ADC_OSR_D_16                    (0x6 << 12)
+#define RT5682_ADC_OSR_D_24                    (0x7 << 12)
+#define RT5682_ADC_OSR_D_32                    (0x8 << 12)
+#define RT5682_ADC_OSR_D_48                    (0x9 << 12)
+#define RT5682_I2S_M_DIV_MASK                  (0xf << 12)
+#define RT5682_I2S_M_DIV_SFT                   8
+#define RT5682_I2S_M_D_1                       (0x0 << 8)
+#define RT5682_I2S_M_D_2                       (0x1 << 8)
+#define RT5682_I2S_M_D_3                       (0x2 << 8)
+#define RT5682_I2S_M_D_4                       (0x3 << 8)
+#define RT5682_I2S_M_D_6                       (0x4 << 8)
+#define RT5682_I2S_M_D_8                       (0x5 << 8)
+#define RT5682_I2S_M_D_12                      (0x6 << 8)
+#define RT5682_I2S_M_D_16                      (0x7 << 8)
+#define RT5682_I2S_M_D_24                      (0x8 << 8)
+#define RT5682_I2S_M_D_32                      (0x9 << 8)
+#define RT5682_I2S_M_D_48                      (0x10 << 8)
+#define RT5682_I2S_CLK_SRC_MASK                        (0x7 << 4)
+#define RT5682_I2S_CLK_SRC_SFT                 4
+#define RT5682_I2S_CLK_SRC_MCLK                        (0x0 << 4)
+#define RT5682_I2S_CLK_SRC_PLL1                        (0x1 << 4)
+#define RT5682_I2S_CLK_SRC_PLL2                        (0x2 << 4)
+#define RT5682_I2S_CLK_SRC_SDW                 (0x3 << 4)
+#define RT5682_I2S_CLK_SRC_RCCLK               (0x4 << 4) /* 25M */
+#define RT5682_DAC_OSR_MASK                    (0xf << 0)
+#define RT5682_DAC_OSR_SFT                     0
+#define RT5682_DAC_OSR_D_1                     (0x0 << 0)
+#define RT5682_DAC_OSR_D_2                     (0x1 << 0)
+#define RT5682_DAC_OSR_D_4                     (0x2 << 0)
+#define RT5682_DAC_OSR_D_6                     (0x3 << 0)
+#define RT5682_DAC_OSR_D_8                     (0x4 << 0)
+#define RT5682_DAC_OSR_D_12                    (0x5 << 0)
+#define RT5682_DAC_OSR_D_16                    (0x6 << 0)
+#define RT5682_DAC_OSR_D_24                    (0x7 << 0)
+#define RT5682_DAC_OSR_D_32                    (0x8 << 0)
+#define RT5682_DAC_OSR_D_48                    (0x9 << 0)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5682_I2S2_BCLK_MS2_MASK              (0x1 << 11)
+#define RT5682_I2S2_BCLK_MS2_SFT               11
+#define RT5682_I2S2_BCLK_MS2_32                        (0x0 << 11)
+#define RT5682_I2S2_BCLK_MS2_64                        (0x1 << 11)
+
+
+/* TDM control 1 (0x0079) */
+#define RT5682_TDM_TX_CH_MASK                  (0x3 << 12)
+#define RT5682_TDM_TX_CH_2                     (0x0 << 12)
+#define RT5682_TDM_TX_CH_4                     (0x1 << 12)
+#define RT5682_TDM_TX_CH_6                     (0x2 << 12)
+#define RT5682_TDM_TX_CH_8                     (0x3 << 12)
+#define RT5682_TDM_RX_CH_MASK                  (0x3 << 8)
+#define RT5682_TDM_RX_CH_2                     (0x0 << 8)
+#define RT5682_TDM_RX_CH_4                     (0x1 << 8)
+#define RT5682_TDM_RX_CH_6                     (0x2 << 8)
+#define RT5682_TDM_RX_CH_8                     (0x3 << 8)
+#define RT5682_TDM_ADC_LCA_MASK                        (0xf << 4)
+#define RT5682_TDM_ADC_LCA_SFT                 4
+#define RT5682_TDM_ADC_DL_SFT                  0
+
+/* TDM control 2 (0x007a) */
+#define RT5682_IF1_ADC1_SEL_SFT                        14
+#define RT5682_IF1_ADC2_SEL_SFT                        12
+#define RT5682_IF1_ADC3_SEL_SFT                        10
+#define RT5682_IF1_ADC4_SEL_SFT                        8
+#define RT5682_TDM_ADC_SEL_SFT                 4
+
+/* TDM control 3 (0x007b) */
+#define RT5682_TDM_EN                          (0x1 << 7)
+
+/* TDM/I2S control (0x007e) */
+#define RT5682_TDM_S_BP_MASK                   (0x1 << 15)
+#define RT5682_TDM_S_BP_SFT                    15
+#define RT5682_TDM_S_BP_NOR                    (0x0 << 15)
+#define RT5682_TDM_S_BP_INV                    (0x1 << 15)
+#define RT5682_TDM_S_LP_MASK                   (0x1 << 14)
+#define RT5682_TDM_S_LP_SFT                    14
+#define RT5682_TDM_S_LP_NOR                    (0x0 << 14)
+#define RT5682_TDM_S_LP_INV                    (0x1 << 14)
+#define RT5682_TDM_DF_MASK                     (0x7 << 11)
+#define RT5682_TDM_DF_SFT                      11
+#define RT5682_TDM_DF_I2S                      (0x0 << 11)
+#define RT5682_TDM_DF_LEFT                     (0x1 << 11)
+#define RT5682_TDM_DF_PCM_A                    (0x2 << 11)
+#define RT5682_TDM_DF_PCM_B                    (0x3 << 11)
+#define RT5682_TDM_DF_PCM_A_N                  (0x6 << 11)
+#define RT5682_TDM_DF_PCM_B_N                  (0x7 << 11)
+#define RT5682_TDM_CL_MASK                     (0x3 << 4)
+#define RT5682_TDM_CL_16                       (0x0 << 4)
+#define RT5682_TDM_CL_20                       (0x1 << 4)
+#define RT5682_TDM_CL_24                       (0x2 << 4)
+#define RT5682_TDM_CL_32                       (0x3 << 4)
+#define RT5682_TDM_M_BP_MASK                   (0x1 << 2)
+#define RT5682_TDM_M_BP_SFT                    2
+#define RT5682_TDM_M_BP_NOR                    (0x0 << 2)
+#define RT5682_TDM_M_BP_INV                    (0x1 << 2)
+#define RT5682_TDM_M_LP_MASK                   (0x1 << 1)
+#define RT5682_TDM_M_LP_SFT                    1
+#define RT5682_TDM_M_LP_NOR                    (0x0 << 1)
+#define RT5682_TDM_M_LP_INV                    (0x1 << 1)
+#define RT5682_TDM_MS_MASK                     (0x1 << 0)
+#define RT5682_TDM_MS_SFT                      0
+#define RT5682_TDM_MS_M                                (0x0 << 0)
+#define RT5682_TDM_MS_S                                (0x1 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5682_SCLK_SRC_MASK                   (0x7 << 13)
+#define RT5682_SCLK_SRC_SFT                    13
+#define RT5682_SCLK_SRC_MCLK                   (0x0 << 13)
+#define RT5682_SCLK_SRC_PLL1                   (0x1 << 13)
+#define RT5682_SCLK_SRC_PLL2                   (0x2 << 13)
+#define RT5682_SCLK_SRC_SDW                    (0x3 << 13)
+#define RT5682_SCLK_SRC_RCCLK                  (0x4 << 13)
+#define RT5682_PLL1_SRC_MASK                   (0x3 << 10)
+#define RT5682_PLL1_SRC_SFT                    10
+#define RT5682_PLL1_SRC_MCLK                   (0x0 << 10)
+#define RT5682_PLL1_SRC_BCLK1                  (0x1 << 10)
+#define RT5682_PLL1_SRC_SDW                    (0x2 << 10)
+#define RT5682_PLL1_SRC_RC                     (0x3 << 10)
+#define RT5682_PLL2_SRC_MASK                   (0x3 << 8)
+#define RT5682_PLL2_SRC_SFT                    8
+#define RT5682_PLL2_SRC_MCLK                   (0x0 << 8)
+#define RT5682_PLL2_SRC_BCLK1                  (0x1 << 8)
+#define RT5682_PLL2_SRC_SDW                    (0x2 << 8)
+#define RT5682_PLL2_SRC_RC                     (0x3 << 8)
+
+
+
+#define RT5682_PLL_INP_MAX                     40000000
+#define RT5682_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5682_PLL_N_MAX                       0x001ff
+#define RT5682_PLL_N_MASK                      (RT5682_PLL_N_MAX << 7)
+#define RT5682_PLL_N_SFT                       7
+#define RT5682_PLL_K_MAX                       0x001f
+#define RT5682_PLL_K_MASK                      (RT5682_PLL_K_MAX)
+#define RT5682_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5682_PLL_M_MAX                       0x00f
+#define RT5682_PLL_M_MASK                      (RT5682_PLL_M_MAX << 12)
+#define RT5682_PLL_M_SFT                       12
+#define RT5682_PLL_M_BP                                (0x1 << 11)
+#define RT5682_PLL_M_BP_SFT                    11
+#define RT5682_PLL_K_BP                                (0x1 << 10)
+#define RT5682_PLL_K_BP_SFT                    10
+#define RT5682_PLL_RST                         (0x1 << 1)
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5682_DA_ASRC_MASK                    (0x1 << 13)
+#define RT5682_DA_ASRC_SFT                     13
+#define RT5682_DAC_STO1_ASRC_MASK              (0x1 << 12)
+#define RT5682_DAC_STO1_ASRC_SFT               12
+#define RT5682_AD_ASRC_MASK                    (0x1 << 8)
+#define RT5682_AD_ASRC_SFT                     8
+#define RT5682_AD_ASRC_SEL_MASK                        (0x1 << 4)
+#define RT5682_AD_ASRC_SEL_SFT                 4
+#define RT5682_DMIC_ASRC_MASK                  (0x1 << 3)
+#define RT5682_DMIC_ASRC_SFT                   3
+#define RT5682_ADC_STO1_ASRC_MASK              (0x1 << 2)
+#define RT5682_ADC_STO1_ASRC_SFT               2
+#define RT5682_DA_ASRC_SEL_MASK                        (0x1 << 0)
+#define RT5682_DA_ASRC_SEL_SFT                 0
+
+/* PLL tracking mode 2 3 (0x0084)(0x0085)*/
+#define RT5682_FILTER_CLK_SEL_MASK             (0x7 << 12)
+#define RT5682_FILTER_CLK_SEL_SFT              12
+#define RT5682_FILTER_CLK_DIV_MASK             (0xf << 8)
+#define RT5682_FILTER_CLK_DIV_SFT              8
+
+/* ASRC Control 4 (0x0086) */
+#define RT5682_ASRCIN_FTK_N1_MASK              (0x3 << 14)
+#define RT5682_ASRCIN_FTK_N1_SFT               14
+#define RT5682_ASRCIN_FTK_N2_MASK              (0x3 << 12)
+#define RT5682_ASRCIN_FTK_N2_SFT               12
+#define RT5682_ASRCIN_FTK_M1_MASK              (0x7 << 8)
+#define RT5682_ASRCIN_FTK_M1_SFT               8
+#define RT5682_ASRCIN_FTK_M2_MASK              (0x7 << 4)
+#define RT5682_ASRCIN_FTK_M2_SFT               4
+
+/* SoundWire reference clk (0x008d) */
+#define RT5682_PLL2_OUT_MASK                   (0x1 << 8)
+#define RT5682_PLL2_OUT_98M                    (0x0 << 8)
+#define RT5682_PLL2_OUT_49M                    (0x1 << 8)
+#define RT5682_SDW_REF_2_MASK                  (0xf << 4)
+#define RT5682_SDW_REF_2_SFT                   4
+#define RT5682_SDW_REF_2_48K                   (0x0 << 4)
+#define RT5682_SDW_REF_2_96K                   (0x1 << 4)
+#define RT5682_SDW_REF_2_192K                  (0x2 << 4)
+#define RT5682_SDW_REF_2_32K                   (0x3 << 4)
+#define RT5682_SDW_REF_2_24K                   (0x4 << 4)
+#define RT5682_SDW_REF_2_16K                   (0x5 << 4)
+#define RT5682_SDW_REF_2_12K                   (0x6 << 4)
+#define RT5682_SDW_REF_2_8K                    (0x7 << 4)
+#define RT5682_SDW_REF_2_44K                   (0x8 << 4)
+#define RT5682_SDW_REF_2_88K                   (0x9 << 4)
+#define RT5682_SDW_REF_2_176K                  (0xa << 4)
+#define RT5682_SDW_REF_2_353K                  (0xb << 4)
+#define RT5682_SDW_REF_2_22K                   (0xc << 4)
+#define RT5682_SDW_REF_2_384K                  (0xd << 4)
+#define RT5682_SDW_REF_2_11K                   (0xe << 4)
+#define RT5682_SDW_REF_1_MASK                  (0xf << 0)
+#define RT5682_SDW_REF_1_SFT                   0
+#define RT5682_SDW_REF_1_48K                   (0x0 << 0)
+#define RT5682_SDW_REF_1_96K                   (0x1 << 0)
+#define RT5682_SDW_REF_1_192K                  (0x2 << 0)
+#define RT5682_SDW_REF_1_32K                   (0x3 << 0)
+#define RT5682_SDW_REF_1_24K                   (0x4 << 0)
+#define RT5682_SDW_REF_1_16K                   (0x5 << 0)
+#define RT5682_SDW_REF_1_12K                   (0x6 << 0)
+#define RT5682_SDW_REF_1_8K                    (0x7 << 0)
+#define RT5682_SDW_REF_1_44K                   (0x8 << 0)
+#define RT5682_SDW_REF_1_88K                   (0x9 << 0)
+#define RT5682_SDW_REF_1_176K                  (0xa << 0)
+#define RT5682_SDW_REF_1_353K                  (0xb << 0)
+#define RT5682_SDW_REF_1_22K                   (0xc << 0)
+#define RT5682_SDW_REF_1_384K                  (0xd << 0)
+#define RT5682_SDW_REF_1_11K                   (0xe << 0)
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5682_PUMP_EN                         (0x1 << 3)
+#define RT5682_PUMP_EN_SFT                             3
+#define RT5682_CAPLESS_EN                      (0x1 << 0)
+#define RT5682_CAPLESS_EN_SFT                  0
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5682_RAMP_MASK                       (0x1 << 12)
+#define RT5682_RAMP_SFT                                12
+#define RT5682_RAMP_DIS                                (0x0 << 12)
+#define RT5682_RAMP_EN                         (0x1 << 12)
+#define RT5682_BPS_MASK                                (0x1 << 11)
+#define RT5682_BPS_SFT                         11
+#define RT5682_BPS_DIS                         (0x0 << 11)
+#define RT5682_BPS_EN                          (0x1 << 11)
+#define RT5682_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5682_FAST_UPDN_SFT                   10
+#define RT5682_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5682_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5682_VLO_MASK                                (0x1 << 7)
+#define RT5682_VLO_SFT                         7
+#define RT5682_VLO_3V                          (0x0 << 7)
+#define RT5682_VLO_33V                         (0x1 << 7)
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5682_OSW_L_MASK                      (0x1 << 11)
+#define RT5682_OSW_L_SFT                       11
+#define RT5682_OSW_L_DIS                       (0x0 << 11)
+#define RT5682_OSW_L_EN                                (0x1 << 11)
+#define RT5682_OSW_R_MASK                      (0x1 << 10)
+#define RT5682_OSW_R_SFT                       10
+#define RT5682_OSW_R_DIS                       (0x0 << 10)
+#define RT5682_OSW_R_EN                                (0x1 << 10)
+#define RT5682_PM_HP_MASK                      (0x3 << 8)
+#define RT5682_PM_HP_SFT                       8
+#define RT5682_PM_HP_LV                                (0x0 << 8)
+#define RT5682_PM_HP_MV                                (0x1 << 8)
+#define RT5682_PM_HP_HV                                (0x2 << 8)
+#define RT5682_IB_HP_MASK                      (0x3 << 6)
+#define RT5682_IB_HP_SFT                       6
+#define RT5682_IB_HP_125IL                     (0x0 << 6)
+#define RT5682_IB_HP_25IL                      (0x1 << 6)
+#define RT5682_IB_HP_5IL                       (0x2 << 6)
+#define RT5682_IB_HP_1IL                       (0x3 << 6)
+
+/* Micbias Control1 (0x93) */
+#define RT5682_MIC1_OV_MASK                    (0x3 << 14)
+#define RT5682_MIC1_OV_SFT                     14
+#define RT5682_MIC1_OV_2V7                     (0x0 << 14)
+#define RT5682_MIC1_OV_2V4                     (0x1 << 14)
+#define RT5682_MIC1_OV_2V25                    (0x3 << 14)
+#define RT5682_MIC1_OV_1V8                     (0x4 << 14)
+#define RT5682_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5682_MIC1_CLK_SFT                    13
+#define RT5682_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5682_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5682_MIC1_OVCD_MASK                  (0x1 << 12)
+#define RT5682_MIC1_OVCD_SFT                   12
+#define RT5682_MIC1_OVCD_DIS                   (0x0 << 12)
+#define RT5682_MIC1_OVCD_EN                    (0x1 << 12)
+#define RT5682_MIC1_OVTH_MASK                  (0x3 << 10)
+#define RT5682_MIC1_OVTH_SFT                   10
+#define RT5682_MIC1_OVTH_768UA                 (0x0 << 10)
+#define RT5682_MIC1_OVTH_960UA                 (0x1 << 10)
+#define RT5682_MIC1_OVTH_1152UA                        (0x2 << 10)
+#define RT5682_MIC1_OVTH_1960UA                        (0x3 << 10)
+#define RT5682_MIC2_OV_MASK                    (0x3 << 8)
+#define RT5682_MIC2_OV_SFT                     8
+#define RT5682_MIC2_OV_2V7                     (0x0 << 8)
+#define RT5682_MIC2_OV_2V4                     (0x1 << 8)
+#define RT5682_MIC2_OV_2V25                    (0x3 << 8)
+#define RT5682_MIC2_OV_1V8                     (0x4 << 8)
+#define RT5682_MIC2_CLK_MASK                   (0x1 << 7)
+#define RT5682_MIC2_CLK_SFT                    7
+#define RT5682_MIC2_CLK_DIS                    (0x0 << 7)
+#define RT5682_MIC2_CLK_EN                     (0x1 << 7)
+#define RT5682_MIC2_OVTH_MASK                  (0x3 << 4)
+#define RT5682_MIC2_OVTH_SFT                   4
+#define RT5682_MIC2_OVTH_768UA                 (0x0 << 4)
+#define RT5682_MIC2_OVTH_960UA                 (0x1 << 4)
+#define RT5682_MIC2_OVTH_1152UA                        (0x2 << 4)
+#define RT5682_MIC2_OVTH_1960UA                        (0x3 << 4)
+#define RT5682_PWR_MB_MASK                     (0x1 << 3)
+#define RT5682_PWR_MB_SFT                      3
+#define RT5682_PWR_MB_PD                       (0x0 << 3)
+#define RT5682_PWR_MB_PU                       (0x1 << 3)
+
+/* Micbias Control2 (0x0094) */
+#define RT5682_PWR_CLK25M_MASK                 (0x1 << 9)
+#define RT5682_PWR_CLK25M_SFT                  9
+#define RT5682_PWR_CLK25M_PD                   (0x0 << 9)
+#define RT5682_PWR_CLK25M_PU                   (0x1 << 9)
+#define RT5682_PWR_CLK1M_MASK                  (0x1 << 8)
+#define RT5682_PWR_CLK1M_SFT                   8
+#define RT5682_PWR_CLK1M_PD                    (0x0 << 8)
+#define RT5682_PWR_CLK1M_PU                    (0x1 << 8)
+
+/* RC Clock Control (0x009f) */
+#define RT5682_POW_IRQ                         (0x1 << 15)
+#define RT5682_POW_JDH                         (0x1 << 14)
+#define RT5682_POW_JDL                         (0x1 << 13)
+#define RT5682_POW_ANA                         (0x1 << 12)
+
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5682_CLK_SRC_MCLK                    (0x0)
+#define RT5682_CLK_SRC_PLL1                    (0x1)
+#define RT5682_CLK_SRC_PLL2                    (0x2)
+#define RT5682_CLK_SRC_SDW                     (0x3)
+#define RT5682_CLK_SRC_RCCLK                   (0x4)
+#define RT5682_I2S_PD_1                                (0x0)
+#define RT5682_I2S_PD_2                                (0x1)
+#define RT5682_I2S_PD_3                                (0x2)
+#define RT5682_I2S_PD_4                                (0x3)
+#define RT5682_I2S_PD_6                                (0x4)
+#define RT5682_I2S_PD_8                                (0x5)
+#define RT5682_I2S_PD_12                       (0x6)
+#define RT5682_I2S_PD_16                       (0x7)
+#define RT5682_I2S_PD_24                       (0x8)
+#define RT5682_I2S_PD_32                       (0x9)
+#define RT5682_I2S_PD_48                       (0xa)
+#define RT5682_I2S2_SRC_MASK                   (0x3 << 4)
+#define RT5682_I2S2_SRC_SFT                    4
+#define RT5682_I2S2_M_PD_MASK                  (0xf << 0)
+#define RT5682_I2S2_M_PD_SFT                   0
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5682_JD1_PULSE_EN_MASK               (0x1 << 10)
+#define RT5682_JD1_PULSE_EN_SFT                        10
+#define RT5682_JD1_PULSE_DIS                   (0x0 << 10)
+#define RT5682_JD1_PULSE_EN                    (0x1 << 10)
+
+/* IRQ Control 2 (0x00b7) */
+#define RT5682_JD1_EN_MASK                     (0x1 << 15)
+#define RT5682_JD1_EN_SFT                      15
+#define RT5682_JD1_DIS                         (0x0 << 15)
+#define RT5682_JD1_EN                          (0x1 << 15)
+#define RT5682_JD1_POL_MASK                    (0x1 << 13)
+#define RT5682_JD1_POL_NOR                     (0x0 << 13)
+#define RT5682_JD1_POL_INV                     (0x1 << 13)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5682_IL_IRQ_MASK                     (0x1 << 7)
+#define RT5682_IL_IRQ_DIS                      (0x0 << 7)
+#define RT5682_IL_IRQ_EN                       (0x1 << 7)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5682_GP1_PIN_MASK                    (0x3 << 14)
+#define RT5682_GP1_PIN_SFT                     14
+#define RT5682_GP1_PIN_GPIO1                   (0x0 << 14)
+#define RT5682_GP1_PIN_IRQ                     (0x1 << 14)
+#define RT5682_GP1_PIN_DMIC_CLK                        (0x2 << 14)
+#define RT5682_GP2_PIN_MASK                    (0x3 << 12)
+#define RT5682_GP2_PIN_SFT                     12
+#define RT5682_GP2_PIN_GPIO2                   (0x0 << 12)
+#define RT5682_GP2_PIN_LRCK2                   (0x1 << 12)
+#define RT5682_GP2_PIN_DMIC_SDA                        (0x2 << 12)
+#define RT5682_GP3_PIN_MASK                    (0x3 << 10)
+#define RT5682_GP3_PIN_SFT                     10
+#define RT5682_GP3_PIN_GPIO3                   (0x0 << 10)
+#define RT5682_GP3_PIN_BCLK2                   (0x1 << 10)
+#define RT5682_GP3_PIN_DMIC_CLK                        (0x2 << 10)
+#define RT5682_GP4_PIN_MASK                    (0x3 << 8)
+#define RT5682_GP4_PIN_SFT                     8
+#define RT5682_GP4_PIN_GPIO4                   (0x0 << 8)
+#define RT5682_GP4_PIN_ADCDAT1                 (0x1 << 8)
+#define RT5682_GP4_PIN_DMIC_CLK                        (0x2 << 8)
+#define RT5682_GP4_PIN_ADCDAT2                 (0x3 << 8)
+#define RT5682_GP5_PIN_MASK                    (0x3 << 6)
+#define RT5682_GP5_PIN_SFT                     6
+#define RT5682_GP5_PIN_GPIO5                   (0x0 << 6)
+#define RT5682_GP5_PIN_DACDAT1                 (0x1 << 6)
+#define RT5682_GP5_PIN_DMIC_SDA                        (0x2 << 6)
+#define RT5682_GP6_PIN_MASK                    (0x1 << 5)
+#define RT5682_GP6_PIN_SFT                     5
+#define RT5682_GP6_PIN_GPIO6                   (0x0 << 5)
+#define RT5682_GP6_PIN_LRCK1                   (0x1 << 5)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5682_GP1_PF_MASK                     (0x1 << 15)
+#define RT5682_GP1_PF_IN                       (0x0 << 15)
+#define RT5682_GP1_PF_OUT                      (0x1 << 15)
+#define RT5682_GP1_OUT_MASK                    (0x1 << 14)
+#define RT5682_GP1_OUT_L                       (0x0 << 14)
+#define RT5682_GP1_OUT_H                       (0x1 << 14)
+#define RT5682_GP2_PF_MASK                     (0x1 << 13)
+#define RT5682_GP2_PF_IN                       (0x0 << 13)
+#define RT5682_GP2_PF_OUT                      (0x1 << 13)
+#define RT5682_GP2_OUT_MASK                    (0x1 << 12)
+#define RT5682_GP2_OUT_L                       (0x0 << 12)
+#define RT5682_GP2_OUT_H                       (0x1 << 12)
+#define RT5682_GP3_PF_MASK                     (0x1 << 11)
+#define RT5682_GP3_PF_IN                       (0x0 << 11)
+#define RT5682_GP3_PF_OUT                      (0x1 << 11)
+#define RT5682_GP3_OUT_MASK                    (0x1 << 10)
+#define RT5682_GP3_OUT_L                       (0x0 << 10)
+#define RT5682_GP3_OUT_H                       (0x1 << 10)
+#define RT5682_GP4_PF_MASK                     (0x1 << 9)
+#define RT5682_GP4_PF_IN                       (0x0 << 9)
+#define RT5682_GP4_PF_OUT                      (0x1 << 9)
+#define RT5682_GP4_OUT_MASK                    (0x1 << 8)
+#define RT5682_GP4_OUT_L                       (0x0 << 8)
+#define RT5682_GP4_OUT_H                       (0x1 << 8)
+#define RT5682_GP5_PF_MASK                     (0x1 << 7)
+#define RT5682_GP5_PF_IN                       (0x0 << 7)
+#define RT5682_GP5_PF_OUT                      (0x1 << 7)
+#define RT5682_GP5_OUT_MASK                    (0x1 << 6)
+#define RT5682_GP5_OUT_L                       (0x0 << 6)
+#define RT5682_GP5_OUT_H                       (0x1 << 6)
+#define RT5682_GP6_PF_MASK                     (0x1 << 5)
+#define RT5682_GP6_PF_IN                       (0x0 << 5)
+#define RT5682_GP6_PF_OUT                      (0x1 << 5)
+#define RT5682_GP6_OUT_MASK                    (0x1 << 4)
+#define RT5682_GP6_OUT_L                       (0x0 << 4)
+#define RT5682_GP6_OUT_H                       (0x1 << 4)
+
+
+/* GPIO Status (0x00c2) */
+#define RT5682_GP6_STA                         (0x1 << 6)
+#define RT5682_GP5_STA                         (0x1 << 5)
+#define RT5682_GP4_STA                         (0x1 << 4)
+#define RT5682_GP3_STA                         (0x1 << 3)
+#define RT5682_GP2_STA                         (0x1 << 2)
+#define RT5682_GP1_STA                         (0x1 << 1)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5682_SV_MASK                         (0x1 << 15)
+#define RT5682_SV_SFT                          15
+#define RT5682_SV_DIS                          (0x0 << 15)
+#define RT5682_SV_EN                           (0x1 << 15)
+#define RT5682_ZCD_MASK                                (0x1 << 10)
+#define RT5682_ZCD_SFT                         10
+#define RT5682_ZCD_PD                          (0x0 << 10)
+#define RT5682_ZCD_PU                          (0x1 << 10)
+#define RT5682_SV_DLY_MASK                     (0xf)
+#define RT5682_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5682_ZCD_BST1_CBJ_MASK               (0x1 << 7)
+#define RT5682_ZCD_BST1_CBJ_SFT                        7
+#define RT5682_ZCD_BST1_CBJ_DIS                        (0x0 << 7)
+#define RT5682_ZCD_BST1_CBJ_EN                 (0x1 << 7)
+#define RT5682_ZCD_RECMIX_MASK                 (0x1)
+#define RT5682_ZCD_RECMIX_SFT                  0
+#define RT5682_ZCD_RECMIX_DIS                  (0x0)
+#define RT5682_ZCD_RECMIX_EN                   (0x1)
+
+/* 4 Button Inline Command Control 2 (0x00e3) */
+#define RT5682_4BTN_IL_MASK                    (0x1 << 15)
+#define RT5682_4BTN_IL_EN                      (0x1 << 15)
+#define RT5682_4BTN_IL_DIS                     (0x0 << 15)
+#define RT5682_4BTN_IL_RST_MASK                        (0x1 << 14)
+#define RT5682_4BTN_IL_NOR                     (0x1 << 14)
+#define RT5682_4BTN_IL_RST                     (0x0 << 14)
+
+/* Analog JD Control (0x00f0) */
+#define RT5682_JDH_RS_MASK                     (0x1 << 4)
+#define RT5682_JDH_NO_PLUG                     (0x1 << 4)
+#define RT5682_JDH_PLUG                                (0x0 << 4)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5682_CKXEN_DAC1_MASK                 (0x1 << 13)
+#define RT5682_CKXEN_DAC1_SFT                  13
+#define RT5682_CKGEN_DAC1_MASK                 (0x1 << 12)
+#define RT5682_CKGEN_DAC1_SFT                  12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5682_CKXEN_ADC1_MASK                 (0x1 << 13)
+#define RT5682_CKXEN_ADC1_SFT                  13
+#define RT5682_CKGEN_ADC1_MASK                 (0x1 << 12)
+#define RT5682_CKGEN_ADC1_SFT                  12
+
+/* Volume test (0x013f)*/
+#define RT5682_SEL_CLK_VOL_MASK                        (0x1 << 15)
+#define RT5682_SEL_CLK_VOL_EN                  (0x1 << 15)
+#define RT5682_SEL_CLK_VOL_DIS                 (0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5682_AD2DA_LB_MASK                   (0x1 << 10)
+#define RT5682_AD2DA_LB_SFT                    10
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5682_NG2_EN_MASK                     (0x1 << 15)
+#define RT5682_NG2_EN                          (0x1 << 15)
+#define RT5682_NG2_DIS                         (0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5682_DEB_STO_DAC_MASK                        (0x7 << 4)
+#define RT5682_DEB_80_MS                       (0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5682_SAR_BUTT_DET_MASK               (0x1 << 15)
+#define RT5682_SAR_BUTT_DET_EN                 (0x1 << 15)
+#define RT5682_SAR_BUTT_DET_DIS                        (0x0 << 15)
+#define RT5682_SAR_BUTDET_MODE_MASK            (0x1 << 14)
+#define RT5682_SAR_BUTDET_POW_SAV              (0x1 << 14)
+#define RT5682_SAR_BUTDET_POW_NORM             (0x0 << 14)
+#define RT5682_SAR_BUTDET_RST_MASK             (0x1 << 13)
+#define RT5682_SAR_BUTDET_RST_NORMAL           (0x1 << 13)
+#define RT5682_SAR_BUTDET_RST                  (0x0 << 13)
+#define RT5682_SAR_POW_MASK                    (0x1 << 12)
+#define RT5682_SAR_POW_EN                      (0x1 << 12)
+#define RT5682_SAR_POW_DIS                     (0x0 << 12)
+#define RT5682_SAR_RST_MASK                    (0x1 << 11)
+#define RT5682_SAR_RST_NORMAL                  (0x1 << 11)
+#define RT5682_SAR_RST                         (0x0 << 11)
+#define RT5682_SAR_BYPASS_MASK                 (0x1 << 10)
+#define RT5682_SAR_BYPASS_EN                   (0x1 << 10)
+#define RT5682_SAR_BYPASS_DIS                  (0x0 << 10)
+#define RT5682_SAR_SEL_MB1_MASK                        (0x1 << 9)
+#define RT5682_SAR_SEL_MB1_SEL                 (0x1 << 9)
+#define RT5682_SAR_SEL_MB1_NOSEL               (0x0 << 9)
+#define RT5682_SAR_SEL_MB2_MASK                        (0x1 << 8)
+#define RT5682_SAR_SEL_MB2_SEL                 (0x1 << 8)
+#define RT5682_SAR_SEL_MB2_NOSEL               (0x0 << 8)
+#define RT5682_SAR_SEL_MODE_MASK               (0x1 << 7)
+#define RT5682_SAR_SEL_MODE_CMP                        (0x1 << 7)
+#define RT5682_SAR_SEL_MODE_ADC                        (0x0 << 7)
+#define RT5682_SAR_SEL_MB1_MB2_MASK            (0x1 << 5)
+#define RT5682_SAR_SEL_MB1_MB2_AUTO            (0x1 << 5)
+#define RT5682_SAR_SEL_MB1_MB2_MANU            (0x0 << 5)
+#define RT5682_SAR_SEL_SIGNAL_MASK             (0x1 << 4)
+#define RT5682_SAR_SEL_SIGNAL_AUTO             (0x1 << 4)
+#define RT5682_SAR_SEL_SIGNAL_MANU             (0x0 << 4)
+
+/* SAR ADC Inline Command Control 13 (0x021c) */
+#define RT5682_SAR_SOUR_MASK                   (0x3f)
+#define RT5682_SAR_SOUR_BTN                    (0x3f)
+#define RT5682_SAR_SOUR_TYPE                   (0x0)
+
+
+/* System Clock Source */
+enum {
+       RT5682_SCLK_S_MCLK,
+       RT5682_SCLK_S_PLL1,
+       RT5682_SCLK_S_PLL2,
+       RT5682_SCLK_S_RCCLK,
+};
+
+/* PLL Source */
+enum {
+       RT5682_PLL1_S_MCLK,
+       RT5682_PLL1_S_BCLK1,
+       RT5682_PLL1_S_RCCLK,
+};
+
+enum {
+       RT5682_AIF1,
+       RT5682_AIF2,
+       RT5682_AIFS
+};
+
+/* filter mask */
+enum {
+       RT5682_DA_STEREO1_FILTER = 0x1,
+       RT5682_AD_STEREO1_FILTER = (0x1 << 1),
+};
+
+enum {
+       RT5682_CLK_SEL_SYS,
+       RT5682_CLK_SEL_I2S1_ASRC,
+       RT5682_CLK_SEL_I2S2_ASRC,
+};
+
+int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+               unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5682_H__ */
similarity index 68%
rename from sound/soc/codecs/dio2125.c
rename to sound/soc/codecs/simple-amplifier.c
index 09451cd44f9b980d6afb3dc14614f846c3d13b3e..85524acf3e9cd2cdda5f56cec04a145c2bc99ade 100644 (file)
@@ -21,9 +21,9 @@
 #include <linux/module.h>
 #include <sound/soc.h>
 
-#define DRV_NAME "dio2125"
+#define DRV_NAME "simple-amplifier"
 
-struct dio2125 {
+struct simple_amp {
        struct gpio_desc *gpiod_enable;
 };
 
@@ -31,7 +31,7 @@ static int drv_event(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *control, int event)
 {
        struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
-       struct dio2125 *priv = snd_soc_component_get_drvdata(c);
+       struct simple_amp *priv = snd_soc_component_get_drvdata(c);
        int val;
 
        switch (event) {
@@ -51,7 +51,7 @@ static int drv_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("INL"),
        SND_SOC_DAPM_INPUT("INR"),
        SND_SOC_DAPM_OUT_DRV_E("DRV", SND_SOC_NOPM, 0, 0, NULL, 0, drv_event,
@@ -60,24 +60,24 @@ static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("OUTR"),
 };
 
-static const struct snd_soc_dapm_route dio2125_dapm_routes[] = {
+static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
        { "DRV", NULL, "INL" },
        { "DRV", NULL, "INR" },
        { "OUTL", NULL, "DRV" },
        { "OUTR", NULL, "DRV" },
 };
 
-static const struct snd_soc_component_driver dio2125_component_driver = {
-       .dapm_widgets           = dio2125_dapm_widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(dio2125_dapm_widgets),
-       .dapm_routes            = dio2125_dapm_routes,
-       .num_dapm_routes        = ARRAY_SIZE(dio2125_dapm_routes),
+static const struct snd_soc_component_driver simple_amp_component_driver = {
+       .dapm_widgets           = simple_amp_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(simple_amp_dapm_widgets),
+       .dapm_routes            = simple_amp_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(simple_amp_dapm_routes),
 };
 
-static int dio2125_probe(struct platform_device *pdev)
+static int simple_amp_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct dio2125 *priv;
+       struct simple_amp *priv;
        int err;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -93,28 +93,30 @@ static int dio2125_probe(struct platform_device *pdev)
                return err;
        }
 
-       return devm_snd_soc_register_component(dev, &dio2125_component_driver,
+       return devm_snd_soc_register_component(dev,
+                                              &simple_amp_component_driver,
                                               NULL, 0);
 }
 
 #ifdef CONFIG_OF
-static const struct of_device_id dio2125_ids[] = {
+static const struct of_device_id simple_amp_ids[] = {
        { .compatible = "dioo,dio2125", },
+       { .compatible = "simple-audio-amplifier", },
        { }
 };
-MODULE_DEVICE_TABLE(of, dio2125_ids);
+MODULE_DEVICE_TABLE(of, simple_amp_ids);
 #endif
 
-static struct platform_driver dio2125_driver = {
+static struct platform_driver simple_amp_driver = {
        .driver = {
                .name = DRV_NAME,
-               .of_match_table = of_match_ptr(dio2125_ids),
+               .of_match_table = of_match_ptr(simple_amp_ids),
        },
-       .probe = dio2125_probe,
+       .probe = simple_amp_probe,
 };
 
-module_platform_driver(dio2125_driver);
+module_platform_driver(simple_amp_driver);
 
-MODULE_DESCRIPTION("ASoC DIO2125 output driver");
+MODULE_DESCRIPTION("ASoC Simple Audio Amplifier driver");
 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 MODULE_LICENSE("GPL");
index 52f34c94ec25691c496b70602dff9dacfa568da5..ca2dfe12344ecf22cc576c06c375bcc286602af7 100644 (file)
@@ -7,6 +7,9 @@
  * TAS5721 support:
  * Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
  *
+ * TAS5707 support:
+ * Copyright (C) 2018 Jerome Brunet, Baylibre SAS <jbrunet@baylibre.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -444,6 +447,111 @@ static const struct tas571x_chip tas5711_chip = {
        .vol_reg_size                   = 1,
 };
 
+static const struct regmap_range tas5707_volatile_regs_range[] = {
+       regmap_reg_range(TAS571X_CLK_CTRL_REG,  TAS571X_ERR_STATUS_REG),
+       regmap_reg_range(TAS571X_OSC_TRIM_REG,  TAS571X_OSC_TRIM_REG),
+       regmap_reg_range(TAS5707_CH1_BQ0_REG, TAS5707_CH2_BQ6_REG),
+};
+
+static const struct regmap_access_table tas5707_volatile_regs = {
+       .yes_ranges =   tas5707_volatile_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(tas5707_volatile_regs_range),
+
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5707_volume_tlv, -7900, 50, 1);
+
+static const char * const tas5707_volume_slew_step_txt[] = {
+       "256", "512", "1024", "2048",
+};
+
+static const unsigned int tas5707_volume_slew_step_values[] = {
+       3, 0, 1, 2,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(tas5707_volume_slew_step_enum,
+                                 TAS571X_VOL_CFG_REG, 0, 0x3,
+                                 tas5707_volume_slew_step_txt,
+                                 tas5707_volume_slew_step_values);
+
+static const struct snd_kcontrol_new tas5707_controls[] = {
+       SOC_SINGLE_TLV("Master Volume",
+                      TAS571X_MVOL_REG,
+                      0, 0xff, 1, tas5707_volume_tlv),
+       SOC_DOUBLE_R_TLV("Speaker Volume",
+                        TAS571X_CH1_VOL_REG,
+                        TAS571X_CH2_VOL_REG,
+                        0, 0xff, 1, tas5707_volume_tlv),
+       SOC_DOUBLE("Speaker Switch",
+                  TAS571X_SOFT_MUTE_REG,
+                  TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+                  1, 1),
+
+       SOC_ENUM("Slew Rate Steps", tas5707_volume_slew_step_enum),
+
+       BIQUAD_COEFS("CH1 - Biquad 0", TAS5707_CH1_BQ0_REG),
+       BIQUAD_COEFS("CH1 - Biquad 1", TAS5707_CH1_BQ1_REG),
+       BIQUAD_COEFS("CH1 - Biquad 2", TAS5707_CH1_BQ2_REG),
+       BIQUAD_COEFS("CH1 - Biquad 3", TAS5707_CH1_BQ3_REG),
+       BIQUAD_COEFS("CH1 - Biquad 4", TAS5707_CH1_BQ4_REG),
+       BIQUAD_COEFS("CH1 - Biquad 5", TAS5707_CH1_BQ5_REG),
+       BIQUAD_COEFS("CH1 - Biquad 6", TAS5707_CH1_BQ6_REG),
+
+       BIQUAD_COEFS("CH2 - Biquad 0", TAS5707_CH2_BQ0_REG),
+       BIQUAD_COEFS("CH2 - Biquad 1", TAS5707_CH2_BQ1_REG),
+       BIQUAD_COEFS("CH2 - Biquad 2", TAS5707_CH2_BQ2_REG),
+       BIQUAD_COEFS("CH2 - Biquad 3", TAS5707_CH2_BQ3_REG),
+       BIQUAD_COEFS("CH2 - Biquad 4", TAS5707_CH2_BQ4_REG),
+       BIQUAD_COEFS("CH2 - Biquad 5", TAS5707_CH2_BQ5_REG),
+       BIQUAD_COEFS("CH2 - Biquad 6", TAS5707_CH2_BQ6_REG),
+};
+
+static const struct reg_default tas5707_reg_defaults[] = {
+       {TAS571X_CLK_CTRL_REG,          0x6c},
+       {TAS571X_DEV_ID_REG,            0x70},
+       {TAS571X_ERR_STATUS_REG,        0x00},
+       {TAS571X_SYS_CTRL_1_REG,        0xa0},
+       {TAS571X_SDI_REG,               0x05},
+       {TAS571X_SYS_CTRL_2_REG,        0x40},
+       {TAS571X_SOFT_MUTE_REG,         0x00},
+       {TAS571X_MVOL_REG,              0xff},
+       {TAS571X_CH1_VOL_REG,           0x30},
+       {TAS571X_CH2_VOL_REG,           0x30},
+       {TAS571X_VOL_CFG_REG,           0x91},
+       {TAS571X_MODULATION_LIMIT_REG,  0x02},
+       {TAS571X_IC_DELAY_CH1_REG,      0xac},
+       {TAS571X_IC_DELAY_CH2_REG,      0x54},
+       {TAS571X_IC_DELAY_CH3_REG,      0xac},
+       {TAS571X_IC_DELAY_CH4_REG,      0x54},
+       {TAS571X_START_STOP_PERIOD_REG, 0x0f},
+       {TAS571X_OSC_TRIM_REG,          0x82},
+       {TAS571X_BKND_ERR_REG,          0x02},
+       {TAS571X_INPUT_MUX_REG,         0x17772},
+       {TAS571X_PWM_MUX_REG,           0x1021345},
+};
+
+static const struct regmap_config tas5707_regmap_config = {
+       .reg_bits                       = 8,
+       .val_bits                       = 32,
+       .max_register                   = 0xff,
+       .reg_read                       = tas571x_reg_read,
+       .reg_write                      = tas571x_reg_write,
+       .reg_defaults                   = tas5707_reg_defaults,
+       .num_reg_defaults               = ARRAY_SIZE(tas5707_reg_defaults),
+       .cache_type                     = REGCACHE_RBTREE,
+       .wr_table                       = &tas571x_write_regs,
+       .volatile_table                 = &tas5707_volatile_regs,
+};
+
+static const struct tas571x_chip tas5707_chip = {
+       .supply_names                   = tas5711_supply_names,
+       .num_supply_names               = ARRAY_SIZE(tas5711_supply_names),
+       .controls                       = tas5707_controls,
+       .num_controls                   = ARRAY_SIZE(tas5707_controls),
+       .regmap_config                  = &tas5707_regmap_config,
+       .vol_reg_size                   = 1,
+};
+
 static const char *const tas5717_supply_names[] = {
        "AVDD",
        "DVDD",
@@ -775,6 +883,7 @@ static int tas571x_i2c_remove(struct i2c_client *client)
 }
 
 static const struct of_device_id tas571x_of_match[] = {
+       { .compatible = "ti,tas5707", .data = &tas5707_chip, },
        { .compatible = "ti,tas5711", .data = &tas5711_chip, },
        { .compatible = "ti,tas5717", .data = &tas5717_chip, },
        { .compatible = "ti,tas5719", .data = &tas5717_chip, },
@@ -784,6 +893,7 @@ static const struct of_device_id tas571x_of_match[] = {
 MODULE_DEVICE_TABLE(of, tas571x_of_match);
 
 static const struct i2c_device_id tas571x_i2c_id[] = {
+       { "tas5707", (kernel_ulong_t) &tas5707_chip },
        { "tas5711", (kernel_ulong_t) &tas5711_chip },
        { "tas5717", (kernel_ulong_t) &tas5717_chip },
        { "tas5719", (kernel_ulong_t) &tas5717_chip },
index c45677bc26ad2fb14fb85efda9239a87f8ec52e7..bd23e89cfe7980b56edaad83d527d72c8a5890bf 100644 (file)
 #define TAS571X_PWM_MUX_REG            0x25
 
 /* 20-byte biquad registers */
+#define TAS5707_CH1_BQ0_REG            0x29
+#define TAS5707_CH1_BQ1_REG            0x2a
+#define TAS5707_CH1_BQ2_REG            0x2b
+#define TAS5707_CH1_BQ3_REG            0x2c
+#define TAS5707_CH1_BQ4_REG            0x2d
+#define TAS5707_CH1_BQ5_REG            0x2e
+#define TAS5707_CH1_BQ6_REG            0x2f
+
+#define TAS5707_CH2_BQ0_REG            0x30
+#define TAS5707_CH2_BQ1_REG            0x31
+#define TAS5707_CH2_BQ2_REG            0x32
+#define TAS5707_CH2_BQ3_REG            0x33
+#define TAS5707_CH2_BQ4_REG            0x34
+#define TAS5707_CH2_BQ5_REG            0x35
+#define TAS5707_CH2_BQ6_REG            0x36
+
 #define TAS5717_CH1_BQ0_REG            0x26
 #define TAS5717_CH1_BQ1_REG            0x27
 #define TAS5717_CH1_BQ2_REG            0x28
index 225c210ac38f845a6ed54ec02300fffab218a020..7f3b79c5a56380b30414df884c75002873d18916 100644 (file)
@@ -142,9 +142,9 @@ struct tda7419_vol_control {
 static inline bool tda7419_vol_is_stereo(struct tda7419_vol_control *tvc)
 {
        if (tvc->reg == tvc->rreg)
-               return 0;
+               return false;
 
-       return 1;
+       return true;
 }
 
 static int tda7419_vol_info(struct snd_kcontrol *kcontrol,
index d18ff17719cc617cd0084358dee0623b95223250..7396a6e5277e68814117e2953839aa85b7ac03aa 100644 (file)
@@ -625,25 +625,34 @@ static int bytes_info_ext(struct snd_kcontrol *kcontrol,
 
 static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
        /* Volumes */
-       SOC_DOUBLE_R_TLV("Headphone Playback Volume", R_HPVOLL, R_HPVOLR,
+       SOC_DOUBLE_R_TLV("Headphone Volume", R_HPVOLL, R_HPVOLR,
                        FB_HPVOLL, 0x7F, 0, hpvol_scale),
-       SOC_DOUBLE_R_TLV("Speaker Playback Volume", R_SPKVOLL, R_SPKVOLR,
+       SOC_DOUBLE_R_TLV("Speaker Volume", R_SPKVOLL, R_SPKVOLR,
                        FB_SPKVOLL, 0x7F, 0, spkvol_scale),
-       SOC_DOUBLE_R_TLV("Master Playback Volume", R_DACVOLL, R_DACVOLR,
+       SOC_DOUBLE_R_TLV("Master Volume", R_DACVOLL, R_DACVOLR,
                        FB_DACVOLL, 0xFF, 0, dacvol_scale),
-       SOC_DOUBLE_R_TLV("PCM Capture Volume", R_ADCVOLL, R_ADCVOLR,
+       SOC_DOUBLE_R_TLV("PCM Volume", R_ADCVOLL, R_ADCVOLR,
                        FB_ADCVOLL, 0xFF, 0, adcvol_scale),
-       SOC_DOUBLE_R_TLV("Master Capture Volume", R_INVOLL, R_INVOLR,
+       SOC_DOUBLE_R_TLV("Input Volume", R_INVOLL, R_INVOLR,
                        FB_INVOLL, 0x3F, 0, invol_scale),
 
        /* INSEL */
-       SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", R_INSELL, R_INSELR,
+       SOC_DOUBLE_R_TLV("Mic Boost Volume", R_INSELL, R_INSELR,
                        FB_INSELL_MICBSTL, FV_INSELL_MICBSTL_30DB,
                        0, mic_boost_scale),
 
        /* Input Channel Map */
        SOC_ENUM("Input Channel Map", ch_map_select_enum),
 
+       /* Mic Bias */
+       SOC_SINGLE("Mic Bias Boost Switch", 0x71, 0x07, 1, 0),
+
+       /* Headphone Auto Switching */
+       SOC_SINGLE("Headphone Auto Switching Switch",
+                       R_CTL, FB_CTL_HPSWEN, 1, 0),
+       SOC_SINGLE("Headphone Detect Polarity Toggle Switch",
+                       R_CTL, FB_CTL_HPSWPOL, 1, 0),
+
        /* Coefficient Ram */
        COEFF_RAM_CTL("Cascade1L BiQuad1", BIQUAD_SIZE, 0x00),
        COEFF_RAM_CTL("Cascade1L BiQuad2", BIQUAD_SIZE, 0x05),
@@ -733,9 +742,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
                R_CLECTL, FB_CLECTL_LIMIT_EN, 1, 0),
        SOC_SINGLE("Comp Switch",
                R_CLECTL, FB_CLECTL_COMP_EN, 1, 0),
-       SOC_SINGLE_TLV("CLE Make-Up Gain Playback Volume",
+       SOC_SINGLE_TLV("CLE Make-Up Gain Volume",
                R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale),
-       SOC_SINGLE_TLV("Comp Thresh Playback Volume",
+       SOC_SINGLE_TLV("Comp Thresh Volume",
                R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale),
        SOC_ENUM("Comp Ratio", compressor_ratio_enum),
        SND_SOC_BYTES("Comp Atk Time", R_CATKTCL, 2),
@@ -766,9 +775,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
 
        SOC_SINGLE("MBC1 Phase Invert Switch",
                R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, 1, 0),
-       SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Playback Volume",
+       SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Volume",
                R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale),
-       SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Playback Volume",
+       SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Volume",
                R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale),
        SOC_ENUM("DAC MBC1 Comp Ratio",
                dac_mbc1_compressor_ratio_enum),
@@ -778,9 +787,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
 
        SOC_SINGLE("MBC2 Phase Invert Switch",
                R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, 1, 0),
-       SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Playback Volume",
+       SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Volume",
                R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale),
-       SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Playback Volume",
+       SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Volume",
                R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale),
        SOC_ENUM("DAC MBC2 Comp Ratio",
                dac_mbc2_compressor_ratio_enum),
@@ -790,9 +799,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
 
        SOC_SINGLE("MBC3 Phase Invert Switch",
                R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, 1, 0),
-       SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Playback Volume",
+       SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Volume",
                R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale),
-       SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Playback Volume",
+       SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Volume",
                R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale),
        SOC_ENUM("DAC MBC3 Comp Ratio",
                dac_mbc3_compressor_ratio_enum),
index 814c8f3c4a68c83b7e9e2c5dc129ca50b7d5dc1b..6b3a210816356b48a2baa432ca57d3e7db63d9d9 100644 (file)
@@ -34,6 +34,7 @@ enum {
 #define R_DACSR         0x19
 #define R_PWRM1         0x1A
 #define R_PWRM2         0x1B
+#define R_CTL          0x1C
 #define R_CONFIG0       0x1F
 #define R_CONFIG1       0x20
 #define R_DMICCTL       0x24
@@ -1110,6 +1111,13 @@ enum {
 #define RV_PWRM2_VREF_DISABLE \
         RV(FV_PWRM2_VREF_DISABLE, FB_PWRM2_VREF)
 
+/******************************
+ *      R_CTL (0x1C)          *
+ ******************************/
+
+/* Fiel Offsets */
+#define FB_CTL_HPSWEN                        7
+#define FB_CTL_HPSWPOL                       6
 
 /******************************
  *      R_CONFIG0 (0x1F)      *
index bfd1abd7225377bb381ad967c54b22450aec3a57..94675da514c8f3e83e0680e962a936d33e8eac82 100644 (file)
@@ -148,7 +148,7 @@ static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
        case TWL6040_REG_HFRCTL:
                return priv->dl2_unmuted;
        default:
-               return 1;
+               return true;
        }
 }
 
index 3663b9fd4d65e102686d6590adb4cffd6fcbef5c..deff651615042f3041f379fae249720977ae29c6 100644 (file)
@@ -1180,6 +1180,9 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
 SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
           WM2200_SPK1R_MUTE_SHIFT, 1, 1),
 SOC_ENUM("RxANC Src", wm2200_rxanc_input_sel),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+WM_ADSP_FW_CONTROL("DSP2", 1),
 };
 
 WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
@@ -1553,15 +1556,10 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
 static int wm2200_probe(struct snd_soc_component *component)
 {
        struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
-       int ret;
 
        wm2200->component = component;
 
-       ret = snd_soc_add_component_controls(component, wm_adsp_fw_controls, 2);
-       if (ret != 0)
-               return ret;
-
-       return ret;
+       return 0;
 }
 
 static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
index e239f4bf2460dddae415a6da9408d8e25b05fdd9..9e987cf07450e56f1498fe97712ef92d2f80a507 100644 (file)
@@ -30,7 +30,7 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
        case WM5100_OUTPUT_STATUS_2:
        case WM5100_INPUT_ENABLES_STATUS:
        case WM5100_MIC_DETECT_3:
-               return 1;
+               return true;
        default:
                if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
                    (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
@@ -41,9 +41,9 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
                    (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
                    (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
                    (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
-                       return 1;
+                       return true;
                else
-                       return 0;
+                       return false;
        }
 }
 
@@ -798,7 +798,7 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
        case WM5100_DSP3_CONTROL_28:
        case WM5100_DSP3_CONTROL_29:
        case WM5100_DSP3_CONTROL_30:
-               return 1;
+               return true;
        default:
                if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
                    (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
@@ -809,9 +809,9 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
                    (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
                    (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
                    (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
-                       return 1;
+                       return true;
                else
-                       return 0;
+                       return false;
        }
 }
 
index a01a0c0e01ebda73b22a0abe311a7e72ee2f4da9..7e817e1877c225adad55ab284ba9c7462eb35a8d 100644 (file)
@@ -985,6 +985,8 @@ ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
index 00c735c585d9b75c8f0d12eabca634dfa4b0e657..b0789a03d699bc0f2fb117a9225d4b7cdd787d6f 100644 (file)
@@ -927,6 +927,11 @@ ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+WM_ADSP_FW_CONTROL("DSP2", 1),
+WM_ADSP_FW_CONTROL("DSP3", 2),
+WM_ADSP_FW_CONTROL("DSP4", 3),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
index 7b8b6ef2f6325a80dc61b54184cbdb9f19f44a40..6cb3c153ba190203d1128d238c98d48bcfc97369 100644 (file)
@@ -251,10 +251,10 @@ static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
        case WM8903_DC_SERVO_READBACK_2:
        case WM8903_DC_SERVO_READBACK_3:
        case WM8903_DC_SERVO_READBACK_4:
-               return 1;
+               return true;
 
        default:
-               return 0;
+               return false;
        }
 }
 
index 9037a35b931dbc7a6c07173439d456f81b3bba76..1965635ec07c704b1301a77fb318020422fd1d05 100644 (file)
@@ -1455,6 +1455,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                aif1 |= 0x3;
                break;
index ba44e3d6c1e0e4d00c6534a996e907a575454ca0..cd204f79647d04bd3b91d2aefa011a9f8da0369e 100644 (file)
@@ -686,6 +686,7 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif |= WM8955_LRP;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                aif |= 0x3;
                break;
index c30f5aa392c6aea25c35f8c0b9710006fd19894d..8dc1f3d6a988e88fbb76c42b44e0e3b280d8a86f 100644 (file)
@@ -839,6 +839,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
                        iface |= 0x000c;
                        break;
                }
+               /* fall through */
        default:
                dev_err(component->dev, "unsupported width %d\n",
                        params_width(params));
index f70f563d59f3e98b989d0712c334cfe41e7bba27..68b4cadc308fb1a841ee00b44d525d6d92f10a13 100644 (file)
@@ -653,6 +653,7 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        case SND_SOC_DAIFMT_DSP_B:
                aif |= WM8961_LRP;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                aif |= 3;
                switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
index a11e9d6bf950f2e032e8db2bdc52475a970436a4..efd8910b1ff77ad6f6b074448b43a77ef8123a7e 100644 (file)
@@ -2649,6 +2649,7 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif0 |= WM8962_LRCLK_INV | 3;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                aif0 |= 3;
 
index 411b9eee88c27e9bbc779954ae43be4b6a5650c6..457bc437ce54af755bb3a90a07fc7c19241c2671 100644 (file)
@@ -40,9 +40,9 @@ static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8990_RESET:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
index 7fdfdf3f6e67e5c045d6b80b0ac516dac3697dea..14f1b0c0d286ab7dd5fa4349362a21dd1d4d3893 100644 (file)
@@ -2432,6 +2432,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
                        snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
                                            WM8994_OPCLK_ENA, 0);
                }
+               break;
 
        default:
                return -EINVAL;
index 60e22783233143ff22b1683db237084c953f71ab..68c99fe3709741cf106b6231068056d309a81e67 100644 (file)
@@ -1465,6 +1465,7 @@ static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif |= WM8995_AIF1_LRCLK_INV;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                aif |= (0x3 << WM8995_AIF1_FMT_SHIFT);
                break;
index d9d206046f8cb2490cd685dd8cb77c4f810a0cb0..91711f8958c56245eef728b8fd8309a7370bc44a 100644 (file)
@@ -1498,9 +1498,9 @@ static bool wm8996_readable_register(struct device *dev, unsigned int reg)
        case WM8996_RIGHT_PDM_SPEAKER:
        case WM8996_PDM_SPEAKER_MUTE_SEQUENCE:
        case WM8996_PDM_SPEAKER_VOLUME:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
@@ -1522,9 +1522,9 @@ static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
        case WM8996_MIC_DETECT_3:
        case WM8996_HEADPHONE_DETECT_1:
        case WM8996_HEADPHONE_DETECT_2:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
@@ -1858,6 +1858,7 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
        case 24576000:
                ratediv = WM8996_SYSCLK_DIV;
                wm8996->sysclk /= 2;
+               /* fall through */
        case 11289600:
        case 12288000:
                snd_soc_component_update_bits(component, WM8996_AIF_RATE,
index 5a0ea7b3c149a46a9c69640ece9a6d21553496c9..399255d1f78a48c3e3abc5d9d721458d41fb0827 100644 (file)
@@ -933,6 +933,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif2 |= WM9081_AIF_LRCLK_INV;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                aif2 |= 0x3;
                break;
index 8f53814d11ea6d1c1faddb0d8ebfced5a1cbcc9b..f61656070225bf643b3223730e12dd7822c23b89 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/ctype.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include "wm_adsp.h"
 
 #define adsp_crit(_dsp, fmt, ...) \
-       dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+       dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
 #define adsp_err(_dsp, fmt, ...) \
-       dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+       dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
 #define adsp_warn(_dsp, fmt, ...) \
-       dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+       dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
 #define adsp_info(_dsp, fmt, ...) \
-       dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+       dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
 #define adsp_dbg(_dsp, fmt, ...) \
-       dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+       dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
 
 #define ADSP1_CONTROL_1                   0x00
 #define ADSP1_CONTROL_2                   0x02
@@ -418,7 +419,7 @@ static const struct wm_adsp_fw_caps ctrl_caps[] = {
        {
                .id = SND_AUDIOCODEC_BESPOKE,
                .desc = {
-                       .max_ch = 1,
+                       .max_ch = 8,
                        .sample_rates = { 16000 },
                        .num_sample_rates = 1,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -608,7 +609,6 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
                                  struct snd_soc_component *component)
 {
        struct dentry *root = NULL;
-       char *root_name;
        int i;
 
        if (!component->debugfs_root) {
@@ -616,13 +616,7 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
                goto err;
        }
 
-       root_name = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!root_name)
-               goto err;
-
-       snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
-       root = debugfs_create_dir(root_name, component->debugfs_root);
-       kfree(root_name);
+       root = debugfs_create_dir(dsp->name, component->debugfs_root);
 
        if (!root)
                goto err;
@@ -684,8 +678,8 @@ static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 }
 #endif
 
-static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -695,9 +689,10 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
 
-static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -721,8 +716,9 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
 
-static const struct soc_enum wm_adsp_fw_enum[] = {
+const struct soc_enum wm_adsp_fw_enum[] = {
        SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
        SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
        SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
@@ -731,24 +727,7 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
        SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
        SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 };
-
-const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
-       SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-};
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
 
 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
                                                        int type)
@@ -1330,12 +1309,12 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
        switch (dsp->fw_ver) {
        case 0:
        case 1:
-               snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
-                        dsp->num, region_name, alg_region->alg);
+               snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
+                        dsp->name, region_name, alg_region->alg);
                break;
        default:
                ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
-                               "DSP%d%c %.12s %x", dsp->num, *region_name,
+                               "%s%c %.12s %x", dsp->name, *region_name,
                                wm_adsp_fw_text[dsp->fw], alg_region->alg);
 
                /* Truncate the subname from the start if it is too long */
@@ -1343,6 +1322,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
                        int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
                        int skip = 0;
 
+                       if (dsp->component->name_prefix)
+                               avail -= strlen(dsp->component->name_prefix) + 1;
+
                        if (subname_len > avail)
                                skip = subname_len - avail;
 
@@ -1604,6 +1586,15 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
                        if (ret)
                                return -EINVAL;
                        break;
+               case WMFW_CTL_TYPE_HOST_BUFFER:
+                       ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+                                               WMFW_CTL_FLAG_SYS |
+                                               WMFW_CTL_FLAG_VOLATILE |
+                                               WMFW_CTL_FLAG_READABLE,
+                                               0);
+                       if (ret)
+                               return -EINVAL;
+                       break;
                default:
                        adsp_err(dsp, "Unknown control type: %d\n",
                                 coeff_blk.ctl_type);
@@ -1651,7 +1642,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
        if (file == NULL)
                return -ENOMEM;
 
-       snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
+       snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
                 wm_adsp_fw[dsp->fw].file);
        file[PAGE_SIZE - 1] = '\0';
 
@@ -1871,9 +1862,11 @@ static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
 }
 
 static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
+                              const struct wm_adsp_region *mem,
                               unsigned int pos, unsigned int len)
 {
        void *alg;
+       unsigned int reg;
        int ret;
        __be32 val;
 
@@ -1888,7 +1881,9 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
        }
 
        /* Read the terminator first to validate the length */
-       ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
+       reg = wm_adsp_region_to_reg(mem, pos + len);
+
+       ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
        if (ret != 0) {
                adsp_err(dsp, "Failed to read algorithm list end: %d\n",
                        ret);
@@ -1897,13 +1892,18 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
 
        if (be32_to_cpu(val) != 0xbedead)
                adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
-                         pos + len, be32_to_cpu(val));
+                         reg, be32_to_cpu(val));
 
-       alg = kcalloc(len, 2, GFP_KERNEL | GFP_DMA);
+       /* Convert length from DSP words to bytes */
+       len *= sizeof(u32);
+
+       alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
        if (!alg)
                return ERR_PTR(-ENOMEM);
 
-       ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
+       reg = wm_adsp_region_to_reg(mem, pos);
+
+       ret = regmap_raw_read(dsp->regmap, reg, alg, len);
        if (ret != 0) {
                adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
                kfree(alg);
@@ -2002,10 +2002,11 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
        if (IS_ERR(alg_region))
                return PTR_ERR(alg_region);
 
-       pos = sizeof(adsp1_id) / 2;
-       len = (sizeof(*adsp1_alg) * n_algs) / 2;
+       /* Calculate offset and length in DSP words */
+       pos = sizeof(adsp1_id) / sizeof(u32);
+       len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
 
-       adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+       adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
        if (IS_ERR(adsp1_alg))
                return PTR_ERR(adsp1_alg);
 
@@ -2113,10 +2114,11 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
        if (IS_ERR(alg_region))
                return PTR_ERR(alg_region);
 
-       pos = sizeof(adsp2_id) / 2;
-       len = (sizeof(*adsp2_alg) * n_algs) / 2;
+       /* Calculate offset and length in DSP words */
+       pos = sizeof(adsp2_id) / sizeof(u32);
+       len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
 
-       adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+       adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
        if (IS_ERR(adsp2_alg))
                return PTR_ERR(adsp2_alg);
 
@@ -2218,7 +2220,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
        if (file == NULL)
                return -ENOMEM;
 
-       snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
+       snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
                 wm_adsp_fw[dsp->fw].file);
        file[PAGE_SIZE - 1] = '\0';
 
@@ -2390,8 +2392,38 @@ out:
        return ret;
 }
 
+static int wm_adsp_create_name(struct wm_adsp *dsp)
+{
+       char *p;
+
+       if (!dsp->name) {
+               dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
+                                          dsp->num);
+               if (!dsp->name)
+                       return -ENOMEM;
+       }
+
+       if (!dsp->fwf_name) {
+               p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+
+               dsp->fwf_name = p;
+               for (; *p != 0; ++p)
+                       *p = tolower(*p);
+       }
+
+       return 0;
+}
+
 int wm_adsp1_init(struct wm_adsp *dsp)
 {
+       int ret;
+
+       ret = wm_adsp_create_name(dsp);
+       if (ret)
+               return ret;
+
        INIT_LIST_HEAD(&dsp->alg_regions);
 
        mutex_init(&dsp->pwr_lock);
@@ -2664,7 +2696,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
        struct wm_adsp *dsp = &dsps[mc->shift - 1];
        char preload[32];
 
-       snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift);
+       snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
 
        dsp->preloaded = ucontrol->value.integer.value[0];
 
@@ -2859,17 +2891,14 @@ int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *comp
 {
        char preload[32];
 
-       snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
-
+       snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
        snd_soc_component_disable_pin(component, preload);
 
        wm_adsp2_init_debugfs(dsp, component);
 
        dsp->component = component;
 
-       return snd_soc_add_component_controls(component,
-                                         &wm_adsp_fw_controls[dsp->num - 1],
-                                         1);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
 
@@ -2885,6 +2914,10 @@ int wm_adsp2_init(struct wm_adsp *dsp)
 {
        int ret;
 
+       ret = wm_adsp_create_name(dsp);
+       if (ret)
+               return ret;
+
        switch (dsp->rev) {
        case 0:
                /*
@@ -3192,7 +3225,7 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
                                       buf->host_buf_ptr + field_offset, data);
 }
 
-static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
 {
        struct wm_adsp_alg_region *alg_region;
        struct wm_adsp *dsp = buf->dsp;
@@ -3231,6 +3264,61 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
        return 0;
 }
 
+static struct wm_coeff_ctl *
+wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf)
+{
+       struct wm_adsp *dsp = buf->dsp;
+       struct wm_coeff_ctl *ctl;
+
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
+                       continue;
+
+               if (!ctl->enabled)
+                       continue;
+
+               return ctl;
+       }
+
+       return NULL;
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+       struct wm_adsp *dsp = buf->dsp;
+       struct wm_coeff_ctl *ctl;
+       unsigned int reg;
+       u32 val;
+       int i, ret;
+
+       ctl = wm_adsp_find_host_buffer_ctrl(buf);
+       if (!ctl)
+               return wm_adsp_legacy_host_buf_addr(buf);
+
+       ret = wm_coeff_base_reg(ctl, &reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < 5; ++i) {
+               ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+               if (ret < 0)
+                       return ret;
+
+               if (val)
+                       break;
+
+               usleep_range(1000, 2000);
+       }
+
+       if (!val)
+               return -EIO;
+
+       buf->host_buf_ptr = be32_to_cpu(val);
+       adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+       return 0;
+}
+
 static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
 {
        const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
index bc6d359f05338428fc60fe8bdbaa917f0da200f9..4b8778b0b06cd4a7baa0310841d66d2d2760ca2e 100644 (file)
@@ -57,6 +57,8 @@ struct wm_adsp_compr_buf;
 
 struct wm_adsp {
        const char *part;
+       const char *name;
+       const char *fwf_name;
        int rev;
        int num;
        int type;
@@ -121,7 +123,11 @@ struct wm_adsp {
        .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
 
-extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
+#define WM_ADSP_FW_CONTROL(dspname, num) \
+       SOC_ENUM_EXT(dspname " Firmware", wm_adsp_fw_enum[num], \
+                    wm_adsp_fw_get, wm_adsp_fw_put)
+
+extern const struct soc_enum wm_adsp_fw_enum[];
 
 int wm_adsp1_init(struct wm_adsp *dsp);
 int wm_adsp2_init(struct wm_adsp *dsp);
@@ -144,6 +150,10 @@ int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
                           struct snd_ctl_elem_value *ucontrol);
 int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
                           struct snd_ctl_elem_value *ucontrol);
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+                  struct snd_ctl_elem_value *ucontrol);
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+                  struct snd_ctl_elem_value *ucontrol);
 
 int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
 int wm_adsp_compr_free(struct snd_compr_stream *stream);
index ec78b9da020fb169be6e8f7d84285efd39a0df58..0c3f50acb8b146d80773151c2493ad6be0e09802 100644 (file)
@@ -29,6 +29,7 @@
 /* Non-ALSA coefficient types start at 0x1000 */
 #define WMFW_CTL_TYPE_ACKED       0x1000 /* acked control */
 #define WMFW_CTL_TYPE_HOSTEVENT   0x1001 /* event control */
+#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
 
 struct wmfw_header {
        char magic[4];
index 807040bb39215a714626da890339966791c7ab38..a3206e65e5e54d3abc84eea1f66fd02cd512e0bb 100644 (file)
@@ -340,6 +340,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                 * rate is lowered.
                 */
                inv_fs = true;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_A:
                dev->mode = MOD_DSP_A;
                break;
index 47c0c821d325f4b14b50b16b8fb9043c06670861..f70db8412c7ccb17915b7cf914677d2e1da24f70 100644 (file)
@@ -320,12 +320,8 @@ static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
                handled_mask |= XUNDRN;
 
                substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
-               if (substream) {
-                       snd_pcm_stream_lock_irq(substream);
-                       if (snd_pcm_running(substream))
-                               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-                       snd_pcm_stream_unlock_irq(substream);
-               }
+               if (substream)
+                       snd_pcm_stop_xrun(substream);
        }
 
        if (!handled_mask)
@@ -355,12 +351,8 @@ static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
                handled_mask |= ROVRN;
 
                substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
-               if (substream) {
-                       snd_pcm_stream_lock_irq(substream);
-                       if (snd_pcm_running(substream))
-                               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-                       snd_pcm_stream_unlock_irq(substream);
-               }
+               if (substream)
+                       snd_pcm_stop_xrun(substream);
        }
 
        if (!handled_mask)
index 4a6750aa36379e30ff5480d7200b8c2a1e73b80f..44433b20435cce7778ea72ee54adf8445dbaca31 100644 (file)
@@ -1,14 +1,10 @@
-/*
- * Freescale Generic ASoC Sound Card driver with ASRC
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale Generic ASoC Sound Card driver with ASRC
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+//
+// Author: Nicolin Chen <nicoleotsuka@gmail.com>
 
 #include <linux/clk.h>
 #include <linux/i2c.h>
@@ -199,7 +195,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 
        mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        snd_mask_none(mask);
-       snd_mask_set(mask, (__force int)priv->asrc_format);
+       snd_mask_set_format(mask, priv->asrc_format);
 
        return 0;
 }
index adfb8135d73996949d4ac2fee2399ffc0354719e..528e8b108422971eea52655b55642ac5cdbe575d 100644 (file)
@@ -1,14 +1,10 @@
-/*
- * Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+//
+// Author: Nicolin Chen <nicoleotsuka@gmail.com>
 
 #include <linux/clk.h>
 #include <linux/delay.h>
index d558dd5499a595675a861d60f23cf121458ba337..c600751125700d70e43fe8c78845aeb3d1ea4179 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * fsl_asrc.h - Freescale ASRC ALSA SoC header file
  *
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
  *
  * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
  */
 
 #ifndef _FSL_ASRC_H
index 565e16d8fe853e9ec0f044f3f1eb1b23afb35430..1033ac6631b08ae0f419679835c89336ed5077b4 100644 (file)
@@ -1,14 +1,10 @@
-/*
- * Freescale ASRC ALSA SoC Platform (DMA) driver
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ASRC ALSA SoC Platform (DMA) driver
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+//
+// Author: Nicolin Chen <nicoleotsuka@gmail.com>
 
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
index 8f43110373b813b9ccd5151f2a617a06ceee08d2..c1d1d06783e53e4d545b3a1e5d7cd4dae275e0cc 100644 (file)
@@ -249,6 +249,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
                break;
        case ESAI_HCKT_EXTAL:
                ecr |= ESAI_ECR_ETI;
+               /* fall through */
        case ESAI_HCKR_EXTAL:
                ecr |= ESAI_ECR_ERI;
                break;
index 9b59d87b61bf7ae16248f520a2c58548286b85aa..740b90df44bb5108a29d05ab14cdb7bd2d281849 100644 (file)
@@ -1118,7 +1118,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
 
        for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
                for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
-                       rate_ideal = rate[index] * txclk_df * 64;
+                       rate_ideal = rate[index] * txclk_df * 64ULL;
                        if (round)
                                rate_actual = clk_round_rate(clk, rate_ideal);
                        else
index 7592b0406370dffd2076f2b1d36d8b1b4440c0ad..7f0fa4b5222318b95c7bf2c41f7bacd6dc47b9fe 100644 (file)
@@ -1,14 +1,10 @@
-/**
- * Freescale ALSA SoC Machine driver utility
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2010 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ALSA SoC Machine driver utility
+//
+// Author: Timur Tabi <timur@freescale.com>
+//
+// Copyright 2010 Freescale Semiconductor, Inc.
 
 #include <linux/module.h>
 #include <linux/of_address.h>
index 1687b66ef18eb5dee972d28fd1da334fa3fe6b6d..c5dc2a14b492ccb42e1ac65c7d1c6c82c03d1b3a 100644 (file)
@@ -1,13 +1,10 @@
-/**
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
  * Freescale ALSA SoC Machine driver utility
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
  * Copyright 2010 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
  */
 
 #ifndef _FSL_UTILS_H
index b99e0b5e00e9b98e2151fb6f4780d78467be4000..c29200cf755add249d6a05b2fce8d91365d9b031 100644 (file)
@@ -1,14 +1,7 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- * Copyright 2012 Linaro Ltd.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2012 Freescale Semiconductor, Inc.
+// Copyright 2012 Linaro Ltd.
 
 #include <linux/module.h>
 #include <linux/of.h>
index d93bacacbd5b4d018b0633b24f71cee60bf756e3..2094d2c8919f53651198a1a85f72456b67a6c6f3 100644 (file)
@@ -1,15 +1,12 @@
-/*
- * ASoC audio graph sound card support
- *
- * Copyright (C) 2016 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on ${LINUX}/sound/soc/generic/simple-card.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC audio graph sound card support
+//
+// Copyright (C) 2016 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// based on ${LINUX}/sound/soc/generic/simple-card.c
+
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
@@ -21,7 +18,6 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
-#include <sound/jack.h>
 #include <sound/simple_card_utils.h>
 
 struct graph_card_data {
@@ -32,6 +28,8 @@ struct graph_card_data {
                unsigned int mclk_fs;
        } *dai_props;
        unsigned int mclk_fs;
+       struct asoc_simple_jack hp_jack;
+       struct asoc_simple_jack mic_jack;
        struct snd_soc_dai_link *dai_link;
        struct gpio_desc *pa_gpio;
 };
@@ -278,6 +276,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
        return count;
 }
 
+static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
+{
+       struct graph_card_data *priv = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL);
+       if (ret < 0)
+               return ret;
+
+       ret = asoc_simple_card_init_mic(card, &priv->mic_jack, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static int asoc_graph_card_probe(struct platform_device *pdev)
 {
        struct graph_card_data *priv;
@@ -319,6 +333,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
        card->num_links = num;
        card->dapm_widgets = asoc_graph_card_dapm_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
+       card->probe     = asoc_graph_soc_card_probe;
 
        ret = asoc_graph_card_parse_of(priv);
        if (ret < 0) {
index 095ef6426d4217ec91e001aee1f8b6997a821651..92882e392d6cf5cbc3be46869dfada2b1393cba1 100644 (file)
@@ -1,17 +1,14 @@
-/*
- * ASoC audio graph SCU sound card support
- *
- * Copyright (C) 2017 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on
- *     ${LINUX}/sound/soc/generic/simple-scu-card.c
- *     ${LINUX}/sound/soc/generic/audio-graph-card.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC audio graph SCU sound card support
+//
+// Copyright (C) 2017 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// based on
+//     ${LINUX}/sound/soc/generic/simple-scu-card.c
+//     ${LINUX}/sound/soc/generic/audio-graph-card.c
+
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
index 3751a07de6aac1c6bab6e670abd9c91832fd7f51..d3f3f0fec74c09377adadcda097de5efc3c38991 100644 (file)
@@ -1,16 +1,17 @@
-/*
- * simple-card-utils.c
- *
- * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// simple-card-utils.c
+//
+// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/of_graph.h>
+#include <sound/jack.h>
 #include <sound/simple_card_utils.h>
 
 void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
@@ -419,6 +420,61 @@ int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
 
+int asoc_simple_card_init_jack(struct snd_soc_card *card,
+                              struct asoc_simple_jack *sjack,
+                              int is_hp, char *prefix)
+{
+       struct device *dev = card->dev;
+       enum of_gpio_flags flags;
+       char prop[128];
+       char *pin_name;
+       char *gpio_name;
+       int mask;
+       int det;
+
+       if (!prefix)
+               prefix = "";
+
+       sjack->gpio.gpio = -ENOENT;
+
+       if (is_hp) {
+               snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
+               pin_name        = "Headphones";
+               gpio_name       = "Headphone detection";
+               mask            = SND_JACK_HEADPHONE;
+       } else {
+               snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
+               pin_name        = "Mic Jack";
+               gpio_name       = "Mic detection";
+               mask            = SND_JACK_MICROPHONE;
+       }
+
+       det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
+       if (det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       if (gpio_is_valid(det)) {
+               sjack->pin.pin          = pin_name;
+               sjack->pin.mask         = mask;
+
+               sjack->gpio.name        = gpio_name;
+               sjack->gpio.report      = mask;
+               sjack->gpio.gpio        = det;
+               sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
+               sjack->gpio.debounce_time = 150;
+
+               snd_soc_card_jack_new(card, pin_name, mask,
+                                     &sjack->jack,
+                                     &sjack->pin, 1);
+
+               snd_soc_jack_add_gpios(&sjack->jack, 1,
+                                      &sjack->gpio);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_init_jack);
+
 /* Module information */
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
index 8b374af86a6e26e7b0af5efa4e45d0fa84c14983..64bf3560c1d1c4af58e6191a4dd22fe93bccac49 100644 (file)
@@ -1,32 +1,20 @@
-/*
- * ASoC simple sound card support
- *
- * Copyright (C) 2012 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC simple sound card support
+//
+// Copyright (C) 2012 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include <linux/clk.h>
 #include <linux/device.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
-#include <sound/jack.h>
 #include <sound/simple_card.h>
 #include <sound/soc-dai.h>
 #include <sound/soc.h>
 
-struct asoc_simple_jack {
-       struct snd_soc_jack jack;
-       struct snd_soc_jack_pin pin;
-       struct snd_soc_jack_gpio gpio;
-};
-
 struct simple_card_data {
        struct snd_soc_card snd_card;
        struct simple_dai_props {
@@ -49,61 +37,6 @@ struct simple_card_data {
 #define CELL   "#sound-dai-cells"
 #define PREFIX "simple-audio-card,"
 
-#define asoc_simple_card_init_hp(card, sjack, prefix)\
-       asoc_simple_card_init_jack(card, sjack, 1, prefix)
-#define asoc_simple_card_init_mic(card, sjack, prefix)\
-       asoc_simple_card_init_jack(card, sjack, 0, prefix)
-static int asoc_simple_card_init_jack(struct snd_soc_card *card,
-                                     struct asoc_simple_jack *sjack,
-                                     int is_hp, char *prefix)
-{
-       struct device *dev = card->dev;
-       enum of_gpio_flags flags;
-       char prop[128];
-       char *pin_name;
-       char *gpio_name;
-       int mask;
-       int det;
-
-       sjack->gpio.gpio = -ENOENT;
-
-       if (is_hp) {
-               snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
-               pin_name        = "Headphones";
-               gpio_name       = "Headphone detection";
-               mask            = SND_JACK_HEADPHONE;
-       } else {
-               snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
-               pin_name        = "Mic Jack";
-               gpio_name       = "Mic detection";
-               mask            = SND_JACK_MICROPHONE;
-       }
-
-       det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
-       if (det == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
-
-       if (gpio_is_valid(det)) {
-               sjack->pin.pin          = pin_name;
-               sjack->pin.mask         = mask;
-
-               sjack->gpio.name        = gpio_name;
-               sjack->gpio.report      = mask;
-               sjack->gpio.gpio        = det;
-               sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
-               sjack->gpio.debounce_time = 150;
-
-               snd_soc_card_jack_new(card, pin_name, mask,
-                                     &sjack->jack,
-                                     &sjack->pin, 1);
-
-               snd_soc_jack_add_gpios(&sjack->jack, 1,
-                                      &sjack->gpio);
-       }
-
-       return 0;
-}
-
 static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -213,14 +146,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        if (ret < 0)
                return ret;
 
-       ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
-       if (ret < 0)
-               return ret;
-
-       ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
@@ -414,6 +339,22 @@ card_parse_end:
        return ret;
 }
 
+static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
+{
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
+       if (ret < 0)
+               return ret;
+
+       ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static int asoc_simple_card_probe(struct platform_device *pdev)
 {
        struct simple_card_data *priv;
@@ -449,6 +390,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        card->dev               = dev;
        card->dai_link          = priv->dai_link;
        card->num_links         = num;
+       card->probe             = asoc_simple_soc_card_probe;
 
        if (np && of_device_is_available(np)) {
 
index 487716559deb6c58762f8c1441264366102387ae..16a83bc51e0e5f1bbb30146c0d39e1ef0cb58315 100644 (file)
@@ -1,15 +1,12 @@
-/*
- * ASoC simple SCU sound card support
- *
- * Copyright (C) 2015 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on ${LINUX}/sound/soc/generic/simple-card.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC simple SCU sound card support
+//
+// Copyright (C) 2015 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// based on ${LINUX}/sound/soc/generic/simple-card.c
+
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/module.h>
index 6a8b253c58d254e9cdaf754747801dc3e1c4efb1..5455d6e0ab53cc60271c90f16afaed3689bdf0fd 100644 (file)
@@ -266,17 +266,15 @@ static int sst_cdev_ack(struct device *dev, unsigned int str_id,
        stream->cumm_bytes += bytes;
        dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
 
-       memcpy_fromio(&fw_tstamp,
-               ((void *)(ctx->mailbox + ctx->tstamp)
-               +(str_id * sizeof(fw_tstamp))),
-               sizeof(fw_tstamp));
+       addr =  ((void __iomem *)(ctx->mailbox + ctx->tstamp)) +
+               (str_id * sizeof(fw_tstamp));
+
+       memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
 
        fw_tstamp.bytes_copied = stream->cumm_bytes;
        dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
                        fw_tstamp.bytes_copied, bytes);
 
-       addr =  ((void *)(ctx->mailbox + ctx->tstamp)) +
-                       (str_id * sizeof(fw_tstamp));
        offset =  offsetof(struct snd_sst_tstamp, bytes_copied);
        sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
        return 0;
@@ -360,11 +358,12 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
        struct snd_sst_tstamp fw_tstamp = {0,};
        struct stream_info *stream;
        struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       void __iomem *addr;
+
+       addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) +
+               (str_id * sizeof(fw_tstamp));
 
-       memcpy_fromio(&fw_tstamp,
-               ((void *)(ctx->mailbox + ctx->tstamp)
-               +(str_id * sizeof(fw_tstamp))),
-               sizeof(fw_tstamp));
+       memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
 
        stream = get_stream_info(ctx, str_id);
        if (!stream)
@@ -530,6 +529,7 @@ static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
        struct snd_sst_tstamp fw_tstamp;
        unsigned int str_id;
        struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       void __iomem *addr;
 
        str_id = info->str_id;
        stream = get_stream_info(ctx, str_id);
@@ -540,10 +540,11 @@ static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
                return -EINVAL;
        substream = stream->pcm_substream;
 
-       memcpy_fromio(&fw_tstamp,
-               ((void *)(ctx->mailbox + ctx->tstamp)
-                       + (str_id * sizeof(fw_tstamp))),
-               sizeof(fw_tstamp));
+       addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) +
+               (str_id * sizeof(fw_tstamp));
+
+       memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
+
        return sst_calc_tstamp(ctx, info, substream, &fw_tstamp);
 }
 
index a686eef2cf7f7a1a4a7f7f23a00808122734a850..27413ebae9566eb356abbd44ec4bb62b9e5cdc90 100644 (file)
@@ -44,15 +44,15 @@ void memcpy32_toio(void __iomem *dst, const void *src, int count)
        /* __iowrite32_copy uses 32-bit count values so divide by 4 for
         * right count in words
         */
-       __iowrite32_copy(dst, src, count/4);
+       __iowrite32_copy(dst, src, count / 4);
 }
 
 void memcpy32_fromio(void *dst, const void __iomem *src, int count)
 {
-       /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+       /* __ioread32_copy uses 32-bit count values so divide by 4 for
         * right count in words
         */
-       __iowrite32_copy(dst, src, count/4);
+       __ioread32_copy(dst, src, count / 4);
 }
 
 /**
index 24797482a3d22d231a73a6e9ba0ff8e4af53a622..cccda87f4b34f12314cb45636a28782fda77ed93 100644 (file)
@@ -281,6 +281,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
          Say Y if you have such a device.
          If unsure select "N".
 
+config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
+       tristate "GLK with RT5682 and MAX98357A in I2S Mode"
+       depends on MFD_INTEL_LPSS && I2C && ACPI
+       select SND_SOC_RT5682
+       select SND_SOC_MAX98357A
+       select SND_SOC_DMIC
+       select SND_SOC_HDAC_HDMI
+       select SND_HDA_DSP_LOADER
+       help
+          This adds support for ASoC machine driver for Geminilake platforms
+          with RT5682 + MAX98357A I2S audio codec.
+          Say Y if you have such a device.
+          If unsure select "N".
+
 endif ## SND_SOC_INTEL_SKYLAKE
 
 endif ## SND_SOC_INTEL_MACH
index 92b5507291af49ff7caf979248f77aa90ee141b6..87ef8b4058e5831f9f21d76e0a815405952f09aa 100644 (file)
@@ -6,6 +6,7 @@ snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
 snd-soc-sst-broadwell-objs := broadwell.o
 snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
 snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
+snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o
 snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
 snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
 obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
index 6ea360f33575ae8520a6cd4dccca6fbd309ae801..efcfd906c8562b6dc13086ce18fc0e7f008705df 100644 (file)
@@ -154,9 +154,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
        channels->min = channels->max = 2;
 
        /* set SSP0 to 16 bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S16_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
        return 0;
 }
 
index 40eb979d5ac1d99b62e0030b495d444be6078bd6..6f052fc8d1e25aa3394cd0cdd242ae8cae6ec72a 100644 (file)
@@ -160,7 +160,7 @@ static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP to 24 bit */
        snd_mask_none(fmt);
-       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 
        return 0;
 }
@@ -324,8 +324,22 @@ static const struct snd_pcm_hw_constraint_list constraints_16000 = {
        .list  = rates_16000,
 };
 
+static const unsigned int ch_mono[] = {
+       1,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_refcap = {
+       .count = ARRAY_SIZE(ch_mono),
+       .list  = ch_mono,
+};
+
 static int broxton_refcap_startup(struct snd_pcm_substream *substream)
 {
+       substream->runtime->hw.channels_max = 1;
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &constraints_refcap);
+
        return snd_pcm_hw_constraint_list(substream->runtime, 0,
                        SNDRV_PCM_HW_PARAM_RATE,
                        &constraints_16000);
@@ -586,7 +600,7 @@ static int broxton_audio_probe(struct platform_device *pdev)
 static struct platform_driver broxton_audio = {
        .probe = broxton_audio_probe,
        .driver = {
-               .name = "bxt_da7219_max98357a_i2s",
+               .name = "bxt_da7219_max98357a",
                .pm = &snd_soc_pm_ops,
        },
 };
@@ -599,4 +613,4 @@ MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>");
 MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bxt_da7219_max98357a_i2s");
+MODULE_ALIAS("platform:bxt_da7219_max98357a");
index b68c289558a8d41a0d1b80dea4b4bd5bf41c176b..27308337ab127a22071369056d471d8c69b1ce81 100644 (file)
@@ -221,7 +221,7 @@ static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP5 to 24 bit */
        snd_mask_none(fmt);
-       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 
        return 0;
 }
index 33065ba294a93b3a69f6bf814443483e6e26cc4f..d32844f94d74b87243e4a16d61311d2c92121dd4 100644 (file)
@@ -404,7 +404,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                },
                .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
                                        BYT_RT5640_JD_SRC_JD1_IN4P |
-                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_TH_1500UA |
                                        BYT_RT5640_OVCD_SF_0P75 |
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
@@ -463,6 +463,22 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {
+               /* Chuwi Vi10 (CWI505) */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"),
+                       DMI_MATCH(DMI_BOARD_NAME, "BYT-PF02"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "ilife"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "S165"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_DIFF_MIC |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
@@ -470,6 +486,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                },
                .driver_data = (void *)(BYT_RT5640_DMIC1_MAP),
        },
+       {       /* Connect Tablet 9 */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Connect"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Tablet 9"),
+               },
+               .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -536,6 +562,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Lenovo Miix 2 8 */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "20326"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "Hiking"),
+               },
+               .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {       /* MSI S100 tablet */
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
@@ -549,6 +588,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_DIFF_MIC |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Nuvison/TMax TM800W560 */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TMAX"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TM800W560L"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_JD_NOT_INV |
+                                       BYT_RT5640_DIFF_MIC |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {       /* Pipo W4 */
                .matches = {
                        DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
index 987720e203f9160717af035bc8d859895fc9fc6f..f8a68bdb388581b600aabe36d1209124e51c6759 100644 (file)
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/dmi.h>
+#include <linux/input.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
 #include <asm/platform_sst_audio.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -42,8 +46,6 @@ enum {
        BYT_RT5651_IN1_MAP,
        BYT_RT5651_IN2_MAP,
        BYT_RT5651_IN1_IN2_MAP,
-       BYT_RT5651_IN1_HS_IN3_MAP,
-       BYT_RT5651_IN2_HS_IN3_MAP,
 };
 
 enum {
@@ -76,21 +78,26 @@ enum {
 #define BYT_RT5651_SSP2_AIF2           BIT(19) /* default is using AIF1  */
 #define BYT_RT5651_SSP0_AIF1           BIT(20)
 #define BYT_RT5651_SSP0_AIF2           BIT(21)
+#define BYT_RT5651_HP_LR_SWAPPED       BIT(22)
+#define BYT_RT5651_MONO_SPEAKER                BIT(23)
+
+#define BYT_RT5651_DEFAULT_QUIRKS      (BYT_RT5651_MCLK_EN | \
+                                        BYT_RT5651_JD1_1   | \
+                                        BYT_RT5651_OVCD_TH_2000UA | \
+                                        BYT_RT5651_OVCD_SF_0P75)
 
 /* jack-detect-source + dmic-en + ovcd-th + -sf + terminating empty entry */
 #define MAX_NO_PROPS 5
 
 struct byt_rt5651_private {
        struct clk *mclk;
+       struct gpio_desc *ext_amp_gpio;
        struct snd_soc_jack jack;
 };
 
 /* Default: jack-detect on JD1_1, internal mic on in2, headsetmic on in3 */
-static unsigned long byt_rt5651_quirk = BYT_RT5651_MCLK_EN |
-                                       BYT_RT5651_JD1_1 |
-                                       BYT_RT5651_OVCD_TH_2000UA |
-                                       BYT_RT5651_OVCD_SF_0P75 |
-                                       BYT_RT5651_IN2_HS_IN3_MAP;
+static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS |
+                                       BYT_RT5651_IN2_MAP;
 
 static void log_quirks(struct device *dev)
 {
@@ -100,10 +107,8 @@ static void log_quirks(struct device *dev)
                dev_info(dev, "quirk IN1_MAP enabled");
        if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
                dev_info(dev, "quirk IN2_MAP enabled");
-       if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_HS_IN3_MAP)
-               dev_info(dev, "quirk IN1_HS_IN3_MAP enabled");
-       if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_HS_IN3_MAP)
-               dev_info(dev, "quirk IN2_HS_IN3_MAP enabled");
+       if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_IN2_MAP)
+               dev_info(dev, "quirk IN1_IN2_MAP enabled");
        if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) {
                dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
                         BYT_RT5651_JDSRC(byt_rt5651_quirk));
@@ -124,6 +129,8 @@ static void log_quirks(struct device *dev)
                dev_info(dev, "quirk SSP0_AIF1 enabled\n");
        if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)
                dev_info(dev, "quirk SSP0_AIF2 enabled\n");
+       if (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER)
+               dev_info(dev, "quirk MONO_SPEAKER enabled\n");
 }
 
 #define BYT_CODEC_DAI1 "rt5651-aif1"
@@ -211,6 +218,20 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int rt5651_ext_amp_power_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_card *card = w->dapm->card;
+       struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpiod_set_value_cansleep(priv->ext_amp_gpio, 1);
+       else
+               gpiod_set_value_cansleep(priv->ext_amp_gpio, 0);
+
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -220,7 +241,9 @@ static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
        SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
                            platform_clock_control, SND_SOC_DAPM_PRE_PMU |
                            SND_SOC_DAPM_POST_PMD),
-
+       SND_SOC_DAPM_SUPPLY("Ext Amp Power", SND_SOC_NOPM, 0, 0,
+                           rt5651_ext_amp_power_event,
+                           SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 };
 
 static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
@@ -228,6 +251,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
        {"Headset Mic", NULL, "Platform Clock"},
        {"Internal Mic", NULL, "Platform Clock"},
        {"Speaker", NULL, "Platform Clock"},
+       {"Speaker", NULL, "Ext Amp Power"},
        {"Line In", NULL, "Platform Clock"},
 
        {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
@@ -241,38 +265,26 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
 };
 
 static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = {
-       {"IN2P", NULL, "Headset Mic"},
        {"DMIC L1", NULL, "Internal Mic"},
        {"DMIC R1", NULL, "Internal Mic"},
+       {"IN3P", NULL, "Headset Mic"},
 };
 
 static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = {
        {"Internal Mic", NULL, "micbias1"},
        {"IN1P", NULL, "Internal Mic"},
-       {"IN2P", NULL, "Headset Mic"},
+       {"IN3P", NULL, "Headset Mic"},
 };
 
 static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
        {"Internal Mic", NULL, "micbias1"},
-       {"IN1P", NULL, "Headset Mic"},
-       {"IN2P", NULL, "Internal Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
-       {"Internal Mic", NULL, "micbias1"},
-       {"IN1P", NULL, "Internal Mic"},
        {"IN2P", NULL, "Internal Mic"},
        {"IN3P", NULL, "Headset Mic"},
 };
 
-static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_hs_in3_map[] = {
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
        {"Internal Mic", NULL, "micbias1"},
        {"IN1P", NULL, "Internal Mic"},
-       {"IN3P", NULL, "Headset Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_hs_in3_map[] = {
-       {"Internal Mic", NULL, "micbias1"},
        {"IN2P", NULL, "Internal Mic"},
        {"IN3P", NULL, "Headset Mic"},
 };
@@ -357,46 +369,72 @@ static int byt_rt5651_quirk_cb(const struct dmi_system_id *id)
 
 static const struct dmi_system_id byt_rt5651_quirk_table[] = {
        {
+               /* Chuwi Hi8 Pro (CWI513) */
                .callback = byt_rt5651_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"),
                },
-               .driver_data = (void *)(BYT_RT5651_IN1_HS_IN3_MAP),
+               .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+                                       BYT_RT5651_IN2_MAP |
+                                       BYT_RT5651_HP_LR_SWAPPED |
+                                       BYT_RT5651_MONO_SPEAKER),
        },
        {
+               /* Chuwi Vi8 Plus (CWI519) */
                .callback = byt_rt5651_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ADI"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"),
                },
-               .driver_data = (void *)(BYT_RT5651_MCLK_EN |
-                                       BYT_RT5651_IN1_HS_IN3_MAP),
+               .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+                                       BYT_RT5651_IN2_MAP |
+                                       BYT_RT5651_HP_LR_SWAPPED |
+                                       BYT_RT5651_MONO_SPEAKER),
+       },
+       {
+               /* I.T.Works TW701, Ployer Momo7w and Trekstor ST70416-6
+                * (these all use the same mainboard) */
+               .callback = byt_rt5651_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "INSYDE Corp."),
+                       /* Partial match for all of itWORKS.G.WI71C.JGBMRBA,
+                        * TREK.G.WI71C.JGBMRBA0x and MOMO.G.WI71C.MABMRBA02 */
+                       DMI_MATCH(DMI_BIOS_VERSION, ".G.WI71C."),
+               },
+               .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+                                       BYT_RT5651_IN2_MAP |
+                                       BYT_RT5651_SSP0_AIF1 |
+                                       BYT_RT5651_MONO_SPEAKER),
        },
        {
+               /* KIANO SlimNote 14.2 */
                .callback = byt_rt5651_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
                },
-               .driver_data = (void *)(BYT_RT5651_MCLK_EN |
-                                       BYT_RT5651_JD1_1 |
-                                       BYT_RT5651_OVCD_TH_2000UA |
-                                       BYT_RT5651_OVCD_SF_0P75 |
+               .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
                                        BYT_RT5651_IN1_IN2_MAP),
        },
        {
-               /* Chuwi Vi8 Plus (CWI519) */
+               /* Minnowboard Max B3 */
                .callback = byt_rt5651_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+               },
+               .driver_data = (void *)(BYT_RT5651_IN1_MAP),
+       },
+       {
+               /* Minnowboard Turbot */
+               .callback = byt_rt5651_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ADI"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"),
                },
                .driver_data = (void *)(BYT_RT5651_MCLK_EN |
-                                       BYT_RT5651_JD1_1 |
-                                       BYT_RT5651_OVCD_TH_2000UA |
-                                       BYT_RT5651_OVCD_SF_0P75 |
-                                       BYT_RT5651_IN2_HS_IN3_MAP),
+                                       BYT_RT5651_IN1_MAP),
        },
        {
                /* VIOS LTH17 */
@@ -405,11 +443,24 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "VIOS"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "LTH17"),
                },
-               .driver_data = (void *)(BYT_RT5651_MCLK_EN |
+               .driver_data = (void *)(BYT_RT5651_IN1_IN2_MAP |
                                        BYT_RT5651_JD1_1 |
                                        BYT_RT5651_OVCD_TH_2000UA |
                                        BYT_RT5651_OVCD_SF_1P0 |
-                                       BYT_RT5651_IN1_IN2_MAP),
+                                       BYT_RT5651_MCLK_EN),
+       },
+       {
+               /* Yours Y8W81 (and others using the same mainboard) */
+               .callback = byt_rt5651_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "INSYDE Corp."),
+                       /* Partial match for all devs with a W86C mainboard */
+                       DMI_MATCH(DMI_BIOS_VERSION, ".F.W86C."),
+               },
+               .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+                                       BYT_RT5651_IN2_MAP |
+                                       BYT_RT5651_SSP0_AIF1 |
+                                       BYT_RT5651_MONO_SPEAKER),
        },
        {}
 };
@@ -418,15 +469,10 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
  * Note this MUST be called before snd_soc_register_card(), so that the props
  * are in place before the codec component driver's probe function parses them.
  */
-static int byt_rt5651_add_codec_device_props(const char *i2c_dev_name)
+static int byt_rt5651_add_codec_device_props(struct device *i2c_dev)
 {
        struct property_entry props[MAX_NO_PROPS] = {};
-       struct device *i2c_dev;
-       int ret, cnt = 0;
-
-       i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name);
-       if (!i2c_dev)
-               return -EPROBE_DEFER;
+       int cnt = 0;
 
        props[cnt++] = PROPERTY_ENTRY_U32("realtek,jack-detect-source",
                                BYT_RT5651_JDSRC(byt_rt5651_quirk));
@@ -440,10 +486,7 @@ static int byt_rt5651_add_codec_device_props(const char *i2c_dev_name)
        if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN)
                props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,dmic-en");
 
-       ret = device_add_properties(i2c_dev, props);
-       put_device(i2c_dev);
-
-       return ret;
+       return device_add_properties(i2c_dev, props);
 }
 
 static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
@@ -475,14 +518,6 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
                custom_map = byt_rt5651_intmic_in1_in2_map;
                num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
                break;
-       case BYT_RT5651_IN1_HS_IN3_MAP:
-               custom_map = byt_rt5651_intmic_in1_hs_in3_map;
-               num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_hs_in3_map);
-               break;
-       case BYT_RT5651_IN2_HS_IN3_MAP:
-               custom_map = byt_rt5651_intmic_in2_hs_in3_map;
-               num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_hs_in3_map);
-               break;
        default:
                custom_map = byt_rt5651_intmic_dmic_map;
                num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
@@ -546,13 +581,17 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
 
        if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) {
                ret = snd_soc_card_jack_new(runtime->card, "Headset",
-                                   SND_JACK_HEADSET, &priv->jack,
-                                   bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins));
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                   &priv->jack, bytcr_jack_pins,
+                                   ARRAY_SIZE(bytcr_jack_pins));
                if (ret) {
                        dev_err(runtime->dev, "jack creation failed %d\n", ret);
                        return ret;
                }
 
+               snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
+                                KEY_PLAYPAUSE);
+
                ret = snd_soc_component_set_jack(codec, &priv->jack, NULL);
                if (ret)
                        return ret;
@@ -691,6 +730,48 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
 };
 
 /* SoC card */
+static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
+static char byt_rt5651_codec_aif_name[12]; /*  = "rt5651-aif[1|2]" */
+static char byt_rt5651_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
+static char byt_rt5651_long_name[50]; /* = "bytcr-rt5651-*-spk-*-mic[-swapped-hp]" */
+
+static int byt_rt5651_suspend(struct snd_soc_card *card)
+{
+       struct snd_soc_component *component;
+
+       if (!BYT_RT5651_JDSRC(byt_rt5651_quirk))
+               return 0;
+
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (!strcmp(component->name, byt_rt5651_codec_name)) {
+                       dev_dbg(component->dev, "disabling jack detect before suspend\n");
+                       snd_soc_component_set_jack(component, NULL, NULL);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int byt_rt5651_resume(struct snd_soc_card *card)
+{
+       struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_component *component;
+
+       if (!BYT_RT5651_JDSRC(byt_rt5651_quirk))
+               return 0;
+
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (!strcmp(component->name, byt_rt5651_codec_name)) {
+                       dev_dbg(component->dev, "re-enabling jack detect after resume\n");
+                       snd_soc_component_set_jack(component, &priv->jack, NULL);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 static struct snd_soc_card byt_rt5651_card = {
        .name = "bytcr-rt5651",
        .owner = THIS_MODULE,
@@ -701,23 +782,86 @@ static struct snd_soc_card byt_rt5651_card = {
        .dapm_routes = byt_rt5651_audio_map,
        .num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map),
        .fully_routed = true,
+       .suspend_pre = byt_rt5651_suspend,
+       .resume_post = byt_rt5651_resume,
 };
 
-static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
-static char byt_rt5651_codec_aif_name[12]; /*  = "rt5651-aif[1|2]" */
-static char byt_rt5651_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
-static char byt_rt5651_long_name[40]; /* = "bytcr-rt5651-*-spk-*-mic" */
+static const struct x86_cpu_id baytrail_cpu_ids[] = {
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, /* Valleyview */
+       {}
+};
+
+static const struct x86_cpu_id cherrytrail_cpu_ids[] = {
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },     /* Braswell */
+       {}
+};
+
+static const struct acpi_gpio_params first_gpio = { 0, 0, false };
+static const struct acpi_gpio_params second_gpio = { 1, 0, false };
+
+static const struct acpi_gpio_mapping byt_rt5651_amp_en_first[] = {
+       { "ext-amp-enable-gpios", &first_gpio, 1 },
+       { },
+};
 
-static bool is_valleyview(void)
+static const struct acpi_gpio_mapping byt_rt5651_amp_en_second[] = {
+       { "ext-amp-enable-gpios", &second_gpio, 1 },
+       { },
+};
+
+/*
+ * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, other
+ * boards may  have I2cSerialBusV2, GpioInt, GpioIo instead. We want the
+ * GpioIo one for the ext-amp-enable-gpio and both count for the index in
+ * acpi_gpio_params index.  So we have 2 different mappings and the code
+ * below figures out which one to use.
+ */
+struct byt_rt5651_acpi_resource_data {
+       int gpio_count;
+       int gpio_int_idx;
+};
+
+static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg)
 {
-       static const struct x86_cpu_id cpu_ids[] = {
-               { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
-               {}
-       };
-
-       if (!x86_match_cpu(cpu_ids))
-               return false;
-       return true;
+       struct byt_rt5651_acpi_resource_data *data = arg;
+
+       if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+               return 0;
+
+       if (ares->data.gpio.connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
+               data->gpio_int_idx = data->gpio_count;
+
+       data->gpio_count++;
+       return 0;
+}
+
+static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec)
+{
+       struct byt_rt5651_acpi_resource_data data = { 0, -1 };
+       LIST_HEAD(resources);
+       int ret;
+
+       ret = acpi_dev_get_resources(ACPI_COMPANION(codec), &resources,
+                                    snd_byt_rt5651_acpi_resource, &data);
+       if (ret < 0) {
+               dev_warn(codec, "Failed to get ACPI resources, not adding external amplifier GPIO mapping\n");
+               return;
+       }
+
+       /* All info we need is gathered during the walk */
+       acpi_dev_free_resource_list(&resources);
+
+       switch (data.gpio_int_idx) {
+       case 0:
+               devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_second);
+               break;
+       case 1:
+               devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_first);
+               break;
+       default:
+               dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n",
+                        data.gpio_int_idx);
+       }
 }
 
 struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
@@ -727,13 +871,12 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
 
 static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 {
-       const char * const intmic_name[] =
-               { "dmic", "in1", "in2", "in12", "in1", "in2" };
-       const char * const hsmic_name[] =
-               {  "in2", "in2", "in1",  "in3", "in3", "in3" };
+       const char * const mic_name[] = { "dmic", "in1", "in2", "in12" };
        struct byt_rt5651_private *priv;
        struct snd_soc_acpi_mach *mach;
+       struct device *codec_dev;
        const char *i2c_name = NULL;
+       const char *hp_swapped;
        bool is_bytcr = false;
        int ret_val = 0;
        int dai_index = 0;
@@ -767,11 +910,16 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
                "%s%s", "i2c-", i2c_name);
        byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name;
 
+       codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL,
+                                           byt_rt5651_codec_name);
+       if (!codec_dev)
+               return -EPROBE_DEFER;
+
        /*
         * swap SSP0 if bytcr is detected
         * (will be overridden if DMI quirk is detected)
         */
-       if (is_valleyview()) {
+       if (x86_match_cpu(baytrail_cpu_ids)) {
                struct sst_platform_info *p_info = mach->pdata;
                const struct sst_res_info *res_info = p_info->res_info;
 
@@ -830,9 +978,37 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
        dmi_check_system(byt_rt5651_quirk_table);
 
        /* Must be called before register_card, also see declaration comment. */
-       ret_val = byt_rt5651_add_codec_device_props(byt_rt5651_codec_name);
-       if (ret_val)
+       ret_val = byt_rt5651_add_codec_device_props(codec_dev);
+       if (ret_val) {
+               put_device(codec_dev);
                return ret_val;
+       }
+
+       /* Cherry Trail devices use an external amplifier enable gpio */
+       if (x86_match_cpu(cherrytrail_cpu_ids)) {
+               snd_byt_rt5651_mc_add_amp_en_gpio_mapping(codec_dev);
+               priv->ext_amp_gpio = devm_fwnode_get_index_gpiod_from_child(
+                                               &pdev->dev, "ext-amp-enable", 0,
+                                               codec_dev->fwnode,
+                                               GPIOD_OUT_LOW, "speaker-amp");
+               if (IS_ERR(priv->ext_amp_gpio)) {
+                       ret_val = PTR_ERR(priv->ext_amp_gpio);
+                       switch (ret_val) {
+                       case -ENOENT:
+                               priv->ext_amp_gpio = NULL;
+                               break;
+                       default:
+                               dev_err(&pdev->dev, "Failed to get ext-amp-enable GPIO: %d\n",
+                                       ret_val);
+                               /* fall through */
+                       case -EPROBE_DEFER:
+                               put_device(codec_dev);
+                               return ret_val;
+                       }
+               }
+       }
+
+       put_device(codec_dev);
 
        log_quirks(&pdev->dev);
 
@@ -876,10 +1052,16 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
                }
        }
 
+       if (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED)
+               hp_swapped = "-hp-swapped";
+       else
+               hp_swapped = "";
+
        snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name),
-                "bytcr-rt5651-%s-intmic-%s-hsmic",
-                intmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
-                hsmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)]);
+                "bytcr-rt5651-%s-spk-%s-mic%s",
+                (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ?
+                       "mono" : "stereo",
+                mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped);
        byt_rt5651_card.long_name = byt_rt5651_long_name;
 
        ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
new file mode 100644 (file)
index 0000000..c4b94e2
--- /dev/null
@@ -0,0 +1,643 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Intel Corporation.
+
+/*
+ * Intel Geminilake I2S Machine Driver with MAX98357A & RT5682 Codecs
+ *
+ * Modified from:
+ *   Intel Apollolake I2S Machine driver
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../skylake/skl.h"
+#include "../../codecs/rt5682.h"
+#include "../../codecs/hdac_hdmi.h"
+
+/* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */
+#define GLK_PLAT_CLK_FREQ 19200000
+#define RT5682_PLL_FREQ (48000 * 512)
+#define GLK_REALTEK_CODEC_DAI "rt5682-aif1"
+#define GLK_MAXIM_CODEC_DAI "HiFi"
+#define MAXIM_DEV0_NAME "MX98357A:00"
+#define DUAL_CHANNEL 2
+#define QUAD_CHANNEL 4
+#define NAME_SIZE 32
+
+static struct snd_soc_jack geminilake_hdmi[3];
+
+struct glk_hdmi_pcm {
+       struct list_head head;
+       struct snd_soc_dai *codec_dai;
+       int device;
+};
+
+struct glk_card_private {
+       struct snd_soc_jack geminilake_headset;
+       struct list_head hdmi_pcm_list;
+};
+
+enum {
+       GLK_DPCM_AUDIO_PB = 0,
+       GLK_DPCM_AUDIO_CP,
+       GLK_DPCM_AUDIO_HS_PB,
+       GLK_DPCM_AUDIO_ECHO_REF_CP,
+       GLK_DPCM_AUDIO_REF_CP,
+       GLK_DPCM_AUDIO_DMIC_CP,
+       GLK_DPCM_AUDIO_HDMI1_PB,
+       GLK_DPCM_AUDIO_HDMI2_PB,
+       GLK_DPCM_AUDIO_HDMI3_PB,
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret = 0;
+
+       codec_dai = snd_soc_card_get_codec_dai(card, GLK_REALTEK_CODEC_DAI);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
+               return -EIO;
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
+               if (ret)
+                       dev_err(card->dev, "failed to stop sysclk: %d\n", ret);
+       } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
+                                       GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ);
+               if (ret < 0) {
+                       dev_err(card->dev, "can't set codec pll: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (ret)
+               dev_err(card->dev, "failed to start internal clk: %d\n", ret);
+
+       return ret;
+}
+
+static const struct snd_kcontrol_new geminilake_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget geminilake_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("Spk", NULL),
+       SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+       SND_SOC_DAPM_SPK("HDMI1", NULL),
+       SND_SOC_DAPM_SPK("HDMI2", NULL),
+       SND_SOC_DAPM_SPK("HDMI3", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+                       platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route geminilake_map[] = {
+       /* HP jack connectors - unknown if we have jack detection */
+       { "Headphone Jack", NULL, "Platform Clock" },
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* speaker */
+       { "Spk", NULL, "Speaker" },
+
+       /* other jacks */
+       { "Headset Mic", NULL, "Platform Clock" },
+       { "IN1P", NULL, "Headset Mic" },
+
+       /* digital mics */
+       { "DMic", NULL, "SoC DMIC" },
+
+       /* CODEC BE connections */
+       { "HiFi Playback", NULL, "ssp1 Tx" },
+       { "ssp1 Tx", NULL, "codec0_out" },
+
+       { "AIF1 Playback", NULL, "ssp2 Tx" },
+       { "ssp2 Tx", NULL, "codec1_out" },
+
+       { "codec0_in", NULL, "ssp2 Rx" },
+       { "ssp2 Rx", NULL, "AIF1 Capture" },
+
+       { "HDMI1", NULL, "hif5-0 Output" },
+       { "HDMI2", NULL, "hif6-0 Output" },
+       { "HDMI2", NULL, "hif7-0 Output" },
+
+       { "hifi3", NULL, "iDisp3 Tx" },
+       { "iDisp3 Tx", NULL, "iDisp3_out" },
+       { "hifi2", NULL, "iDisp2 Tx" },
+       { "iDisp2 Tx", NULL, "iDisp2_out" },
+       { "hifi1", NULL, "iDisp1 Tx" },
+       { "iDisp1 Tx", NULL, "iDisp1_out" },
+
+       /* DMIC */
+       { "dmic01_hifi", NULL, "DMIC01 Rx" },
+       { "DMIC01 Rx", NULL, "DMIC AIF" },
+};
+
+static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = DUAL_CHANNEL;
+
+       /* set SSP to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_component *component = rtd->codec_dai->component;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_jack *jack;
+       int ret;
+
+       /* Configure sysclk for codec */
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
+                                       RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       /*
+        * Headset buttons map to the google Reference headset.
+        * These can be configured by userspace.
+        */
+       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                       &ctx->geminilake_headset, NULL, 0);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       jack = &ctx->geminilake_headset;
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+       ret = snd_soc_component_set_jack(component, jack, NULL);
+
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+};
+
+static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       /* Set valid bitmask & configuration for I2S in 24 bit */
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 24);
+       if (ret < 0) {
+               dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static struct snd_soc_ops geminilake_rt5682_ops = {
+       .hw_params = geminilake_rt5682_hw_params,
+};
+
+static int geminilake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct glk_hdmi_pcm *pcm;
+
+       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       pcm->device = GLK_DPCM_AUDIO_HDMI1_PB + dai->id;
+       pcm->codec_dai = dai;
+
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+static int geminilake_rt5682_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *component = rtd->cpu_dai->component;
+       struct snd_soc_dapm_context *dapm;
+       int ret;
+
+       dapm = snd_soc_component_get_dapm(component);
+       ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+       if (ret) {
+               dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static const unsigned int rates[] = {
+       48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static const unsigned int channels[] = {
+       DUAL_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static unsigned int channels_quad[] = {
+       QUAD_CHANNEL,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
+       .count = ARRAY_SIZE(channels_quad),
+       .list = channels_quad,
+       .mask = 0,
+};
+
+static int geminilake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *channels = hw_param_interval(params,
+                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /*
+        * set BE channel constraint as user FE channels
+        */
+       channels->min = channels->max = 4;
+
+       return 0;
+}
+
+static int geminilake_dmic_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                       &constraints_channels_quad);
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static const struct snd_soc_ops geminilake_dmic_ops = {
+       .startup = geminilake_dmic_startup,
+};
+
+static const unsigned int rates_16000[] = {
+       16000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
+       .count = ARRAY_SIZE(rates_16000),
+       .list  = rates_16000,
+};
+
+static int geminilake_refcap_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE,
+                               &constraints_16000);
+};
+
+static const struct snd_soc_ops geminilake_refcap_ops = {
+       .startup = geminilake_refcap_startup,
+};
+
+/* geminilake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link geminilake_dais[] = {
+       /* Front End DAI links */
+       [GLK_DPCM_AUDIO_PB] = {
+               .name = "Glk Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:0e.0",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .init = geminilake_rt5682_fe_init,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       [GLK_DPCM_AUDIO_CP] = {
+               .name = "Glk Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:0e.0",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+       },
+       [GLK_DPCM_AUDIO_HS_PB] = {
+               .name = "Glk Audio Headset Playback",
+               .stream_name = "Headset Audio",
+               .cpu_dai_name = "System Pin2",
+               .platform_name = "0000:00:0e.0",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .dpcm_playback = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [GLK_DPCM_AUDIO_ECHO_REF_CP] = {
+               .name = "Glk Audio Echo Reference cap",
+               .stream_name = "Echoreference Capture",
+               .cpu_dai_name = "Echoref Pin",
+               .platform_name = "0000:00:0e.0",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .init = NULL,
+               .capture_only = 1,
+               .nonatomic = 1,
+       },
+       [GLK_DPCM_AUDIO_REF_CP] = {
+               .name = "Glk Audio Reference cap",
+               .stream_name = "Refcap",
+               .cpu_dai_name = "Reference Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:0e.0",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &geminilake_refcap_ops,
+       },
+       [GLK_DPCM_AUDIO_DMIC_CP] = {
+               .name = "Glk Audio DMIC cap",
+               .stream_name = "dmiccap",
+               .cpu_dai_name = "DMIC Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:0e.0",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+               .ops = &geminilake_dmic_ops,
+       },
+       [GLK_DPCM_AUDIO_HDMI1_PB] = {
+               .name = "Glk HDMI Port1",
+               .stream_name = "Hdmi1",
+               .cpu_dai_name = "HDMI1 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:0e.0",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [GLK_DPCM_AUDIO_HDMI2_PB] =     {
+               .name = "Glk HDMI Port2",
+               .stream_name = "Hdmi2",
+               .cpu_dai_name = "HDMI2 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:0e.0",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [GLK_DPCM_AUDIO_HDMI3_PB] =     {
+               .name = "Glk HDMI Port3",
+               .stream_name = "Hdmi3",
+               .cpu_dai_name = "HDMI3 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:0e.0",
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .init = NULL,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       /* Back End DAI links */
+       {
+               /* SSP1 - Codec */
+               .name = "SSP1-Codec",
+               .id = 0,
+               .cpu_dai_name = "SSP1 Pin",
+               .platform_name = "0000:00:0e.0",
+               .no_pcm = 1,
+               .codec_name = MAXIM_DEV0_NAME,
+               .codec_dai_name = GLK_MAXIM_CODEC_DAI,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = geminilake_ssp_fixup,
+               .dpcm_playback = 1,
+       },
+       {
+               /* SSP2 - Codec */
+               .name = "SSP2-Codec",
+               .id = 1,
+               .cpu_dai_name = "SSP2 Pin",
+               .platform_name = "0000:00:0e.0",
+               .no_pcm = 1,
+               .codec_name = "i2c-10EC5682:00",
+               .codec_dai_name = GLK_REALTEK_CODEC_DAI,
+               .init = geminilake_rt5682_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = geminilake_ssp_fixup,
+               .ops = &geminilake_rt5682_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "dmic01",
+               .id = 2,
+               .cpu_dai_name = "DMIC01 Pin",
+               .codec_name = "dmic-codec",
+               .codec_dai_name = "dmic-hifi",
+               .platform_name = "0000:00:0e.0",
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = geminilake_dmic_fixup,
+               .dpcm_capture = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp1",
+               .id = 3,
+               .cpu_dai_name = "iDisp1 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:0e.0",
+               .init = geminilake_hdmi_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp2",
+               .id = 4,
+               .cpu_dai_name = "iDisp2 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi2",
+               .platform_name = "0000:00:0e.0",
+               .init = geminilake_hdmi_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp3",
+               .id = 5,
+               .cpu_dai_name = "iDisp3 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi3",
+               .platform_name = "0000:00:0e.0",
+               .init = geminilake_hdmi_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+static int glk_card_late_probe(struct snd_soc_card *card)
+{
+       struct glk_card_private *ctx = snd_soc_card_get_drvdata(card);
+       struct snd_soc_component *component = NULL;
+       char jack_name[NAME_SIZE];
+       struct glk_hdmi_pcm *pcm;
+       int err = 0;
+       int i = 0;
+
+       list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               component = pcm->codec_dai->component;
+               snprintf(jack_name, sizeof(jack_name),
+                       "HDMI/DP, pcm=%d Jack", pcm->device);
+               err = snd_soc_card_jack_new(card, jack_name,
+                                       SND_JACK_AVOUT, &geminilake_hdmi[i],
+                                       NULL, 0);
+
+               if (err)
+                       return err;
+
+               err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+                                               &geminilake_hdmi[i]);
+               if (err < 0)
+                       return err;
+
+               i++;
+       }
+
+       if (!component)
+               return -EINVAL;
+
+       return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+/* geminilake audio machine driver for SPT + RT5682 */
+static struct snd_soc_card glk_audio_card_rt5682_m98357a = {
+       .name = "glkrt5682max",
+       .owner = THIS_MODULE,
+       .dai_link = geminilake_dais,
+       .num_links = ARRAY_SIZE(geminilake_dais),
+       .controls = geminilake_controls,
+       .num_controls = ARRAY_SIZE(geminilake_controls),
+       .dapm_widgets = geminilake_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(geminilake_widgets),
+       .dapm_routes = geminilake_map,
+       .num_dapm_routes = ARRAY_SIZE(geminilake_map),
+       .fully_routed = true,
+       .late_probe = glk_card_late_probe,
+};
+
+static int geminilake_audio_probe(struct platform_device *pdev)
+{
+       struct glk_card_private *ctx;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+       glk_audio_card_rt5682_m98357a.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx);
+
+       return devm_snd_soc_register_card(&pdev->dev,
+                                       &glk_audio_card_rt5682_m98357a);
+}
+
+static const struct platform_device_id glk_board_ids[] = {
+       {
+               .name = "glk_rt5682_max98357a",
+               .driver_data =
+                       (kernel_ulong_t)&glk_audio_card_rt5682_m98357a,
+       },
+       { }
+};
+
+static struct platform_driver geminilake_audio = {
+       .probe = geminilake_audio_probe,
+       .driver = {
+               .name = "glk_rt5682_max98357a",
+               .pm = &snd_soc_pm_ops,
+       },
+       .id_table = glk_board_ids,
+};
+module_platform_driver(geminilake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mode");
+MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:glk_rt5682_max98357a");
index 94294c27d1dbf9b2774e2890d547859201c02ee2..38f6ab74709d06df483a22639d1fc40c48b8e263 100644 (file)
@@ -152,7 +152,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP to 24 bit */
        snd_mask_none(fmt);
-       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 
        return 0;
 }
@@ -380,6 +380,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
                .trigger = {
                        SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
                .dpcm_capture = 1,
+               .ops = &kabylake_da7219_fe_ops,
        },
        [KBL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Kbl Audio DMIC cap",
index 3a61252fe450dec7af275f2076d906dafe019899..21a6490746a6f9ab4611d7fd2de6dd96fe6cb042 100644 (file)
@@ -434,14 +434,14 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
                rate->min = rate->max = 48000;
                channels->min = channels->max = 2;
                snd_mask_none(fmt);
-               snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
        }
        /*
         * The speaker on the SSP0 supports S16_LE and not S24_LE.
         * thus changing the mask here
         */
        if (!strcmp(be_dai_link->name, "SSP0-Codec"))
-               snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 
        return 0;
 }
index 92f5fb2ae0a36bf9c75eedc02ca6724880103dd1..a892b37eab7c924bcf24a21fc2352c0fce13976a 100644 (file)
@@ -307,7 +307,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
                rate->min = rate->max = 48000;
                channels->min = channels->max = 2;
                snd_mask_none(fmt);
-               snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
        } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) {
                if (params_channels(params) == 2 ||
                                DMIC_CH(dmic_constraints) == 2)
@@ -320,7 +320,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
         * thus changing the mask here
         */
        if (!strcmp(be_dai_link->name, "SSP0-Codec"))
-               snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
 
        return 0;
 }
index 3ff6646cfa21a10347d4c0e3071dd369acf57da2..d31482b8c9bbb02a0dcbd6e1c74fe5e01db9f657 100644 (file)
@@ -157,7 +157,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP0 to 24 bit */
        snd_mask_none(fmt);
-       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 
        return 0;
 }
index b0610bba3cfab3bc65693c4b630d7f1101717e25..e877bb60beb10b3634efe82dcb5ae870e768b3a8 100644 (file)
@@ -346,7 +346,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP0 to 24 bit */
        snd_mask_none(fmt);
-       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
        return 0;
 }
 
index 38a1495c29cfbb84bfdf9fdc3cc3a62a53c0cffe..0e1818dd4cc69fec726ae29ee97d9756bb925c06 100644 (file)
@@ -229,7 +229,7 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
 
        /* set SSP0 to 24 bit */
        snd_mask_none(fmt);
-       snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
        return 0;
 }
 
index 7379d8830c391e422ec89d0c15f0e0d1fcc94ff4..915a34cdc8acbb2b8f281c377a4a45394aa6ed26 100644 (file)
@@ -3,7 +3,11 @@ snd-soc-sst-dsp-objs := sst-dsp.o
 snd-soc-sst-acpi-objs := sst-acpi.o
 snd-soc-sst-ipc-objs := sst-ipc.o
 snd-soc-sst-firmware-objs := sst-firmware.o
-snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o soc-acpi-intel-hsw-bdw-match.o
+snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \
+       soc-acpi-intel-hsw-bdw-match.o \
+       soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
+       soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
+       soc-acpi-intel-cnl-match.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
 obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
new file mode 100644 (file)
index 0000000..f39386e
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-bxt-match.c - tables and support for BXT ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static struct snd_soc_acpi_codecs bxt_codecs = {
+       .num_codecs = 1,
+       .codecs = {"MX98357A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
+       {
+               .id = "INT343A",
+               .drv_name = "bxt_alc298s_i2s",
+               .fw_filename = "intel/dsp_fw_bxtn.bin",
+       },
+       {
+               .id = "DLGS7219",
+               .drv_name = "bxt_da7219_max98357a",
+               .fw_filename = "intel/dsp_fw_bxtn.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &bxt_codecs,
+               .sof_fw_filename = "intel/sof-apl.ri",
+               .sof_tplg_filename = "intel/sof-apl-da7219.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
+       },
+       {
+               .id = "104C5122",
+               .drv_name = "bxt-pcm512x",
+               .sof_fw_filename = "intel/sof-apl.ri",
+               .sof_tplg_filename = "intel/sof-apl-pcm512x.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
+       },
+       {
+               .id = "1AEC8804",
+               .drv_name = "bxt-wm8804",
+               .sof_fw_filename = "intel/sof-apl.ri",
+               .sof_tplg_filename = "intel/sof-apl-wm8804.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
+       },
+       {
+               .id = "INT34C3",
+               .drv_name = "bxt_tdf8532",
+               .sof_fw_filename = "intel/sof-apl.ri",
+               .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_bxt_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
index bfe1ca68a54234ce512c6eb57f545ae49da0b8a0..4daa8a4f0c0c6907c176d66a9aad8fbf2df59218 100644 (file)
@@ -59,8 +59,8 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = {
        .drv_name = "cht-bsw-rt5672",
        .fw_filename = "intel/fw_sst_0f28.bin",
        .board = "cht-bsw",
-       .sof_fw_filename = "intel/reef-byt.ri",
-       .sof_tplg_filename = "intel/reef-byt-rt5670.tplg",
+       .sof_fw_filename = "intel/sof-byt.ri",
+       .sof_tplg_filename = "intel/sof-byt-rt5670.tplg",
        .asoc_plat_name = "sst-mfld-platform",
 };
 
@@ -98,8 +98,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "bytcr_rt5640",
                .machine_quirk = byt_quirk,
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-rt5640.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -107,8 +107,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "bytcr_rt5640",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "bytcr_rt5640",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-rt5640.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -116,8 +116,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "bytcr_rt5640",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "bytcr_rt5640",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-rt5640.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -125,8 +125,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "bytcr_rt5651",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "bytcr_rt5651",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-rt5651.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-rt5651.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -134,8 +134,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "bytcht_da7213",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "bytcht_da7213",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-da7213.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-da7213.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -143,8 +143,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "bytcht_da7213",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "bytcht_da7213",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-da7213.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-da7213.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        /* some Baytrail platforms rely on RT5645, use CHT machine driver */
@@ -153,8 +153,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "cht-bsw-rt5645",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-rt5645.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-rt5645.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -162,8 +162,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "cht-bsw-rt5645",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-rt5645.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-rt5645.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        /* use CHT driver to Baytrail Chromebooks */
@@ -172,8 +172,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_baytrail_machines[] = {
                .drv_name = "cht-bsw-max98090",
                .fw_filename = "intel/fw_sst_0f28.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-byt.ri",
-               .sof_tplg_filename = "intel/reef-byt-max98090.tplg",
+               .sof_fw_filename = "intel/sof-byt.ri",
+               .sof_tplg_filename = "intel/sof-byt-max98090.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
index ad1eb2d644beab3333aa58b5415136ced1509544..91bb99b69601dded2e7aa2aa299d50dd4651db22 100644 (file)
@@ -44,8 +44,8 @@ static struct snd_soc_acpi_mach cht_surface_mach = {
        .drv_name = "cht-bsw-rt5645",
        .fw_filename = "intel/fw_sst_22a8.bin",
        .board = "cht-bsw",
-       .sof_fw_filename = "intel/reef-cht.ri",
-       .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+       .sof_fw_filename = "intel/sof-cht.ri",
+       .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
        .asoc_plat_name = "sst-mfld-platform",
 };
 
@@ -68,8 +68,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-rt5672",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5670.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5670.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -77,8 +77,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-rt5672",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5670.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5670.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -86,8 +86,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-rt5645",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -95,8 +95,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-rt5645",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -104,8 +104,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-rt5645",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -113,8 +113,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-max98090",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-max98090.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-max98090.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -122,8 +122,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "cht-bsw-nau8824",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "cht-bsw",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-nau8824.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-nau8824.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -131,8 +131,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "bytcht_da7213",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "bytcht_da7213",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-da7213.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-da7213.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -140,8 +140,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "bytcht_da7213",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "bytcht_da7213",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-da7213.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-da7213.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -149,8 +149,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "bytcht_es8316",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "bytcht_es8316",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-es8316.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-es8316.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
@@ -160,8 +160,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "bytcr_rt5640",
                .machine_quirk = cht_quirk,
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5640.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5640.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        {
@@ -169,8 +169,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "bytcr_rt5640",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "bytcr_rt5640",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5640.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5640.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
        /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
@@ -179,8 +179,8 @@ struct snd_soc_acpi_mach  snd_soc_acpi_intel_cherrytrail_machines[] = {
                .drv_name = "bytcr_rt5651",
                .fw_filename = "intel/fw_sst_22a8.bin",
                .board = "bytcr_rt5651",
-               .sof_fw_filename = "intel/reef-cht.ri",
-               .sof_tplg_filename = "intel/reef-cht-rt5651.tplg",
+               .sof_fw_filename = "intel/sof-cht.ri",
+               .sof_tplg_filename = "intel/sof-cht-rt5651.tplg",
                .asoc_plat_name = "sst-mfld-platform",
        },
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
new file mode 100644 (file)
index 0000000..ec8e28e
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-cnl-match.c - tables and support for CNL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata cnl_pdata = {
+       .use_tplg_pcm = true,
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
+       {
+               .id = "INT34C2",
+               .drv_name = "cnl_rt274",
+               .fw_filename = "intel/dsp_fw_cnl.bin",
+               .pdata = &cnl_pdata,
+               .sof_fw_filename = "intel/sof-cnl.ri",
+               .sof_tplg_filename = "intel/sof-cnl-rt274.tplg",
+               .asoc_plat_name = "0000:00:1f.3",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
new file mode 100644 (file)
index 0000000..305875a
--- /dev/null
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-glk-match.c - tables and support for GLK ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static struct snd_soc_acpi_codecs glk_codecs = {
+       .num_codecs = 1,
+       .codecs = {"MX98357A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
+       {
+               .id = "INT343A",
+               .drv_name = "glk_alc298s_i2s",
+               .fw_filename = "intel/dsp_fw_glk.bin",
+               .sof_fw_filename = "intel/sof-glk.ri",
+               .sof_tplg_filename = "intel/sof-glk-alc298.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
+       },
+       {
+               .id = "DLGS7219",
+               .drv_name = "glk_da7219_max98357a",
+               .fw_filename = "intel/dsp_fw_glk.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &glk_codecs,
+               .sof_fw_filename = "intel/sof-glk.ri",
+               .sof_tplg_filename = "intel/sof-glk-da7219.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
index e0e8c8c27528cb89ae4781e2a3b696ba1fb15714..494a0ea9b02903a4e25c77c28780693cf327535b 100644 (file)
@@ -23,8 +23,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = {
                .id = "INT33CA",
                .drv_name = "haswell-audio",
                .fw_filename = "intel/IntcSST1.bin",
-               .sof_fw_filename = "intel/reef-hsw.ri",
-               .sof_tplg_filename = "intel/reef-hsw.tplg",
+               .sof_fw_filename = "intel/sof-hsw.ri",
+               .sof_tplg_filename = "intel/sof-hsw.tplg",
                .asoc_plat_name = "haswell-pcm-audio",
        },
        {}
@@ -36,24 +36,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
                .id = "INT343A",
                .drv_name = "broadwell-audio",
                .fw_filename =  "intel/IntcSST2.bin",
-               .sof_fw_filename = "intel/reef-bdw.ri",
-               .sof_tplg_filename = "intel/reef-bdw-rt286.tplg",
+               .sof_fw_filename = "intel/sof-bdw.ri",
+               .sof_tplg_filename = "intel/sof-bdw-rt286.tplg",
                .asoc_plat_name = "haswell-pcm-audio",
        },
        {
                .id = "RT5677CE",
                .drv_name = "bdw-rt5677",
                .fw_filename =  "intel/IntcSST2.bin",
-               .sof_fw_filename = "intel/reef-bdw.ri",
-               .sof_tplg_filename = "intel/reef-bdw-rt286.tplg",
+               .sof_fw_filename = "intel/sof-bdw.ri",
+               .sof_tplg_filename = "intel/sof-bdw-rt5677.tplg",
                .asoc_plat_name = "haswell-pcm-audio",
        },
        {
                .id = "INT33CA",
                .drv_name = "haswell-audio",
                .fw_filename = "intel/IntcSST2.bin",
-               .sof_fw_filename = "intel/reef-bdw.ri",
-               .sof_tplg_filename = "intel/reef-bdw-rt5640.tplg",
+               .sof_fw_filename = "intel/sof-bdw.ri",
+               .sof_tplg_filename = "intel/sof-bdw-rt5640.tplg",
                .asoc_plat_name = "haswell-pcm-audio",
        },
        {}
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
new file mode 100644 (file)
index 0000000..0ee173c
--- /dev/null
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-kbl-match.c - tables and support for KBL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata skl_dmic_data;
+
+static struct snd_soc_acpi_codecs kbl_codecs = {
+       .num_codecs = 1,
+       .codecs = {"10508825"}
+};
+
+static struct snd_soc_acpi_codecs kbl_poppy_codecs = {
+       .num_codecs = 1,
+       .codecs = {"10EC5663"}
+};
+
+static struct snd_soc_acpi_codecs kbl_5663_5514_codecs = {
+       .num_codecs = 2,
+       .codecs = {"10EC5663", "10EC5514"}
+};
+
+static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = {
+       .num_codecs = 1,
+       .codecs = {"MX98357A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
+       {
+               .id = "INT343A",
+               .drv_name = "kbl_alc286s_i2s",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+       },
+       {
+               .id = "INT343B",
+               .drv_name = "kbl_n88l25_s4567",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &kbl_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {
+               .id = "MX98357A",
+               .drv_name = "kbl_n88l25_m98357a",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &kbl_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {
+               .id = "MX98927",
+               .drv_name = "kbl_r5514_5663_max",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &kbl_5663_5514_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {
+               .id = "MX98927",
+               .drv_name = "kbl_rt5663_m98927",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &kbl_poppy_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {
+               .id = "10EC5663",
+               .drv_name = "kbl_rt5663",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+       },
+       {
+               .id = "DLGS7219",
+               .drv_name = "kbl_da7219_max98357a",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &kbl_7219_98357_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
new file mode 100644 (file)
index 0000000..0c9c0ed
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-skl-match.c - tables and support for SKL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata skl_dmic_data;
+
+static struct snd_soc_acpi_codecs skl_codecs = {
+       .num_codecs = 1,
+       .codecs = {"10508825"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = {
+       {
+               .id = "INT343A",
+               .drv_name = "skl_alc286s_i2s",
+               .fw_filename = "intel/dsp_fw_release.bin",
+       },
+       {
+               .id = "INT343B",
+               .drv_name = "skl_n88l25_s4567",
+               .fw_filename = "intel/dsp_fw_release.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &skl_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {
+               .id = "MX98357A",
+               .drv_name = "skl_n88l25_m98357a",
+               .fw_filename = "intel/dsp_fw_release.bin",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &skl_codecs,
+               .pdata = &skl_dmic_data,
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_skl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
index 657afc02f1c47813b55cffa4bd2f53465539f0b8..11041aedea312cf1bae7ae4de23cacde9552d9d5 100644 (file)
@@ -270,7 +270,7 @@ void sst_dsp_dma_put_channel(struct sst_dsp *dsp)
 }
 EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel);
 
-int sst_dma_new(struct sst_dsp *sst)
+static int sst_dma_new(struct sst_dsp *sst)
 {
        struct sst_pdata *sst_pdata = sst->pdata;
        struct sst_dma *dma;
@@ -320,9 +320,8 @@ err_dma_dev:
        devm_kfree(sst->dev, dma);
        return ret;
 }
-EXPORT_SYMBOL(sst_dma_new);
 
-void sst_dma_free(struct sst_dma *dma)
+static void sst_dma_free(struct sst_dma *dma)
 {
 
        if (dma == NULL)
@@ -335,7 +334,6 @@ void sst_dma_free(struct sst_dma *dma)
                dw_remove(dma->chip);
 
 }
-EXPORT_SYMBOL(sst_dma_free);
 
 /* create new generic firmware object */
 struct sst_fw *sst_fw_new(struct sst_dsp *dsp, 
index b2bec36d074cf12b91039e189b775e0311c900ae..a28220e67cdf5ba490fbdc4c2098de19ccd812c4 100644 (file)
@@ -93,29 +93,31 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
        struct sst_module_template template;
        int count, ret;
        void __iomem *ram;
+       int type = le16_to_cpu(module->type);
+       int entry_point = le32_to_cpu(module->entry_point);
 
        /* TODO: allowed module types need to be configurable */
-       if (module->type != SST_HSW_MODULE_BASE_FW
-               && module->type != SST_HSW_MODULE_PCM_SYSTEM
-               && module->type != SST_HSW_MODULE_PCM
-               && module->type != SST_HSW_MODULE_PCM_REFERENCE
-               && module->type != SST_HSW_MODULE_PCM_CAPTURE
-               && module->type != SST_HSW_MODULE_WAVES
-               && module->type != SST_HSW_MODULE_LPAL)
+       if (type != SST_HSW_MODULE_BASE_FW &&
+           type != SST_HSW_MODULE_PCM_SYSTEM &&
+           type != SST_HSW_MODULE_PCM &&
+           type != SST_HSW_MODULE_PCM_REFERENCE &&
+           type != SST_HSW_MODULE_PCM_CAPTURE &&
+           type != SST_HSW_MODULE_WAVES &&
+           type != SST_HSW_MODULE_LPAL)
                return 0;
 
        dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
                module->signature, module->mod_size,
-               module->blocks, module->type);
-       dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
+               module->blocks, type);
+       dev_dbg(dsp->dev, " entrypoint 0x%x\n", entry_point);
        dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
                module->info.persistent_size, module->info.scratch_size);
 
        memset(&template, 0, sizeof(template));
-       template.id = module->type;
-       template.entry = module->entry_point - 4;
-       template.persistent_size = module->info.persistent_size;
-       template.scratch_size = module->info.scratch_size;
+       template.id = type;
+       template.entry = entry_point - 4;
+       template.persistent_size = le32_to_cpu(module->info.persistent_size);
+       template.scratch_size = le32_to_cpu(module->info.scratch_size);
 
        mod = sst_module_new(fw, &template, NULL);
        if (mod == NULL)
@@ -123,26 +125,26 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
 
        block = (void *)module + sizeof(*module);
 
-       for (count = 0; count < module->blocks; count++) {
+       for (count = 0; count < le32_to_cpu(module->blocks); count++) {
 
-               if (block->size <= 0) {
+               if (le32_to_cpu(block->size) <= 0) {
                        dev_err(dsp->dev,
                                "error: block %d size invalid\n", count);
                        sst_module_free(mod);
                        return -EINVAL;
                }
 
-               switch (block->type) {
+               switch (le32_to_cpu(block->type)) {
                case SST_HSW_IRAM:
                        ram = dsp->addr.lpe;
-                       mod->offset =
-                               block->ram_offset + dsp->addr.iram_offset;
+                       mod->offset = le32_to_cpu(block->ram_offset) +
+                               dsp->addr.iram_offset;
                        mod->type = SST_MEM_IRAM;
                        break;
                case SST_HSW_DRAM:
                case SST_HSW_REGS:
                        ram = dsp->addr.lpe;
-                       mod->offset = block->ram_offset;
+                       mod->offset = le32_to_cpu(block->ram_offset);
                        mod->type = SST_MEM_DRAM;
                        break;
                default:
@@ -152,7 +154,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
                        return -EINVAL;
                }
 
-               mod->size = block->size;
+               mod->size = le32_to_cpu(block->size);
                mod->data = (void *)block + sizeof(*block);
                mod->data_offset = mod->data - fw->dma_buf;
 
@@ -169,7 +171,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
                        return ret;
                }
 
-               block = (void *)block + sizeof(*block) + block->size;
+               block = (void *)block + sizeof(*block) +
+                       le32_to_cpu(block->size);
        }
        mod->state = SST_MODULE_STATE_LOADED;
 
@@ -188,7 +191,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
 
        /* verify FW */
        if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
-               (sst_fw->size != header->file_size + sizeof(*header))) {
+           (sst_fw->size !=
+            le32_to_cpu(header->file_size) + sizeof(*header))) {
                dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
                return -EINVAL;
        }
@@ -199,7 +203,7 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
 
        /* parse each module */
        module = (void *)sst_fw->dma_buf + sizeof(*header);
-       for (count = 0; count < header->modules; count++) {
+       for (count = 0; count < le32_to_cpu(header->modules); count++) {
 
                /* module */
                ret = hsw_parse_module(dsp, sst_fw, module);
@@ -207,7 +211,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
                        dev_err(dsp->dev, "error: invalid module %d\n", count);
                        return ret;
                }
-               module = (void *)module + sizeof(*module) + module->mod_size;
+               module = (void *)module + sizeof(*module) +
+                       le32_to_cpu(module->mod_size);
        }
 
        return 0;
index d5f9c30eba32cb01de6b037fe9811681b2a175ad..8bfb8b0fa3d5959b25ee42ef9bcb35255b2eb97f 100644 (file)
@@ -33,8 +33,7 @@
 static int skl_alloc_dma_buf(struct device *dev,
                struct snd_dma_buffer *dmab, size_t size)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
 
        if (!bus)
                return -ENODEV;
@@ -44,8 +43,7 @@ static int skl_alloc_dma_buf(struct device *dev,
 
 static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
 
        if (!bus)
                return -ENODEV;
@@ -89,8 +87,7 @@ void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
 static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
                                int stream_tag, int enable)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
        struct hdac_stream *stream = snd_hdac_get_stream(bus,
                        SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
        struct hdac_ext_stream *estream;
@@ -100,10 +97,10 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
 
        estream = stream_to_hdac_ext_stream(stream);
        /* enable/disable SPIB for this hdac stream */
-       snd_hdac_ext_stream_spbcap_enable(ebus, enable, stream->index);
+       snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index);
 
        /* set the spib value */
-       snd_hdac_ext_stream_set_spib(ebus, estream, size);
+       snd_hdac_ext_stream_set_spib(bus, estream, size);
 
        return 0;
 }
@@ -111,8 +108,7 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
 static int skl_dsp_prepare(struct device *dev, unsigned int format,
                        unsigned int size, struct snd_dma_buffer *dmab)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
        struct hdac_ext_stream *estream;
        struct hdac_stream *stream;
        struct snd_pcm_substream substream;
@@ -124,7 +120,7 @@ static int skl_dsp_prepare(struct device *dev, unsigned int format,
        memset(&substream, 0, sizeof(substream));
        substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
 
-       estream = snd_hdac_ext_stream_assign(ebus, &substream,
+       estream = snd_hdac_ext_stream_assign(bus, &substream,
                                        HDAC_EXT_STREAM_TYPE_HOST);
        if (!estream)
                return -ENODEV;
@@ -143,9 +139,8 @@ static int skl_dsp_prepare(struct device *dev, unsigned int format,
 
 static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
        struct hdac_stream *stream;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
 
        if (!bus)
                return -ENODEV;
@@ -163,10 +158,9 @@ static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag)
 static int skl_dsp_cleanup(struct device *dev,
                struct snd_dma_buffer *dmab, int stream_tag)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
        struct hdac_stream *stream;
        struct hdac_ext_stream *estream;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
 
        if (!bus)
                return -ENODEV;
@@ -270,8 +264,7 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
 int skl_init_dsp(struct skl *skl)
 {
        void __iomem *mmio_base;
-       struct hdac_ext_bus *ebus = &skl->ebus;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct skl_dsp_loader_ops loader_ops;
        int irq = bus->irq;
        const struct skl_dsp_ops *ops;
@@ -279,8 +272,8 @@ int skl_init_dsp(struct skl *skl)
        int ret;
 
        /* enable ppcap interrupt */
-       snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
-       snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
+       snd_hdac_ext_bus_ppcap_enable(bus, true);
+       snd_hdac_ext_bus_ppcap_int_enable(bus, true);
 
        /* read the BAR of the ADSP MMIO */
        mmio_base = pci_ioremap_bar(skl->pci, 4);
@@ -335,12 +328,11 @@ unmap_mmio:
 
 int skl_free_dsp(struct skl *skl)
 {
-       struct hdac_ext_bus *ebus = &skl->ebus;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct skl_sst *ctx = skl->skl_sst;
 
        /* disable  ppcap interrupt */
-       snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
+       snd_hdac_ext_bus_ppcap_int_enable(bus, false);
 
        ctx->dsp_ops->cleanup(bus->dev, ctx);
 
@@ -383,10 +375,11 @@ int skl_suspend_late_dsp(struct skl *skl)
 int skl_suspend_dsp(struct skl *skl)
 {
        struct skl_sst *ctx = skl->skl_sst;
+       struct hdac_bus *bus = skl_to_bus(skl);
        int ret;
 
        /* if ppcap is not supported return 0 */
-       if (!skl->ebus.bus.ppcap)
+       if (!bus->ppcap)
                return 0;
 
        ret = skl_dsp_sleep(ctx->dsp);
@@ -394,8 +387,8 @@ int skl_suspend_dsp(struct skl *skl)
                return ret;
 
        /* disable ppcap interrupt */
-       snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
-       snd_hdac_ext_bus_ppcap_enable(&skl->ebus, false);
+       snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+       snd_hdac_ext_bus_ppcap_enable(bus, false);
 
        return 0;
 }
@@ -403,15 +396,16 @@ int skl_suspend_dsp(struct skl *skl)
 int skl_resume_dsp(struct skl *skl)
 {
        struct skl_sst *ctx = skl->skl_sst;
+       struct hdac_bus *bus = skl_to_bus(skl);
        int ret;
 
        /* if ppcap is not supported return 0 */
-       if (!skl->ebus.bus.ppcap)
+       if (!bus->ppcap)
                return 0;
 
        /* enable ppcap interrupt */
-       snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
-       snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
+       snd_hdac_ext_bus_ppcap_enable(bus, true);
+       snd_hdac_ext_bus_ppcap_int_enable(bus, true);
 
        /* check if DSP 1st boot is done */
        if (skl->skl_sst->is_first_boot == true)
index b9b140275be09908e93e1936a7d9d86772387106..01a050cf877537ddab712863e50fe1b523db98de 100644 (file)
@@ -141,7 +141,7 @@ struct nhlt_specific_cfg
 {
        struct nhlt_fmt *fmt;
        struct nhlt_endpoint *epnt;
-       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct device *dev = bus->dev;
        struct nhlt_specific_cfg *sp_config;
        struct nhlt_acpi_table *nhlt = skl->nhlt;
@@ -228,7 +228,7 @@ static void skl_nhlt_trim_space(char *trim)
 int skl_nhlt_update_topology_bin(struct skl *skl)
 {
        struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
-       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct device *dev = bus->dev;
 
        dev_dbg(dev, "oem_id %.6s, oem_table_id %8s oem_revision %d\n",
@@ -248,8 +248,8 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
+       struct skl *skl = bus_to_skl(bus);
        struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
        char platform_id[32];
 
index afa86b9e4dcf310d63c6930eaad4be6b096ff25e..823e39103edd30bedefaf50ff84cd60004eb9fbb 100644 (file)
@@ -67,16 +67,15 @@ struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream)
        return substream->runtime->private_data;
 }
 
-static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream)
+static struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
        struct hdac_stream *hstream = hdac_stream(stream);
        struct hdac_bus *bus = hstream->bus;
-
-       return hbus_to_ebus(bus);
+       return bus;
 }
 
-static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus,
+static int skl_substream_alloc_pages(struct hdac_bus *bus,
                                 struct snd_pcm_substream *substream,
                                 size_t size)
 {
@@ -95,7 +94,7 @@ static int skl_substream_free_pages(struct hdac_bus *bus,
        return snd_pcm_lib_free_pages(substream);
 }
 
-static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
+static void skl_set_pcm_constrains(struct hdac_bus *bus,
                                 struct snd_pcm_runtime *runtime)
 {
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
@@ -105,9 +104,9 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
                                     20, 178000000);
 }
 
-static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus)
+static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus)
 {
-       if ((ebus_to_hbus(ebus))->ppcap)
+       if (bus->ppcap)
                return HDAC_EXT_STREAM_TYPE_HOST;
        else
                return HDAC_EXT_STREAM_TYPE_COUPLED;
@@ -123,9 +122,9 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e
 static void skl_set_suspend_active(struct snd_pcm_substream *substream,
                                         struct snd_soc_dai *dai, bool enable)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct snd_soc_dapm_widget *w;
-       struct skl *skl = ebus_to_skl(ebus);
+       struct skl *skl = bus_to_skl(bus);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                w = dai->playback_widget;
@@ -140,8 +139,7 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream,
 
 int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
        unsigned int format_val;
        struct hdac_stream *hstream;
        struct hdac_ext_stream *stream;
@@ -153,7 +151,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
                return -EINVAL;
 
        stream = stream_to_hdac_ext_stream(hstream);
-       snd_hdac_ext_stream_decouple(ebus, stream, true);
+       snd_hdac_ext_stream_decouple(bus, stream, true);
 
        format_val = snd_hdac_calc_stream_format(params->s_freq,
                        params->ch, params->format, params->host_bps, 0);
@@ -177,8 +175,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
 
 int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
        unsigned int format_val;
        struct hdac_stream *hstream;
        struct hdac_ext_stream *stream;
@@ -190,7 +187,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
                return -EINVAL;
 
        stream = stream_to_hdac_ext_stream(hstream);
-       snd_hdac_ext_stream_decouple(ebus, stream, true);
+       snd_hdac_ext_stream_decouple(bus, stream, true);
        format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
                                        params->format, params->link_bps, 0);
 
@@ -201,7 +198,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
 
        snd_hdac_ext_link_stream_setup(stream, format_val);
 
-       list_for_each_entry(link, &ebus->hlink_list, list) {
+       list_for_each_entry(link, &bus->hlink_list, list) {
                if (link->index == params->link_index)
                        snd_hdac_ext_link_set_stream_id(link,
                                        hstream->stream_tag);
@@ -215,7 +212,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
 static int skl_pcm_open(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct hdac_ext_stream *stream;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct skl_dma_params *dma_params;
@@ -224,12 +221,12 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
-       stream = snd_hdac_ext_stream_assign(ebus, substream,
-                                       skl_get_host_stream_type(ebus));
+       stream = snd_hdac_ext_stream_assign(bus, substream,
+                                       skl_get_host_stream_type(bus));
        if (stream == NULL)
                return -EBUSY;
 
-       skl_set_pcm_constrains(ebus, runtime);
+       skl_set_pcm_constrains(bus, runtime);
 
        /*
         * disable WALLCLOCK timestamps for capture streams
@@ -301,7 +298,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct skl_pipe_params p_params = {0};
@@ -309,7 +306,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
        int ret, dma_id;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-       ret = skl_substream_alloc_pages(ebus, substream,
+       ret = skl_substream_alloc_pages(bus, substream,
                                          params_buffer_bytes(params));
        if (ret < 0)
                return ret;
@@ -343,14 +340,14 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct skl_dma_params *dma_params = NULL;
-       struct skl *skl = ebus_to_skl(ebus);
+       struct skl *skl = bus_to_skl(bus);
        struct skl_module_cfg *mconfig;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
-       snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus));
+       snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus));
 
        dma_params = snd_soc_dai_get_dma_data(dai, substream);
        /*
@@ -380,7 +377,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
 static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
        struct skl *skl = get_skl_ctx(dai->dev);
        struct skl_module_cfg *mconfig;
@@ -400,7 +397,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
        snd_hdac_stream_cleanup(hdac_stream(stream));
        hdac_stream(stream)->prepared = 0;
 
-       return skl_substream_free_pages(ebus_to_hbus(ebus), substream);
+       return skl_substream_free_pages(bus, substream);
 }
 
 static int skl_be_hw_params(struct snd_pcm_substream *substream,
@@ -420,8 +417,7 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream,
 static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
                int cmd)
 {
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = get_bus_ctx(substream);
        struct hdac_ext_stream *stream;
        int start;
        unsigned long cookie;
@@ -470,7 +466,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
        struct skl *skl = get_skl_ctx(dai->dev);
        struct skl_sst *ctx = skl->skl_sst;
        struct skl_module_cfg *mconfig;
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_bus *bus = get_bus_ctx(substream);
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
        struct snd_soc_dapm_widget *w;
        int ret;
@@ -492,9 +488,9 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                         * dpib & lpib position to resume before starting the
                         * DMA
                         */
-                       snd_hdac_ext_stream_drsm_enable(ebus, true,
+                       snd_hdac_ext_stream_drsm_enable(bus, true,
                                                hdac_stream(stream)->index);
-                       snd_hdac_ext_stream_set_dpibr(ebus, stream,
+                       snd_hdac_ext_stream_set_dpibr(bus, stream,
                                                        stream->lpib);
                        snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
                }
@@ -528,14 +524,14 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                ret = skl_decoupled_trigger(substream, cmd);
                if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
                        /* save the dpib and lpib positions */
-                       stream->dpib = readl(ebus->bus.remap_addr +
+                       stream->dpib = readl(bus->remap_addr +
                                        AZX_REG_VS_SDXDPIB_XBASE +
                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
                                        hdac_stream(stream)->index));
 
                        stream->lpib = snd_hdac_stream_get_pos_lpib(
                                                        hdac_stream(stream));
-                       snd_hdac_ext_stream_decouple(ebus, stream, false);
+                       snd_hdac_ext_stream_decouple(bus, stream, false);
                }
                break;
 
@@ -546,11 +542,12 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
+
 static int skl_link_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct hdac_ext_stream *link_dev;
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
@@ -558,14 +555,14 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
        struct hdac_ext_link *link;
        int stream_tag;
 
-       link_dev = snd_hdac_ext_stream_assign(ebus, substream,
+       link_dev = snd_hdac_ext_stream_assign(bus, substream,
                                        HDAC_EXT_STREAM_TYPE_LINK);
        if (!link_dev)
                return -EBUSY;
 
        snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
 
-       link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name);
+       link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
        if (!link)
                return -EINVAL;
 
@@ -610,7 +607,7 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
 {
        struct hdac_ext_stream *link_dev =
                                snd_soc_dai_get_dma_data(dai, substream);
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_bus *bus = get_bus_ctx(substream);
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
 
        dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
@@ -626,7 +623,7 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_STOP:
                snd_hdac_ext_link_stream_clear(link_dev);
                if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
-                       snd_hdac_ext_stream_decouple(ebus, stream, false);
+                       snd_hdac_ext_stream_decouple(bus, stream, false);
                break;
 
        default:
@@ -638,7 +635,7 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
 static int skl_link_hw_free(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        struct hdac_ext_stream *link_dev =
                                snd_soc_dai_get_dma_data(dai, substream);
@@ -648,7 +645,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
 
        link_dev->link_prepared = 0;
 
-       link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name);
+       link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
        if (!link)
                return -EINVAL;
 
@@ -1017,10 +1014,11 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
 },
 };
 
-int skl_dai_load(struct snd_soc_component *cmp,
-                struct snd_soc_dai_driver *pcm_dai)
+int skl_dai_load(struct snd_soc_component *cmp, int index,
+                       struct snd_soc_dai_driver *dai_drv,
+                       struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
 {
-       pcm_dai->ops = &skl_pcm_dai_ops;
+       dai_drv->ops = &skl_pcm_dai_ops;
 
        return 0;
 }
@@ -1041,8 +1039,7 @@ static int skl_platform_open(struct snd_pcm_substream *substream)
 static int skl_coupled_trigger(struct snd_pcm_substream *substream,
                                        int cmd)
 {
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = get_bus_ctx(substream);
        struct hdac_ext_stream *stream;
        struct snd_pcm_substream *s;
        bool start;
@@ -1115,9 +1112,9 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream,
 static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
                                        int cmd)
 {
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_bus *bus = get_bus_ctx(substream);
 
-       if (!(ebus_to_hbus(ebus))->ppcap)
+       if (!bus->ppcap)
                return skl_coupled_trigger(substream, cmd);
 
        return 0;
@@ -1127,7 +1124,7 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
                        (struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
-       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+       struct hdac_bus *bus = get_bus_ctx(substream);
        unsigned int pos;
 
        /*
@@ -1152,12 +1149,12 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
         */
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
+               pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
                                (AZX_REG_VS_SDXDPIB_XINTERVAL *
                                hdac_stream(hstream)->index));
        } else {
                udelay(20);
-               readl(ebus->bus.remap_addr +
+               readl(bus->remap_addr +
                                AZX_REG_VS_SDXDPIB_XBASE +
                                (AZX_REG_VS_SDXDPIB_XINTERVAL *
                                 hdac_stream(hstream)->index));
@@ -1242,11 +1239,11 @@ static void skl_pcm_free(struct snd_pcm *pcm)
 static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->cpu_dai;
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct hdac_bus *bus = dev_get_drvdata(dai->dev);
        struct snd_pcm *pcm = rtd->pcm;
        unsigned int size;
        int retval = 0;
-       struct skl *skl = ebus_to_skl(ebus);
+       struct skl *skl = bus_to_skl(bus);
 
        if (dai->driver->playback.channels_min ||
                dai->driver->capture.channels_min) {
@@ -1356,19 +1353,19 @@ static int skl_populate_modules(struct skl *skl)
 
 static int skl_platform_soc_probe(struct snd_soc_component *component)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(component->dev);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(component->dev);
+       struct skl *skl = bus_to_skl(bus);
        const struct skl_dsp_ops *ops;
        int ret;
 
        pm_runtime_get_sync(component->dev);
-       if ((ebus_to_hbus(ebus))->ppcap) {
+       if (bus->ppcap) {
                skl->component = component;
 
                /* init debugfs */
                skl->debugfs = skl_debugfs_init(skl);
 
-               ret = skl_tplg_init(component, ebus);
+               ret = skl_tplg_init(component, bus);
                if (ret < 0) {
                        dev_err(component->dev, "Failed to init topology!\n");
                        return ret;
@@ -1425,10 +1422,10 @@ static const struct snd_soc_component_driver skl_component  = {
 int skl_platform_register(struct device *dev)
 {
        int ret;
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct skl *skl = ebus_to_skl(ebus);
        struct snd_soc_dai_driver *dais;
        int num_dais = ARRAY_SIZE(skl_platform_dai);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
+       struct skl *skl = bus_to_skl(bus);
 
        INIT_LIST_HEAD(&skl->ppl_list);
        INIT_LIST_HEAD(&skl->bind_list);
@@ -1464,8 +1461,8 @@ err:
 
 int skl_platform_unregister(struct device *dev)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
+       struct skl *skl = bus_to_skl(bus);
        struct skl_module_deferred_bind *modules, *tmp;
 
        if (!list_empty(&skl->bind_list)) {
index d2b1d60fec021cdf00e5e264f50c111d9f163fa8..5bc0d38da7e3584c46cbaed2b34f8f274a6feb09 100644 (file)
@@ -83,9 +83,9 @@ static void skl_cldma_stream_clear(struct sst_dsp  *ctx)
 /* Code loader helper APIs */
 static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
                struct snd_dma_buffer *dmab_data,
-               u32 **bdlp, int size, int with_ioc)
+               __le32 **bdlp, int size, int with_ioc)
 {
-       u32 *bdl = *bdlp;
+       __le32 *bdl = *bdlp;
 
        ctx->cl_dev.frags = 0;
        while (size > 0) {
@@ -330,7 +330,7 @@ void skl_cldma_process_intr(struct sst_dsp *ctx)
 int skl_cldma_prepare(struct sst_dsp *ctx)
 {
        int ret;
-       u32 *bdl;
+       __le32 *bdl;
 
        ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE;
 
@@ -359,7 +359,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
                ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
                return ret;
        }
-       bdl = (u32 *)ctx->cl_dev.dmab_bdl.area;
+       bdl = (__le32 *)ctx->cl_dev.dmab_bdl.area;
 
        /* Allocate BDLs */
        ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data,
index 5b730a1a0ae47c15594a890607cdf89a30416dc5..ec736921a0834610a5748c16103a28d1b879b963 100644 (file)
@@ -203,7 +203,7 @@ struct sst_dsp;
 struct skl_cl_dev_ops {
        void (*cl_setup_bdle)(struct sst_dsp *ctx,
                        struct snd_dma_buffer *dmab_data,
-                       u32 **bdlp, int size, int with_ioc);
+                       __le32 **bdlp, int size, int with_ioc);
        void (*cl_setup_controller)(struct sst_dsp *ctx,
                        struct snd_dma_buffer *dmab_bdl,
                        unsigned int max_size, u32 page_count);
index fcdc716754b6349b4ec304c31a535748842b2dc9..2620d77729c52edf06dd4d347825b9872b9070da 100644 (file)
@@ -108,6 +108,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai_out:
        case snd_soc_dapm_switch:
+       case snd_soc_dapm_output:
+       case snd_soc_dapm_mux:
+
                return false;
        default:
                return true;
@@ -934,7 +937,7 @@ static int skl_tplg_find_moduleid_from_uuid(struct skl *skl,
        struct soc_bytes_ext *sb = (void *) k->private_value;
        struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
        struct skl_kpb_params *uuid_params, *params;
-       struct hdac_bus *bus = ebus_to_hbus(skl_to_ebus(skl));
+       struct hdac_bus *bus = skl_to_bus(skl);
        int i, size, module_id;
 
        if (bc->set_params == SKL_PARAM_BIND && bc->max) {
@@ -3024,14 +3027,13 @@ void skl_cleanup_resources(struct skl *skl)
  * information to the driver about module and pipeline parameters which DSP
  * FW expects like ids, resource values, formats etc
  */
-static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
+static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
                                struct snd_soc_dapm_widget *w,
                                struct snd_soc_tplg_dapm_widget *tplg_w)
 {
        int ret;
-       struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
-       struct skl *skl = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
+       struct skl *skl = bus_to_skl(bus);
        struct skl_module_cfg *mconfig;
 
        if (!tplg_w->priv.size)
@@ -3131,14 +3133,14 @@ static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
 }
 
 static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
+                               int index,
                                struct snd_kcontrol_new *kctl,
                                struct snd_soc_tplg_ctl_hdr *hdr)
 {
        struct soc_bytes_ext *sb;
        struct snd_soc_tplg_bytes_control *tplg_bc;
        struct snd_soc_tplg_enum_control *tplg_ec;
-       struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
        struct soc_enum *se;
 
        switch (hdr->ops.info) {
@@ -3619,12 +3621,11 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
        return 0;
 }
 
-static int skl_manifest_load(struct snd_soc_component *cmpnt,
+static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
                                struct snd_soc_tplg_manifest *manifest)
 {
-       struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
+       struct skl *skl = bus_to_skl(bus);
 
        /* proceed only if we have private data defined */
        if (manifest->priv.size == 0)
@@ -3713,12 +3714,11 @@ static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
 /*
  * SKL topology init routine
  */
-int skl_tplg_init(struct snd_soc_component *component, struct hdac_ext_bus *ebus)
+int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
 {
        int ret;
        const struct firmware *fw;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct skl *skl = bus_to_skl(bus);
        struct skl_pipeline *ppl;
 
        ret = request_firmware(&fw, skl->tplg_name, bus->dev);
index 6d7e0569695f92db3d859a355660d86e54e31e9f..82282cac9751ed37b3b18aa91f1ca06bb65afbd1 100644 (file)
@@ -458,9 +458,9 @@ enum skl_channel {
 
 static inline struct skl *get_skl_ctx(struct device *dev)
 {
-       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+       struct hdac_bus *bus = dev_get_drvdata(dev);
 
-       return ebus_to_skl(ebus);
+       return bus_to_skl(bus);
 }
 
 int skl_tplg_be_update_params(struct snd_soc_dai *dai,
@@ -470,7 +470,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
 void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
        struct skl_pipe_params *params, int stream);
 int skl_tplg_init(struct snd_soc_component *component,
-                               struct hdac_ext_bus *ebus);
+                               struct hdac_bus *ebus);
 struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
                struct snd_soc_dai *dai, int stream);
 int skl_tplg_update_pipe_params(struct device *dev,
@@ -512,8 +512,9 @@ int skl_pcm_host_dma_prepare(struct device *dev,
 int skl_pcm_link_dma_prepare(struct device *dev,
                        struct skl_pipe_params *params);
 
-int skl_dai_load(struct snd_soc_component *cmp,
-                struct snd_soc_dai_driver *pcm_dai);
+int skl_dai_load(struct snd_soc_component *cmp, int index,
+               struct snd_soc_dai_driver *dai_drv,
+               struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai);
 void skl_tplg_add_moduleid_in_bind_params(struct skl *skl,
                                struct snd_soc_dapm_widget *w);
 #endif
index f0d9793f872abad4b40be720a0f16572f89e78ba..dce64948564940ea7383e0f4975de4b4ec7293ec 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/delay.h>
 #include <sound/pcm.h>
 #include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
 #include <sound/hda_register.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
@@ -36,8 +37,6 @@
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 
-static struct skl_machine_pdata skl_dmic_data;
-
 /*
  * initialize the PCI registers
  */
@@ -54,7 +53,7 @@ static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg,
 
 static void skl_init_pci(struct skl *skl)
 {
-       struct hdac_ext_bus *ebus = &skl->ebus;
+       struct hdac_bus *bus = skl_to_bus(skl);
 
        /*
         * Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
@@ -63,7 +62,7 @@ static void skl_init_pci(struct skl *skl)
         * codecs.
         * The PCI register TCSEL is defined in the Intel manuals.
         */
-       dev_dbg(ebus_to_hbus(ebus)->dev, "Clearing TCSEL\n");
+       dev_dbg(bus->dev, "Clearing TCSEL\n");
        skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
 }
 
@@ -103,8 +102,7 @@ static void skl_enable_miscbdcge(struct device *dev, bool enable)
 static void skl_clock_power_gating(struct device *dev, bool enable)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
        u32 val;
 
        /* Update PDCGE bit of CGCTL register */
@@ -127,7 +125,6 @@ static void skl_clock_power_gating(struct device *dev, bool enable)
  */
 static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
 {
-       struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
        struct hdac_ext_link *hlink;
        int ret;
 
@@ -135,7 +132,7 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
        ret = snd_hdac_bus_init_chip(bus, full_reset);
 
        /* Reset stream-to-link mapping */
-       list_for_each_entry(hlink, &ebus->hlink_list, list)
+       list_for_each_entry(hlink, &bus->hlink_list, list)
                bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
 
        skl_enable_miscbdcge(bus->dev, true);
@@ -146,8 +143,7 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
 void skl_update_d0i3c(struct device *dev, bool enable)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
        u8 reg;
        int timeout = 50;
 
@@ -197,8 +193,7 @@ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
 
 static irqreturn_t skl_interrupt(int irq, void *dev_id)
 {
-       struct hdac_ext_bus *ebus = dev_id;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_id;
        u32 status;
 
        if (!pm_runtime_active(bus->dev))
@@ -227,8 +222,7 @@ static irqreturn_t skl_interrupt(int irq, void *dev_id)
 
 static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
 {
-       struct hdac_ext_bus *ebus = dev_id;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = dev_id;
        u32 status;
 
        status = snd_hdac_chip_readl(bus, INTSTS);
@@ -238,16 +232,15 @@ static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
+static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect)
 {
-       struct skl *skl = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl = bus_to_skl(bus);
        int ret;
 
        ret = request_threaded_irq(skl->pci->irq, skl_interrupt,
                        skl_threaded_handler,
                        IRQF_SHARED,
-                       KBUILD_MODNAME, ebus);
+                       KBUILD_MODNAME, bus);
        if (ret) {
                dev_err(bus->dev,
                        "unable to grab IRQ %d, disabling device\n",
@@ -264,21 +257,20 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
 static int skl_suspend_late(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
+       struct skl *skl = bus_to_skl(bus);
 
        return skl_suspend_late_dsp(skl);
 }
 
 #ifdef CONFIG_PM
-static int _skl_suspend(struct hdac_ext_bus *ebus)
+static int _skl_suspend(struct hdac_bus *bus)
 {
-       struct skl *skl = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl = bus_to_skl(bus);
        struct pci_dev *pci = to_pci_dev(bus->dev);
        int ret;
 
-       snd_hdac_ext_bus_link_power_down_all(ebus);
+       snd_hdac_ext_bus_link_power_down_all(bus);
 
        ret = skl_suspend_dsp(skl);
        if (ret < 0)
@@ -295,10 +287,9 @@ static int _skl_suspend(struct hdac_ext_bus *ebus)
        return 0;
 }
 
-static int _skl_resume(struct hdac_ext_bus *ebus)
+static int _skl_resume(struct hdac_bus *bus)
 {
-       struct skl *skl = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl = bus_to_skl(bus);
 
        skl_init_pci(skl);
        skl_init_chip(bus, true);
@@ -314,9 +305,8 @@ static int _skl_resume(struct hdac_ext_bus *ebus)
 static int skl_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct skl *skl  = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
+       struct skl *skl  = bus_to_skl(bus);
        int ret = 0;
 
        /*
@@ -325,15 +315,15 @@ static int skl_suspend(struct device *dev)
         */
        if (skl->supend_active) {
                /* turn off the links and stop the CORB/RIRB DMA if it is On */
-               snd_hdac_ext_bus_link_power_down_all(ebus);
+               snd_hdac_ext_bus_link_power_down_all(bus);
 
-               if (ebus->cmd_dma_state)
-                       snd_hdac_bus_stop_cmd_io(&ebus->bus);
+               if (bus->cmd_dma_state)
+                       snd_hdac_bus_stop_cmd_io(bus);
 
                enable_irq_wake(bus->irq);
                pci_save_state(pci);
        } else {
-               ret = _skl_suspend(ebus);
+               ret = _skl_suspend(bus);
                if (ret < 0)
                        return ret;
                skl->skl_sst->fw_loaded = false;
@@ -352,9 +342,8 @@ static int skl_suspend(struct device *dev)
 static int skl_resume(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct skl *skl  = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
+       struct skl *skl  = bus_to_skl(bus);
        struct hdac_ext_link *hlink = NULL;
        int ret;
 
@@ -374,32 +363,32 @@ static int skl_resume(struct device *dev)
         */
        if (skl->supend_active) {
                pci_restore_state(pci);
-               snd_hdac_ext_bus_link_power_up_all(ebus);
+               snd_hdac_ext_bus_link_power_up_all(bus);
                disable_irq_wake(bus->irq);
                /*
                 * turn On the links which are On before active suspend
                 * and start the CORB/RIRB DMA if On before
                 * active suspend.
                 */
-               list_for_each_entry(hlink, &ebus->hlink_list, list) {
+               list_for_each_entry(hlink, &bus->hlink_list, list) {
                        if (hlink->ref_count)
                                snd_hdac_ext_bus_link_power_up(hlink);
                }
 
-               if (ebus->cmd_dma_state)
-                       snd_hdac_bus_init_cmd_io(&ebus->bus);
                ret = 0;
+               if (bus->cmd_dma_state)
+                       snd_hdac_bus_init_cmd_io(bus);
        } else {
-               ret = _skl_resume(ebus);
+               ret = _skl_resume(bus);
 
                /* turn off the links which are off before suspend */
-               list_for_each_entry(hlink, &ebus->hlink_list, list) {
+               list_for_each_entry(hlink, &bus->hlink_list, list) {
                        if (!hlink->ref_count)
                                snd_hdac_ext_bus_link_power_down(hlink);
                }
 
-               if (!ebus->cmd_dma_state)
-                       snd_hdac_bus_stop_cmd_io(&ebus->bus);
+               if (!bus->cmd_dma_state)
+                       snd_hdac_bus_stop_cmd_io(bus);
        }
 
        return ret;
@@ -410,23 +399,21 @@ static int skl_resume(struct device *dev)
 static int skl_runtime_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
 
        dev_dbg(bus->dev, "in %s\n", __func__);
 
-       return _skl_suspend(ebus);
+       return _skl_suspend(bus);
 }
 
 static int skl_runtime_resume(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
 
        dev_dbg(bus->dev, "in %s\n", __func__);
 
-       return _skl_resume(ebus);
+       return _skl_resume(bus);
 }
 #endif /* CONFIG_PM */
 
@@ -439,20 +426,19 @@ static const struct dev_pm_ops skl_pm = {
 /*
  * destructor
  */
-static int skl_free(struct hdac_ext_bus *ebus)
+static int skl_free(struct hdac_bus *bus)
 {
-       struct skl *skl  = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl  = bus_to_skl(bus);
 
        skl->init_done = 0; /* to be sure */
 
-       snd_hdac_ext_stop_streams(ebus);
+       snd_hdac_ext_stop_streams(bus);
 
        if (bus->irq >= 0)
-               free_irq(bus->irq, (void *)ebus);
+               free_irq(bus->irq, (void *)bus);
        snd_hdac_bus_free_stream_pages(bus);
-       snd_hdac_stream_free_all(ebus);
-       snd_hdac_link_free_all(ebus);
+       snd_hdac_stream_free_all(bus);
+       snd_hdac_link_free_all(bus);
 
        if (bus->remap_addr)
                iounmap(bus->remap_addr);
@@ -460,11 +446,11 @@ static int skl_free(struct hdac_ext_bus *ebus)
        pci_release_regions(skl->pci);
        pci_disable_device(skl->pci);
 
-       snd_hdac_ext_bus_exit(ebus);
+       snd_hdac_ext_bus_exit(bus);
 
        cancel_work_sync(&skl->probe_work);
        if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
-               snd_hdac_i915_exit(&ebus->bus);
+               snd_hdac_i915_exit(bus);
 
        return 0;
 }
@@ -488,8 +474,8 @@ static struct skl_ssp_clk skl_ssp_clks[] = {
 
 static int skl_find_machine(struct skl *skl, void *driver_data)
 {
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct snd_soc_acpi_mach *mach = driver_data;
-       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
        struct skl_machine_pdata *pdata;
 
        mach = snd_soc_acpi_find_machine(mach);
@@ -500,17 +486,19 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
 
        skl->mach = mach;
        skl->fw_name = mach->fw_filename;
-       pdata = skl->mach->pdata;
+       pdata = mach->pdata;
 
-       if (mach->pdata)
+       if (pdata) {
                skl->use_tplg_pcm = pdata->use_tplg_pcm;
+               pdata->dmic_num = skl_get_dmic_geo(skl);
+       }
 
        return 0;
 }
 
 static int skl_machine_device_register(struct skl *skl)
 {
-       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct snd_soc_acpi_mach *mach = skl->mach;
        struct platform_device *pdev;
        int ret;
@@ -544,7 +532,7 @@ static void skl_machine_device_unregister(struct skl *skl)
 
 static int skl_dmic_device_register(struct skl *skl)
 {
-       struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct platform_device *pdev;
        int ret;
 
@@ -643,12 +631,13 @@ static void skl_clock_device_unregister(struct skl *skl)
 /*
  * Probe the given codec address
  */
-static int probe_codec(struct hdac_ext_bus *ebus, int addr)
+static int probe_codec(struct hdac_bus *bus, int addr)
 {
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
        unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
                (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
        unsigned int res = -1;
+       struct skl *skl = bus_to_skl(bus);
+       struct hdac_device *hdev;
 
        mutex_lock(&bus->cmd_mutex);
        snd_hdac_bus_send_cmd(bus, cmd);
@@ -658,13 +647,16 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
                return -EIO;
        dev_dbg(bus->dev, "codec #%d probed OK\n", addr);
 
-       return snd_hdac_ext_bus_device_init(ebus, addr);
+       hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL);
+       if (!hdev)
+               return -ENOMEM;
+
+       return snd_hdac_ext_bus_device_init(bus, addr, hdev);
 }
 
 /* Codec initialization */
-static void skl_codec_create(struct hdac_ext_bus *ebus)
+static void skl_codec_create(struct hdac_bus *bus)
 {
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
        int c, max_slots;
 
        max_slots = HDA_MAX_CODECS;
@@ -672,7 +664,7 @@ static void skl_codec_create(struct hdac_ext_bus *ebus)
        /* First try to probe all given codec slots */
        for (c = 0; c < max_slots; c++) {
                if ((bus->codec_mask & (1 << c))) {
-                       if (probe_codec(ebus, c) < 0) {
+                       if (probe_codec(bus, c) < 0) {
                                /*
                                 * Some BIOSen give you wrong codec addresses
                                 * that don't exist
@@ -722,8 +714,7 @@ static int skl_i915_init(struct hdac_bus *bus)
 static void skl_probe_work(struct work_struct *work)
 {
        struct skl *skl = container_of(work, struct skl, probe_work);
-       struct hdac_ext_bus *ebus = &skl->ebus;
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = skl_to_bus(skl);
        struct hdac_ext_link *hlink = NULL;
        int err;
 
@@ -744,7 +735,7 @@ static void skl_probe_work(struct work_struct *work)
                dev_info(bus->dev, "no hda codecs found!\n");
 
        /* create codec instances */
-       skl_codec_create(ebus);
+       skl_codec_create(bus);
 
        /* register platform dai and controls */
        err = skl_platform_register(bus->dev);
@@ -773,8 +764,8 @@ static void skl_probe_work(struct work_struct *work)
        /*
         * we are done probing so decrement link counts
         */
-       list_for_each_entry(hlink, &ebus->hlink_list, list)
-               snd_hdac_ext_bus_link_put(ebus, hlink);
+       list_for_each_entry(hlink, &bus->hlink_list, list)
+               snd_hdac_ext_bus_link_put(bus, hlink);
 
        /* configure PM */
        pm_runtime_put_noidle(bus->dev);
@@ -796,7 +787,7 @@ static int skl_create(struct pci_dev *pci,
                      struct skl **rskl)
 {
        struct skl *skl;
-       struct hdac_ext_bus *ebus;
+       struct hdac_bus *bus;
 
        int err;
 
@@ -811,23 +802,22 @@ static int skl_create(struct pci_dev *pci,
                pci_disable_device(pci);
                return -ENOMEM;
        }
-       ebus = &skl->ebus;
-       snd_hdac_ext_bus_init(ebus, &pci->dev, &bus_core_ops, io_ops);
-       ebus->bus.use_posbuf = 1;
+
+       bus = skl_to_bus(skl);
+       snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL);
+       bus->use_posbuf = 1;
        skl->pci = pci;
        INIT_WORK(&skl->probe_work, skl_probe_work);
-
-       ebus->bus.bdl_pos_adj = 0;
+       bus->bdl_pos_adj = 0;
 
        *rskl = skl;
 
        return 0;
 }
 
-static int skl_first_init(struct hdac_ext_bus *ebus)
+static int skl_first_init(struct hdac_bus *bus)
 {
-       struct skl *skl = ebus_to_skl(ebus);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl = bus_to_skl(bus);
        struct pci_dev *pci = skl->pci;
        int err;
        unsigned short gcap;
@@ -848,7 +838,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
 
        snd_hdac_bus_parse_capabilities(bus);
 
-       if (skl_acquire_irq(ebus, 0) < 0)
+       if (skl_acquire_irq(bus, 0) < 0)
                return -EBUSY;
 
        pci_set_master(pci);
@@ -872,14 +862,14 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
        if (!pb_streams && !cp_streams)
                return -EIO;
 
-       ebus->num_streams = cp_streams + pb_streams;
+       bus->num_streams = cp_streams + pb_streams;
 
        /* initialize streams */
        snd_hdac_ext_stream_init_all
-               (ebus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
+               (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
        start_idx = cp_streams;
        snd_hdac_ext_stream_init_all
-               (ebus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
+               (bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
 
        err = snd_hdac_bus_alloc_stream_pages(bus);
        if (err < 0)
@@ -895,7 +885,6 @@ static int skl_probe(struct pci_dev *pci,
                     const struct pci_device_id *pci_id)
 {
        struct skl *skl;
-       struct hdac_ext_bus *ebus = NULL;
        struct hdac_bus *bus = NULL;
        int err;
 
@@ -904,10 +893,9 @@ static int skl_probe(struct pci_dev *pci,
        if (err < 0)
                return err;
 
-       ebus = &skl->ebus;
-       bus = ebus_to_hbus(ebus);
+       bus = skl_to_bus(skl);
 
-       err = skl_first_init(ebus);
+       err = skl_first_init(bus);
        if (err < 0)
                goto out_free;
 
@@ -928,9 +916,7 @@ static int skl_probe(struct pci_dev *pci,
 
        skl_nhlt_update_topology_bin(skl);
 
-       pci_set_drvdata(skl->pci, ebus);
-
-       skl_dmic_data.dmic_num = skl_get_dmic_geo(skl);
+       pci_set_drvdata(skl->pci, bus);
 
        /* check if dsp is there */
        if (bus->ppcap) {
@@ -952,7 +938,7 @@ static int skl_probe(struct pci_dev *pci,
                skl->skl_sst->clock_power_gating = skl_clock_power_gating;
        }
        if (bus->mlcap)
-               snd_hdac_ext_bus_get_ml_capabilities(ebus);
+               snd_hdac_ext_bus_get_ml_capabilities(bus);
 
        snd_hdac_bus_stop_chip(bus);
 
@@ -972,31 +958,30 @@ out_clk_free:
 out_nhlt_free:
        skl_nhlt_free(skl->nhlt);
 out_free:
-       skl_free(ebus);
+       skl_free(bus);
 
        return err;
 }
 
 static void skl_shutdown(struct pci_dev *pci)
 {
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
        struct hdac_stream *s;
        struct hdac_ext_stream *stream;
        struct skl *skl;
 
-       if (ebus == NULL)
+       if (!bus)
                return;
 
-       skl = ebus_to_skl(ebus);
+       skl = bus_to_skl(bus);
 
        if (!skl->init_done)
                return;
 
-       snd_hdac_ext_stop_streams(ebus);
+       snd_hdac_ext_stop_streams(bus);
        list_for_each_entry(s, &bus->stream_list, list) {
                stream = stream_to_hdac_ext_stream(s);
-               snd_hdac_ext_stream_decouple(ebus, stream, false);
+               snd_hdac_ext_stream_decouple(bus, stream, false);
        }
 
        snd_hdac_bus_stop_chip(bus);
@@ -1004,15 +989,15 @@ static void skl_shutdown(struct pci_dev *pci)
 
 static void skl_remove(struct pci_dev *pci)
 {
-       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
-       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = pci_get_drvdata(pci);
+       struct skl *skl = bus_to_skl(bus);
 
        release_firmware(skl->tplg);
 
        pm_runtime_get_noresume(&pci->dev);
 
        /* codec removal, invoke bus_device_remove */
-       snd_hdac_ext_bus_device_remove(ebus);
+       snd_hdac_ext_bus_device_remove(bus);
 
        skl->debugfs = NULL;
        skl_platform_unregister(&pci->dev);
@@ -1022,176 +1007,27 @@ static void skl_remove(struct pci_dev *pci)
        skl_clock_device_unregister(skl);
        skl_nhlt_remove_sysfs(skl);
        skl_nhlt_free(skl->nhlt);
-       skl_free(ebus);
+       skl_free(bus);
        dev_set_drvdata(&pci->dev, NULL);
 }
 
-static struct snd_soc_acpi_codecs skl_codecs = {
-       .num_codecs = 1,
-       .codecs = {"10508825"}
-};
-
-static struct snd_soc_acpi_codecs kbl_codecs = {
-       .num_codecs = 1,
-       .codecs = {"10508825"}
-};
-
-static struct snd_soc_acpi_codecs bxt_codecs = {
-       .num_codecs = 1,
-       .codecs = {"MX98357A"}
-};
-
-static struct snd_soc_acpi_codecs kbl_poppy_codecs = {
-       .num_codecs = 1,
-       .codecs = {"10EC5663"}
-};
-
-static struct snd_soc_acpi_codecs kbl_5663_5514_codecs = {
-       .num_codecs = 2,
-       .codecs = {"10EC5663", "10EC5514"}
-};
-
-static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = {
-       .num_codecs = 1,
-       .codecs = {"MX98357A"}
-};
-
-static struct skl_machine_pdata cnl_pdata = {
-       .use_tplg_pcm = true,
-};
-
-static struct snd_soc_acpi_mach sst_skl_devdata[] = {
-       {
-               .id = "INT343A",
-               .drv_name = "skl_alc286s_i2s",
-               .fw_filename = "intel/dsp_fw_release.bin",
-       },
-       {
-               .id = "INT343B",
-               .drv_name = "skl_n88l25_s4567",
-               .fw_filename = "intel/dsp_fw_release.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &skl_codecs,
-               .pdata = &skl_dmic_data
-       },
-       {
-               .id = "MX98357A",
-               .drv_name = "skl_n88l25_m98357a",
-               .fw_filename = "intel/dsp_fw_release.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &skl_codecs,
-               .pdata = &skl_dmic_data
-       },
-       {}
-};
-
-static struct snd_soc_acpi_mach sst_bxtp_devdata[] = {
-       {
-               .id = "INT343A",
-               .drv_name = "bxt_alc298s_i2s",
-               .fw_filename = "intel/dsp_fw_bxtn.bin",
-       },
-       {
-               .id = "DLGS7219",
-               .drv_name = "bxt_da7219_max98357a_i2s",
-               .fw_filename = "intel/dsp_fw_bxtn.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &bxt_codecs,
-       },
-       {}
-};
-
-static struct snd_soc_acpi_mach sst_kbl_devdata[] = {
-       {
-               .id = "INT343A",
-               .drv_name = "kbl_alc286s_i2s",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-       },
-       {
-               .id = "INT343B",
-               .drv_name = "kbl_n88l25_s4567",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &kbl_codecs,
-               .pdata = &skl_dmic_data
-       },
-       {
-               .id = "MX98357A",
-               .drv_name = "kbl_n88l25_m98357a",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &kbl_codecs,
-               .pdata = &skl_dmic_data
-       },
-       {
-               .id = "MX98927",
-               .drv_name = "kbl_r5514_5663_max",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &kbl_5663_5514_codecs,
-               .pdata = &skl_dmic_data
-       },
-       {
-               .id = "MX98927",
-               .drv_name = "kbl_rt5663_m98927",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &kbl_poppy_codecs,
-               .pdata = &skl_dmic_data
-       },
-       {
-               .id = "10EC5663",
-               .drv_name = "kbl_rt5663",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-       },
-       {
-               .id = "DLGS7219",
-               .drv_name = "kbl_da7219_max98357a",
-               .fw_filename = "intel/dsp_fw_kbl.bin",
-               .machine_quirk = snd_soc_acpi_codec_list,
-               .quirk_data = &kbl_7219_98357_codecs,
-               .pdata = &skl_dmic_data
-       },
-
-       {}
-};
-
-static struct snd_soc_acpi_mach sst_glk_devdata[] = {
-       {
-               .id = "INT343A",
-               .drv_name = "glk_alc298s_i2s",
-               .fw_filename = "intel/dsp_fw_glk.bin",
-       },
-       {}
-};
-
-static const struct snd_soc_acpi_mach sst_cnl_devdata[] = {
-       {
-               .id = "INT34C2",
-               .drv_name = "cnl_rt274",
-               .fw_filename = "intel/dsp_fw_cnl.bin",
-               .pdata = &cnl_pdata,
-       },
-       {}
-};
-
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
-               .driver_data = (unsigned long)&sst_skl_devdata},
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
        /* BXT-P */
        { PCI_DEVICE(0x8086, 0x5a98),
-               .driver_data = (unsigned long)&sst_bxtp_devdata},
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
        /* KBL */
        { PCI_DEVICE(0x8086, 0x9D71),
-               .driver_data = (unsigned long)&sst_kbl_devdata},
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
        /* GLK */
        { PCI_DEVICE(0x8086, 0x3198),
-               .driver_data = (unsigned long)&sst_glk_devdata},
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
        /* CNL */
        { PCI_DEVICE(0x8086, 0x9dc8),
-               .driver_data = (unsigned long)&sst_cnl_devdata},
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
index 0d5375cbcf6ec3cff3fdc044e87493e6c46b3765..78aa8bdcb61929dcafcd93112e4a2b05cca9fbc1 100644 (file)
@@ -71,7 +71,7 @@ struct skl_fw_config {
 };
 
 struct skl {
-       struct hdac_ext_bus ebus;
+       struct hdac_bus hbus;
        struct pci_dev *pci;
 
        unsigned int init_done:1; /* delayed init status */
@@ -105,9 +105,8 @@ struct skl {
        struct snd_soc_acpi_mach *mach;
 };
 
-#define skl_to_ebus(s) (&(s)->ebus)
-#define ebus_to_skl(sbus) \
-       container_of(sbus, struct skl, sbus)
+#define skl_to_bus(s)  (&(s)->hbus)
+#define bus_to_skl(bus) container_of(bus, struct skl, hbus)
 
 /* to pass dai dma data */
 struct skl_dma_params {
index 51ec4ff6ed955f6d5e05f604e59861d96571fd0a..697aa50aff9a7fc6b78ab809a40b721bd5ae0f3f 100644 (file)
 
 int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
 {
-       struct snd_soc_dai_driver *sub_dai_drivers;
+       struct mtk_base_afe_dai *dai;
        size_t num_dai_drivers = 0, dai_idx = 0;
-       int i;
-
-       if (!afe->sub_dais) {
-               dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
-               return -EINVAL;
-       }
 
        /* calcualte total dai driver size */
-       for (i = 0; i < afe->num_sub_dais; i++) {
-               if (afe->sub_dais[i].dai_drivers &&
-                   afe->sub_dais[i].num_dai_drivers != 0)
-                       num_dai_drivers += afe->sub_dais[i].num_dai_drivers;
+       list_for_each_entry(dai, &afe->sub_dais, list) {
+               num_dai_drivers += dai->num_dai_drivers;
        }
 
        dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
@@ -42,19 +34,14 @@ int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
        if (!afe->dai_drivers)
                return -ENOMEM;
 
-       for (i = 0; i < afe->num_sub_dais; i++) {
-               if (afe->sub_dais[i].dai_drivers &&
-                   afe->sub_dais[i].num_dai_drivers != 0) {
-                       sub_dai_drivers = afe->sub_dais[i].dai_drivers;
-                       /* dai driver */
-                       memcpy(&afe->dai_drivers[dai_idx],
-                              sub_dai_drivers,
-                              afe->sub_dais[i].num_dai_drivers *
-                              sizeof(struct snd_soc_dai_driver));
-                       dai_idx += afe->sub_dais[i].num_dai_drivers;
-               }
+       list_for_each_entry(dai, &afe->sub_dais, list) {
+               /* dai driver */
+               memcpy(&afe->dai_drivers[dai_idx],
+                      dai->dai_drivers,
+                      dai->num_dai_drivers *
+                      sizeof(struct snd_soc_dai_driver));
+               dai_idx += dai->num_dai_drivers;
        }
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
@@ -62,28 +49,25 @@ EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
 int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
 {
        struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
-       int i;
+       struct mtk_base_afe_dai *dai;
 
-       if (!afe->sub_dais) {
-               dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < afe->num_sub_dais; i++) {
-               if (afe->sub_dais[i].controls)
+       list_for_each_entry(dai, &afe->sub_dais, list) {
+               if (dai->controls)
                        snd_soc_add_component_controls(component,
-                               afe->sub_dais[i].controls,
-                               afe->sub_dais[i].num_controls);
+                                                      dai->controls,
+                                                      dai->num_controls);
 
-               if (afe->sub_dais[i].dapm_widgets)
+               if (dai->dapm_widgets)
                        snd_soc_dapm_new_controls(&component->dapm,
-                               afe->sub_dais[i].dapm_widgets,
-                               afe->sub_dais[i].num_dapm_widgets);
-
-               if (afe->sub_dais[i].dapm_routes)
+                                                 dai->dapm_widgets,
+                                                 dai->num_dapm_widgets);
+       }
+       /* add routes after all widgets are added */
+       list_for_each_entry(dai, &afe->sub_dais, list) {
+               if (dai->dapm_routes)
                        snd_soc_dapm_add_routes(&component->dapm,
-                               afe->sub_dais[i].dapm_routes,
-                               afe->sub_dais[i].num_dapm_routes);
+                                               dai->dapm_routes,
+                                               dai->num_dapm_routes);
        }
 
        snd_soc_dapm_new_widgets(component->dapm.card);
index bcf562f029b648dcae555b4a99bce90aaa8defaf..bd8d5e0c68430dbe5d20d535e65b62bd374d8c95 100644 (file)
@@ -46,6 +46,7 @@ struct mtk_base_irq_data {
 };
 
 struct device;
+struct list_head;
 struct mtk_base_afe_memif;
 struct mtk_base_afe_irq;
 struct mtk_base_afe_dai;
@@ -72,8 +73,7 @@ struct mtk_base_afe {
        struct mtk_base_afe_irq *irqs;
        int irqs_size;
 
-       struct mtk_base_afe_dai *sub_dais;
-       int num_sub_dais;
+       struct list_head sub_dais;
        struct snd_soc_dai_driver *dai_drivers;
        unsigned int num_dai_drivers;
 
@@ -110,6 +110,8 @@ struct mtk_base_afe_dai {
        unsigned int num_dapm_widgets;
        const struct snd_soc_dapm_route *dapm_routes;
        unsigned int num_dapm_routes;
+
+       struct list_head list;
 };
 
 #endif
index 22eb7b455cf1eac81bcbff8c9a89807cc3821355..4eac9977b2b0d88b826f0484a095bf43634947fb 100644 (file)
@@ -10,6 +10,7 @@
 #define _MT_6797_AFE_COMMON_H_
 
 #include <sound/soc.h>
+#include <linux/list.h>
 #include <linux/regmap.h>
 #include "../common/mtk-base-afe.h"
 
index 6c5dd9fc99766e6109d21a957b5b74d839692f26..192f4d7b37b6ad003d558dcc9b6b74f125225792 100644 (file)
@@ -733,6 +733,34 @@ static const struct snd_soc_component_driver mt6797_afe_component = {
        .probe = mt6797_afe_component_probe,
 };
 
+static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mt6797_memif_dai_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mt6797_memif_dai_driver);
+
+       dai->dapm_widgets = mt6797_memif_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mt6797_memif_widgets);
+       dai->dapm_routes = mt6797_memif_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mt6797_memif_routes);
+       return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+       mt6797_dai_adda_register,
+       mt6797_dai_pcm_register,
+       mt6797_dai_hostless_register,
+       mt6797_dai_memif_register,
+};
+
 static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
 {
        struct mtk_base_afe *afe;
@@ -811,29 +839,24 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
        }
 
        /* init sub_dais */
-       afe->num_sub_dais = MT6797_DAI_NUM;
-       afe->sub_dais = devm_kcalloc(dev, afe->num_sub_dais,
-                                    sizeof(*afe->sub_dais),
-                                    GFP_KERNEL);
-       if (!afe->sub_dais)
-               return -ENOMEM;
-
-       mt6797_dai_adda_register(afe);
-       mt6797_dai_pcm_register(afe);
-       mt6797_dai_hostless_register(afe);
-
-       afe->sub_dais[MT6797_MEMIF_DL1].dai_drivers = mt6797_memif_dai_driver;
-       afe->sub_dais[MT6797_MEMIF_DL1].num_dai_drivers =
-               ARRAY_SIZE(mt6797_memif_dai_driver);
-       afe->sub_dais[MT6797_MEMIF_DL1].dapm_widgets = mt6797_memif_widgets;
-       afe->sub_dais[MT6797_MEMIF_DL1].num_dapm_widgets =
-               ARRAY_SIZE(mt6797_memif_widgets);
-       afe->sub_dais[MT6797_MEMIF_DL1].dapm_routes = mt6797_memif_routes;
-       afe->sub_dais[MT6797_MEMIF_DL1].num_dapm_routes =
-               ARRAY_SIZE(mt6797_memif_routes);
+       INIT_LIST_HEAD(&afe->sub_dais);
+
+       for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+               ret = dai_register_cbs[i](afe);
+               if (ret) {
+                       dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+                                i, ret);
+                       return ret;
+               }
+       }
 
        /* init dai_driver and component_driver */
-       mtk_afe_combine_sub_dai(afe);
+       ret = mtk_afe_combine_sub_dai(afe);
+       if (ret) {
+               dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+                        ret);
+               return ret;
+       }
 
        afe->mtk_afe_hardware = &mt6797_afe_hardware;
        afe->memif_fs = mt6797_memif_fs;
index ad083265ce944bf01e82a8a84e464add6c458151..0ac6409c6d61f273003bd27ad1776596f7b529fa 100644 (file)
@@ -383,14 +383,20 @@ static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
 
 int mt6797_dai_adda_register(struct mtk_base_afe *afe)
 {
-       int id = MT6797_DAI_ADDA;
+       struct mtk_base_afe_dai *dai;
 
-       afe->sub_dais[id].dai_drivers = mtk_dai_adda_driver;
-       afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
 
-       afe->sub_dais[id].dapm_widgets = mtk_dai_adda_widgets;
-       afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
-       afe->sub_dais[id].dapm_routes = mtk_dai_adda_routes;
-       afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_adda_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+       dai->dapm_widgets = mtk_dai_adda_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+       dai->dapm_routes = mtk_dai_adda_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
        return 0;
 }
index 4cf985b15a11e9b9c136280f64f9c81451b62dda..ed23e6a53b086f63e42ab539916d94e889a521c8 100644 (file)
@@ -100,13 +100,19 @@ static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
 
 int mt6797_dai_hostless_register(struct mtk_base_afe *afe)
 {
-       int id = MT6797_DAI_HOSTLESS_LPBK;
+       struct mtk_base_afe_dai *dai;
 
-       afe->sub_dais[id].dai_drivers = mtk_dai_hostless_driver;
-       afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
 
-       afe->sub_dais[id].dapm_routes = mtk_dai_hostless_routes;
-       afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_hostless_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+       dai->dapm_routes = mtk_dai_hostless_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
 
        return 0;
 }
index 16d5b5067204ad9f25654744c755e5e4f641ddb4..3136f0bc7827d789703d798957a711a7d9abb411 100644 (file)
@@ -298,15 +298,20 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
 
 int mt6797_dai_pcm_register(struct mtk_base_afe *afe)
 {
-       int id = MT6797_DAI_PCM_1;
+       struct mtk_base_afe_dai *dai;
 
-       afe->sub_dais[id].dai_drivers = mtk_dai_pcm_driver;
-       afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
 
-       afe->sub_dais[id].dapm_widgets = mtk_dai_pcm_widgets;
-       afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
-       afe->sub_dais[id].dapm_routes = mtk_dai_pcm_routes;
-       afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+       list_add(&dai->list, &afe->sub_dais);
 
+       dai->dai_drivers = mtk_dai_pcm_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+       dai->dapm_widgets = mtk_dai_pcm_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+       dai->dapm_routes = mtk_dai_pcm_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
        return 0;
 }
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
new file mode 100644 (file)
index 0000000..8af8bc3
--- /dev/null
@@ -0,0 +1,65 @@
+menu "ASoC support for Amlogic platforms"
+       depends on ARCH_MESON || COMPILE_TEST
+
+config SND_MESON_AXG_FIFO
+       tristate
+       select REGMAP_MMIO
+
+config SND_MESON_AXG_FRDDR
+       tristate "Amlogic AXG Playback FIFO support"
+       select SND_MESON_AXG_FIFO
+       help
+         Select Y or M to add support for the frontend playback interfaces
+         embedded in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_TODDR
+       tristate "Amlogic AXG Capture FIFO support"
+       select SND_MESON_AXG_FIFO
+       help
+         Select Y or M to add support for the frontend capture interfaces
+         embedded in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_TDM_FORMATTER
+       tristate
+       select REGMAP_MMIO
+
+config SND_MESON_AXG_TDM_INTERFACE
+       tristate
+       select SND_MESON_AXG_TDM_FORMATTER
+
+config SND_MESON_AXG_TDMIN
+       tristate "Amlogic AXG TDM Input Support"
+       select SND_MESON_AXG_TDM_FORMATTER
+       select SND_MESON_AXG_TDM_INTERFACE
+       help
+         Select Y or M to add support for TDM input formatter embedded
+         in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_TDMOUT
+       tristate "Amlogic AXG TDM Output Support"
+       select SND_MESON_AXG_TDM_FORMATTER
+       select SND_MESON_AXG_TDM_INTERFACE
+       help
+         Select Y or M to add support for TDM output formatter embedded
+         in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_SOUND_CARD
+       tristate "Amlogic AXG Sound Card Support"
+       select SND_MESON_AXG_TDM_INTERFACE
+       imply SND_MESON_AXG_FRDDR
+       imply SND_MESON_AXG_TODDR
+       imply SND_MESON_AXG_TDMIN
+       imply SND_MESON_AXG_TDMOUT
+       imply SND_MESON_AXG_SPDIFOUT
+       help
+         Select Y or M to add support for the AXG SoC sound card
+
+config SND_MESON_AXG_SPDIFOUT
+       tristate "Amlogic AXG SPDIF Output Support"
+       select SND_PCM_IEC958
+       imply SND_SOC_SPDIF
+       help
+         Select Y or M to add support for SPDIF output serializer embedded
+         in the Amlogic AXG SoC family
+
+endmenu
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
new file mode 100644 (file)
index 0000000..c5e003b
--- /dev/null
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+snd-soc-meson-axg-fifo-objs := axg-fifo.o
+snd-soc-meson-axg-frddr-objs := axg-frddr.o
+snd-soc-meson-axg-toddr-objs := axg-toddr.o
+snd-soc-meson-axg-tdm-formatter-objs := axg-tdm-formatter.o
+snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o
+snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
+snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
+snd-soc-meson-axg-sound-card-objs := axg-card.o
+snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
+
+obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
+obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o
+obj-$(CONFIG_SND_MESON_AXG_TODDR) += snd-soc-meson-axg-toddr.o
+obj-$(CONFIG_SND_MESON_AXG_TDM_FORMATTER) += snd-soc-meson-axg-tdm-formatter.o
+obj-$(CONFIG_SND_MESON_AXG_TDM_INTERFACE) += snd-soc-meson-axg-tdm-interface.o
+obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
+obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
+obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
new file mode 100644 (file)
index 0000000..2914ba0
--- /dev/null
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm.h"
+
+struct axg_card {
+       struct snd_soc_card card;
+       void **link_data;
+};
+
+struct axg_dai_link_tdm_mask {
+       u32 tx;
+       u32 rx;
+};
+
+struct axg_dai_link_tdm_data {
+       unsigned int mclk_fs;
+       unsigned int slots;
+       unsigned int slot_width;
+       u32 *tx_mask;
+       u32 *rx_mask;
+       struct axg_dai_link_tdm_mask *codec_masks;
+};
+
+#define PREFIX "amlogic,"
+
+static int axg_card_reallocate_links(struct axg_card *priv,
+                                    unsigned int num_links)
+{
+       struct snd_soc_dai_link *links;
+       void **ldata;
+
+       links = krealloc(priv->card.dai_link,
+                        num_links * sizeof(*priv->card.dai_link),
+                        GFP_KERNEL | __GFP_ZERO);
+       ldata = krealloc(priv->link_data,
+                        num_links * sizeof(*priv->link_data),
+                        GFP_KERNEL | __GFP_ZERO);
+
+       if (!links || !ldata) {
+               dev_err(priv->card.dev, "failed to allocate links\n");
+               return -ENOMEM;
+       }
+
+       priv->card.dai_link = links;
+       priv->link_data = ldata;
+       priv->card.num_links = num_links;
+       return 0;
+}
+
+static int axg_card_parse_dai(struct snd_soc_card *card,
+                             struct device_node *node,
+                             struct device_node **dai_of_node,
+                             const char **dai_name)
+{
+       struct of_phandle_args args;
+       int ret;
+
+       if (!dai_name || !dai_of_node || !node)
+               return -EINVAL;
+
+       ret = of_parse_phandle_with_args(node, "sound-dai",
+                                        "#sound-dai-cells", 0, &args);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(card->dev, "can't parse dai %d\n", ret);
+               return ret;
+       }
+       *dai_of_node = args.np;
+
+       return snd_soc_get_dai_name(&args, dai_name);
+}
+
+static int axg_card_set_link_name(struct snd_soc_card *card,
+                                 struct snd_soc_dai_link *link,
+                                 const char *prefix)
+{
+       char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
+                                   prefix, link->cpu_of_node->full_name);
+       if (!name)
+               return -ENOMEM;
+
+       link->name = name;
+       link->stream_name = name;
+
+       return 0;
+}
+
+static void axg_card_clean_references(struct axg_card *priv)
+{
+       struct snd_soc_card *card = &priv->card;
+       struct snd_soc_dai_link *link;
+       int i, j;
+
+       if (card->dai_link) {
+               for (i = 0; i < card->num_links; i++) {
+                       link = &card->dai_link[i];
+                       of_node_put(link->cpu_of_node);
+                       for (j = 0; j < link->num_codecs; j++)
+                               of_node_put(link->codecs[j].of_node);
+               }
+       }
+
+       if (card->aux_dev) {
+               for (i = 0; i < card->num_aux_devs; i++)
+                       of_node_put(card->aux_dev[i].codec_of_node);
+       }
+
+       kfree(card->dai_link);
+       kfree(priv->link_data);
+}
+
+static int axg_card_add_aux_devices(struct snd_soc_card *card)
+{
+       struct device_node *node = card->dev->of_node;
+       struct snd_soc_aux_dev *aux;
+       int num, i;
+
+       num = of_count_phandle_with_args(node, "audio-aux-devs", NULL);
+       if (num == -ENOENT) {
+               /*
+                * It is ok to have no auxiliary devices but for this card it
+                * is a strange situtation. Let's warn the about it.
+                */
+               dev_warn(card->dev, "card has no auxiliary devices\n");
+               return 0;
+       } else if (num < 0) {
+               dev_err(card->dev, "error getting auxiliary devices: %d\n",
+                       num);
+               return num;
+       }
+
+       aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL);
+       if (!aux)
+               return -ENOMEM;
+       card->aux_dev = aux;
+       card->num_aux_devs = num;
+
+       for (i = 0; i < card->num_aux_devs; i++, aux++) {
+               aux->codec_of_node =
+                       of_parse_phandle(node, "audio-aux-devs", i);
+               if (!aux->codec_of_node)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct axg_dai_link_tdm_data *be =
+               (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+       struct snd_soc_dai *codec_dai;
+       unsigned int mclk;
+       int ret, i;
+
+       if (be->mclk_fs) {
+               mclk = params_rate(params) * be->mclk_fs;
+
+               for (i = 0; i < rtd->num_codecs; i++) {
+                       codec_dai = rtd->codec_dais[i];
+                       ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+                                                    SND_SOC_CLOCK_IN);
+                       if (ret && ret != -ENOTSUPP)
+                               return ret;
+               }
+
+               ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk,
+                                            SND_SOC_CLOCK_OUT);
+               if (ret && ret != -ENOTSUPP)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops axg_card_tdm_be_ops = {
+       .hw_params = axg_card_tdm_be_hw_params,
+};
+
+static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct axg_dai_link_tdm_data *be =
+               (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+       struct snd_soc_dai *codec_dai;
+       int ret, i;
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               codec_dai = rtd->codec_dais[i];
+               ret = snd_soc_dai_set_tdm_slot(codec_dai,
+                                              be->codec_masks[i].tx,
+                                              be->codec_masks[i].rx,
+                                              be->slots, be->slot_width);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(codec_dai->dev,
+                               "setting tdm link slots failed\n");
+                       return ret;
+               }
+       }
+
+       ret = axg_tdm_set_tdm_slots(rtd->cpu_dai, be->tx_mask, be->rx_mask,
+                                   be->slots, be->slot_width);
+       if (ret) {
+               dev_err(rtd->cpu_dai->dev, "setting tdm link slots failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct axg_dai_link_tdm_data *be =
+               (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+       int ret;
+
+       /* The loopback rx_mask is the pad tx_mask */
+       ret = axg_tdm_set_tdm_slots(rtd->cpu_dai, NULL, be->tx_mask,
+                                   be->slots, be->slot_width);
+       if (ret) {
+               dev_err(rtd->cpu_dai->dev, "setting tdm link slots failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
+                                    int *index)
+{
+       struct axg_card *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai_link *pad = &card->dai_link[*index];
+       struct snd_soc_dai_link *lb;
+       int ret;
+
+       /* extend links */
+       ret = axg_card_reallocate_links(priv, card->num_links + 1);
+       if (ret)
+               return ret;
+
+       lb = &card->dai_link[*index + 1];
+
+       lb->name = kasprintf(GFP_KERNEL, "%s-lb", pad->name);
+       if (!lb->name)
+               return -ENOMEM;
+
+       lb->stream_name = lb->name;
+       lb->cpu_of_node = pad->cpu_of_node;
+       lb->cpu_dai_name = "TDM Loopback";
+       lb->codec_name = "snd-soc-dummy";
+       lb->codec_dai_name = "snd-soc-dummy-dai";
+       lb->dpcm_capture = 1;
+       lb->no_pcm = 1;
+       lb->ops = &axg_card_tdm_be_ops;
+       lb->init = axg_card_tdm_dai_lb_init;
+
+       /* Provide the same link data to the loopback */
+       priv->link_data[*index + 1] = priv->link_data[*index];
+
+       /*
+        * axg_card_clean_references() will iterate over this link,
+        * make sure the node count is balanced
+        */
+       of_node_get(lb->cpu_of_node);
+
+       /* Let add_links continue where it should */
+       *index += 1;
+
+       return 0;
+}
+
+static unsigned int axg_card_parse_daifmt(struct device_node *node,
+                                         struct device_node *cpu_node)
+{
+       struct device_node *bitclkmaster = NULL;
+       struct device_node *framemaster = NULL;
+       unsigned int daifmt;
+
+       daifmt = snd_soc_of_parse_daifmt(node, PREFIX,
+                                        &bitclkmaster, &framemaster);
+       daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+       /* If no master is provided, default to cpu master */
+       if (!bitclkmaster || bitclkmaster == cpu_node) {
+               daifmt |= (!framemaster || framemaster == cpu_node) ?
+                       SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
+       } else {
+               daifmt |= (!framemaster || framemaster == cpu_node) ?
+                       SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
+       }
+
+       of_node_put(bitclkmaster);
+       of_node_put(framemaster);
+
+       return daifmt;
+}
+
+static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
+                                       struct snd_soc_dai_link *link,
+                                       struct device_node *node,
+                                       struct axg_dai_link_tdm_data *be)
+{
+       char propname[32];
+       u32 tx, rx;
+       int i;
+
+       be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+                                  sizeof(*be->tx_mask), GFP_KERNEL);
+       be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+                                  sizeof(*be->rx_mask), GFP_KERNEL);
+       if (!be->tx_mask || !be->rx_mask)
+               return -ENOMEM;
+
+       for (i = 0, tx = 0; i < AXG_TDM_NUM_LANES; i++) {
+               snprintf(propname, 32, "dai-tdm-slot-tx-mask-%d", i);
+               snd_soc_of_get_slot_mask(node, propname, &be->tx_mask[i]);
+               tx = max(tx, be->tx_mask[i]);
+       }
+
+       /* Disable playback is the interface has no tx slots */
+       if (!tx)
+               link->dpcm_playback = 0;
+
+       for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) {
+               snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i);
+               snd_soc_of_get_slot_mask(node, propname, &be->rx_mask[i]);
+               rx = max(rx, be->rx_mask[i]);
+       }
+
+       /* Disable capture is the interface has no rx slots */
+       if (!rx)
+               link->dpcm_capture = 0;
+
+       /* ... but the interface should at least have one of them */
+       if (!tx && !rx) {
+               dev_err(card->dev, "tdm link has no cpu slots\n");
+               return -EINVAL;
+       }
+
+       of_property_read_u32(node, "dai-tdm-slot-num", &be->slots);
+       if (!be->slots) {
+               /*
+                * If the slot number is not provided, set it such as it
+                * accommodates the largest mask
+                */
+               be->slots = fls(max(tx, rx));
+       } else if (be->slots < fls(max(tx, rx)) || be->slots > 32) {
+               /*
+                * Error if the slots can't accommodate the largest mask or
+                * if it is just too big
+                */
+               dev_err(card->dev, "bad slot number\n");
+               return -EINVAL;
+       }
+
+       of_property_read_u32(node, "dai-tdm-slot-width", &be->slot_width);
+
+       return 0;
+}
+
+static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
+                                      struct snd_soc_dai_link *link,
+                                      struct device_node *node,
+                                      struct axg_dai_link_tdm_data *be)
+{
+       struct axg_dai_link_tdm_mask *codec_mask;
+       struct device_node *np;
+
+       codec_mask = devm_kcalloc(card->dev, link->num_codecs,
+                                 sizeof(*codec_mask), GFP_KERNEL);
+       if (!codec_mask)
+               return -ENOMEM;
+
+       be->codec_masks = codec_mask;
+
+       for_each_child_of_node(node, np) {
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask",
+                                        &codec_mask->rx);
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask",
+                                        &codec_mask->tx);
+
+               codec_mask++;
+       }
+
+       return 0;
+}
+
+static int axg_card_parse_tdm(struct snd_soc_card *card,
+                             struct device_node *node,
+                             int *index)
+{
+       struct axg_card *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai_link *link = &card->dai_link[*index];
+       struct axg_dai_link_tdm_data *be;
+       int ret;
+
+       /* Allocate tdm link parameters */
+       be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
+       if (!be)
+               return -ENOMEM;
+       priv->link_data[*index] = be;
+
+       /* Setup tdm link */
+       link->ops = &axg_card_tdm_be_ops;
+       link->init = axg_card_tdm_dai_init;
+       link->dai_fmt = axg_card_parse_daifmt(node, link->cpu_of_node);
+
+       of_property_read_u32(node, "mclk-fs", &be->mclk_fs);
+
+       ret = axg_card_parse_cpu_tdm_slots(card, link, node, be);
+       if (ret) {
+               dev_err(card->dev, "error parsing tdm link slots\n");
+               return ret;
+       }
+
+       ret = axg_card_parse_codecs_masks(card, link, node, be);
+       if (ret)
+               return ret;
+
+       /* Add loopback if the pad dai has playback */
+       if (link->dpcm_playback) {
+               ret = axg_card_add_tdm_loopback(card, index);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int axg_card_set_be_link(struct snd_soc_card *card,
+                               struct snd_soc_dai_link *link,
+                               struct device_node *node)
+{
+       struct snd_soc_dai_link_component *codec;
+       struct device_node *np;
+       int ret, num_codecs;
+
+       link->no_pcm = 1;
+       link->dpcm_playback = 1;
+       link->dpcm_capture = 1;
+
+       num_codecs = of_get_child_count(node);
+       if (!num_codecs) {
+               dev_err(card->dev, "be link %s has no codec\n",
+                       node->full_name);
+               return -EINVAL;
+       }
+
+       codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
+       if (!codec)
+               return -ENOMEM;
+
+       link->codecs = codec;
+       link->num_codecs = num_codecs;
+
+       for_each_child_of_node(node, np) {
+               ret = axg_card_parse_dai(card, np, &codec->of_node,
+                                        &codec->dai_name);
+               if (ret) {
+                       of_node_put(np);
+                       return ret;
+               }
+
+               codec++;
+       }
+
+       ret = axg_card_set_link_name(card, link, "be");
+       if (ret)
+               dev_err(card->dev, "error setting %s link name\n", np->name);
+
+       return ret;
+}
+
+static int axg_card_set_fe_link(struct snd_soc_card *card,
+                               struct snd_soc_dai_link *link,
+                               bool is_playback)
+{
+       link->dynamic = 1;
+       link->dpcm_merged_format = 1;
+       link->dpcm_merged_chan = 1;
+       link->dpcm_merged_rate = 1;
+       link->codec_dai_name = "snd-soc-dummy-dai";
+       link->codec_name = "snd-soc-dummy";
+
+       if (is_playback)
+               link->dpcm_playback = 1;
+       else
+               link->dpcm_capture = 1;
+
+       return axg_card_set_link_name(card, link, "fe");
+}
+
+static int axg_card_cpu_is_capture_fe(struct device_node *np)
+{
+       return of_device_is_compatible(np, PREFIX "axg-toddr");
+}
+
+static int axg_card_cpu_is_playback_fe(struct device_node *np)
+{
+       return of_device_is_compatible(np, PREFIX "axg-frddr");
+}
+
+static int axg_card_cpu_is_tdm_iface(struct device_node *np)
+{
+       return of_device_is_compatible(np, PREFIX "axg-tdm-iface");
+}
+
+static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
+                            int *index)
+{
+       struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
+       int ret;
+
+       ret = axg_card_parse_dai(card, np, &dai_link->cpu_of_node,
+                                &dai_link->cpu_dai_name);
+       if (ret)
+               return ret;
+
+       if (axg_card_cpu_is_playback_fe(dai_link->cpu_of_node))
+               ret = axg_card_set_fe_link(card, dai_link, true);
+       else if (axg_card_cpu_is_capture_fe(dai_link->cpu_of_node))
+               ret = axg_card_set_fe_link(card, dai_link, false);
+       else
+               ret = axg_card_set_be_link(card, dai_link, np);
+
+       if (ret)
+               return ret;
+
+       if (axg_card_cpu_is_tdm_iface(dai_link->cpu_of_node))
+               ret = axg_card_parse_tdm(card, np, index);
+
+       return ret;
+}
+
+static int axg_card_add_links(struct snd_soc_card *card)
+{
+       struct axg_card *priv = snd_soc_card_get_drvdata(card);
+       struct device_node *node = card->dev->of_node;
+       struct device_node *np;
+       int num, i, ret;
+
+       num = of_get_child_count(node);
+       if (!num) {
+               dev_err(card->dev, "card has no links\n");
+               return -EINVAL;
+       }
+
+       ret = axg_card_reallocate_links(priv, num);
+       if (ret)
+               return ret;
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               ret = axg_card_add_link(card, np, &i);
+               if (ret) {
+                       of_node_put(np);
+                       return ret;
+               }
+
+               i++;
+       }
+
+       return 0;
+}
+
+static int axg_card_parse_of_optional(struct snd_soc_card *card,
+                                     const char *propname,
+                                     int (*func)(struct snd_soc_card *c,
+                                                 const char *p))
+{
+       /* If property is not provided, don't fail ... */
+       if (!of_property_read_bool(card->dev->of_node, propname))
+               return 0;
+
+       /* ... but do fail if it is provided and the parsing fails */
+       return func(card, propname);
+}
+
+static const struct of_device_id axg_card_of_match[] = {
+       { .compatible = "amlogic,axg-sound-card", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, axg_card_of_match);
+
+static int axg_card_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct axg_card *priv;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+       snd_soc_card_set_drvdata(&priv->card, priv);
+
+       priv->card.owner = THIS_MODULE;
+       priv->card.dev = dev;
+
+       ret = snd_soc_of_parse_card_name(&priv->card, "model");
+       if (ret < 0)
+               return ret;
+
+       ret = axg_card_parse_of_optional(&priv->card, "audio-routing",
+                                        snd_soc_of_parse_audio_routing);
+       if (ret) {
+               dev_err(dev, "error while parsing routing\n");
+               return ret;
+       }
+
+       ret = axg_card_parse_of_optional(&priv->card, "audio-widgets",
+                                        snd_soc_of_parse_audio_simple_widgets);
+       if (ret) {
+               dev_err(dev, "error while parsing widgets\n");
+               return ret;
+       }
+
+       ret = axg_card_add_links(&priv->card);
+       if (ret)
+               goto out_err;
+
+       ret = axg_card_add_aux_devices(&priv->card);
+       if (ret)
+               goto out_err;
+
+       ret = devm_snd_soc_register_card(dev, &priv->card);
+       if (ret)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       axg_card_clean_references(priv);
+       return ret;
+}
+
+static int axg_card_remove(struct platform_device *pdev)
+{
+       struct axg_card *priv = platform_get_drvdata(pdev);
+
+       axg_card_clean_references(priv);
+
+       return 0;
+}
+
+static struct platform_driver axg_card_pdrv = {
+       .probe = axg_card_probe,
+       .remove = axg_card_remove,
+       .driver = {
+               .name = "axg-sound-card",
+               .of_match_table = axg_card_of_match,
+       },
+};
+module_platform_driver(axg_card_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG ALSA machine driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
new file mode 100644 (file)
index 0000000..3026255
--- /dev/null
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-fifo.h"
+
+/*
+ * This file implements the platform operations common to the playback and
+ * capture frontend DAI. The logic behind this two types of fifo is very
+ * similar but some difference exist.
+ * These differences the respective DAI drivers
+ */
+
+static struct snd_pcm_hardware axg_fifo_hw = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_PAUSE),
+
+       .formats = AXG_FIFO_FORMATS,
+       .rate_min = 5512,
+       .rate_max = 192000,
+       .channels_min = 1,
+       .channels_max = AXG_FIFO_CH_MAX,
+       .period_bytes_min = AXG_FIFO_MIN_DEPTH,
+       .period_bytes_max = UINT_MAX,
+       .periods_min = 2,
+       .periods_max = UINT_MAX,
+
+       /* No real justification for this */
+       .buffer_bytes_max = 1 * 1024 * 1024,
+};
+
+static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss)
+{
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+
+       return rtd->cpu_dai;
+}
+
+static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss)
+{
+       struct snd_soc_dai *dai = axg_fifo_dai(ss);
+
+       return snd_soc_dai_get_drvdata(dai);
+}
+
+static struct device *axg_fifo_dev(struct snd_pcm_substream *ss)
+{
+       struct snd_soc_dai *dai = axg_fifo_dai(ss);
+
+       return dai->dev;
+}
+
+static void __dma_enable(struct axg_fifo *fifo,  bool enable)
+{
+       regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_DMA_EN,
+                          enable ? CTRL0_DMA_EN : 0);
+}
+
+static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               __dma_enable(fifo, true);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_STOP:
+               __dma_enable(fifo, false);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss)
+{
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+       struct snd_pcm_runtime *runtime = ss->runtime;
+       unsigned int addr;
+
+       regmap_read(fifo->map, FIFO_STATUS2, &addr);
+
+       return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
+}
+
+static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = ss->runtime;
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+       dma_addr_t end_ptr;
+       unsigned int burst_num;
+       int ret;
+
+       ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(params));
+       if (ret < 0)
+               return ret;
+
+       /* Setup dma memory pointers */
+       end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
+       regmap_write(fifo->map, FIFO_START_ADDR, runtime->dma_addr);
+       regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
+
+       /* Setup interrupt periodicity */
+       burst_num = params_period_bytes(params) / AXG_FIFO_BURST;
+       regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
+
+       /* Enable block count irq */
+       regmap_update_bits(fifo->map, FIFO_CTRL0,
+                          CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
+                          CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT));
+
+       return 0;
+}
+
+static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss)
+{
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+
+       /* Disable the block count irq */
+       regmap_update_bits(fifo->map, FIFO_CTRL0,
+                          CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
+
+       return snd_pcm_lib_free_pages(ss);
+}
+
+static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
+{
+       regmap_update_bits(fifo->map, FIFO_CTRL1,
+                          CTRL1_INT_CLR(FIFO_INT_MASK),
+                          CTRL1_INT_CLR(mask));
+
+       /* Clear must also be cleared */
+       regmap_update_bits(fifo->map, FIFO_CTRL1,
+                          CTRL1_INT_CLR(FIFO_INT_MASK),
+                          0);
+}
+
+static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
+{
+       struct snd_pcm_substream *ss = dev_id;
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+       unsigned int status;
+
+       regmap_read(fifo->map, FIFO_STATUS1, &status);
+
+       status = STATUS1_INT_STS(status) & FIFO_INT_MASK;
+       if (status & FIFO_INT_COUNT_REPEAT)
+               snd_pcm_period_elapsed(ss);
+       else
+               dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
+                       status);
+
+       /* Ack irqs */
+       axg_fifo_ack_irq(fifo, status);
+
+       return IRQ_RETVAL(status);
+}
+
+static int axg_fifo_pcm_open(struct snd_pcm_substream *ss)
+{
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+       struct device *dev = axg_fifo_dev(ss);
+       int ret;
+
+       snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw);
+
+       /*
+        * Make sure the buffer and period size are multiple of the FIFO
+        * minimum depth size
+        */
+       ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                        AXG_FIFO_MIN_DEPTH);
+       if (ret)
+               return ret;
+
+       ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                        AXG_FIFO_MIN_DEPTH);
+       if (ret)
+               return ret;
+
+       ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
+                         dev_name(dev), ss);
+
+       /* Enable pclk to access registers and clock the fifo ip */
+       ret = clk_prepare_enable(fifo->pclk);
+       if (ret)
+               return ret;
+
+       /* Setup status2 so it reports the memory pointer */
+       regmap_update_bits(fifo->map, FIFO_CTRL1,
+                          CTRL1_STATUS2_SEL_MASK,
+                          CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ));
+
+       /* Make sure the dma is initially disabled */
+       __dma_enable(fifo, false);
+
+       /* Disable irqs until params are ready */
+       regmap_update_bits(fifo->map, FIFO_CTRL0,
+                          CTRL0_INT_EN(FIFO_INT_MASK), 0);
+
+       /* Clear any pending interrupt */
+       axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
+
+       /* Take memory arbitror out of reset */
+       ret = reset_control_deassert(fifo->arb);
+       if (ret)
+               clk_disable_unprepare(fifo->pclk);
+
+       return ret;
+}
+
+static int axg_fifo_pcm_close(struct snd_pcm_substream *ss)
+{
+       struct axg_fifo *fifo = axg_fifo_data(ss);
+       int ret;
+
+       /* Put the memory arbitror back in reset */
+       ret = reset_control_assert(fifo->arb);
+
+       /* Disable fifo ip and register access */
+       clk_disable_unprepare(fifo->pclk);
+
+       /* remove IRQ */
+       free_irq(fifo->irq, ss);
+
+       return ret;
+}
+
+const struct snd_pcm_ops axg_fifo_pcm_ops = {
+       .open =         axg_fifo_pcm_open,
+       .close =        axg_fifo_pcm_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    axg_fifo_pcm_hw_params,
+       .hw_free =      axg_fifo_pcm_hw_free,
+       .pointer =      axg_fifo_pcm_pointer,
+       .trigger =      axg_fifo_pcm_trigger,
+};
+EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops);
+
+int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       size_t size = axg_fifo_hw.buffer_bytes_max;
+
+       return snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream,
+                                            SNDRV_DMA_TYPE_DEV, card->dev,
+                                            size, size);
+}
+EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
+
+static const struct regmap_config axg_fifo_regmap_cfg = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = FIFO_STATUS2,
+};
+
+int axg_fifo_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const struct axg_fifo_match_data *data;
+       struct axg_fifo *fifo;
+       struct resource *res;
+       void __iomem *regs;
+
+       data = of_device_get_match_data(dev);
+       if (!data) {
+               dev_err(dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
+       fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
+       if (!fifo)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, fifo);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg);
+       if (IS_ERR(fifo->map)) {
+               dev_err(dev, "failed to init regmap: %ld\n",
+                       PTR_ERR(fifo->map));
+               return PTR_ERR(fifo->map);
+       }
+
+       fifo->pclk = devm_clk_get(dev, NULL);
+       if (IS_ERR(fifo->pclk)) {
+               if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get pclk: %ld\n",
+                               PTR_ERR(fifo->pclk));
+               return PTR_ERR(fifo->pclk);
+       }
+
+       fifo->arb = devm_reset_control_get_exclusive(dev, NULL);
+       if (IS_ERR(fifo->arb)) {
+               if (PTR_ERR(fifo->arb) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get arb reset: %ld\n",
+                               PTR_ERR(fifo->arb));
+               return PTR_ERR(fifo->arb);
+       }
+
+       fifo->irq = of_irq_get(dev->of_node, 0);
+       if (fifo->irq <= 0) {
+               dev_err(dev, "failed to get irq: %d\n", fifo->irq);
+               return fifo->irq;
+       }
+
+       return devm_snd_soc_register_component(dev, data->component_drv,
+                                              data->dai_drv, 1);
+}
+EXPORT_SYMBOL_GPL(axg_fifo_probe);
+
+MODULE_DESCRIPTION("Amlogic AXG fifo driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
new file mode 100644 (file)
index 0000000..cb6c401
--- /dev/null
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef _MESON_AXG_FIFO_H
+#define _MESON_AXG_FIFO_H
+
+struct clk;
+struct platform_device;
+struct regmap;
+struct reset_control;
+
+struct snd_soc_component_driver;
+struct snd_soc_dai;
+struct snd_soc_dai_driver;
+struct snd_pcm_ops;
+struct snd_soc_pcm_runtime;
+
+#define AXG_FIFO_CH_MAX                        128
+#define AXG_FIFO_RATES                 (SNDRV_PCM_RATE_5512 |          \
+                                        SNDRV_PCM_RATE_8000_192000)
+#define AXG_FIFO_FORMATS               (SNDRV_PCM_FMTBIT_S8 |          \
+                                        SNDRV_PCM_FMTBIT_S16_LE |      \
+                                        SNDRV_PCM_FMTBIT_S20_LE |      \
+                                        SNDRV_PCM_FMTBIT_S24_LE |      \
+                                        SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AXG_FIFO_BURST                 8
+#define AXG_FIFO_MIN_CNT               64
+#define AXG_FIFO_MIN_DEPTH             (AXG_FIFO_BURST * AXG_FIFO_MIN_CNT)
+
+#define FIFO_INT_ADDR_FINISH           BIT(0)
+#define FIFO_INT_ADDR_INT              BIT(1)
+#define FIFO_INT_COUNT_REPEAT          BIT(2)
+#define FIFO_INT_COUNT_ONCE            BIT(3)
+#define FIFO_INT_FIFO_ZERO             BIT(4)
+#define FIFO_INT_FIFO_DEPTH            BIT(5)
+#define FIFO_INT_MASK                  GENMASK(7, 0)
+
+#define FIFO_CTRL0                     0x00
+#define  CTRL0_DMA_EN                  BIT(31)
+#define  CTRL0_INT_EN(x)               ((x) << 16)
+#define  CTRL0_SEL_MASK                        GENMASK(2, 0)
+#define  CTRL0_SEL_SHIFT               0
+#define FIFO_CTRL1                     0x04
+#define  CTRL1_INT_CLR(x)              ((x) << 0)
+#define  CTRL1_STATUS2_SEL_MASK                GENMASK(11, 8)
+#define  CTRL1_STATUS2_SEL(x)          ((x) << 8)
+#define   STATUS2_SEL_DDR_READ         0
+#define  CTRL1_THRESHOLD_MASK          GENMASK(23, 16)
+#define  CTRL1_THRESHOLD(x)            ((x) << 16)
+#define  CTRL1_FRDDR_DEPTH_MASK                GENMASK(31, 24)
+#define  CTRL1_FRDDR_DEPTH(x)          ((x) << 24)
+#define FIFO_START_ADDR                        0x08
+#define FIFO_FINISH_ADDR               0x0c
+#define FIFO_INT_ADDR                  0x10
+#define FIFO_STATUS1                   0x14
+#define  STATUS1_INT_STS(x)            ((x) << 0)
+#define FIFO_STATUS2                   0x18
+
+struct axg_fifo {
+       struct regmap *map;
+       struct clk *pclk;
+       struct reset_control *arb;
+       int irq;
+};
+
+struct axg_fifo_match_data {
+       const struct snd_soc_component_driver *component_drv;
+       struct snd_soc_dai_driver *dai_drv;
+};
+
+extern const struct snd_pcm_ops axg_fifo_pcm_ops;
+
+int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type);
+int axg_fifo_probe(struct platform_device *pdev);
+
+#endif /* _MESON_AXG_FIFO_H */
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
new file mode 100644 (file)
index 0000000..a6f6f6a
--- /dev/null
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+/* This driver implements the frontend playback DAI of AXG based SoCs */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-fifo.h"
+
+#define CTRL0_FRDDR_PP_MODE    BIT(30)
+
+static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+       unsigned int fifo_depth, fifo_threshold;
+       int ret;
+
+       /* Enable pclk to access registers and clock the fifo ip */
+       ret = clk_prepare_enable(fifo->pclk);
+       if (ret)
+               return ret;
+
+       /* Apply single buffer mode to the interface */
+       regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
+
+       /*
+        * TODO: We could adapt the fifo depth and the fifo threshold
+        * depending on the expected memory throughput and lantencies
+        * For now, we'll just use the same values as the vendor kernel
+        * Depth and threshold are zero based.
+        */
+       fifo_depth = AXG_FIFO_MIN_CNT - 1;
+       fifo_threshold = (AXG_FIFO_MIN_CNT / 2) - 1;
+       regmap_update_bits(fifo->map, FIFO_CTRL1,
+                          CTRL1_FRDDR_DEPTH_MASK | CTRL1_THRESHOLD_MASK,
+                          CTRL1_FRDDR_DEPTH(fifo_depth) |
+                          CTRL1_THRESHOLD(fifo_threshold));
+
+       return 0;
+}
+
+static void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream,
+                                  struct snd_soc_dai *dai)
+{
+       struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable_unprepare(fifo->pclk);
+}
+
+static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
+                            struct snd_soc_dai *dai)
+{
+       return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static const struct snd_soc_dai_ops axg_frddr_ops = {
+       .startup        = axg_frddr_dai_startup,
+       .shutdown       = axg_frddr_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver axg_frddr_dai_drv = {
+       .name = "FRDDR",
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 1,
+               .channels_max   = AXG_FIFO_CH_MAX,
+               .rates          = AXG_FIFO_RATES,
+               .formats        = AXG_FIFO_FORMATS,
+       },
+       .ops            = &axg_frddr_ops,
+       .pcm_new        = axg_frddr_pcm_new,
+};
+
+static const char * const axg_frddr_sel_texts[] = {
+       "OUT 0", "OUT 1", "OUT 2", "OUT 3"
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
+                           axg_frddr_sel_texts);
+
+static const struct snd_kcontrol_new axg_frddr_out_demux =
+       SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum);
+
+static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = {
+       SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0,
+                          &axg_frddr_out_demux),
+       SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = {
+       { "SINK SEL", NULL, "Playback" },
+       { "OUT 0", "OUT 0",  "SINK SEL" },
+       { "OUT 1", "OUT 1",  "SINK SEL" },
+       { "OUT 2", "OUT 2",  "SINK SEL" },
+       { "OUT 3", "OUT 3",  "SINK SEL" },
+};
+
+static const struct snd_soc_component_driver axg_frddr_component_drv = {
+       .dapm_widgets           = axg_frddr_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(axg_frddr_dapm_widgets),
+       .dapm_routes            = axg_frddr_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(axg_frddr_dapm_routes),
+       .ops                    = &axg_fifo_pcm_ops
+};
+
+static const struct axg_fifo_match_data axg_frddr_match_data = {
+       .component_drv  = &axg_frddr_component_drv,
+       .dai_drv        = &axg_frddr_dai_drv
+};
+
+static const struct of_device_id axg_frddr_of_match[] = {
+       {
+               .compatible = "amlogic,axg-frddr",
+               .data = &axg_frddr_match_data,
+       }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
+
+static struct platform_driver axg_frddr_pdrv = {
+       .probe = axg_fifo_probe,
+       .driver = {
+               .name = "axg-frddr",
+               .of_match_table = axg_frddr_of_match,
+       },
+};
+module_platform_driver(axg_frddr_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG playback fifo driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c
new file mode 100644 (file)
index 0000000..9dea528
--- /dev/null
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm_iec958.h>
+
+/*
+ * NOTE:
+ * The meaning of bits SPDIFOUT_CTRL0_XXX_SEL is actually the opposite
+ * of what the documentation says. Manual control on V, U and C bits is
+ * applied when the related sel bits are cleared
+ */
+
+#define SPDIFOUT_STAT                  0x00
+#define SPDIFOUT_GAIN0                 0x04
+#define SPDIFOUT_GAIN1                 0x08
+#define SPDIFOUT_CTRL0                 0x0c
+#define  SPDIFOUT_CTRL0_EN             BIT(31)
+#define  SPDIFOUT_CTRL0_RST_OUT                BIT(29)
+#define  SPDIFOUT_CTRL0_RST_IN         BIT(28)
+#define  SPDIFOUT_CTRL0_USEL           BIT(26)
+#define  SPDIFOUT_CTRL0_USET           BIT(25)
+#define  SPDIFOUT_CTRL0_CHSTS_SEL      BIT(24)
+#define  SPDIFOUT_CTRL0_DATA_SEL       BIT(20)
+#define  SPDIFOUT_CTRL0_MSB_FIRST      BIT(19)
+#define  SPDIFOUT_CTRL0_VSEL           BIT(18)
+#define  SPDIFOUT_CTRL0_VSET           BIT(17)
+#define  SPDIFOUT_CTRL0_MASK_MASK      GENMASK(11, 4)
+#define  SPDIFOUT_CTRL0_MASK(x)                ((x) << 4)
+#define SPDIFOUT_CTRL1                 0x10
+#define  SPDIFOUT_CTRL1_MSB_POS_MASK   GENMASK(12, 8)
+#define  SPDIFOUT_CTRL1_MSB_POS(x)     ((x) << 8)
+#define  SPDIFOUT_CTRL1_TYPE_MASK      GENMASK(6, 4)
+#define  SPDIFOUT_CTRL1_TYPE(x)                ((x) << 4)
+#define SPDIFOUT_PREAMB                        0x14
+#define SPDIFOUT_SWAP                  0x18
+#define SPDIFOUT_CHSTS0                        0x1c
+#define SPDIFOUT_CHSTS1                        0x20
+#define SPDIFOUT_CHSTS2                        0x24
+#define SPDIFOUT_CHSTS3                        0x28
+#define SPDIFOUT_CHSTS4                        0x2c
+#define SPDIFOUT_CHSTS5                        0x30
+#define SPDIFOUT_CHSTS6                        0x34
+#define SPDIFOUT_CHSTS7                        0x38
+#define SPDIFOUT_CHSTS8                        0x3c
+#define SPDIFOUT_CHSTS9                        0x40
+#define SPDIFOUT_CHSTSA                        0x44
+#define SPDIFOUT_CHSTSB                        0x48
+#define SPDIFOUT_MUTE_VAL              0x4c
+
+struct axg_spdifout {
+       struct regmap *map;
+       struct clk *mclk;
+       struct clk *pclk;
+};
+
+static void axg_spdifout_enable(struct regmap *map)
+{
+       /* Apply both reset */
+       regmap_update_bits(map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_RST_OUT | SPDIFOUT_CTRL0_RST_IN,
+                          0);
+
+       /* Clear out reset before in reset */
+       regmap_update_bits(map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_RST_OUT, SPDIFOUT_CTRL0_RST_OUT);
+       regmap_update_bits(map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_RST_IN,  SPDIFOUT_CTRL0_RST_IN);
+
+       /* Enable spdifout */
+       regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN,
+                          SPDIFOUT_CTRL0_EN);
+}
+
+static void axg_spdifout_disable(struct regmap *map)
+{
+       regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN, 0);
+}
+
+static int axg_spdifout_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               axg_spdifout_enable(priv->map);
+               return 0;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               axg_spdifout_disable(priv->map);
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int axg_spdifout_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+
+       /* Use spdif valid bit to perform digital mute */
+       regmap_update_bits(priv->map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_VSET,
+                          mute ? SPDIFOUT_CTRL0_VSET : 0);
+
+       return 0;
+}
+
+static int axg_spdifout_sample_fmt(struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+       unsigned int val;
+
+       /* Set the samples spdifout will pull from the FIFO */
+       switch (params_channels(params)) {
+       case 1:
+               val = SPDIFOUT_CTRL0_MASK(0x1);
+               break;
+       case 2:
+               val = SPDIFOUT_CTRL0_MASK(0x3);
+               break;
+       default:
+               dev_err(dai->dev, "too many channels for spdif dai: %u\n",
+                       params_channels(params));
+               return -EINVAL;
+       }
+
+       regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_MASK_MASK, val);
+
+       /* FIFO data are arranged in chunks of 64bits */
+       switch (params_physical_width(params)) {
+       case 8:
+               /* 8 samples of 8 bits */
+               val = SPDIFOUT_CTRL1_TYPE(0);
+               break;
+       case 16:
+               /* 4 samples of 16 bits - right justified */
+               val = SPDIFOUT_CTRL1_TYPE(2);
+               break;
+       case 32:
+               /* 2 samples of 32 bits - right justified */
+               val = SPDIFOUT_CTRL1_TYPE(4);
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported physical width: %u\n",
+                       params_physical_width(params));
+               return -EINVAL;
+       }
+
+       /* Position of the MSB in FIFO samples */
+       val |= SPDIFOUT_CTRL1_MSB_POS(params_width(params) - 1);
+
+       regmap_update_bits(priv->map, SPDIFOUT_CTRL1,
+                          SPDIFOUT_CTRL1_MSB_POS_MASK |
+                          SPDIFOUT_CTRL1_TYPE_MASK, val);
+
+       regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
+                          0);
+
+       return 0;
+}
+
+static int axg_spdifout_set_chsts(struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+       unsigned int offset;
+       int ret;
+       u8 cs[4];
+       u32 val;
+
+       ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, 4);
+       if (ret < 0) {
+               dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
+                       ret);
+               return ret;
+       }
+       val = cs[0] | cs[1] << 8 | cs[2] << 16 | cs[3] << 24;
+
+       /* Setup channel status A bits [31 - 0]*/
+       regmap_write(priv->map, SPDIFOUT_CHSTS0, val);
+
+       /* Clear channel status A bits [191 - 32] */
+       for (offset = SPDIFOUT_CHSTS1; offset <= SPDIFOUT_CHSTS5;
+            offset += regmap_get_reg_stride(priv->map))
+               regmap_write(priv->map, offset, 0);
+
+       /* Setup channel status B bits [31 - 0]*/
+       regmap_write(priv->map, SPDIFOUT_CHSTS6, val);
+
+       /* Clear channel status B bits [191 - 32] */
+       for (offset = SPDIFOUT_CHSTS7; offset <= SPDIFOUT_CHSTSB;
+            offset += regmap_get_reg_stride(priv->map))
+               regmap_write(priv->map, offset, 0);
+
+       return 0;
+}
+
+static int axg_spdifout_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       int ret;
+
+       /* 2 * 32bits per subframe * 2 channels = 128 */
+       ret = clk_set_rate(priv->mclk, rate * 128);
+       if (ret) {
+               dev_err(dai->dev, "failed to set spdif clock\n");
+               return ret;
+       }
+
+       ret = axg_spdifout_sample_fmt(params, dai);
+       if (ret) {
+               dev_err(dai->dev, "failed to setup sample format\n");
+               return ret;
+       }
+
+       ret = axg_spdifout_set_chsts(params, dai);
+       if (ret) {
+               dev_err(dai->dev, "failed to setup channel status words\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int axg_spdifout_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       /* Clock the spdif output block */
+       ret = clk_prepare_enable(priv->pclk);
+       if (ret) {
+               dev_err(dai->dev, "failed to enable pclk\n");
+               return ret;
+       }
+
+       /* Make sure the block is initially stopped */
+       axg_spdifout_disable(priv->map);
+
+       /* Insert data from bit 27 lsb first */
+       regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
+                          0);
+
+       /* Manual control of V, C and U, U = 0 */
+       regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+                          SPDIFOUT_CTRL0_CHSTS_SEL | SPDIFOUT_CTRL0_VSEL |
+                          SPDIFOUT_CTRL0_USEL | SPDIFOUT_CTRL0_USET,
+                          0);
+
+       /* Static SWAP configuration ATM */
+       regmap_write(priv->map, SPDIFOUT_SWAP, 0x10);
+
+       return 0;
+}
+
+static void axg_spdifout_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable_unprepare(priv->pclk);
+}
+
+static const struct snd_soc_dai_ops axg_spdifout_ops = {
+       .trigger        = axg_spdifout_trigger,
+       .digital_mute   = axg_spdifout_digital_mute,
+       .hw_params      = axg_spdifout_hw_params,
+       .startup        = axg_spdifout_startup,
+       .shutdown       = axg_spdifout_shutdown,
+};
+
+static struct snd_soc_dai_driver axg_spdifout_dai_drv[] = {
+       {
+               .name = "SPDIF Output",
+               .playback = {
+                       .stream_name    = "Playback",
+                       .channels_min   = 1,
+                       .channels_max   = 2,
+                       .rates          = (SNDRV_PCM_RATE_32000  |
+                                          SNDRV_PCM_RATE_44100  |
+                                          SNDRV_PCM_RATE_48000  |
+                                          SNDRV_PCM_RATE_88200  |
+                                          SNDRV_PCM_RATE_96000  |
+                                          SNDRV_PCM_RATE_176400 |
+                                          SNDRV_PCM_RATE_192000),
+                       .formats        = (SNDRV_PCM_FMTBIT_S8     |
+                                          SNDRV_PCM_FMTBIT_S16_LE |
+                                          SNDRV_PCM_FMTBIT_S20_LE |
+                                          SNDRV_PCM_FMTBIT_S24_LE),
+               },
+               .ops = &axg_spdifout_ops,
+       },
+};
+
+static const char * const spdifout_sel_texts[] = {
+       "IN 0", "IN 1", "IN 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_spdifout_sel_enum, SPDIFOUT_CTRL1, 24,
+                           spdifout_sel_texts);
+
+static const struct snd_kcontrol_new axg_spdifout_in_mux =
+       SOC_DAPM_ENUM("Input Source", axg_spdifout_sel_enum);
+
+static const struct snd_soc_dapm_widget axg_spdifout_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_spdifout_in_mux),
+};
+
+static const struct snd_soc_dapm_route axg_spdifout_dapm_routes[] = {
+       { "SRC SEL", "IN 0", "IN 0" },
+       { "SRC SEL", "IN 1", "IN 1" },
+       { "SRC SEL", "IN 2", "IN 2" },
+       { "Playback", NULL, "SRC SEL" },
+};
+
+static const struct snd_kcontrol_new axg_spdifout_controls[] = {
+       SOC_DOUBLE("Playback Volume", SPDIFOUT_GAIN0,  0,  8, 255, 0),
+       SOC_DOUBLE("Playback Switch", SPDIFOUT_CTRL0, 22, 21, 1, 1),
+       SOC_SINGLE("Playback Gain Enable Switch",
+                  SPDIFOUT_CTRL1, 26, 1, 0),
+       SOC_SINGLE("Playback Channels Mix Switch",
+                  SPDIFOUT_CTRL0, 23, 1, 0),
+};
+
+static int axg_spdifout_set_bias_level(struct snd_soc_component *component,
+                                      enum snd_soc_bias_level level)
+{
+       struct axg_spdifout *priv = snd_soc_component_get_drvdata(component);
+       enum snd_soc_bias_level now =
+               snd_soc_component_get_bias_level(component);
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (now == SND_SOC_BIAS_STANDBY)
+                       ret = clk_prepare_enable(priv->mclk);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (now == SND_SOC_BIAS_PREPARE)
+                       clk_disable_unprepare(priv->mclk);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_ON:
+               break;
+       }
+
+       return ret;
+}
+
+static const struct snd_soc_component_driver axg_spdifout_component_drv = {
+       .controls               = axg_spdifout_controls,
+       .num_controls           = ARRAY_SIZE(axg_spdifout_controls),
+       .dapm_widgets           = axg_spdifout_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(axg_spdifout_dapm_widgets),
+       .dapm_routes            = axg_spdifout_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(axg_spdifout_dapm_routes),
+       .set_bias_level         = axg_spdifout_set_bias_level,
+};
+
+static const struct regmap_config axg_spdifout_regmap_cfg = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = SPDIFOUT_MUTE_VAL,
+};
+
+static const struct of_device_id axg_spdifout_of_match[] = {
+       { .compatible = "amlogic,axg-spdifout", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, axg_spdifout_of_match);
+
+static int axg_spdifout_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct axg_spdifout *priv;
+       struct resource *res;
+       void __iomem *regs;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, priv);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifout_regmap_cfg);
+       if (IS_ERR(priv->map)) {
+               dev_err(dev, "failed to init regmap: %ld\n",
+                       PTR_ERR(priv->map));
+               return PTR_ERR(priv->map);
+       }
+
+       priv->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(priv->pclk)) {
+               ret = PTR_ERR(priv->pclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get pclk: %d\n", ret);
+               return ret;
+       }
+
+       priv->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(priv->mclk)) {
+               ret = PTR_ERR(priv->mclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get mclk: %d\n", ret);
+               return ret;
+       }
+
+       return devm_snd_soc_register_component(dev, &axg_spdifout_component_drv,
+                       axg_spdifout_dai_drv, ARRAY_SIZE(axg_spdifout_dai_drv));
+}
+
+static struct platform_driver axg_spdifout_pdrv = {
+       .probe = axg_spdifout_probe,
+       .driver = {
+               .name = "axg-spdifout",
+               .of_match_table = axg_spdifout_of_match,
+       },
+};
+module_platform_driver(axg_spdifout_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG SPDIF Output driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
new file mode 100644 (file)
index 0000000..43e390f
--- /dev/null
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "axg-tdm-formatter.h"
+
+struct axg_tdm_formatter {
+       struct list_head list;
+       struct axg_tdm_stream *stream;
+       const struct axg_tdm_formatter_driver *drv;
+       struct clk *pclk;
+       struct clk *sclk;
+       struct clk *lrclk;
+       struct clk *sclk_sel;
+       struct clk *lrclk_sel;
+       bool enabled;
+       struct regmap *map;
+};
+
+int axg_tdm_formatter_set_channel_masks(struct regmap *map,
+                                       struct axg_tdm_stream *ts,
+                                       unsigned int offset)
+{
+       unsigned int val, ch = ts->channels;
+       unsigned long mask;
+       int i, j;
+
+       /*
+        * Distribute the channels of the stream over the available slots
+        * of each TDM lane
+        */
+       for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
+               val = 0;
+               mask = ts->mask[i];
+
+               for (j = find_first_bit(&mask, 32);
+                    (j < 32) && ch;
+                    j = find_next_bit(&mask, 32, j + 1)) {
+                       val |= 1 << j;
+                       ch -= 1;
+               }
+
+               regmap_write(map, offset, val);
+               offset += regmap_get_reg_stride(map);
+       }
+
+       /*
+        * If we still have channel left at the end of the process, it means
+        * the stream has more channels than we can accommodate and we should
+        * have caught this earlier.
+        */
+       if (WARN_ON(ch != 0)) {
+               pr_err("channel mask error\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
+
+static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter)
+{
+       struct axg_tdm_stream *ts = formatter->stream;
+       bool invert = formatter->drv->invert_sclk;
+       int ret;
+
+       /* Do nothing if the formatter is already enabled */
+       if (formatter->enabled)
+               return 0;
+
+       /*
+        * If sclk is inverted, invert it back and provide the inversion
+        * required by the formatter
+        */
+       invert ^= axg_tdm_sclk_invert(ts->iface->fmt);
+       ret = clk_set_phase(formatter->sclk, invert ? 180 : 0);
+       if (ret)
+               return ret;
+
+       /* Setup the stream parameter in the formatter */
+       ret = formatter->drv->ops->prepare(formatter->map, formatter->stream);
+       if (ret)
+               return ret;
+
+       /* Enable the signal clocks feeding the formatter */
+       ret = clk_prepare_enable(formatter->sclk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(formatter->lrclk);
+       if (ret) {
+               clk_disable_unprepare(formatter->sclk);
+               return ret;
+       }
+
+       /* Finally, actually enable the formatter */
+       formatter->drv->ops->enable(formatter->map);
+       formatter->enabled = true;
+
+       return 0;
+}
+
+static void axg_tdm_formatter_disable(struct axg_tdm_formatter *formatter)
+{
+       /* Do nothing if the formatter is already disabled */
+       if (!formatter->enabled)
+               return;
+
+       formatter->drv->ops->disable(formatter->map);
+       clk_disable_unprepare(formatter->lrclk);
+       clk_disable_unprepare(formatter->sclk);
+       formatter->enabled = false;
+}
+
+static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
+{
+       struct axg_tdm_stream *ts = formatter->stream;
+       int ret = 0;
+
+       mutex_lock(&ts->lock);
+
+       /* Catch up if the stream is already running when we attach */
+       if (ts->ready) {
+               ret = axg_tdm_formatter_enable(formatter);
+               if (ret) {
+                       pr_err("failed to enable formatter\n");
+                       goto out;
+               }
+       }
+
+       list_add_tail(&formatter->list, &ts->formatter_list);
+out:
+       mutex_unlock(&ts->lock);
+       return ret;
+}
+
+static void axg_tdm_formatter_dettach(struct axg_tdm_formatter *formatter)
+{
+       struct axg_tdm_stream *ts = formatter->stream;
+
+       mutex_lock(&ts->lock);
+       list_del(&formatter->list);
+       mutex_unlock(&ts->lock);
+
+       axg_tdm_formatter_disable(formatter);
+}
+
+static int axg_tdm_formatter_power_up(struct axg_tdm_formatter *formatter,
+                                     struct snd_soc_dapm_widget *w)
+{
+       struct axg_tdm_stream *ts = formatter->drv->ops->get_stream(w);
+       int ret;
+
+       /*
+        * If we don't get a stream at this stage, it would mean that the
+        * widget is powering up but is not attached to any backend DAI.
+        * It should not happen, ever !
+        */
+       if (WARN_ON(!ts))
+               return -ENODEV;
+
+       /* Clock our device */
+       ret = clk_prepare_enable(formatter->pclk);
+       if (ret)
+               return ret;
+
+       /* Reparent the bit clock to the TDM interface */
+       ret = clk_set_parent(formatter->sclk_sel, ts->iface->sclk);
+       if (ret)
+               goto disable_pclk;
+
+       /* Reparent the sample clock to the TDM interface */
+       ret = clk_set_parent(formatter->lrclk_sel, ts->iface->lrclk);
+       if (ret)
+               goto disable_pclk;
+
+       formatter->stream = ts;
+       ret = axg_tdm_formatter_attach(formatter);
+       if (ret)
+               goto disable_pclk;
+
+       return 0;
+
+disable_pclk:
+       clk_disable_unprepare(formatter->pclk);
+       return ret;
+}
+
+static void axg_tdm_formatter_power_down(struct axg_tdm_formatter *formatter)
+{
+       axg_tdm_formatter_dettach(formatter);
+       clk_disable_unprepare(formatter->pclk);
+       formatter->stream = NULL;
+}
+
+int axg_tdm_formatter_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *control,
+                           int event)
+{
+       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+       struct axg_tdm_formatter *formatter = snd_soc_component_get_drvdata(c);
+       int ret = 0;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               ret = axg_tdm_formatter_power_up(formatter, w);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               axg_tdm_formatter_power_down(formatter);
+               break;
+
+       default:
+               dev_err(c->dev, "Unexpected event %d\n", event);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_formatter_event);
+
+int axg_tdm_formatter_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const struct axg_tdm_formatter_driver *drv;
+       struct axg_tdm_formatter *formatter;
+       struct resource *res;
+       void __iomem *regs;
+       int ret;
+
+       drv = of_device_get_match_data(dev);
+       if (!drv) {
+               dev_err(dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
+       formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+       if (!formatter)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, formatter);
+       formatter->drv = drv;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg);
+       if (IS_ERR(formatter->map)) {
+               dev_err(dev, "failed to init regmap: %ld\n",
+                       PTR_ERR(formatter->map));
+               return PTR_ERR(formatter->map);
+       }
+
+       /* Peripharal clock */
+       formatter->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(formatter->pclk)) {
+               ret = PTR_ERR(formatter->pclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get pclk: %d\n", ret);
+               return ret;
+       }
+
+       /* Formatter bit clock */
+       formatter->sclk = devm_clk_get(dev, "sclk");
+       if (IS_ERR(formatter->sclk)) {
+               ret = PTR_ERR(formatter->sclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get sclk: %d\n", ret);
+               return ret;
+       }
+
+       /* Formatter sample clock */
+       formatter->lrclk = devm_clk_get(dev, "lrclk");
+       if (IS_ERR(formatter->lrclk)) {
+               ret = PTR_ERR(formatter->lrclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get lrclk: %d\n", ret);
+               return ret;
+       }
+
+       /* Formatter bit clock input multiplexer */
+       formatter->sclk_sel = devm_clk_get(dev, "sclk_sel");
+       if (IS_ERR(formatter->sclk_sel)) {
+               ret = PTR_ERR(formatter->sclk_sel);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get sclk_sel: %d\n", ret);
+               return ret;
+       }
+
+       /* Formatter sample clock input multiplexer */
+       formatter->lrclk_sel = devm_clk_get(dev, "lrclk_sel");
+       if (IS_ERR(formatter->lrclk_sel)) {
+               ret = PTR_ERR(formatter->lrclk_sel);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get lrclk_sel: %d\n", ret);
+               return ret;
+       }
+
+       return devm_snd_soc_register_component(dev, drv->component_drv,
+                                              NULL, 0);
+}
+EXPORT_SYMBOL_GPL(axg_tdm_formatter_probe);
+
+int axg_tdm_stream_start(struct axg_tdm_stream *ts)
+{
+       struct axg_tdm_formatter *formatter;
+       int ret = 0;
+
+       mutex_lock(&ts->lock);
+       ts->ready = true;
+
+       /* Start all the formatters attached to the stream */
+       list_for_each_entry(formatter, &ts->formatter_list, list) {
+               ret = axg_tdm_formatter_enable(formatter);
+               if (ret) {
+                       pr_err("failed to start tdm stream\n");
+                       goto out;
+               }
+       }
+
+out:
+       mutex_unlock(&ts->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_start);
+
+void axg_tdm_stream_stop(struct axg_tdm_stream *ts)
+{
+       struct axg_tdm_formatter *formatter;
+
+       mutex_lock(&ts->lock);
+       ts->ready = false;
+
+       /* Stop all the formatters attached to the stream */
+       list_for_each_entry(formatter, &ts->formatter_list, list) {
+               axg_tdm_formatter_disable(formatter);
+       }
+
+       mutex_unlock(&ts->lock);
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_stop);
+
+struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface)
+{
+       struct axg_tdm_stream *ts;
+
+       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+       if (ts) {
+               INIT_LIST_HEAD(&ts->formatter_list);
+               mutex_init(&ts->lock);
+               ts->iface = iface;
+       }
+
+       return ts;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_alloc);
+
+void axg_tdm_stream_free(struct axg_tdm_stream *ts)
+{
+       /*
+        * If the list is not empty, it would mean that one of the formatter
+        * widget is still powered and attached to the interface while we
+        * we are removing the TDM DAI. It should not be possible
+        */
+       WARN_ON(!list_empty(&ts->formatter_list));
+       mutex_destroy(&ts->lock);
+       kfree(ts);
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_free);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-formatter.h b/sound/soc/meson/axg-tdm-formatter.h
new file mode 100644 (file)
index 0000000..cf947ca
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ *
+ * Copyright (c) 2018 Baylibre SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef _MESON_AXG_TDM_FORMATTER_H
+#define _MESON_AXG_TDM_FORMATTER_H
+
+#include "axg-tdm.h"
+
+struct platform_device;
+struct regmap;
+struct snd_soc_dapm_widget;
+struct snd_kcontrol;
+
+struct axg_tdm_formatter_ops {
+       struct axg_tdm_stream *(*get_stream)(struct snd_soc_dapm_widget *w);
+       void (*enable)(struct regmap *map);
+       void (*disable)(struct regmap *map);
+       int (*prepare)(struct regmap *map, struct axg_tdm_stream *ts);
+};
+
+struct axg_tdm_formatter_driver {
+       const struct snd_soc_component_driver *component_drv;
+       const struct regmap_config *regmap_cfg;
+       const struct axg_tdm_formatter_ops *ops;
+       bool invert_sclk;
+};
+
+int axg_tdm_formatter_set_channel_masks(struct regmap *map,
+                                       struct axg_tdm_stream *ts,
+                                       unsigned int offset);
+int axg_tdm_formatter_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *control,
+                           int event);
+int axg_tdm_formatter_probe(struct platform_device *pdev);
+
+#endif /* _MESON_AXG_TDM_FORMATTER_H */
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
new file mode 100644 (file)
index 0000000..7b8baf4
--- /dev/null
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm.h"
+
+enum {
+       TDM_IFACE_PAD,
+       TDM_IFACE_LOOPBACK,
+};
+
+static unsigned int axg_tdm_slots_total(u32 *mask)
+{
+       unsigned int slots = 0;
+       int i;
+
+       if (!mask)
+               return 0;
+
+       /* Count the total number of slots provided by all 4 lanes */
+       for (i = 0; i < AXG_TDM_NUM_LANES; i++)
+               slots += hweight32(mask[i]);
+
+       return slots;
+}
+
+int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
+                         u32 *rx_mask, unsigned int slots,
+                         unsigned int slot_width)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       struct axg_tdm_stream *tx = (struct axg_tdm_stream *)
+               dai->playback_dma_data;
+       struct axg_tdm_stream *rx = (struct axg_tdm_stream *)
+               dai->capture_dma_data;
+       unsigned int tx_slots, rx_slots;
+
+       tx_slots = axg_tdm_slots_total(tx_mask);
+       rx_slots = axg_tdm_slots_total(rx_mask);
+
+       /* We should at least have a slot for a valid interface */
+       if (!tx_slots && !rx_slots) {
+               dev_err(dai->dev, "interface has no slot\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Amend the dai driver channel number and let dpcm channel merge do
+        * its job
+        */
+       if (tx) {
+               tx->mask = tx_mask;
+               dai->driver->playback.channels_max = tx_slots;
+       }
+
+       if (rx) {
+               rx->mask = rx_mask;
+               dai->driver->capture.channels_max = rx_slots;
+       }
+
+       iface->slots = slots;
+
+       switch (slot_width) {
+       case 0:
+               /* defaults width to 32 if not provided */
+               iface->slot_width = 32;
+               break;
+       case 8:
+       case 16:
+       case 24:
+       case 32:
+               iface->slot_width = slot_width;
+               break;
+       default:
+               dev_err(dai->dev, "unsupported slot width: %d\n", slot_width);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_set_tdm_slots);
+
+static int axg_tdm_iface_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                   unsigned int freq, int dir)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       int ret = -ENOTSUPP;
+
+       if (dir == SND_SOC_CLOCK_OUT && clk_id == 0) {
+               if (!iface->mclk) {
+                       dev_warn(dai->dev, "master clock not provided\n");
+               } else {
+                       ret = clk_set_rate(iface->mclk, freq);
+                       if (!ret)
+                               iface->mclk_rate = freq;
+               }
+       }
+
+       return ret;
+}
+
+static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+
+       /* These modes are not supported */
+       if (fmt & (SND_SOC_DAIFMT_CBS_CFM | SND_SOC_DAIFMT_CBM_CFS)) {
+               dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
+               return -EINVAL;
+       }
+
+       /* If the TDM interface is the clock master, it requires mclk */
+       if (!iface->mclk && (fmt & SND_SOC_DAIFMT_CBS_CFS)) {
+               dev_err(dai->dev, "cpu clock master: mclk missing\n");
+               return -ENODEV;
+       }
+
+       iface->fmt = fmt;
+       return 0;
+}
+
+static int axg_tdm_iface_startup(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       struct axg_tdm_stream *ts =
+               snd_soc_dai_get_dma_data(dai, substream);
+       int ret;
+
+       if (!axg_tdm_slots_total(ts->mask)) {
+               dev_err(dai->dev, "interface has not slots\n");
+               return -EINVAL;
+       }
+
+       /* Apply component wide rate symmetry */
+       if (dai->component->active) {
+               ret = snd_pcm_hw_constraint_single(substream->runtime,
+                                                  SNDRV_PCM_HW_PARAM_RATE,
+                                                  iface->rate);
+               if (ret < 0) {
+                       dev_err(dai->dev,
+                               "can't set iface rate constraint\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+       unsigned int channels = params_channels(params);
+       unsigned int width = params_width(params);
+
+       /* Save rate and sample_bits for component symmetry */
+       iface->rate = params_rate(params);
+
+       /* Make sure this interface can cope with the stream */
+       if (axg_tdm_slots_total(ts->mask) < channels) {
+               dev_err(dai->dev, "not enough slots for channels\n");
+               return -EINVAL;
+       }
+
+       if (iface->slot_width < width) {
+               dev_err(dai->dev, "incompatible slots width for stream\n");
+               return -EINVAL;
+       }
+
+       /* Save the parameter for tdmout/tdmin widgets */
+       ts->physical_width = params_physical_width(params);
+       ts->width = params_width(params);
+       ts->channels = params_channels(params);
+
+       return 0;
+}
+
+static int axg_tdm_iface_set_lrclk(struct snd_soc_dai *dai,
+                                  struct snd_pcm_hw_params *params)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       unsigned int ratio_num;
+       int ret;
+
+       ret = clk_set_rate(iface->lrclk, params_rate(params));
+       if (ret) {
+               dev_err(dai->dev, "setting sample clock failed: %d\n", ret);
+               return ret;
+       }
+
+       switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               /* 50% duty cycle ratio */
+               ratio_num = 1;
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /*
+                * A zero duty cycle ratio will result in setting the mininum
+                * ratio possible which, for this clock, is 1 cycle of the
+                * parent bclk clock high and the rest low, This is exactly
+                * what we want here.
+                */
+               ratio_num = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       ret = clk_set_duty_cycle(iface->lrclk, ratio_num, 2);
+       if (ret) {
+               dev_err(dai->dev,
+                       "setting sample clock duty cycle failed: %d\n", ret);
+               return ret;
+       }
+
+       /* Set sample clock inversion */
+       ret = clk_set_phase(iface->lrclk,
+                           axg_tdm_lrclk_invert(iface->fmt) ? 180 : 0);
+       if (ret) {
+               dev_err(dai->dev,
+                       "setting sample clock phase failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       unsigned long srate;
+       int ret;
+
+       srate = iface->slots * iface->slot_width * params_rate(params);
+
+       if (!iface->mclk_rate) {
+               /* If no specific mclk is requested, default to bit clock * 4 */
+               clk_set_rate(iface->mclk, 4 * srate);
+       } else {
+               /* Check if we can actually get the bit clock from mclk */
+               if (iface->mclk_rate % srate) {
+                       dev_err(dai->dev,
+                               "can't derive sclk %lu from mclk %lu\n",
+                               srate, iface->mclk_rate);
+                       return -EINVAL;
+               }
+       }
+
+       ret = clk_set_rate(iface->sclk, srate);
+       if (ret) {
+               dev_err(dai->dev, "setting bit clock failed: %d\n", ret);
+               return ret;
+       }
+
+       /* Set the bit clock inversion */
+       ret = clk_set_phase(iface->sclk,
+                           axg_tdm_sclk_invert(iface->fmt) ? 0 : 180);
+       if (ret) {
+               dev_err(dai->dev, "setting bit clock phase failed: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               if (iface->slots > 2) {
+                       dev_err(dai->dev, "bad slot number for format: %d\n",
+                               iface->slots);
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAI_FORMAT_DSP_A:
+       case SND_SOC_DAI_FORMAT_DSP_B:
+               break;
+
+       default:
+               dev_err(dai->dev, "unsupported dai format\n");
+               return -EINVAL;
+       }
+
+       ret = axg_tdm_iface_set_stream(substream, params, dai);
+       if (ret)
+               return ret;
+
+       if (iface->fmt & SND_SOC_DAIFMT_CBS_CFS) {
+               ret = axg_tdm_iface_set_sclk(dai, params);
+               if (ret)
+                       return ret;
+
+               ret = axg_tdm_iface_set_lrclk(dai, params);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+
+       /* Stop all attached formatters */
+       axg_tdm_stream_stop(ts);
+
+       return 0;
+}
+
+static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+
+       /* Force all attached formatters to update */
+       return axg_tdm_stream_reset(ts);
+}
+
+static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai)
+{
+       if (dai->capture_dma_data)
+               axg_tdm_stream_free(dai->capture_dma_data);
+
+       if (dai->playback_dma_data)
+               axg_tdm_stream_free(dai->playback_dma_data);
+
+       return 0;
+}
+
+static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai)
+{
+       struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+
+       if (dai->capture_widget) {
+               dai->capture_dma_data = axg_tdm_stream_alloc(iface);
+               if (!dai->capture_dma_data)
+                       return -ENOMEM;
+       }
+
+       if (dai->playback_widget) {
+               dai->playback_dma_data = axg_tdm_stream_alloc(iface);
+               if (!dai->playback_dma_data) {
+                       axg_tdm_iface_remove_dai(dai);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
+       .set_sysclk     = axg_tdm_iface_set_sysclk,
+       .set_fmt        = axg_tdm_iface_set_fmt,
+       .startup        = axg_tdm_iface_startup,
+       .hw_params      = axg_tdm_iface_hw_params,
+       .prepare        = axg_tdm_iface_prepare,
+       .hw_free        = axg_tdm_iface_hw_free,
+};
+
+/* TDM Backend DAIs */
+static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
+       [TDM_IFACE_PAD] = {
+               .name = "TDM Pad",
+               .playback = {
+                       .stream_name    = "Playback",
+                       .channels_min   = 1,
+                       .channels_max   = AXG_TDM_CHANNEL_MAX,
+                       .rates          = AXG_TDM_RATES,
+                       .formats        = AXG_TDM_FORMATS,
+               },
+               .capture = {
+                       .stream_name    = "Capture",
+                       .channels_min   = 1,
+                       .channels_max   = AXG_TDM_CHANNEL_MAX,
+                       .rates          = AXG_TDM_RATES,
+                       .formats        = AXG_TDM_FORMATS,
+               },
+               .id = TDM_IFACE_PAD,
+               .ops = &axg_tdm_iface_ops,
+               .probe = axg_tdm_iface_probe_dai,
+               .remove = axg_tdm_iface_remove_dai,
+       },
+       [TDM_IFACE_LOOPBACK] = {
+               .name = "TDM Loopback",
+               .capture = {
+                       .stream_name    = "Loopback",
+                       .channels_min   = 1,
+                       .channels_max   = AXG_TDM_CHANNEL_MAX,
+                       .rates          = AXG_TDM_RATES,
+                       .formats        = AXG_TDM_FORMATS,
+               },
+               .id = TDM_IFACE_LOOPBACK,
+               .ops = &axg_tdm_iface_ops,
+               .probe = axg_tdm_iface_probe_dai,
+               .remove = axg_tdm_iface_remove_dai,
+       },
+};
+
+static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
+                                       enum snd_soc_bias_level level)
+{
+       struct axg_tdm_iface *iface = snd_soc_component_get_drvdata(component);
+       enum snd_soc_bias_level now =
+               snd_soc_component_get_bias_level(component);
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (now == SND_SOC_BIAS_STANDBY)
+                       ret = clk_prepare_enable(iface->mclk);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (now == SND_SOC_BIAS_PREPARE)
+                       clk_disable_unprepare(iface->mclk);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_ON:
+               break;
+       }
+
+       return ret;
+}
+
+static const struct snd_soc_component_driver axg_tdm_iface_component_drv = {
+       .set_bias_level = axg_tdm_iface_set_bias_level,
+};
+
+static const struct of_device_id axg_tdm_iface_of_match[] = {
+       { .compatible = "amlogic,axg-tdm-iface", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, axg_tdm_iface_of_match);
+
+static int axg_tdm_iface_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct snd_soc_dai_driver *dai_drv;
+       struct axg_tdm_iface *iface;
+       int ret, i;
+
+       iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL);
+       if (!iface)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, iface);
+
+       /*
+        * Duplicate dai driver: depending on the slot masks configuration
+        * We'll change the number of channel provided by DAI stream, so dpcm
+        * channel merge can be done properly
+        */
+       dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv),
+                              sizeof(*dai_drv), GFP_KERNEL);
+       if (!dai_drv)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++)
+               memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i],
+                      sizeof(*dai_drv));
+
+       /* Bit clock provided on the pad */
+       iface->sclk = devm_clk_get(dev, "sclk");
+       if (IS_ERR(iface->sclk)) {
+               ret = PTR_ERR(iface->sclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get sclk: %d\n", ret);
+               return ret;
+       }
+
+       /* Sample clock provided on the pad */
+       iface->lrclk = devm_clk_get(dev, "lrclk");
+       if (IS_ERR(iface->lrclk)) {
+               ret = PTR_ERR(iface->lrclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get lrclk: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * mclk maybe be missing when the cpu dai is in slave mode and
+        * the codec does not require it to provide a master clock.
+        * At this point, ignore the error if mclk is missing. We'll
+        * throw an error if the cpu dai is master and mclk is missing
+        */
+       iface->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(iface->mclk)) {
+               ret = PTR_ERR(iface->mclk);
+               if (ret == -ENOENT) {
+                       iface->mclk = NULL;
+               } else {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to get mclk: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return devm_snd_soc_register_component(dev,
+                                       &axg_tdm_iface_component_drv, dai_drv,
+                                       ARRAY_SIZE(axg_tdm_iface_dai_drv));
+}
+
+static struct platform_driver axg_tdm_iface_pdrv = {
+       .probe = axg_tdm_iface_probe,
+       .driver = {
+               .name = "axg-tdm-iface",
+               .of_match_table = axg_tdm_iface_of_match,
+       },
+};
+module_platform_driver(axg_tdm_iface_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM interface driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h
new file mode 100644 (file)
index 0000000..e578b6f
--- /dev/null
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ *
+ * Copyright (c) 2018 Baylibre SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef _MESON_AXG_TDM_H
+#define _MESON_AXG_TDM_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#define AXG_TDM_NUM_LANES      4
+#define AXG_TDM_CHANNEL_MAX    128
+#define AXG_TDM_RATES          (SNDRV_PCM_RATE_5512 |          \
+                                SNDRV_PCM_RATE_8000_192000)
+#define AXG_TDM_FORMATS                (SNDRV_PCM_FMTBIT_S8 |          \
+                                SNDRV_PCM_FMTBIT_S16_LE |      \
+                                SNDRV_PCM_FMTBIT_S20_LE |      \
+                                SNDRV_PCM_FMTBIT_S24_LE |      \
+                                SNDRV_PCM_FMTBIT_S32_LE)
+
+struct axg_tdm_iface {
+       struct clk *sclk;
+       struct clk *lrclk;
+       struct clk *mclk;
+       unsigned long mclk_rate;
+
+       /* format is common to all the DAIs of the iface */
+       unsigned int fmt;
+       unsigned int slots;
+       unsigned int slot_width;
+
+       /* For component wide symmetry */
+       int rate;
+};
+
+static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
+{
+       return (fmt & SND_SOC_DAIFMT_I2S) ^
+               !!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
+}
+
+static inline bool axg_tdm_sclk_invert(unsigned int fmt)
+{
+       return fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_IB_NF);
+}
+
+struct axg_tdm_stream {
+       struct axg_tdm_iface *iface;
+       struct list_head formatter_list;
+       struct mutex lock;
+       unsigned int channels;
+       unsigned int width;
+       unsigned int physical_width;
+       u32 *mask;
+       bool ready;
+};
+
+struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
+void axg_tdm_stream_free(struct axg_tdm_stream *ts);
+int axg_tdm_stream_start(struct axg_tdm_stream *ts);
+void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
+
+static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
+{
+       axg_tdm_stream_stop(ts);
+       return axg_tdm_stream_start(ts);
+}
+
+int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
+                         u32 *rx_mask, unsigned int slots,
+                         unsigned int slot_width);
+
+#endif /* _MESON_AXG_TDM_H */
diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c
new file mode 100644 (file)
index 0000000..bbac44c
--- /dev/null
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm-formatter.h"
+
+#define TDMIN_CTRL                     0x00
+#define  TDMIN_CTRL_ENABLE             BIT(31)
+#define  TDMIN_CTRL_I2S_MODE           BIT(30)
+#define  TDMIN_CTRL_RST_OUT            BIT(29)
+#define  TDMIN_CTRL_RST_IN             BIT(28)
+#define  TDMIN_CTRL_WS_INV             BIT(25)
+#define  TDMIN_CTRL_SEL_SHIFT          20
+#define  TDMIN_CTRL_IN_BIT_SKEW_MASK   GENMASK(18, 16)
+#define  TDMIN_CTRL_IN_BIT_SKEW(x)     ((x) << 16)
+#define  TDMIN_CTRL_LSB_FIRST          BIT(5)
+#define  TDMIN_CTRL_BITNUM_MASK        GENMASK(4, 0)
+#define  TDMIN_CTRL_BITNUM(x)          ((x) << 0)
+#define TDMIN_SWAP                     0x04
+#define TDMIN_MASK0                    0x08
+#define TDMIN_MASK1                    0x0c
+#define TDMIN_MASK2                    0x10
+#define TDMIN_MASK3                    0x14
+#define TDMIN_STAT                     0x18
+#define TDMIN_MUTE_VAL                 0x1c
+#define TDMIN_MUTE0                    0x20
+#define TDMIN_MUTE1                    0x24
+#define TDMIN_MUTE2                    0x28
+#define TDMIN_MUTE3                    0x2c
+
+static const struct regmap_config axg_tdmin_regmap_cfg = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = TDMIN_MUTE3,
+};
+
+static const char * const axg_tdmin_sel_texts[] = {
+       "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5",
+};
+
+/* Change to special mux control to reset dapm */
+static SOC_ENUM_SINGLE_DECL(axg_tdmin_sel_enum, TDMIN_CTRL,
+                           TDMIN_CTRL_SEL_SHIFT, axg_tdmin_sel_texts);
+
+static const struct snd_kcontrol_new axg_tdmin_in_mux =
+       SOC_DAPM_ENUM("Input Source", axg_tdmin_sel_enum);
+
+static struct snd_soc_dai *
+axg_tdmin_get_be(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_path *p = NULL;
+       struct snd_soc_dai *be;
+
+       snd_soc_dapm_widget_for_each_source_path(w, p) {
+               if (!p->connect)
+                       continue;
+
+               if (p->source->id == snd_soc_dapm_dai_out)
+                       return (struct snd_soc_dai *)p->source->priv;
+
+               be = axg_tdmin_get_be(p->source);
+               if (be)
+                       return be;
+       }
+
+       return NULL;
+}
+
+static struct axg_tdm_stream *
+axg_tdmin_get_tdm_stream(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dai *be = axg_tdmin_get_be(w);
+
+       if (!be)
+               return NULL;
+
+       return be->capture_dma_data;
+}
+
+static void axg_tdmin_enable(struct regmap *map)
+{
+       /* Apply both reset */
+       regmap_update_bits(map, TDMIN_CTRL,
+                          TDMIN_CTRL_RST_OUT | TDMIN_CTRL_RST_IN, 0);
+
+       /* Clear out reset before in reset */
+       regmap_update_bits(map, TDMIN_CTRL,
+                          TDMIN_CTRL_RST_OUT, TDMIN_CTRL_RST_OUT);
+       regmap_update_bits(map, TDMIN_CTRL,
+                          TDMIN_CTRL_RST_IN,  TDMIN_CTRL_RST_IN);
+
+       /* Actually enable tdmin */
+       regmap_update_bits(map, TDMIN_CTRL,
+                          TDMIN_CTRL_ENABLE, TDMIN_CTRL_ENABLE);
+}
+
+static void axg_tdmin_disable(struct regmap *map)
+{
+       regmap_update_bits(map, TDMIN_CTRL, TDMIN_CTRL_ENABLE, 0);
+}
+
+static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts)
+{
+       unsigned int val = 0;
+
+       /* Set stream skew */
+       switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_DSP_A:
+               val |= TDMIN_CTRL_IN_BIT_SKEW(3);
+               break;
+
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_DSP_B:
+               val = TDMIN_CTRL_IN_BIT_SKEW(2);
+               break;
+
+       default:
+               pr_err("Unsupported format: %u\n",
+                      ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+               return -EINVAL;
+       }
+
+       /* Set stream format mode */
+       switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val |= TDMIN_CTRL_I2S_MODE;
+               break;
+       }
+
+       /* If the sample clock is inverted, invert it back for the formatter */
+       if (axg_tdm_lrclk_invert(ts->iface->fmt))
+               val |= TDMIN_CTRL_WS_INV;
+
+       /* Set the slot width */
+       val |= TDMIN_CTRL_BITNUM(ts->iface->slot_width - 1);
+
+       /*
+        * The following also reset LSB_FIRST which result in the formatter
+        * placing the first bit received at bit 31
+        */
+       regmap_update_bits(map, TDMIN_CTRL,
+                          (TDMIN_CTRL_IN_BIT_SKEW_MASK | TDMIN_CTRL_WS_INV |
+                           TDMIN_CTRL_I2S_MODE | TDMIN_CTRL_LSB_FIRST |
+                           TDMIN_CTRL_BITNUM_MASK), val);
+
+       /* Set static swap mask configuration */
+       regmap_write(map, TDMIN_SWAP, 0x76543210);
+
+       return axg_tdm_formatter_set_channel_masks(map, ts, TDMIN_MASK0);
+}
+
+static const struct snd_soc_dapm_widget axg_tdmin_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmin_in_mux),
+       SND_SOC_DAPM_PGA_E("DEC", SND_SOC_NOPM, 0, 0, NULL, 0,
+                          axg_tdm_formatter_event,
+                          (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
+       SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_tdmin_dapm_routes[] = {
+       { "SRC SEL", "IN 0", "IN 0" },
+       { "SRC SEL", "IN 1", "IN 1" },
+       { "SRC SEL", "IN 2", "IN 2" },
+       { "SRC SEL", "IN 3", "IN 3" },
+       { "SRC SEL", "IN 4", "IN 4" },
+       { "SRC SEL", "IN 5", "IN 5" },
+       { "DEC", NULL, "SRC SEL" },
+       { "OUT", NULL, "DEC" },
+};
+
+static const struct snd_soc_component_driver axg_tdmin_component_drv = {
+       .dapm_widgets           = axg_tdmin_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(axg_tdmin_dapm_widgets),
+       .dapm_routes            = axg_tdmin_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(axg_tdmin_dapm_routes),
+};
+
+static const struct axg_tdm_formatter_ops axg_tdmin_ops = {
+       .get_stream     = axg_tdmin_get_tdm_stream,
+       .prepare        = axg_tdmin_prepare,
+       .enable         = axg_tdmin_enable,
+       .disable        = axg_tdmin_disable,
+};
+
+static const struct axg_tdm_formatter_driver axg_tdmin_drv = {
+       .component_drv  = &axg_tdmin_component_drv,
+       .regmap_cfg     = &axg_tdmin_regmap_cfg,
+       .ops            = &axg_tdmin_ops,
+       .invert_sclk    = false,
+};
+
+static const struct of_device_id axg_tdmin_of_match[] = {
+       {
+               .compatible = "amlogic,axg-tdmin",
+               .data = &axg_tdmin_drv,
+       }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_tdmin_of_match);
+
+static struct platform_driver axg_tdmin_pdrv = {
+       .probe = axg_tdm_formatter_probe,
+       .driver = {
+               .name = "axg-tdmin",
+               .of_match_table = axg_tdmin_of_match,
+       },
+};
+module_platform_driver(axg_tdmin_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM input formatter driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c
new file mode 100644 (file)
index 0000000..f73368e
--- /dev/null
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm-formatter.h"
+
+#define TDMOUT_CTRL0                   0x00
+#define  TDMOUT_CTRL0_BITNUM_MASK      GENMASK(4, 0)
+#define  TDMOUT_CTRL0_BITNUM(x)                ((x) << 0)
+#define  TDMOUT_CTRL0_SLOTNUM_MASK     GENMASK(9, 5)
+#define  TDMOUT_CTRL0_SLOTNUM(x)       ((x) << 5)
+#define  TDMOUT_CTRL0_INIT_BITNUM_MASK GENMASK(19, 15)
+#define  TDMOUT_CTRL0_INIT_BITNUM(x)   ((x) << 15)
+#define  TDMOUT_CTRL0_ENABLE           BIT(31)
+#define  TDMOUT_CTRL0_RST_OUT          BIT(29)
+#define  TDMOUT_CTRL0_RST_IN           BIT(28)
+#define TDMOUT_CTRL1                   0x04
+#define  TDMOUT_CTRL1_TYPE_MASK                GENMASK(6, 4)
+#define  TDMOUT_CTRL1_TYPE(x)          ((x) << 4)
+#define  TDMOUT_CTRL1_MSB_POS_MASK     GENMASK(12, 8)
+#define  TDMOUT_CTRL1_MSB_POS(x)       ((x) << 8)
+#define  TDMOUT_CTRL1_SEL_SHIFT                24
+#define  TDMOUT_CTRL1_GAIN_EN          26
+#define  TDMOUT_CTRL1_WS_INV           BIT(28)
+#define TDMOUT_SWAP                    0x08
+#define TDMOUT_MASK0                   0x0c
+#define TDMOUT_MASK1                   0x10
+#define TDMOUT_MASK2                   0x14
+#define TDMOUT_MASK3                   0x18
+#define TDMOUT_STAT                    0x1c
+#define TDMOUT_GAIN0                   0x20
+#define TDMOUT_GAIN1                   0x24
+#define TDMOUT_MUTE_VAL                        0x28
+#define TDMOUT_MUTE0                   0x2c
+#define TDMOUT_MUTE1                   0x30
+#define TDMOUT_MUTE2                   0x34
+#define TDMOUT_MUTE3                   0x38
+#define TDMOUT_MASK_VAL                        0x3c
+
+static const struct regmap_config axg_tdmout_regmap_cfg = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = TDMOUT_MASK_VAL,
+};
+
+static const struct snd_kcontrol_new axg_tdmout_controls[] = {
+       SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0,  0,  8, 255, 0),
+       SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0),
+       SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1,  0,  8, 255, 0),
+       SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0),
+       SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1,
+                  TDMOUT_CTRL1_GAIN_EN, 1, 0),
+};
+
+static const char * const tdmout_sel_texts[] = {
+       "IN 0", "IN 1", "IN 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1,
+                           TDMOUT_CTRL1_SEL_SHIFT, tdmout_sel_texts);
+
+static const struct snd_kcontrol_new axg_tdmout_in_mux =
+       SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum);
+
+static struct snd_soc_dai *
+axg_tdmout_get_be(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_path *p = NULL;
+       struct snd_soc_dai *be;
+
+       snd_soc_dapm_widget_for_each_sink_path(w, p) {
+               if (!p->connect)
+                       continue;
+
+               if (p->sink->id == snd_soc_dapm_dai_in)
+                       return (struct snd_soc_dai *)p->sink->priv;
+
+               be = axg_tdmout_get_be(p->sink);
+               if (be)
+                       return be;
+       }
+
+       return NULL;
+}
+
+static struct axg_tdm_stream *
+axg_tdmout_get_tdm_stream(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dai *be = axg_tdmout_get_be(w);
+
+       if (!be)
+               return NULL;
+
+       return be->playback_dma_data;
+}
+
+static void axg_tdmout_enable(struct regmap *map)
+{
+       /* Apply both reset */
+       regmap_update_bits(map, TDMOUT_CTRL0,
+                          TDMOUT_CTRL0_RST_OUT | TDMOUT_CTRL0_RST_IN, 0);
+
+       /* Clear out reset before in reset */
+       regmap_update_bits(map, TDMOUT_CTRL0,
+                          TDMOUT_CTRL0_RST_OUT, TDMOUT_CTRL0_RST_OUT);
+       regmap_update_bits(map, TDMOUT_CTRL0,
+                          TDMOUT_CTRL0_RST_IN,  TDMOUT_CTRL0_RST_IN);
+
+       /* Actually enable tdmout */
+       regmap_update_bits(map, TDMOUT_CTRL0,
+                          TDMOUT_CTRL0_ENABLE, TDMOUT_CTRL0_ENABLE);
+}
+
+static void axg_tdmout_disable(struct regmap *map)
+{
+       regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0);
+}
+
+static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts)
+{
+       unsigned int val = 0;
+
+       /* Set the stream skew */
+       switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_DSP_A:
+               val |= TDMOUT_CTRL0_INIT_BITNUM(1);
+               break;
+
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_DSP_B:
+               val |= TDMOUT_CTRL0_INIT_BITNUM(2);
+               break;
+
+       default:
+               pr_err("Unsupported format: %u\n",
+                      ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+               return -EINVAL;
+       }
+
+       /* Set the slot width */
+       val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1);
+
+       /* Set the slot number */
+       val |= TDMOUT_CTRL0_SLOTNUM(ts->iface->slots - 1);
+
+       regmap_update_bits(map, TDMOUT_CTRL0,
+                          TDMOUT_CTRL0_INIT_BITNUM_MASK |
+                          TDMOUT_CTRL0_BITNUM_MASK |
+                          TDMOUT_CTRL0_SLOTNUM_MASK, val);
+
+       /* Set the sample width */
+       val = TDMOUT_CTRL1_MSB_POS(ts->width - 1);
+
+       /* FIFO data are arranged in chunks of 64bits */
+       switch (ts->physical_width) {
+       case 8:
+               /* 8 samples of 8 bits */
+               val |= TDMOUT_CTRL1_TYPE(0);
+               break;
+       case 16:
+               /* 4 samples of 16 bits - right justified */
+               val |= TDMOUT_CTRL1_TYPE(2);
+               break;
+       case 32:
+               /* 2 samples of 32 bits - right justified */
+               val |= TDMOUT_CTRL1_TYPE(4);
+               break;
+       default:
+               pr_err("Unsupported physical width: %u\n",
+                      ts->physical_width);
+               return -EINVAL;
+       }
+
+       /* If the sample clock is inverted, invert it back for the formatter */
+       if (axg_tdm_lrclk_invert(ts->iface->fmt))
+               val |= TDMOUT_CTRL1_WS_INV;
+
+       regmap_update_bits(map, TDMOUT_CTRL1,
+                          (TDMOUT_CTRL1_TYPE_MASK | TDMOUT_CTRL1_MSB_POS_MASK |
+                           TDMOUT_CTRL1_WS_INV), val);
+
+       /* Set static swap mask configuration */
+       regmap_write(map, TDMOUT_SWAP, 0x76543210);
+
+       return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0);
+}
+
+static const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmout_in_mux),
+       SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0,
+                          axg_tdm_formatter_event,
+                          (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
+       SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_tdmout_dapm_routes[] = {
+       { "SRC SEL", "IN 0", "IN 0" },
+       { "SRC SEL", "IN 1", "IN 1" },
+       { "SRC SEL", "IN 2", "IN 2" },
+       { "ENC", NULL, "SRC SEL" },
+       { "OUT", NULL, "ENC" },
+};
+
+static const struct snd_soc_component_driver axg_tdmout_component_drv = {
+       .controls               = axg_tdmout_controls,
+       .num_controls           = ARRAY_SIZE(axg_tdmout_controls),
+       .dapm_widgets           = axg_tdmout_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(axg_tdmout_dapm_widgets),
+       .dapm_routes            = axg_tdmout_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(axg_tdmout_dapm_routes),
+};
+
+static const struct axg_tdm_formatter_ops axg_tdmout_ops = {
+       .get_stream     = axg_tdmout_get_tdm_stream,
+       .prepare        = axg_tdmout_prepare,
+       .enable         = axg_tdmout_enable,
+       .disable        = axg_tdmout_disable,
+};
+
+static const struct axg_tdm_formatter_driver axg_tdmout_drv = {
+       .component_drv  = &axg_tdmout_component_drv,
+       .regmap_cfg     = &axg_tdmout_regmap_cfg,
+       .ops            = &axg_tdmout_ops,
+       .invert_sclk    = true,
+};
+
+static const struct of_device_id axg_tdmout_of_match[] = {
+       {
+               .compatible = "amlogic,axg-tdmout",
+               .data = &axg_tdmout_drv,
+       }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_tdmout_of_match);
+
+static struct platform_driver axg_tdmout_pdrv = {
+       .probe = axg_tdm_formatter_probe,
+       .driver = {
+               .name = "axg-tdmout",
+               .of_match_table = axg_tdmout_of_match,
+       },
+};
+module_platform_driver(axg_tdmout_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM output formatter driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
new file mode 100644 (file)
index 0000000..c2c9bb3
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+/* This driver implements the frontend capture DAI of AXG based SoCs */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-fifo.h"
+
+#define CTRL0_TODDR_SEL_RESAMPLE       BIT(30)
+#define CTRL0_TODDR_EXT_SIGNED         BIT(29)
+#define CTRL0_TODDR_PP_MODE            BIT(28)
+#define CTRL0_TODDR_TYPE_MASK          GENMASK(15, 13)
+#define CTRL0_TODDR_TYPE(x)            ((x) << 13)
+#define CTRL0_TODDR_MSB_POS_MASK       GENMASK(12, 8)
+#define CTRL0_TODDR_MSB_POS(x)         ((x) << 8)
+#define CTRL0_TODDR_LSB_POS_MASK       GENMASK(7, 3)
+#define CTRL0_TODDR_LSB_POS(x)         ((x) << 3)
+
+static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
+                            struct snd_soc_dai *dai)
+{
+       return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+       unsigned int type, width, msb = 31;
+
+       /*
+        * NOTE:
+        * Almost all backend will place the MSB at bit 31, except SPDIF Input
+        * which will put it at index 28. When adding support for the SPDIF
+        * Input, we'll need to find which type of backend we are connected to.
+        */
+
+       switch (params_physical_width(params)) {
+       case 8:
+               type = 0; /* 8 samples of 8 bits */
+               break;
+       case 16:
+               type = 2; /* 4 samples of 16 bits - right justified */
+               break;
+       case 32:
+               type = 4; /* 2 samples of 32 bits - right justified */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       width = params_width(params);
+
+       regmap_update_bits(fifo->map, FIFO_CTRL0,
+                          CTRL0_TODDR_TYPE_MASK |
+                          CTRL0_TODDR_MSB_POS_MASK |
+                          CTRL0_TODDR_LSB_POS_MASK,
+                          CTRL0_TODDR_TYPE(type) |
+                          CTRL0_TODDR_MSB_POS(msb) |
+                          CTRL0_TODDR_LSB_POS(msb - (width - 1)));
+
+       return 0;
+}
+
+static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+       unsigned int fifo_threshold;
+       int ret;
+
+       /* Enable pclk to access registers and clock the fifo ip */
+       ret = clk_prepare_enable(fifo->pclk);
+       if (ret)
+               return ret;
+
+       /* Select orginal data - resampling not supported ATM */
+       regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_SEL_RESAMPLE, 0);
+
+       /* Only signed format are supported ATM */
+       regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_EXT_SIGNED,
+                          CTRL0_TODDR_EXT_SIGNED);
+
+       /* Apply single buffer mode to the interface */
+       regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_PP_MODE, 0);
+
+       /* TODDR does not have a configurable fifo depth */
+       fifo_threshold = AXG_FIFO_MIN_CNT - 1;
+       regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_THRESHOLD_MASK,
+                          CTRL1_THRESHOLD(fifo_threshold));
+
+       return 0;
+}
+
+static void axg_toddr_dai_shutdown(struct snd_pcm_substream *substream,
+                                  struct snd_soc_dai *dai)
+{
+       struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable_unprepare(fifo->pclk);
+}
+
+static const struct snd_soc_dai_ops axg_toddr_ops = {
+       .hw_params      = axg_toddr_dai_hw_params,
+       .startup        = axg_toddr_dai_startup,
+       .shutdown       = axg_toddr_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver axg_toddr_dai_drv = {
+       .name = "TODDR",
+       .capture = {
+               .stream_name    = "Capture",
+               .channels_min   = 1,
+               .channels_max   = AXG_FIFO_CH_MAX,
+               .rates          = AXG_FIFO_RATES,
+               .formats        = AXG_FIFO_FORMATS,
+       },
+       .ops            = &axg_toddr_ops,
+       .pcm_new        = axg_toddr_pcm_new,
+};
+
+static const char * const axg_toddr_sel_texts[] = {
+       "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 6"
+};
+
+static const unsigned int axg_toddr_sel_values[] = {
+       0, 1, 2, 3, 4, 6
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0,
+                                 CTRL0_SEL_SHIFT, CTRL0_SEL_MASK,
+                                 axg_toddr_sel_texts, axg_toddr_sel_values);
+
+static const struct snd_kcontrol_new axg_toddr_in_mux =
+       SOC_DAPM_ENUM("Input Source", axg_toddr_sel_enum);
+
+static const struct snd_soc_dapm_widget axg_toddr_dapm_widgets[] = {
+       SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_toddr_in_mux),
+       SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = {
+       { "Capture", NULL, "SRC SEL" },
+       { "SRC SEL", "IN 0", "IN 0" },
+       { "SRC SEL", "IN 1", "IN 1" },
+       { "SRC SEL", "IN 2", "IN 2" },
+       { "SRC SEL", "IN 3", "IN 3" },
+       { "SRC SEL", "IN 4", "IN 4" },
+       { "SRC SEL", "IN 6", "IN 6" },
+};
+
+static const struct snd_soc_component_driver axg_toddr_component_drv = {
+       .dapm_widgets           = axg_toddr_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(axg_toddr_dapm_widgets),
+       .dapm_routes            = axg_toddr_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(axg_toddr_dapm_routes),
+       .ops                    = &axg_fifo_pcm_ops
+};
+
+static const struct axg_fifo_match_data axg_toddr_match_data = {
+       .component_drv  = &axg_toddr_component_drv,
+       .dai_drv        = &axg_toddr_dai_drv
+};
+
+static const struct of_device_id axg_toddr_of_match[] = {
+       {
+               .compatible = "amlogic,axg-toddr",
+               .data = &axg_toddr_match_data,
+       }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_toddr_of_match);
+
+static struct platform_driver axg_toddr_pdrv = {
+       .probe = axg_fifo_probe,
+       .driver = {
+               .name = "axg-toddr",
+               .of_match_table = axg_toddr_of_match,
+       },
+};
+module_platform_driver(axg_toddr_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG capture fifo driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index 15ccbf479c9664019159b215cbb5f97e2f37cd62..d5ae9eb8c7569f6364f8fc5173be2967cd9be092 100644 (file)
@@ -40,7 +40,7 @@ struct abe_twl6040 {
        int     mclk_freq;      /* MCLK frequency speed for twl6040 */
 };
 
-struct platform_device *dmic_codec_dev;
+static struct platform_device *dmic_codec_dev;
 
 static int omap_abe_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
index 51dd7c65096bd62c67013bea6e7e383e48c626a3..fe966272bd0cd0ba6d049bb60d80f759722eb96d 100644 (file)
@@ -213,8 +213,10 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
        switch (channels) {
        case 6:
                dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
+               /* fall through */
        case 4:
                dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
+               /* fall through */
        case 2:
                dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
                break;
index 0e97360f9890980ce9e069e99c1a04a975986033..4c1be36c22075b3b449325dfc44eccd565c50f1a 100644 (file)
@@ -310,15 +310,19 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
                        /* up to 3 channels for capture */
                        return -EINVAL;
                link_mask |= 1 << 4;
+               /* fall through */
        case 4:
                if (stream == SNDRV_PCM_STREAM_CAPTURE)
                        /* up to 3 channels for capture */
                        return -EINVAL;
                link_mask |= 1 << 3;
+               /* fall through */
        case 3:
                link_mask |= 1 << 2;
+               /* fall through */
        case 2:
                link_mask |= 1 << 1;
+               /* fall through */
        case 1:
                link_mask |= 1 << 0;
                break;
index 960744e46edc0549854f2ec5e28e68bf8a60a232..776e148b0aa20f6a9ab3a00e63d3ea0f251e0266 100644 (file)
@@ -24,15 +24,19 @@ config SND_PXA2XX_AC97
 config SND_PXA2XX_SOC_AC97
        tristate
        select AC97_BUS
+       select SND_PXA2XX_LIB
        select SND_PXA2XX_LIB_AC97
        select SND_SOC_AC97_BUS
 
 config SND_PXA2XX_SOC_I2S
+       select SND_PXA2XX_LIB
        tristate
 
 config SND_PXA_SOC_SSP
-       tristate
+       tristate "Soc Audio via PXA2xx/PXA3xx SSP ports"
+       depends on PLAT_PXA
        select PXA_SSP
+       select SND_PXA2XX_LIB
 
 config SND_MMP_SOC_SSPA
        tristate
index 2fc012b06c439bcba72b436e271e1ed26abafb36..935a248e5bf68375540a0f26c439a7578316f45c 100644 (file)
@@ -90,95 +90,9 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int acps, acds, width;
-       unsigned int div4 = PXA_SSP_CLK_SCDB_4;
+       unsigned int width;
        int ret = 0;
 
-       width = snd_pcm_format_physical_width(params_format(params));
-
-       /*
-        * rate = SSPSCLK / (2 * width(16 or 32))
-        * SSPSCLK = (ACPS / ACDS) / SSPSCLKDIV(div4 or div1)
-        */
-       switch (params_rate(params)) {
-       case 8000:
-               /* off by a factor of 2: bug in the PXA27x audio clock? */
-               acps = 32842000;
-               switch (width) {
-               case 16:
-                       /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_16;
-                       break;
-               default: /* 32 */
-                       /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_8;
-               }
-               break;
-       case 11025:
-               acps = 5622000;
-               switch (width) {
-               case 16:
-                       /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_4;
-                       break;
-               default: /* 32 */
-                       /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_2;
-               }
-               break;
-       case 22050:
-               acps = 5622000;
-               switch (width) {
-               case 16:
-                       /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_2;
-                       break;
-               default: /* 32 */
-                       /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_1;
-               }
-               break;
-       case 44100:
-               acps = 5622000;
-               switch (width) {
-               case 16:
-                       /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_2;
-                       break;
-               default: /* 32 */
-                       /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_1;
-               }
-               break;
-       case 48000:
-               acps = 12235000;
-               switch (width) {
-               case 16:
-                       /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_2;
-                       break;
-               default: /* 32 */
-                       /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_1;
-               }
-               break;
-       case 96000:
-       default:
-               acps = 12235000;
-               switch (width) {
-               case 16:
-                       /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_1;
-                       break;
-               default: /* 32 */
-                       /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */
-                       acds = PXA_SSP_CLK_AUDIO_DIV_2;
-                       div4 = PXA_SSP_CLK_SCDB_1;
-                       break;
-               }
-               break;
-       }
-
        /* set codec DAI configuration */
        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
                        SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
@@ -191,6 +105,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       width = snd_pcm_format_physical_width(params_format(params));
        ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width);
        if (ret < 0)
                return ret;
@@ -201,23 +116,6 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       /* set the SSP audio system clock ACDS divider */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai,
-                       PXA_SSP_AUDIO_DIV_ACDS, acds);
-       if (ret < 0)
-               return ret;
-
-       /* set the SSP audio system clock SCDB divider4 */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai,
-                       PXA_SSP_AUDIO_DIV_SCDB, div4);
-       if (ret < 0)
-               return ret;
-
-       /* set SSP audio pll clock */
-       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
index 6fc9860801309b9fc3427151ccd911dd648505e0..69033e1a84e6ad52ef7c01b395af3a8f48a91c15 100644 (file)
@@ -34,7 +34,6 @@
 #include <sound/pxa2xx-lib.h>
 #include <sound/dmaengine_pcm.h>
 
-#include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
 
 /*
@@ -42,6 +41,8 @@
  */
 struct ssp_priv {
        struct ssp_device *ssp;
+       struct clk *extclk;
+       unsigned long ssp_clk;
        unsigned int sysclk;
        unsigned int dai_fmt;
        unsigned int configured_dai_fmt;
@@ -105,9 +106,8 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
        dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
        if (!dma)
                return -ENOMEM;
-
-       dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-                               &ssp->drcmr_tx : &ssp->drcmr_rx;
+       dma->chan_name = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+               "tx" : "rx";
 
        snd_soc_dai_set_dma_data(cpu_dai, substream, dma);
 
@@ -194,21 +194,6 @@ static void pxa_ssp_set_scr(struct ssp_device *ssp, u32 div)
        pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 }
 
-/**
- * pxa_ssp_get_clkdiv - get SSP clock divider
- */
-static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
-{
-       u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
-       u32 div;
-
-       if (ssp->type == PXA25x_SSP)
-               div = ((sscr0 >> 8) & 0xff) * 2 + 2;
-       else
-               div = ((sscr0 >> 8) & 0xfff) + 1;
-       return div;
-}
-
 /*
  * Set the SSP ports SYSCLK.
  */
@@ -221,6 +206,21 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
                ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
 
+       if (priv->extclk) {
+               int ret;
+
+               /*
+                * For DT based boards, if an extclk is given, use it
+                * here and configure PXA_SSP_CLK_EXT.
+                */
+
+               ret = clk_set_rate(priv->extclk, freq);
+               if (ret < 0)
+                       return ret;
+
+               clk_id = PXA_SSP_CLK_EXT;
+       }
+
        dev_dbg(&ssp->pdev->dev,
                "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
                cpu_dai->id, clk_id, freq);
@@ -264,67 +264,18 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-/*
- * Set the SSP clock dividers.
- */
-static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-       int div_id, int div)
-{
-       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
-       struct ssp_device *ssp = priv->ssp;
-       int val;
-
-       switch (div_id) {
-       case PXA_SSP_AUDIO_DIV_ACDS:
-               val = (pxa_ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div);
-               pxa_ssp_write_reg(ssp, SSACD, val);
-               break;
-       case PXA_SSP_AUDIO_DIV_SCDB:
-               val = pxa_ssp_read_reg(ssp, SSACD);
-               val &= ~SSACD_SCDB;
-               if (ssp->type == PXA3xx_SSP)
-                       val &= ~SSACD_SCDX8;
-               switch (div) {
-               case PXA_SSP_CLK_SCDB_1:
-                       val |= SSACD_SCDB;
-                       break;
-               case PXA_SSP_CLK_SCDB_4:
-                       break;
-               case PXA_SSP_CLK_SCDB_8:
-                       if (ssp->type == PXA3xx_SSP)
-                               val |= SSACD_SCDX8;
-                       else
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               pxa_ssp_write_reg(ssp, SSACD, val);
-               break;
-       case PXA_SSP_DIV_SCR:
-               pxa_ssp_set_scr(ssp, div);
-               break;
-       default:
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
 /*
  * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
  */
-static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
-       int source, unsigned int freq_in, unsigned int freq_out)
+static int pxa_ssp_set_pll(struct ssp_priv *priv, unsigned int freq)
 {
-       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
 
        if (ssp->type == PXA3xx_SSP)
                pxa_ssp_write_reg(ssp, SSACDD, 0);
 
-       switch (freq_out) {
+       switch (freq) {
        case 5622000:
                break;
        case 11345000:
@@ -355,7 +306,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
                        u64 tmp = 19968;
 
                        tmp *= 1000000;
-                       do_div(tmp, freq_out);
+                       do_div(tmp, freq);
                        val = tmp;
 
                        val = (val << 16) | 64;
@@ -365,7 +316,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 
                        dev_dbg(&ssp->pdev->dev,
                                "Using SSACDD %x to supply %uHz\n",
-                               val, freq_out);
+                               val, freq);
                        break;
                }
 
@@ -535,6 +486,7 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
 
        case SND_SOC_DAIFMT_DSP_A:
                sspsp |= SSPSP_FSRT;
+               /* fall through */
        case SND_SOC_DAIFMT_DSP_B:
                sscr0 |= SSCR0_MOD | SSCR0_PSP;
                sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
@@ -570,6 +522,24 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
        return 0;
 }
 
+struct pxa_ssp_clock_mode {
+       int rate;
+       int pll;
+       u8 acds;
+       u8 scdb;
+};
+
+static const struct pxa_ssp_clock_mode pxa_ssp_clock_modes[] = {
+       { .rate =  8000, .pll = 32842000, .acds = SSACD_ACDS_32, .scdb = SSACD_SCDB_4X },
+       { .rate = 11025, .pll =  5622000, .acds = SSACD_ACDS_4,  .scdb = SSACD_SCDB_4X },
+       { .rate = 16000, .pll = 32842000, .acds = SSACD_ACDS_16, .scdb = SSACD_SCDB_4X },
+       { .rate = 22050, .pll =  5622000, .acds = SSACD_ACDS_2,  .scdb = SSACD_SCDB_4X },
+       { .rate = 44100, .pll = 11345000, .acds = SSACD_ACDS_2,  .scdb = SSACD_SCDB_4X },
+       { .rate = 48000, .pll = 12235000, .acds = SSACD_ACDS_2,  .scdb = SSACD_SCDB_4X },
+       { .rate = 96000, .pll = 12235000, .acds = SSACD_ACDS_4,  .scdb = SSACD_SCDB_1X },
+       {}
+};
+
 /*
  * Set the SSP audio DMA parameters and sample size.
  * Can be called multiple times by oss emulation.
@@ -581,11 +551,12 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int chn = params_channels(params);
-       u32 sscr0;
-       u32 sspsp;
+       u32 sscr0, sspsp;
        int width = snd_pcm_format_physical_width(params_format(params));
        int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
        struct snd_dmaengine_dai_dma_data *dma_data;
+       int rate = params_rate(params);
+       int bclk = rate * chn * (width / 8);
        int ret;
 
        dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -625,11 +596,57 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        }
        pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 
+       if (sscr0 & SSCR0_ACS) {
+               ret = pxa_ssp_set_pll(priv, bclk);
+
+               /*
+                * If we were able to generate the bclk directly,
+                * all is fine. Otherwise, look up the closest rate
+                * from the table and also set the dividers.
+                */
+
+               if (ret < 0) {
+                       const struct pxa_ssp_clock_mode *m;
+                       int ssacd, acds;
+
+                       for (m = pxa_ssp_clock_modes; m->rate; m++) {
+                               if (m->rate == rate)
+                                       break;
+                       }
+
+                       if (!m->rate)
+                               return -EINVAL;
+
+                       acds = m->acds;
+
+                       /* The values in the table are for 16 bits */
+                       if (width == 32)
+                               acds--;
+
+                       ret = pxa_ssp_set_pll(priv, bclk);
+                       if (ret < 0)
+                               return ret;
+
+                       ssacd = pxa_ssp_read_reg(ssp, SSACD);
+                       ssacd &= ~(SSACD_ACDS(7) | SSACD_SCDB_1X);
+                       ssacd |= SSACD_ACDS(m->acds);
+                       ssacd |= m->scdb;
+                       pxa_ssp_write_reg(ssp, SSACD, ssacd);
+               }
+       } else if (sscr0 & SSCR0_ECS) {
+               /*
+                * For setups with external clocking, the PLL and its diviers
+                * are not active. Instead, the SCR bits in SSCR0 can be used
+                * to divide the clock.
+                */
+               pxa_ssp_set_scr(ssp, bclk / rate);
+       }
+
        switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
               sspsp = pxa_ssp_read_reg(ssp, SSPSP);
 
-               if ((pxa_ssp_get_scr(ssp) == 4) && (width == 16)) {
+               if (((priv->sysclk / bclk) == 64) && (width == 16)) {
                        /* This is a special case where the bitclk is 64fs
                         * and we're not dealing with 2*32 bits of audio
                         * samples.
@@ -773,6 +790,15 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai)
                        ret = -ENODEV;
                        goto err_priv;
                }
+
+               priv->extclk = devm_clk_get(dev, "extclk");
+               if (IS_ERR(priv->extclk)) {
+                       ret = PTR_ERR(priv->extclk);
+                       if (ret == -EPROBE_DEFER)
+                               return ret;
+
+                       priv->extclk = NULL;
+               }
        } else {
                priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
                if (priv->ssp == NULL) {
@@ -814,8 +840,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .trigger        = pxa_ssp_trigger,
        .hw_params      = pxa_ssp_hw_params,
        .set_sysclk     = pxa_ssp_set_dai_sysclk,
-       .set_clkdiv     = pxa_ssp_set_dai_clkdiv,
-       .set_pll        = pxa_ssp_set_dai_pll,
        .set_fmt        = pxa_ssp_set_dai_fmt,
        .set_tdm_slot   = pxa_ssp_set_dai_tdm_slot,
        .set_tristate   = pxa_ssp_set_dai_tristate,
@@ -843,6 +867,9 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
 
 static const struct snd_soc_component_driver pxa_ssp_component = {
        .name           = "pxa-ssp",
+       .ops            = &pxa2xx_pcm_ops,
+       .pcm_new        = pxa2xx_soc_pcm_new,
+       .pcm_free       = pxa2xx_pcm_free_dma_buffers,
 };
 
 #ifdef CONFIG_OF
index 803818aabee98f03ffc6bd877830aa73f463392e..9f779657bc8611e1b3b4ae23d2678cb9a706e4fd 100644 (file)
@@ -68,61 +68,39 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_cold_reset,
 };
 
-static struct pxad_param pxa2xx_ac97_pcm_stereo_in_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 11,
-};
-
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .chan_name      = "pcm_pcm_stereo_in",
        .maxburst       = 32,
-       .filter_data    = &pxa2xx_ac97_pcm_stereo_in_req,
-};
-
-static struct pxad_param pxa2xx_ac97_pcm_stereo_out_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 12,
 };
 
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .chan_name      = "pcm_pcm_stereo_out",
        .maxburst       = 32,
-       .filter_data    = &pxa2xx_ac97_pcm_stereo_out_req,
 };
 
-static struct pxad_param pxa2xx_ac97_pcm_aux_mono_out_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 10,
-};
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
        .addr           = __PREG(MODR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
+       .chan_name      = "pcm_aux_mono_out",
        .maxburst       = 16,
-       .filter_data    = &pxa2xx_ac97_pcm_aux_mono_out_req,
 };
 
-static struct pxad_param pxa2xx_ac97_pcm_aux_mono_in_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 9,
-};
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
        .addr           = __PREG(MODR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
+       .chan_name      = "pcm_aux_mono_in",
        .maxburst       = 16,
-       .filter_data    = &pxa2xx_ac97_pcm_aux_mono_in_req,
 };
 
-static struct pxad_param pxa2xx_ac97_pcm_aux_mic_mono_req = {
-       .prio = PXAD_PRIO_LOWEST,
-       .drcmr = 8,
-};
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
        .addr           = __PREG(MCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
+       .chan_name      = "pcm_aux_mic_mono",
        .maxburst       = 16,
-       .filter_data    = &pxa2xx_ac97_pcm_aux_mic_mono_req,
 };
 
 static int pxa2xx_ac97_hifi_startup(struct snd_pcm_substream *substream,
@@ -236,7 +214,21 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
 
 static const struct snd_soc_component_driver pxa_ac97_component = {
        .name           = "pxa-ac97",
+       .ops            = &pxa2xx_pcm_ops,
+       .pcm_new        = pxa2xx_soc_pcm_new,
+       .pcm_free       = pxa2xx_pcm_free_dma_buffers,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pxa2xx_ac97_dt_ids[] = {
+       { .compatible = "marvell,pxa250-ac97", },
+       { .compatible = "marvell,pxa270-ac97", },
+       { .compatible = "marvell,pxa300-ac97", },
+       { }
 };
+MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids);
+
+#endif
 
 static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
@@ -296,6 +288,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
 #ifdef CONFIG_PM_SLEEP
                .pm     = &pxa2xx_ac97_pm_ops,
 #endif
+               .of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids),
        },
 };
 
index 3fb60baf6eab0f53d8d524b880091e316607552c..42820121e5b9f910b37f9a6ffe5281cd47266e2f 100644 (file)
@@ -82,20 +82,18 @@ static struct pxa_i2s_port pxa_i2s;
 static struct clk *clk_i2s;
 static int clk_ena = 0;
 
-static unsigned long pxa2xx_i2s_pcm_stereo_out_req = 3;
 static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
        .addr           = __PREG(SADR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .chan_name      = "tx",
        .maxburst       = 32,
-       .filter_data    = &pxa2xx_i2s_pcm_stereo_out_req,
 };
 
-static unsigned long pxa2xx_i2s_pcm_stereo_in_req = 2;
 static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
        .addr           = __PREG(SADR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .chan_name      = "rx",
        .maxburst       = 32,
-       .filter_data    = &pxa2xx_i2s_pcm_stereo_in_req,
 };
 
 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
@@ -366,6 +364,9 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
 
 static const struct snd_soc_component_driver pxa_i2s_component = {
        .name           = "pxa-i2s",
+       .ops            = &pxa2xx_pcm_ops,
+       .pcm_new        = pxa2xx_soc_pcm_new,
+       .pcm_free       = pxa2xx_pcm_free_dma_buffers,
 };
 
 static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
index 8b6a70e94c01da6d1a7179eefe48a3da8f7b3837..72eaaef1b426d28e0b0f3c034be5ec950b1fb164 100644 (file)
 #include <sound/pxa2xx-lib.h>
 #include <sound/dmaengine_pcm.h>
 
-#include "../../arm/pxa2xx-pcm.h"
-
-static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_dmaengine_dai_dma_data *dma;
-
-       dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       /* return if this is a bufferless transfer e.g.
-        * codec <--> BT codec or GSM modem -- lg FIXME */
-       if (!dma)
-               return 0;
-
-       return __pxa2xx_pcm_hw_params(substream, params);
-}
-
-static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       __pxa2xx_pcm_hw_free(substream);
-
-       return 0;
-}
-
-static const struct snd_pcm_ops pxa2xx_pcm_ops = {
-       .open           = __pxa2xx_pcm_open,
-       .close          = __pxa2xx_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pxa2xx_pcm_hw_params,
-       .hw_free        = pxa2xx_pcm_hw_free,
-       .prepare        = __pxa2xx_pcm_prepare,
-       .trigger        = pxa2xx_pcm_trigger,
-       .pointer        = pxa2xx_pcm_pointer,
-       .mmap           = pxa2xx_pcm_mmap,
-};
-
-static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret;
-
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
-}
-
 static const struct snd_soc_component_driver pxa2xx_soc_platform = {
        .ops            = &pxa2xx_pcm_ops,
        .pcm_new        = pxa2xx_soc_pcm_new,
@@ -96,18 +32,9 @@ static int pxa2xx_soc_platform_probe(struct platform_device *pdev)
                                               NULL, 0);
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id snd_soc_pxa_audio_match[] = {
-       { .compatible   = "mrvl,pxa-pcm-audio" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, snd_soc_pxa_audio_match);
-#endif
-
 static struct platform_driver pxa_pcm_driver = {
        .driver = {
                .name = "pxa-pcm-audio",
-               .of_match_table = of_match_ptr(snd_soc_pxa_audio_match),
        },
 
        .probe = pxa2xx_soc_platform_probe,
index ba468e560dd257bdbd460288141dff75c0babaf6..230eee450f453ccf3f8b919a70db6deb7f4991ab 100644 (file)
@@ -83,11 +83,9 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int pll_out = 0;
        unsigned int wm9713_div = 0;
        int ret = 0;
        int rate = params_rate(params);
-       int width = snd_pcm_format_physical_width(params_format(params));
 
        /* Only support ratios that we can generate neatly from the AC97
         * based master clock - in particular, this excludes 44.1kHz.
@@ -109,17 +107,10 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* Add 1 to the width for the leading clock cycle */
-       pll_out = rate * (width + 1) * 8;
-
        ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out);
-       if (ret < 0)
-               return ret;
-
        if (clk_pout)
                ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
                                             WM9713_PCMDIV(wm9713_div));
index 87838fa2799751bb3acbb99f15c96200b0285337..2a4c912d1e484df0c605af91371fa6ee3460bf63 100644 (file)
@@ -41,6 +41,9 @@ config SND_SOC_APQ8016_SBC
           APQ8016 SOC-based systems.
           Say Y if you want to use audio devices on MI2S.
 
+config SND_SOC_QCOM_COMMON
+       tristate
+
 config SND_SOC_QDSP6_COMMON
        tristate
 
@@ -86,7 +89,18 @@ config SND_SOC_MSM8996
        tristate "SoC Machine driver for MSM8996 and APQ8096 boards"
        depends on QCOM_APR
        select SND_SOC_QDSP6
+       select SND_SOC_QCOM_COMMON
        help
           Support for Qualcomm Technologies LPASS audio block in
           APQ8096 SoC-based systems.
           Say Y if you want to use audio device on this SoCs
+
+config SND_SOC_SDM845
+       tristate "SoC Machine driver for SDM845 boards"
+       depends on QCOM_APR
+       select SND_SOC_QDSP6
+       select SND_SOC_QCOM_COMMON
+       help
+         To add support for audio on Qualcomm Technologies Inc.
+         SDM845 SoC-based systems.
+         Say Y if you want to use audio device on this SoCs.
index 206945bb9ba178e078835f4533743599ba20a13e..41b2c7a23a4db6c0237a21f8c5cbb5cc63cb6d19 100644 (file)
@@ -14,10 +14,14 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 snd-soc-storm-objs := storm.o
 snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 snd-soc-apq8096-objs := apq8096.o
+snd-soc-sdm845-objs := sdm845.o
+snd-soc-qcom-common-objs := common.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
 obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
 obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
+obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
 
 #DSP lib
 obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
index 561cd429e6f21c5001bdb90602c091d435ac69ea..1543e85629f8037c60a37637a3f3607d7a83ad1e 100644 (file)
@@ -1,14 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2018, Linaro Limited
 
-#include <linux/soc/qcom/apr.h>
 #include <linux/module.h>
-#include <linux/component.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
+#include "common.h"
 
 static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                      struct snd_pcm_hw_params *params)
@@ -24,211 +23,57 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static int apq8096_sbc_parse_of(struct snd_soc_card *card)
+static void apq8096_add_be_ops(struct snd_soc_card *card)
 {
-       struct device_node *np;
-       struct device_node *codec = NULL;
-       struct device_node *platform = NULL;
-       struct device_node *cpu = NULL;
-       struct device *dev = card->dev;
-       struct snd_soc_dai_link *link;
-       int ret, num_links;
-
-       ret = snd_soc_of_parse_card_name(card, "qcom,model");
-       if (ret) {
-               dev_err(dev, "Error parsing card name: %d\n", ret);
-               return ret;
-       }
-
-       /* DAPM routes */
-       if (of_property_read_bool(dev->of_node, "qcom,audio-routing")) {
-               ret = snd_soc_of_parse_audio_routing(card,
-                                       "qcom,audio-routing");
-               if (ret)
-                       return ret;
-       }
-
-       /* Populate links */
-       num_links = of_get_child_count(dev->of_node);
+       struct snd_soc_dai_link *link = card->dai_link;
+       int i, num_links = card->num_links;
 
-       /* Allocate the DAI link array */
-       card->dai_link = kcalloc(num_links, sizeof(*link), GFP_KERNEL);
-       if (!card->dai_link)
-               return -ENOMEM;
-
-       card->num_links = num_links;
-       link = card->dai_link;
-
-       for_each_child_of_node(dev->of_node, np) {
-               cpu = of_get_child_by_name(np, "cpu");
-               if (!cpu) {
-                       dev_err(dev, "Can't find cpu DT node\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
-               if (!link->cpu_of_node) {
-                       dev_err(card->dev, "error getting cpu phandle\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
-               if (ret) {
-                       dev_err(card->dev, "error getting cpu dai name\n");
-                       goto err;
-               }
-
-               platform = of_get_child_by_name(np, "platform");
-               codec = of_get_child_by_name(np, "codec");
-               if (codec && platform) {
-                       link->platform_of_node = of_parse_phandle(platform,
-                                                                 "sound-dai",
-                                                                  0);
-                       if (!link->platform_of_node) {
-                               dev_err(card->dev, "platform dai not found\n");
-                               ret = -EINVAL;
-                               goto err;
-                       }
-
-                       ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
-                       if (ret < 0) {
-                               dev_err(card->dev, "codec dai not found\n");
-                               goto err;
-                       }
-                       link->no_pcm = 1;
-                       link->ignore_pmdown_time = 1;
+       for (i = 0; i < num_links; i++) {
+               if (link->no_pcm == 1)
                        link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
-               } else {
-                       link->platform_of_node = link->cpu_of_node;
-                       link->codec_dai_name = "snd-soc-dummy-dai";
-                       link->codec_name = "snd-soc-dummy";
-                       link->dynamic = 1;
-               }
-
-               link->ignore_suspend = 1;
-               ret = of_property_read_string(np, "link-name", &link->name);
-               if (ret) {
-                       dev_err(card->dev, "error getting codec dai_link name\n");
-                       goto err;
-               }
-
-               link->dpcm_playback = 1;
-               link->dpcm_capture = 1;
-               link->stream_name = link->name;
                link++;
        }
-
-       return 0;
-err:
-       of_node_put(cpu);
-       of_node_put(codec);
-       of_node_put(platform);
-       kfree(card->dai_link);
-       return ret;
 }
 
-static int apq8096_bind(struct device *dev)
+static int apq8096_platform_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
        int ret;
 
        card = kzalloc(sizeof(*card), GFP_KERNEL);
        if (!card)
                return -ENOMEM;
 
-       component_bind_all(dev, card);
        card->dev = dev;
-       ret = apq8096_sbc_parse_of(card);
+       dev_set_drvdata(dev, card);
+       ret = qcom_snd_parse_of(card);
        if (ret) {
                dev_err(dev, "Error parsing OF data\n");
                goto err;
        }
 
+       apq8096_add_be_ops(card);
        ret = snd_soc_register_card(card);
        if (ret)
-               goto err;
+               goto err_card_register;
 
        return 0;
 
+err_card_register:
+       kfree(card->dai_link);
 err:
-       component_unbind_all(dev, card);
        kfree(card);
        return ret;
 }
 
-static void apq8096_unbind(struct device *dev)
+static int apq8096_platform_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = dev_get_drvdata(dev);
+       struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_card(card);
-       component_unbind_all(dev, card);
        kfree(card->dai_link);
        kfree(card);
-}
-
-static const struct component_master_ops apq8096_ops = {
-       .bind = apq8096_bind,
-       .unbind = apq8096_unbind,
-};
-
-static int apq8016_compare_of(struct device *dev, void *data)
-{
-       return dev->of_node == data;
-}
-
-static void apq8016_release_of(struct device *dev, void *data)
-{
-       of_node_put(data);
-}
-
-static int add_audio_components(struct device *dev,
-                               struct component_match **matchptr)
-{
-       struct device_node *np, *platform, *cpu, *node, *dai_node;
-
-       node = dev->of_node;
-
-       for_each_child_of_node(node, np) {
-               cpu = of_get_child_by_name(np, "cpu");
-               if (cpu) {
-                       dai_node = of_parse_phandle(cpu, "sound-dai", 0);
-                       of_node_get(dai_node);
-                       component_match_add_release(dev, matchptr,
-                                                   apq8016_release_of,
-                                                   apq8016_compare_of,
-                                                   dai_node);
-               }
-
-               platform = of_get_child_by_name(np, "platform");
-               if (platform) {
-                       dai_node = of_parse_phandle(platform, "sound-dai", 0);
-                       component_match_add_release(dev, matchptr,
-                                                   apq8016_release_of,
-                                                   apq8016_compare_of,
-                                                   dai_node);
-               }
-       }
-
-       return 0;
-}
-
-static int apq8096_platform_probe(struct platform_device *pdev)
-{
-       struct component_match *match = NULL;
-       int ret;
-
-       ret = add_audio_components(&pdev->dev, &match);
-       if (ret)
-               return ret;
-
-       return component_master_add_with_match(&pdev->dev, &apq8096_ops, match);
-}
-
-static int apq8096_platform_remove(struct platform_device *pdev)
-{
-       component_master_del(&pdev->dev, &apq8096_ops);
 
        return 0;
 }
@@ -245,7 +90,6 @@ static struct platform_driver msm_snd_apq8096_driver = {
        .remove = apq8096_platform_remove,
        .driver = {
                .name = "msm-snd-apq8096",
-               .owner = THIS_MODULE,
                .of_match_table = msm_snd_apq8096_dt_match,
        },
 };
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
new file mode 100644 (file)
index 0000000..eb1b9da
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Linaro Limited.
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include "common.h"
+
+int qcom_snd_parse_of(struct snd_soc_card *card)
+{
+       struct device_node *np;
+       struct device_node *codec = NULL;
+       struct device_node *platform = NULL;
+       struct device_node *cpu = NULL;
+       struct device *dev = card->dev;
+       struct snd_soc_dai_link *link;
+       int ret, num_links;
+
+       ret = snd_soc_of_parse_card_name(card, "model");
+       if (ret) {
+               dev_err(dev, "Error parsing card name: %d\n", ret);
+               return ret;
+       }
+
+       /* DAPM routes */
+       if (of_property_read_bool(dev->of_node, "audio-routing")) {
+               ret = snd_soc_of_parse_audio_routing(card,
+                               "audio-routing");
+               if (ret)
+                       return ret;
+       }
+
+       /* Populate links */
+       num_links = of_get_child_count(dev->of_node);
+
+       /* Allocate the DAI link array */
+       card->dai_link = kcalloc(num_links, sizeof(*link), GFP_KERNEL);
+       if (!card->dai_link)
+               return -ENOMEM;
+
+       card->num_links = num_links;
+       link = card->dai_link;
+       for_each_child_of_node(dev->of_node, np) {
+               cpu = of_get_child_by_name(np, "cpu");
+               if (!cpu) {
+                       dev_err(dev, "Can't find cpu DT node\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+               if (!link->cpu_of_node) {
+                       dev_err(card->dev, "error getting cpu phandle\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
+               if (ret) {
+                       dev_err(card->dev, "error getting cpu dai name\n");
+                       goto err;
+               }
+
+               platform = of_get_child_by_name(np, "platform");
+               codec = of_get_child_by_name(np, "codec");
+               if (codec && platform) {
+                       link->platform_of_node = of_parse_phandle(platform,
+                                       "sound-dai",
+                                       0);
+                       if (!link->platform_of_node) {
+                               dev_err(card->dev, "platform dai not found\n");
+                               ret = -EINVAL;
+                               goto err;
+                       }
+
+                       ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
+                       if (ret < 0) {
+                               dev_err(card->dev, "codec dai not found\n");
+                               goto err;
+                       }
+                       link->no_pcm = 1;
+                       link->ignore_pmdown_time = 1;
+               } else {
+                       link->platform_of_node = link->cpu_of_node;
+                       link->codec_dai_name = "snd-soc-dummy-dai";
+                       link->codec_name = "snd-soc-dummy";
+                       link->dynamic = 1;
+               }
+
+               link->ignore_suspend = 1;
+               ret = of_property_read_string(np, "link-name", &link->name);
+               if (ret) {
+                       dev_err(card->dev, "error getting codec dai_link name\n");
+                       goto err;
+               }
+
+               link->dpcm_playback = 1;
+               link->dpcm_capture = 1;
+               link->stream_name = link->name;
+               link++;
+       }
+
+       return 0;
+err:
+       of_node_put(cpu);
+       of_node_put(codec);
+       of_node_put(platform);
+       kfree(card->dai_link);
+       return ret;
+}
+EXPORT_SYMBOL(qcom_snd_parse_of);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
new file mode 100644 (file)
index 0000000..f05c05b
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#ifndef __QCOM_SND_COMMON_H__
+#define __QCOM_SND_COMMON_H__
+
+#include <sound/soc.h>
+
+int qcom_snd_parse_of(struct snd_soc_card *card);
+
+#endif
index 31fe78aa207fc175bf36bff01b3138757b0d2e14..d07271ea4c45165b694a51777af7957b36d454ad 100644 (file)
@@ -458,7 +458,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
                        return IRQ_NONE;
                }
                dev_warn(soc_runtime->dev, "xrun warning\n");
-               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stop_xrun(substream);
                ret = IRQ_HANDLED;
        }
 
index 9983c665a9417489d761ad9f19dcace5e8c22d60..932c3ebfd2524559d092798547899d68874531ab 100644 (file)
@@ -64,7 +64,6 @@ struct q6adm {
        struct aprv2_ibasic_rsp_result_t result;
        struct mutex lock;
        wait_queue_head_t matrix_map_wait;
-       struct platform_device *pdev_routing;
 };
 
 struct q6adm_cmd_device_open_v5 {
@@ -588,7 +587,6 @@ EXPORT_SYMBOL_GPL(q6adm_close);
 static int q6adm_probe(struct apr_device *adev)
 {
        struct device *dev = &adev->dev;
-       struct device_node *dais_np;
        struct q6adm *adm;
 
        adm = devm_kzalloc(&adev->dev, sizeof(*adm), GFP_KERNEL);
@@ -605,22 +603,12 @@ static int q6adm_probe(struct apr_device *adev)
        INIT_LIST_HEAD(&adm->copps_list);
        spin_lock_init(&adm->copps_list_lock);
 
-       dais_np = of_get_child_by_name(dev->of_node, "routing");
-       if (dais_np) {
-               adm->pdev_routing = of_platform_device_create(dais_np,
-                                                          "q6routing", dev);
-               of_node_put(dais_np);
-       }
-
-       return 0;
+       return of_platform_populate(dev->of_node, NULL, NULL, dev);
 }
 
 static int q6adm_remove(struct apr_device *adev)
 {
-       struct q6adm *adm = dev_get_drvdata(&adev->dev);
-
-       if (adm->pdev_routing)
-               of_platform_device_destroy(&adm->pdev_routing->dev, NULL);
+       of_platform_depopulate(&adev->dev);
 
        return 0;
 }
index 9ba95956ada8b6b2dc183d2562fb96dc8ca99e16..60ff4a2d35774eebdaced12f36a275ce2738f5f2 100644 (file)
@@ -4,7 +4,6 @@
 
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/component.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
@@ -81,7 +80,6 @@ static int q6slim_hw_params(struct snd_pcm_substream *substream,
        struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
        struct q6afe_slim_cfg *slim = &dai_data->port_config[dai->id].slim;
 
-       slim->num_channels = params_channels(params);
        slim->sample_rate = params_rate(params);
 
        switch (params_format(params)) {
@@ -385,23 +383,31 @@ static int q6slim_set_channel_map(struct snd_soc_dai *dai,
        struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
        int i;
 
-       if (!rx_slot) {
-               pr_err("%s: rx slot not found\n", __func__);
-               return -EINVAL;
-       }
+       if (dai->id & 0x1) {
+               /* TX */
+               if (!tx_slot) {
+                       pr_err("%s: tx slot not found\n", __func__);
+                       return -EINVAL;
+               }
 
-       for (i = 0; i < rx_num; i++) {
-               pcfg->slim.ch_mapping[i] =   rx_slot[i];
-               pr_debug("%s: find number of channels[%d] ch[%d]\n",
-                      __func__, i, rx_slot[i]);
-       }
+               for (i = 0; i < tx_num; i++)
+                       pcfg->slim.ch_mapping[i] = tx_slot[i];
 
-       pcfg->slim.num_channels = rx_num;
+               pcfg->slim.num_channels = tx_num;
 
-       pr_debug("%s: SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
-               (dai->id - SLIMBUS_0_RX) / 2, rx_num,
-               pcfg->slim.ch_mapping[0],
-               pcfg->slim.ch_mapping[1]);
+
+       } else {
+               if (!rx_slot) {
+                       pr_err("%s: rx slot not found\n", __func__);
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < rx_num; i++)
+                       pcfg->slim.ch_mapping[i] =   rx_slot[i];
+
+               pcfg->slim.num_channels = rx_num;
+
+       }
 
        return 0;
 }
@@ -446,6 +452,14 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
        {"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"},
        {"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"},
 
+       {"SLIMBUS_0_TX", NULL, "Slimbus Capture"},
+       {"SLIMBUS_1_TX", NULL, "Slimbus1 Capture"},
+       {"SLIMBUS_2_TX", NULL, "Slimbus2 Capture"},
+       {"SLIMBUS_3_TX", NULL, "Slimbus3 Capture"},
+       {"SLIMBUS_4_TX", NULL, "Slimbus4 Capture"},
+       {"SLIMBUS_5_TX", NULL, "Slimbus5 Capture"},
+       {"SLIMBUS_6_TX", NULL, "Slimbus6 Capture"},
+
        {"Primary MI2S Playback", NULL, "PRI_MI2S_RX"},
        {"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"},
        {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
@@ -639,6 +653,24 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                        .rate_min = 8000,
                        .rate_max = 192000,
                },
+       }, {
+               .name = "SLIMBUS_0_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_0_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Slimbus1 Playback",
@@ -657,6 +689,24 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                .id = SLIMBUS_1_RX,
                .probe = msm_dai_q6_dai_probe,
                .remove = msm_dai_q6_dai_remove,
+       }, {
+               .name = "SLIMBUS_1_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_1_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus1 Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Slimbus2 Playback",
@@ -675,6 +725,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                .id = SLIMBUS_2_RX,
                .probe = msm_dai_q6_dai_probe,
                .remove = msm_dai_q6_dai_remove,
+
+       }, {
+               .name = "SLIMBUS_2_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_2_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus2 Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Slimbus3 Playback",
@@ -693,6 +762,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                .id = SLIMBUS_3_RX,
                .probe = msm_dai_q6_dai_probe,
                .remove = msm_dai_q6_dai_remove,
+
+       }, {
+               .name = "SLIMBUS_3_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_3_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus3 Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Slimbus4 Playback",
@@ -711,6 +799,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                .id = SLIMBUS_4_RX,
                .probe = msm_dai_q6_dai_probe,
                .remove = msm_dai_q6_dai_remove,
+
+       }, {
+               .name = "SLIMBUS_4_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_4_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus4 Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Slimbus5 Playback",
@@ -729,6 +836,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                .id = SLIMBUS_5_RX,
                .probe = msm_dai_q6_dai_probe,
                .remove = msm_dai_q6_dai_remove,
+
+       }, {
+               .name = "SLIMBUS_5_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_5_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus5 Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Slimbus6 Playback",
@@ -747,6 +873,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
                .id = SLIMBUS_6_RX,
                .probe = msm_dai_q6_dai_probe,
                .remove = msm_dai_q6_dai_remove,
+
+       }, {
+               .name = "SLIMBUS_6_TX",
+               .ops = &q6slim_ops,
+               .id = SLIMBUS_6_TX,
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+               .capture = {
+                       .stream_name = "Slimbus6 Capture",
+                       .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+                                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 192000,
+               },
        }, {
                .playback = {
                        .stream_name = "Primary MI2S Playback",
@@ -975,6 +1120,13 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
        SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback", 0, 0, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_RX", "Slimbus6 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_2_TX", "Slimbus2 Capture", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_6_TX", "Slimbus6 Capture", 0, 0, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
                                                0, 0, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
@@ -1252,11 +1404,12 @@ static void of_q6afe_parse_dai_data(struct device *dev,
        }
 }
 
-static int q6afe_dai_bind(struct device *dev, struct device *master, void *data)
+static int q6afe_dai_dev_probe(struct platform_device *pdev)
 {
        struct q6afe_dai_data *dai_data;
+       struct device *dev = &pdev->dev;
 
-       dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL);
+       dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL);
        if (!dai_data)
                return -ENOMEM;
 
@@ -1264,41 +1417,22 @@ static int q6afe_dai_bind(struct device *dev, struct device *master, void *data)
 
        of_q6afe_parse_dai_data(dev, dai_data);
 
-       return snd_soc_register_component(dev, &q6afe_dai_component,
+       return devm_snd_soc_register_component(dev, &q6afe_dai_component,
                                          q6afe_dais, ARRAY_SIZE(q6afe_dais));
 }
 
-static void q6afe_dai_unbind(struct device *dev, struct device *master,
-                            void *data)
-{
-       struct q6afe_dai_data *dai_data = dev_get_drvdata(dev);
-
-       snd_soc_unregister_component(dev);
-       kfree(dai_data);
-}
-
-static const struct component_ops q6afe_dai_comp_ops = {
-       .bind   = q6afe_dai_bind,
-       .unbind = q6afe_dai_unbind,
+static const struct of_device_id q6afe_dai_device_id[] = {
+       { .compatible = "qcom,q6afe-dais" },
+       {},
 };
-
-static int q6afe_dai_dev_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &q6afe_dai_comp_ops);
-}
-
-static int q6afe_dai_dev_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &q6afe_dai_comp_ops);
-       return 0;
-}
+MODULE_DEVICE_TABLE(of, q6afe_dai_device_id);
 
 static struct platform_driver q6afe_dai_platform_driver = {
        .driver = {
                .name = "q6afe-dai",
+               .of_match_table = of_match_ptr(q6afe_dai_device_id),
        },
        .probe = q6afe_dai_dev_probe,
-       .remove = q6afe_dai_dev_remove,
 };
 module_platform_driver(q6afe_dai_platform_driver);
 
index 01f43218984b9d59ee2230ca210e26306dd8ee56..000775b4bba83d5d7e877acfb5aefca6d5b759be 100644 (file)
@@ -316,7 +316,6 @@ struct q6afe {
        struct mutex lock;
        struct list_head port_list;
        spinlock_t port_list_lock;
-       struct platform_device *pdev_dais;
 };
 
 struct afe_port_cmd_device_start {
@@ -515,6 +514,20 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
                                SLIMBUS_5_RX, 1, 1},
        [SLIMBUS_6_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX,
                                SLIMBUS_6_RX, 1, 1},
+       [SLIMBUS_0_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX,
+                               SLIMBUS_0_TX, 0, 1},
+       [SLIMBUS_1_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX,
+                               SLIMBUS_1_TX, 0, 1},
+       [SLIMBUS_2_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX,
+                               SLIMBUS_2_TX, 0, 1},
+       [SLIMBUS_3_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX,
+                               SLIMBUS_3_TX, 0, 1},
+       [SLIMBUS_4_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX,
+                               SLIMBUS_4_TX, 0, 1},
+       [SLIMBUS_5_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX,
+                               SLIMBUS_5_TX, 0, 1},
+       [SLIMBUS_6_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX,
+                               SLIMBUS_6_TX, 0, 1},
        [PRIMARY_MI2S_RX] = { AFE_PORT_ID_PRIMARY_MI2S_RX,
                                PRIMARY_MI2S_RX, 1, 1},
        [PRIMARY_MI2S_TX] = { AFE_PORT_ID_PRIMARY_MI2S_TX,
@@ -777,7 +790,7 @@ static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data)
  */
 int q6afe_get_port_id(int index)
 {
-       if (index < 0 || index > AFE_PORT_MAX)
+       if (index < 0 || index >= AFE_PORT_MAX)
                return -EINVAL;
 
        return port_maps[index].port_id;
@@ -1014,7 +1027,7 @@ int q6afe_port_stop(struct q6afe_port *port)
 
        port_id = port->id;
        index = port->token;
-       if (index < 0 || index > AFE_PORT_MAX) {
+       if (index < 0 || index >= AFE_PORT_MAX) {
                dev_err(afe->dev, "AFE port index[%d] invalid!\n", index);
                return -EINVAL;
        }
@@ -1355,7 +1368,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
        unsigned long flags;
        int cfg_type;
 
-       if (id < 0 || id > AFE_PORT_MAX) {
+       if (id < 0 || id >= AFE_PORT_MAX) {
                dev_err(dev, "AFE port token[%d] invalid!\n", id);
                return ERR_PTR(-EINVAL);
        }
@@ -1373,6 +1386,13 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
        case AFE_PORT_ID_MULTICHAN_HDMI_RX:
                cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
                break;
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX:
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX:
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX:
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX:
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX:
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX:
+       case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX:
        case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX:
        case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX:
        case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX:
@@ -1438,7 +1458,6 @@ static int q6afe_probe(struct apr_device *adev)
 {
        struct q6afe *afe;
        struct device *dev = &adev->dev;
-       struct device_node *dais_np;
 
        afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
        if (!afe)
@@ -1453,22 +1472,12 @@ static int q6afe_probe(struct apr_device *adev)
 
        dev_set_drvdata(dev, afe);
 
-       dais_np = of_get_child_by_name(dev->of_node, "dais");
-       if (dais_np) {
-               afe->pdev_dais = of_platform_device_create(dais_np,
-                                                          "q6afe-dai", dev);
-               of_node_put(dais_np);
-       }
-
-       return 0;
+       return of_platform_populate(dev->of_node, NULL, NULL, dev);
 }
 
 static int q6afe_remove(struct apr_device *adev)
 {
-       struct q6afe *afe = dev_get_drvdata(&adev->dev);
-
-       if (afe->pdev_dais)
-               of_platform_device_destroy(&afe->pdev_dais->dev, NULL);
+       of_platform_depopulate(&adev->dev);
 
        return 0;
 }
index 360936703b3d5357884416304e3b9a7ef1c61a7e..9db9a2944ef26d23bb1bd95b33a1af6ac2a1517c 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/component.h>
 #include <sound/soc.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -563,14 +562,15 @@ static struct snd_soc_dai_driver q6asm_fe_dais[] = {
        Q6ASM_FEDAI_DRIVER(8),
 };
 
-static int q6asm_dai_bind(struct device *dev, struct device *master, void *data)
+static int q6asm_dai_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct device_node *node = dev->of_node;
        struct of_phandle_args args;
        struct q6asm_dai_data *pdata;
        int rc;
 
-       pdata = kzalloc(sizeof(struct q6asm_dai_data), GFP_KERNEL);
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
 
@@ -582,43 +582,23 @@ static int q6asm_dai_bind(struct device *dev, struct device *master, void *data)
 
        dev_set_drvdata(dev, pdata);
 
-       return snd_soc_register_component(dev, &q6asm_fe_dai_component,
+       return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
                                        q6asm_fe_dais,
                                        ARRAY_SIZE(q6asm_fe_dais));
 }
-static void q6asm_dai_unbind(struct device *dev, struct device *master,
-                            void *data)
-{
-       struct q6asm_dai_data *pdata = dev_get_drvdata(dev);
-
-       snd_soc_unregister_component(dev);
-
-       kfree(pdata);
 
-}
-
-static const struct component_ops q6asm_dai_comp_ops = {
-       .bind   = q6asm_dai_bind,
-       .unbind = q6asm_dai_unbind,
+static const struct of_device_id q6asm_dai_device_id[] = {
+       { .compatible = "qcom,q6asm-dais" },
+       {},
 };
-
-static int q6asm_dai_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &q6asm_dai_comp_ops);
-}
-
-static int q6asm_dai_dev_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &q6asm_dai_comp_ops);
-       return 0;
-}
+MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
 
 static struct platform_driver q6asm_dai_platform_driver = {
        .driver = {
                .name = "q6asm-dai",
+               .of_match_table = of_match_ptr(q6asm_dai_device_id),
        },
        .probe = q6asm_dai_probe,
-       .remove = q6asm_dai_dev_remove,
 };
 module_platform_driver(q6asm_dai_platform_driver);
 
index 530852385cadc847cb8dfff14fa11f4f26d202a1..2b2c7233bb5fae1359a57ffcb85cf0d04cb8bbcf 100644 (file)
@@ -174,10 +174,8 @@ struct q6asm {
        struct device *dev;
        struct q6core_svc_api_info ainfo;
        wait_queue_head_t mem_wait;
-       struct platform_device *pcmdev;
        spinlock_t slock;
        struct audio_client *session[MAX_SESSIONS + 1];
-       struct platform_device *pdev_dais;
 };
 
 struct audio_client {
@@ -1344,7 +1342,6 @@ EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
 static int q6asm_probe(struct apr_device *adev)
 {
        struct device *dev = &adev->dev;
-       struct device_node *dais_np;
        struct q6asm *q6asm;
 
        q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
@@ -1359,22 +1356,12 @@ static int q6asm_probe(struct apr_device *adev)
        spin_lock_init(&q6asm->slock);
        dev_set_drvdata(dev, q6asm);
 
-       dais_np = of_get_child_by_name(dev->of_node, "dais");
-       if (dais_np) {
-               q6asm->pdev_dais = of_platform_device_create(dais_np,
-                                                          "q6asm-dai", dev);
-               of_node_put(dais_np);
-       }
-
-       return 0;
+       return of_platform_populate(dev->of_node, NULL, NULL, dev);
 }
 
 static int q6asm_remove(struct apr_device *adev)
 {
-       struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
-
-       if (q6asm->pdev_dais)
-               of_platform_device_destroy(&q6asm->pdev_dais->dev, NULL);
+       of_platform_depopulate(&adev->dev);
 
        return 0;
 }
index 7a19d627840681e4e5c7c2154ad5f13963e73589..dc94c5c53788b044b183f2406df7a5d9234cc5fc 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
 #include <linux/bitops.h>
-#include <linux/component.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
        { mix_name, "SEC_MI2S_TX", "SEC_MI2S_TX" },     \
        { mix_name, "QUAT_MI2S_TX", "QUAT_MI2S_TX" },   \
        { mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" },           \
+       { mix_name, "SLIMBUS_0_TX", "SLIMBUS_0_TX" },           \
+       { mix_name, "SLIMBUS_1_TX", "SLIMBUS_1_TX" },           \
+       { mix_name, "SLIMBUS_2_TX", "SLIMBUS_2_TX" },           \
+       { mix_name, "SLIMBUS_3_TX", "SLIMBUS_3_TX" },           \
+       { mix_name, "SLIMBUS_4_TX", "SLIMBUS_4_TX" },           \
+       { mix_name, "SLIMBUS_5_TX", "SLIMBUS_5_TX" },           \
+       { mix_name, "SLIMBUS_6_TX", "SLIMBUS_6_TX" },           \
        { mix_name, "PRIMARY_TDM_TX_0", "PRIMARY_TDM_TX_0"},    \
        { mix_name, "PRIMARY_TDM_TX_1", "PRIMARY_TDM_TX_1"},    \
        { mix_name, "PRIMARY_TDM_TX_2", "PRIMARY_TDM_TX_2"},    \
        SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,              \
                id, 1, 0, msm_routing_get_audio_mixer,                  \
                msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_0_TX", SLIMBUS_0_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_1_TX", SLIMBUS_1_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_2_TX", SLIMBUS_2_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_3_TX", SLIMBUS_3_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_4_TX", SLIMBUS_4_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_5_TX", SLIMBUS_5_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
+       SOC_SINGLE_EXT("SLIMBUS_6_TX", SLIMBUS_6_TX,                    \
+               id, 1, 0, msm_routing_get_audio_mixer,                  \
+               msm_routing_put_audio_mixer),                           \
        SOC_SINGLE_EXT("PRIMARY_TDM_TX_0", PRIMARY_TDM_TX_0,            \
                id, 1, 0, msm_routing_get_audio_mixer,                  \
                msm_routing_put_audio_mixer),                           \
@@ -310,7 +337,7 @@ int q6routing_stream_open(int fedai_id, int perf_mode,
                              session->channels, topology, perf_mode,
                              session->bits_per_sample, 0, 0);
 
-       if (!copp) {
+       if (IS_ERR_OR_NULL(copp)) {
                mutex_unlock(&routing_data->lock);
                return -EINVAL;
        }
@@ -949,9 +976,10 @@ static const struct snd_soc_component_driver msm_soc_routing_component = {
        .num_dapm_routes = ARRAY_SIZE(intercon),
 };
 
-static int q6routing_dai_bind(struct device *dev, struct device *master,
-                             void *data)
+static int q6pcm_routing_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
+
        routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL);
        if (!routing_data)
                return -ENOMEM;
@@ -961,41 +989,28 @@ static int q6routing_dai_bind(struct device *dev, struct device *master,
        mutex_init(&routing_data->lock);
        dev_set_drvdata(dev, routing_data);
 
-       return snd_soc_register_component(dev, &msm_soc_routing_component,
+       return devm_snd_soc_register_component(dev, &msm_soc_routing_component,
                                          NULL, 0);
 }
 
-static void q6routing_dai_unbind(struct device *dev, struct device *master,
-                                void *d)
+static int q6pcm_routing_remove(struct platform_device *pdev)
 {
-       struct msm_routing_data *data = dev_get_drvdata(dev);
-
-       snd_soc_unregister_component(dev);
-
-       kfree(data);
-
+       kfree(routing_data);
        routing_data = NULL;
-}
-
-static const struct component_ops q6routing_dai_comp_ops = {
-       .bind   = q6routing_dai_bind,
-       .unbind = q6routing_dai_unbind,
-};
 
-static int q6pcm_routing_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &q6routing_dai_comp_ops);
-}
-
-static int q6pcm_routing_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &q6routing_dai_comp_ops);
        return 0;
 }
 
+static const struct of_device_id q6pcm_routing_device_id[] = {
+       { .compatible = "qcom,q6adm-routing" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, q6pcm_routing_device_id);
+
 static struct platform_driver q6pcm_routing_platform_driver = {
        .driver = {
                .name = "q6routing",
+               .of_match_table = of_match_ptr(q6pcm_routing_device_id),
        },
        .probe = q6pcm_routing_probe,
        .remove = q6pcm_routing_remove,
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
new file mode 100644 (file)
index 0000000..2a781d8
--- /dev/null
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "common.h"
+#include "qdsp6/q6afe.h"
+
+#define DEFAULT_SAMPLE_RATE_48K                48000
+#define DEFAULT_MCLK_RATE              24576000
+#define DEFAULT_BCLK_RATE              12288000
+
+struct sdm845_snd_data {
+       struct snd_soc_card *card;
+       uint32_t pri_mi2s_clk_count;
+       uint32_t quat_tdm_clk_count;
+};
+
+static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret = 0;
+       int channels, slot_width;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               slot_width = 32;
+               break;
+       default:
+               dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
+                               __func__, params_format(params));
+               return -EINVAL;
+       }
+
+       channels = params_channels(params);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
+                               8, slot_width);
+               if (ret < 0) {
+                       dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
+                                       __func__, ret);
+                       goto end;
+               }
+
+               ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+                               channels, tdm_slot_offset);
+               if (ret < 0) {
+                       dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
+                                       __func__, ret);
+                       goto end;
+               }
+       } else {
+               ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
+                               8, slot_width);
+               if (ret < 0) {
+                       dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
+                                       __func__, ret);
+                       goto end;
+               }
+
+               ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
+                               tdm_slot_offset, 0, NULL);
+               if (ret < 0) {
+                       dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
+                                       __func__, ret);
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret = 0;
+
+       switch (cpu_dai->id) {
+       case QUATERNARY_TDM_RX_0:
+       case QUATERNARY_TDM_TX_0:
+               ret = sdm845_tdm_snd_hw_params(substream, params);
+               break;
+       default:
+               pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
+               break;
+       }
+       return ret;
+}
+
+static int sdm845_snd_startup(struct snd_pcm_substream *substream)
+{
+       unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+       struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+       switch (cpu_dai->id) {
+       case PRIMARY_MI2S_RX:
+       case PRIMARY_MI2S_TX:
+               if (++(data->pri_mi2s_clk_count) == 1) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_MCLK_1,
+                               DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+                               DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+               snd_soc_dai_set_fmt(cpu_dai, fmt);
+               break;
+
+       case QUATERNARY_TDM_RX_0:
+       case QUATERNARY_TDM_TX_0:
+               if (++(data->quat_tdm_clk_count) == 1) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
+                               DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+               break;
+
+       default:
+               pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
+               break;
+       }
+       return 0;
+}
+
+static void  sdm845_snd_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+       struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+       switch (cpu_dai->id) {
+       case PRIMARY_MI2S_RX:
+       case PRIMARY_MI2S_TX:
+               if (--(data->pri_mi2s_clk_count) == 0) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_MCLK_1,
+                               0, SNDRV_PCM_STREAM_PLAYBACK);
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+                               0, SNDRV_PCM_STREAM_PLAYBACK);
+               };
+               break;
+
+       case QUATERNARY_TDM_RX_0:
+       case QUATERNARY_TDM_TX_0:
+               if (--(data->quat_tdm_clk_count) == 0) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
+                               0, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+               break;
+
+       default:
+               pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
+               break;
+       }
+}
+
+static struct snd_soc_ops sdm845_be_ops = {
+       .hw_params = sdm845_snd_hw_params,
+       .startup = sdm845_snd_startup,
+       .shutdown = sdm845_snd_shutdown,
+};
+
+static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
+       channels->min = channels->max = 2;
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+
+       return 0;
+}
+
+static void sdm845_add_be_ops(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link = card->dai_link;
+       int i, num_links = card->num_links;
+
+       for (i = 0; i < num_links; i++) {
+               if (link->no_pcm == 1) {
+                       link->ops = &sdm845_be_ops;
+                       link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
+               }
+               link++;
+       }
+}
+
+static int sdm845_snd_platform_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct sdm845_snd_data *data;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       card = kzalloc(sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       /* Allocate the private data */
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto data_alloc_fail;
+       }
+
+       card->dev = dev;
+       dev_set_drvdata(dev, card);
+       ret = qcom_snd_parse_of(card);
+       if (ret) {
+               dev_err(dev, "Error parsing OF data\n");
+               goto parse_dt_fail;
+       }
+
+       data->card = card;
+       snd_soc_card_set_drvdata(card, data);
+
+       sdm845_add_be_ops(card);
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(dev, "Sound card registration failed\n");
+               goto register_card_fail;
+       }
+       return ret;
+
+register_card_fail:
+       kfree(card->dai_link);
+parse_dt_fail:
+       kfree(data);
+data_alloc_fail:
+       kfree(card);
+       return ret;
+}
+
+static int sdm845_snd_platform_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
+       struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+       kfree(card->dai_link);
+       kfree(data);
+       kfree(card);
+       return 0;
+}
+
+static const struct of_device_id sdm845_snd_device_id[]  = {
+       { .compatible = "qcom,sdm845-sndcard" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
+
+static struct platform_driver sdm845_snd_driver = {
+       .probe = sdm845_snd_platform_probe,
+       .remove = sdm845_snd_platform_remove,
+       .driver = {
+               .name = "msm-snd-sdm845",
+               .of_match_table = sdm845_snd_device_id,
+       },
+};
+module_platform_driver(sdm845_snd_driver);
+
+MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
index 05b078e7b87f9ba75e3901fec4cd7239626cff76..65e814d460064d5b26a188923c81364bdec73559 100644 (file)
@@ -1,10 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0
 # ROCKCHIP Platform Support
 snd-soc-rockchip-i2s-objs := rockchip_i2s.o
+snd-soc-rockchip-pcm-objs := rockchip_pcm.o
 snd-soc-rockchip-pdm-objs := rockchip_pdm.o
 snd-soc-rockchip-spdif-objs := rockchip_spdif.o
 
-obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o snd-soc-rockchip-pcm.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_PDM) += snd-soc-rockchip-pdm.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
index 950823d69e9cdf21c907c04eae0c96a81ef3a4b0..60d43d53a8f5e8fb00166085531eba66aaef1b79 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/dmaengine_pcm.h>
 
 #include "rockchip_i2s.h"
+#include "rockchip_pcm.h"
 
 #define DRV_NAME "rockchip-i2s"
 
@@ -674,7 +675,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
                goto err_suspend;
        }
 
-       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       ret = rockchip_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM\n");
                return ret;
diff --git a/sound/soc/rockchip/rockchip_pcm.c b/sound/soc/rockchip/rockchip_pcm.c
new file mode 100644 (file)
index 0000000..f775383
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "rockchip_pcm.h"
+
+static const struct snd_pcm_hardware snd_rockchip_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 1,
+       .periods_max            = 52,
+       .buffer_bytes_max       = 64 * 1024,
+       .fifo_size              = 32,
+};
+
+static const struct snd_dmaengine_pcm_config rk_dmaengine_pcm_config = {
+       .pcm_hardware = &snd_rockchip_hardware,
+       .prealloc_buffer_size = 32 * 1024,
+};
+
+int rockchip_pcm_platform_register(struct device *dev)
+{
+       return devm_snd_dmaengine_pcm_register(dev, &rk_dmaengine_pcm_config,
+               SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(rockchip_pcm_platform_register);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/rockchip/rockchip_pcm.h b/sound/soc/rockchip/rockchip_pcm.h
new file mode 100644 (file)
index 0000000..d6c3611
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ROCKCHIP_PCM_H
+#define _ROCKCHIP_PCM_H
+
+int rockchip_pcm_platform_register(struct device *dev);
+
+#endif
index 4db4fd56db358f4549f434a3e3712ed450f5776c..881c324988086b68eaf8d6426f9188c1934d343e 100644 (file)
@@ -181,7 +181,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
        if (!rk_dailink.cpu_of_node) {
                dev_err(&pdev->dev,
                        "Property 'rockchip,i2s-controller' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_codec_of_node;
        }
 
        rk_dailink.platform_of_node = rk_dailink.cpu_of_node;
@@ -190,17 +191,36 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev,
                        "Soc parse card name failed %d\n", ret);
-               return ret;
+               goto put_cpu_of_node;
        }
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev,
                        "Soc register card failed %d\n", ret);
-               return ret;
+               goto put_cpu_of_node;
        }
 
        return ret;
+
+put_cpu_of_node:
+       of_node_put(rk_dailink.cpu_of_node);
+       rk_dailink.cpu_of_node = NULL;
+put_codec_of_node:
+       of_node_put(rk_dailink.codec_of_node);
+       rk_dailink.codec_of_node = NULL;
+
+       return ret;
+}
+
+static int snd_rk_mc_remove(struct platform_device *pdev)
+{
+       of_node_put(rk_dailink.cpu_of_node);
+       rk_dailink.cpu_of_node = NULL;
+       of_node_put(rk_dailink.codec_of_node);
+       rk_dailink.codec_of_node = NULL;
+
+       return 0;
 }
 
 static const struct of_device_id rockchip_rt5645_of_match[] = {
@@ -212,6 +232,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match);
 
 static struct platform_driver snd_rk_mc_driver = {
        .probe = snd_rk_mc_probe,
+       .remove = snd_rk_mc_remove,
        .driver = {
                .name = DRV_NAME,
                .pm = &snd_soc_pm_ops,
index f914ed45db7d6b72c97af5b4822fc1f9144044b3..d6c62aa130414369f729bbc5333c82052bdcc9d2 100644 (file)
@@ -710,6 +710,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_channels(params)) {
        case 6:
                val |= MOD_DC2_EN;
+               /* fall through */
        case 4:
                val |= MOD_DC1_EN;
                break;
index 0ae0800bf3a8b471c4641640f61ef84121f5a56b..dc20f0f7080a091e6f695d75a82c8bd6283bb343 100644 (file)
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
 menu "SoC Audio support for Renesas SoCs"
        depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
 
index 2dc3b762fdd9cab938ececae2088a187031543cc..922fb6aa3ed191c5047ae21ecb5d708287a81f35 100644 (file)
@@ -1,16 +1,14 @@
-/*
- * SH7760 ("camelot") DMABRG audio DMA unit support
- *
- * Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- *  licensed under the terms outlined in the file COPYING at the root
- *  of the linux kernel sources.
- *
- * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
- * trigger an interrupt when one half of the programmed transfer size
- * has been xmitted.
- *
- * FIXME: little-endian only for now
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// SH7760 ("camelot") DMABRG audio DMA unit support
+//
+// Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+// trigger an interrupt when one half of the programmed transfer size
+// has been xmitted.
+//
+// FIXME: little-endian only for now
 
 #include <linux/module.h>
 #include <linux/gfp.h>
@@ -341,6 +339,6 @@ static struct platform_driver sh7760_pcm_driver = {
 
 module_platform_driver(sh7760_pcm_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index 3bae06dd121f6c78cc61bd6c3cf2cf1ebdf2189d..aa7e902f0c0252fda0c29ee87ee27e47e6ee5800 100644 (file)
@@ -1,16 +1,12 @@
-/*
- * Fifo-attached Serial Interface (FSI) support for SH7724
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ssi.c
- * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Fifo-attached Serial Interface (FSI) support for SH7724
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Based on ssi.c
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
 
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
index 624aaf569feff86a042056a15da5a7557636fae9..c2b496398e6b5c519dab0b7339d75e23ef357fd8 100644 (file)
@@ -1,13 +1,11 @@
-/*
- * Hitachi Audio Controller (AC97) support for SH7760/SH7780
- *
- * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- *  licensed under the terms outlined in the file COPYING at the root
- *  of the linux kernel sources.
- *
- * dont forget to set IPSEL/OMSEL register bits (in your board code) to
- * enable HAC output pins!
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Hitachi Audio Controller (AC97) support for SH7760/SH7780
+//
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// dont forget to set IPSEL/OMSEL register bits (in your board code) to
+// enable HAC output pins!
 
 /* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
  * the FIRST can be used since ASoC does not pass any information to the
@@ -343,6 +341,6 @@ static struct platform_driver hac_pcm_driver = {
 
 module_platform_driver(hac_pcm_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index ecb057ff9fbb66d12c034ee44d2efba2d0577f0d..8739c9f60672ced9588c05677e9affeb70f38c6b 100644 (file)
@@ -1,12 +1,8 @@
-/*
- * ALSA SoC driver for Migo-R
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC driver for Migo-R
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 
 #include <linux/clkdev.h>
 #include <linux/device.h>
index 9c3d5aed99d1441322fc80ec23a6ac165f65ba7e..5d1ff8ef26f9ae541b6a5d2f67e133669f82d6aa 100644 (file)
@@ -1,2 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
 snd-soc-rcar-objs      := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
 obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
index 4672688cac325ce79970c620c5f9e6d2d81b3525..3a3064dda57f329a96be5ef17b1dea8251f09f72 100644 (file)
@@ -1,12 +1,9 @@
-/*
- * Helper routines for R-Car sound ADG.
- *
- *  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Helper routines for R-Car sound ADG.
+//
+//  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include <linux/clk-provider.h>
 #include "rsnd.h"
 
index 5900fb535a2bf9f4f91d82e16a7a516b1d9506f5..cc191cd5fb82dcb768f04ed5e1d0b69f7ce952c4 100644 (file)
@@ -1,13 +1,10 @@
-/*
- * Renesas R-Car CMD support
- *
- * Copyright (C) 2015 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car CMD support
+//
+// Copyright (C) 2015 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include "rsnd.h"
 
 struct rsnd_cmd {
@@ -89,7 +86,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
                        cmd_case[rsnd_mod_id(src)] << 16;
        }
 
-       dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+       dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
 
        rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
        rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
index 39be88be2c025e90e37d09722f2a8a708f082cb2..f8425d8b44d2b54aff876f8759e81c740cb6157a 100644 (file)
@@ -1,16 +1,12 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on fsi.c
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRU/SCU/SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
 
 /*
  * Renesas R-Car sound device structure
@@ -552,6 +548,15 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
        return priv->rdai + id;
 }
 
+static struct snd_soc_dai_driver
+*rsnd_daidrv_get(struct rsnd_priv *priv, int id)
+{
+       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
+               return NULL;
+
+       return priv->daidrv + id;
+}
+
 #define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
 static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
 {
@@ -1037,7 +1042,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
        int io_i;
 
        rdai            = rsnd_rdai_get(priv, dai_i);
-       drv             = priv->daidrv + dai_i;
+       drv             = rsnd_daidrv_get(priv, dai_i);
        io_playback     = &rdai->playback;
        io_capture      = &rdai->capture;
 
@@ -1612,7 +1617,7 @@ static struct platform_driver rsnd_driver = {
 };
 module_platform_driver(rsnd_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Renesas R-Car audio driver");
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 MODULE_ALIAS("platform:rcar-pcm-audio");
index 83be7d3ae0a8390ad7eab05c4dd666708bf62b16..6a55aa7530031364617f0ba01c4725741b05f183 100644 (file)
@@ -1,12 +1,9 @@
-/*
- * ctu.c
- *
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ctu.c
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include "rsnd.h"
 
 #define CTU_NAME_SIZE  16
index ef82b94d038bfcbeb4f61ac7d09fdc049971d03b..fe63ef8600d02f259743a8339ce7059ea2b1be25 100644 (file)
@@ -1,13 +1,10 @@
-/*
- * Renesas R-Car Audio DMAC support
- *
- * Copyright (C) 2015 Renesas Electronics Corp.
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Audio DMAC support
+//
+// Copyright (C) 2015 Renesas Electronics Corp.
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include <linux/delay.h>
 #include <linux/of_dma.h>
 #include "rsnd.h"
index ca1780e0b8304afc0567585d002b965fc978682b..2b16e0ce6bc5374aff6e3bc0ade4a3faed6a3087 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Renesas R-Car DVC support
- *
- * Copyright (C) 2014 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car DVC support
+//
+// Copyright (C) 2014 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
 /*
  * Playback Volume
index 25642e92dae0681131932838001097c8fe1fc46e..0230301fe07801ab7f19bb6620451bb90ffaf747 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Renesas R-Car Gen1 SRU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Gen1 SRU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
 /*
  * #define DEBUG
index 1881b2de9126e3b6cc3218a5a067f32aa5b56868..8e3b57eaa708da568e0688d5310f5150eba2eaa4 100644 (file)
@@ -1,12 +1,8 @@
-/*
- * mix.c
- *
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// mix.c
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
 /*
  *                 CTUn        MIXn
index 6d7280d2d9be082c8a5c67309bede9cead5bdba0..96d93330b1e1a59ebba22668ff76fb4f8a325d3d 100644 (file)
@@ -1,13 +1,10 @@
-/*
- * Renesas R-Car
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #ifndef RSND_H
 #define RSND_H
 
index 6c72d1a81cf5e56237c9e3b4f34128316afdfd36..beccfbac7581ce6e1bd69d10a6758c39558e4aac 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Renesas R-Car SRC support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRC support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
 /*
  * you can enable below define if you don't need
index 7f644eb7621052bb9a0cc9c156f8909087f46c0c..8304e4ec9242c68eeabeca2516938990678aabc8 100644 (file)
@@ -1,16 +1,12 @@
-/*
- * Renesas R-Car SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on fsi.c
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
 
 /*
  * you can enable below define if you don't need
index 47bdba9fc58228878289f0f5b3b2245785812c6b..016fbf5ac242cc1137fa8957641ef5f50b886263 100644 (file)
@@ -1,12 +1,9 @@
-/*
- * Renesas R-Car SSIU support
- *
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SSIU support
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
 #include "rsnd.h"
 
 #define SSIU_NAME "ssiu"
index 4a3568a9bf59015cc2e1692edd29ee77d8291c2a..4bb4c13cf86086b2b6d759287a7bc6f426f0e60d 100644 (file)
@@ -1,10 +1,8 @@
-/*
- * Generic AC97 sound support for SH7760
- *
- * (c) 2007 Manuel Lauss
- *
- * Licensed under the GPLv2.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Generic AC97 sound support for SH7760
+//
+// (c) 2007 Manuel Lauss
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -68,6 +66,6 @@ static void __exit sh7760_ac97_exit(void)
 module_init(sh7760_ac97_init);
 module_exit(sh7760_ac97_exit);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index 6088d627c0e4b3d000539ed4e4549b5a98292ed3..63a508fdfe788571ed26a94be1f30c10e52a75b4 100644 (file)
@@ -1,23 +1,9 @@
-/*
- * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
 
 #ifndef SIU_H
 #define SIU_H
index ee2211635e92199e2e280d8be516d7dee80af8dc..f2a386fcd92e4da317556ae333de646bb6dcd1f5 100644 (file)
@@ -1,23 +1,9 @@
-/*
- * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
 
 #include <linux/delay.h>
 #include <linux/firmware.h>
index 172909570ed518ff6d89f1ff4ec5148689180cae..e263757e4a69153695ce6366769007339461b3b5 100644 (file)
@@ -1,23 +1,10 @@
-/*
- * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
index 89ed1b107ac52c5f808ba9208dc3ef45e84803e8..8125fa3840b60f6b20480215d43bda1401e5f6e3 100644 (file)
@@ -1,14 +1,11 @@
-/*
- * Serial Sound Interface (I2S) support for SH7760/SH7780
- *
- * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- *
- *  licensed under the terms outlined in the file COPYING at the root
- *  of the linux kernel sources.
- *
- * dont forget to set IPSEL/OMSEL register bits (in your board code) to
- * enable SSI output pins!
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Serial Sound Interface (I2S) support for SH7760/SH7780
+//
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// dont forget to set IPSEL/OMSEL register bits (in your board code) to
+// enable SSI output pins!
 
 /*
  * LIMITATIONS:
@@ -400,6 +397,6 @@ static struct platform_driver sh4_ssi_driver = {
 
 module_platform_driver(sh4_ssi_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index 77e7dcf969d0ce2e642f881c497d534bb7029df5..d70fcd4a1adf7428884bdf04400a5ecbb998845a 100644 (file)
@@ -370,10 +370,9 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, usp);
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap(&pdev->dev, mem_res->start,
-               resource_size(mem_res));
-       if (base == NULL)
-               return -ENOMEM;
+       base = devm_ioremap_resource(&pdev->dev, mem_res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
        usp->regmap = devm_regmap_init_mmio(&pdev->dev, base,
                                            &sirf_usp_regmap_config);
        if (IS_ERR(usp->regmap))
index 3f424f214bcaec9d9dcf752dc5c72155765a4132..c086786e4471cfcfdd43cf2268689f6c77ebe62f 100644 (file)
@@ -1,20 +1,15 @@
-/*
- * soc-ac97.c  --  ALSA SoC Audio Layer AC97 support
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- *         with code, comments and ideas from :-
- *         Richard Purdie <richard@openedhand.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-ac97.c  --  ALSA SoC Audio Layer AC97 support
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+//         with code, comments and ideas from :-
+//         Richard Purdie <richard@openedhand.com>
 
 #include <linux/ctype.h>
 #include <linux/delay.h>
index 3d7e1ff7913931cd762ba44346e899db7f4ca40d..b8e72b52db30ea44c92092dc2a0a4135218624fc 100644 (file)
@@ -1,18 +1,8 @@
-/*
- * soc-apci.c - support for ACPI enumeration.
- *
- * Copyright (c) 2013-15, Intel Corporation.
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// soc-apci.c - support for ACPI enumeration.
+//
+// Copyright (c) 2013-15, Intel Corporation.
 
 #include <sound/soc-acpi.h>
 
index e095115fa9f9b24825a8818d00e453cf227bb556..409d082e80d15b75576ce7be3501183ce0370547 100644 (file)
@@ -1,18 +1,12 @@
-/*
- * soc-compress.c  --  ALSA SoC Compress
- *
- * Copyright (C) 2012 Intel Corp.
- *
- * Authors: Namarta Kohli <namartax.kohli@intel.com>
- *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
- *          Vinod Koul <vinod.koul@linux.intel.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-compress.c  --  ALSA SoC Compress
+//
+// Copyright (C) 2012 Intel Corp.
+//
+// Authors: Namarta Kohli <namartax.kohli@intel.com>
+//          Ramesh Babu K V <ramesh.babu@linux.intel.com>
+//          Vinod Koul <vinod.koul@linux.intel.com>
 
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -146,6 +140,30 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
                stream = SNDRV_PCM_STREAM_CAPTURE;
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       fe->dpcm[stream].runtime = fe_substream->runtime;
+
+       ret = dpcm_path_get(fe, stream, &list);
+       if (ret < 0)
+               goto be_err;
+       else if (ret == 0)
+               dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
+                       fe->dai_link->name, stream ? "capture" : "playback");
+       /* calculate valid and active FE <-> BE dpcms */
+       dpcm_process_paths(fe, stream, &list, 1);
+       fe->dpcm[stream].runtime = fe_substream->runtime;
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       ret = dpcm_be_dai_startup(fe, stream);
+       if (ret < 0) {
+               /* clean up all links */
+               list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+                       dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+               dpcm_be_disconnect(fe, stream);
+               fe->dpcm[stream].runtime = NULL;
+               goto out;
+       }
 
        if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
                ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
@@ -159,7 +177,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 
        ret = soc_compr_components_open(cstream, &component);
        if (ret < 0)
-               goto machine_err;
+               goto open_err;
 
        if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
                ret = fe->dai_link->compr_ops->startup(cstream);
@@ -170,31 +188,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
                }
        }
 
-       fe->dpcm[stream].runtime = fe_substream->runtime;
-
-       ret = dpcm_path_get(fe, stream, &list);
-       if (ret < 0)
-               goto fe_err;
-       else if (ret == 0)
-               dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
-                       fe->dai_link->name, stream ? "capture" : "playback");
-
-       /* calculate valid and active FE <-> BE dpcms */
-       dpcm_process_paths(fe, stream, &list, 1);
-
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
-
-       ret = dpcm_be_dai_startup(fe, stream);
-       if (ret < 0) {
-               /* clean up all links */
-               list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
-                       dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
-
-               dpcm_be_disconnect(fe, stream);
-               fe->dpcm[stream].runtime = NULL;
-               goto path_err;
-       }
-
        dpcm_clear_pending_state(fe, stream);
        dpcm_path_put(&list);
 
@@ -207,17 +200,14 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 
        return 0;
 
-path_err:
-       dpcm_path_put(&list);
-fe_err:
-       if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
-               fe->dai_link->compr_ops->shutdown(cstream);
 machine_err:
        soc_compr_components_free(cstream, component);
-
+open_err:
        if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
                cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
 out:
+       dpcm_path_put(&list);
+be_err:
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
        mutex_unlock(&fe->card->mutex);
        return ret;
@@ -557,6 +547,24 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
+       /*
+        * Create an empty hw_params for the BE as the machine driver must
+        * fix this up to match DSP decoder and ASRC configuration.
+        * I.e. machine driver fixup for compressed BE is mandatory.
+        */
+       memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
+               sizeof(struct snd_pcm_hw_params));
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       ret = dpcm_be_dai_hw_params(fe, stream);
+       if (ret < 0)
+               goto out;
+
+       ret = dpcm_be_dai_prepare(fe, stream);
+       if (ret < 0)
+               goto out;
+
        if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
                ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
                if (ret < 0)
@@ -583,24 +591,6 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
                        goto out;
        }
 
-       /*
-        * Create an empty hw_params for the BE as the machine driver must
-        * fix this up to match DSP decoder and ASRC configuration.
-        * I.e. machine driver fixup for compressed BE is mandatory.
-        */
-       memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
-               sizeof(struct snd_pcm_hw_params));
-
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
-
-       ret = dpcm_be_dai_hw_params(fe, stream);
-       if (ret < 0)
-               goto out;
-
-       ret = dpcm_be_dai_prepare(fe, stream);
-       if (ret < 0)
-               goto out;
-
        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 
index 4663de3cf495278f42b2950a3474ee4afb293674..9cfe10d8040cf8f0cea83d85d2dfb68a6b508f6d 100644 (file)
@@ -1,26 +1,21 @@
-/*
- * soc-core.c  --  ALSA SoC Audio Layer
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- *         with code, comments and ideas from :-
- *         Richard Purdie <richard@openedhand.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  TODO:
- *   o Add hw rules to enforce rates, etc.
- *   o More testing with other codecs/machines.
- *   o Add more codecs and platforms to ensure good API coverage.
- *   o Support TDM on PCM and I2S
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-core.c  --  ALSA SoC Audio Layer
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+//         with code, comments and ideas from :-
+//         Richard Purdie <richard@openedhand.com>
+//
+//  TODO:
+//   o Add hw rules to enforce rates, etc.
+//   o More testing with other codecs/machines.
+//   o Add more codecs and platforms to ensure good API coverage.
+//   o Support TDM on PCM and I2S
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -533,6 +528,7 @@ int snd_soc_suspend(struct device *dev)
                                                "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
                                }
+                               /* fall through */
 
                        case SND_SOC_BIAS_OFF:
                                if (component->driver->suspend)
@@ -852,6 +848,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
        const char *platform_name;
        int i;
 
+       if (dai_link->ignore)
+               return 0;
+
        dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
 
        if (soc_is_dai_link_bound(card, dai_link)) {
@@ -1195,15 +1194,27 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
 
+static void soc_set_of_name_prefix(struct snd_soc_component *component)
+{
+       struct device_node *component_of_node = component->dev->of_node;
+       const char *str;
+       int ret;
+
+       if (!component_of_node && component->dev->parent)
+               component_of_node = component->dev->parent->of_node;
+
+       ret = of_property_read_string(component_of_node, "sound-name-prefix",
+                                     &str);
+       if (!ret)
+               component->name_prefix = str;
+}
+
 static void soc_set_name_prefix(struct snd_soc_card *card,
                                struct snd_soc_component *component)
 {
        int i;
 
-       if (card->codec_conf == NULL)
-               return;
-
-       for (i = 0; i < card->num_configs; i++) {
+       for (i = 0; i < card->num_configs && card->codec_conf; i++) {
                struct snd_soc_codec_conf *map = &card->codec_conf[i];
                struct device_node *component_of_node = component->dev->of_node;
 
@@ -1215,8 +1226,14 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
                if (map->dev_name && strcmp(component->name, map->dev_name))
                        continue;
                component->name_prefix = map->name_prefix;
-               break;
+               return;
        }
+
+       /*
+        * If there is no configuration table or no match in the table,
+        * check if a prefix is provided in the node
+        */
+       soc_set_of_name_prefix(component);
 }
 
 static int soc_probe_component(struct snd_soc_card *card,
@@ -1461,7 +1478,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
 {
        struct snd_soc_dai_link *dai_link = rtd->dai_link;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int i, ret;
+       struct snd_soc_rtdcom_list *rtdcom;
+       struct snd_soc_component *component;
+       int i, ret, num;
 
        dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
                        card->name, rtd->num, order);
@@ -1507,9 +1526,28 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
                soc_dpcm_debugfs_add(rtd);
 #endif
 
+       num = rtd->num;
+
+       /*
+        * most drivers will register their PCMs using DAI link ordering but
+        * topology based drivers can use the DAI link id field to set PCM
+        * device number and then use rtd + a base offset of the BEs.
+        */
+       for_each_rtdcom(rtd, rtdcom) {
+               component = rtdcom->component;
+
+               if (!component->driver->use_dai_pcm_id)
+                       continue;
+
+               if (rtd->dai_link->no_pcm)
+                       num += component->driver->be_pcm_base;
+               else
+                       num = rtd->dai_link->id;
+       }
+
        if (cpu_dai->driver->compress_new) {
                /*create compress_device"*/
-               ret = cpu_dai->driver->compress_new(rtd, rtd->num);
+               ret = cpu_dai->driver->compress_new(rtd, num);
                if (ret < 0) {
                        dev_err(card->dev, "ASoC: can't create compress %s\n",
                                         dai_link->stream_name);
@@ -1519,7 +1557,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
 
                if (!dai_link->params) {
                        /* create the pcm */
-                       ret = soc_new_pcm(rtd, rtd->num);
+                       ret = soc_new_pcm(rtd, num);
                        if (ret < 0) {
                                dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
                                       dai_link->stream_name, ret);
@@ -1846,6 +1884,74 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
 EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
 #endif /* CONFIG_DMI */
 
+static void soc_check_tplg_fes(struct snd_soc_card *card)
+{
+       struct snd_soc_component *component;
+       const struct snd_soc_component_driver *comp_drv;
+       struct snd_soc_dai_link *dai_link;
+       int i;
+
+       list_for_each_entry(component, &component_list, list) {
+
+               /* does this component override FEs ? */
+               if (!component->driver->ignore_machine)
+                       continue;
+
+               /* for this machine ? */
+               if (strcmp(component->driver->ignore_machine,
+                          card->dev->driver->name))
+                       continue;
+
+               /* machine matches, so override the rtd data */
+               for (i = 0; i < card->num_links; i++) {
+
+                       dai_link = &card->dai_link[i];
+
+                       /* ignore this FE */
+                       if (dai_link->dynamic) {
+                               dai_link->ignore = true;
+                               continue;
+                       }
+
+                       dev_info(card->dev, "info: override FE DAI link %s\n",
+                                card->dai_link[i].name);
+
+                       /* override platform component */
+                       dai_link->platform_name = component->name;
+
+                       /* convert non BE into BE */
+                       dai_link->no_pcm = 1;
+
+                       /* override any BE fixups */
+                       dai_link->be_hw_params_fixup =
+                               component->driver->be_hw_params_fixup;
+
+                       /* most BE links don't set stream name, so set it to
+                        * dai link name if it's NULL to help bind widgets.
+                        */
+                       if (!dai_link->stream_name)
+                               dai_link->stream_name = dai_link->name;
+               }
+
+               /* Inform userspace we are using alternate topology */
+               if (component->driver->topology_name_prefix) {
+
+                       /* topology shortname created ? */
+                       if (!card->topology_shortname_created) {
+                               comp_drv = component->driver;
+
+                               snprintf(card->topology_shortname, 32, "%s-%s",
+                                        comp_drv->topology_name_prefix,
+                                        card->name);
+                               card->topology_shortname_created = true;
+                       }
+
+                       /* use topology shortname */
+                       card->name = card->topology_shortname;
+               }
+       }
+}
+
 static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
        struct snd_soc_pcm_runtime *rtd;
@@ -1855,6 +1961,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        mutex_lock(&client_mutex);
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
+       /* check whether any platform is ignore machine FE and using topology */
+       soc_check_tplg_fes(card);
+
        /* bind DAIs */
        for (i = 0; i < card->num_links; i++) {
                ret = soc_bind_dai_link(card, &card->dai_link[i]);
@@ -2522,6 +2631,28 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
 
+/**
+ * snd_soc_dai_get_channel_map - Get DAI audio channel map
+ * @dai: DAI
+ * @tx_num: how many TX channels
+ * @tx_slot: pointer to an array which imply the TX slot number channel
+ *           0~num-1 uses
+ * @rx_num: how many RX channels
+ * @rx_slot: pointer to an array which imply the RX slot number channel
+ *           0~num-1 uses
+ */
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+       unsigned int *tx_num, unsigned int *tx_slot,
+       unsigned int *rx_num, unsigned int *rx_slot)
+{
+       if (dai->driver->ops->get_channel_map)
+               return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
+                       rx_num, rx_slot);
+       else
+               return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
+
 /**
  * snd_soc_dai_set_tristate - configure DAI system or master clock.
  * @dai: DAI
@@ -3258,9 +3389,9 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
 
-static int snd_soc_of_get_slot_mask(struct device_node *np,
-                                   const char *prop_name,
-                                   unsigned int *mask)
+int snd_soc_of_get_slot_mask(struct device_node *np,
+                            const char *prop_name,
+                            unsigned int *mask)
 {
        u32 val;
        const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
@@ -3275,6 +3406,7 @@ static int snd_soc_of_get_slot_mask(struct device_node *np,
 
        return val;
 }
+EXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask);
 
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
                              unsigned int *tx_mask,
index a099c3e4550478e81b16546bfc0012e407d15d24..7e96793050c9b1a1b634d34e4e0ad9a658cf4111 100644 (file)
@@ -1,27 +1,21 @@
-/*
- * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  Features:
- *    o Changes power status of internal codec blocks depending on the
- *      dynamic configuration of codec internal audio paths and active
- *      DACs/ADCs.
- *    o Platform power domain - can support external components i.e. amps and
- *      mic/headphone insertion events.
- *    o Automatic Mic Bias support
- *    o Jack insertion power event initiation - e.g. hp insertion will enable
- *      sinks, dacs, etc
- *    o Delayed power down of audio subsystem to reduce pops between a quick
- *      device reopen.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+//
+//  Features:
+//    o Changes power status of internal codec blocks depending on the
+//      dynamic configuration of codec internal audio paths and active
+//      DACs/ADCs.
+//    o Platform power domain - can support external components i.e. amps and
+//      mic/headphone insertion events.
+//    o Automatic Mic Bias support
+//    o Jack insertion power event initiation - e.g. hp insertion will enable
+//      sinks, dacs, etc
+//    o Delayed power down of audio subsystem to reduce pops between a quick
+//      device reopen.
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -3662,7 +3656,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
        struct snd_pcm_substream substream;
        struct snd_pcm_hw_params *params = NULL;
        struct snd_pcm_runtime *runtime = NULL;
-       u64 fmt;
+       unsigned int fmt;
        int ret;
 
        if (WARN_ON(!config) ||
index 7ac745df1412689c6adf0bf246399870b79e44e7..a9ea172a66a700c36fbbf02484ed00ae5ec03f81 100644 (file)
@@ -1,13 +1,8 @@
-/*
- * soc-devres.c  --  ALSA SoC Audio Layer devres functions
- *
- * Copyright (C) 2013 Linaro Ltd
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-devres.c  --  ALSA SoC Audio Layer devres functions
+//
+// Copyright (C) 2013 Linaro Ltd
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index 56a541b9ff9e2340eabc996c803a9b3a7427853c..52fd7af952a5366e9d436d10aa61bc39212001af 100644 (file)
@@ -1,17 +1,8 @@
-/*
- *  Copyright (C) 2013, Analog Devices Inc.
- *     Author: Lars-Peter Clausen <lars@metafoo.de>
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under  the terms of the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the License, or (at your
- *  option) any later version.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+//  Copyright (C) 2013, Analog Devices Inc.
+//     Author: Lars-Peter Clausen <lars@metafoo.de>
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/dmaengine.h>
@@ -197,7 +188,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
                        case 32:
                        case 64:
                                if (addr_widths & (1 << (bits / 8)))
-                                       hw.formats |= (1LL << i);
+                                       hw.formats |= pcm_format_to_bits(i);
                                break;
                        default:
                                /* Unsupported types */
@@ -343,7 +334,7 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
 
 static int dmaengine_copy_user(struct snd_pcm_substream *substream,
                               int channel, unsigned long hwoff,
-                              void *buf, unsigned long bytes)
+                              void __user *buf, unsigned long bytes)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_component *component =
@@ -359,18 +350,17 @@ static int dmaengine_copy_user(struct snd_pcm_substream *substream,
        int ret;
 
        if (is_playback)
-               if (copy_from_user(dma_ptr, (void __user *)buf, bytes))
+               if (copy_from_user(dma_ptr, buf, bytes))
                        return -EFAULT;
 
        if (process) {
-               ret = process(substream, channel, hwoff,
-                             (void __user *)buf, bytes);
+               ret = process(substream, channel, hwoff, (__force void *)buf, bytes);
                if (ret < 0)
                        return ret;
        }
 
        if (!is_playback)
-               if (copy_to_user((void __user *)buf, dma_ptr, bytes))
+               if (copy_to_user(buf, dma_ptr, bytes))
                        return -EFAULT;
 
        return 0;
index 026cd5347e53af2d2f2c6ac943cf648d1019837f..1ff9175e9d5e614d6b01af0fa4c16f3009b538a7 100644 (file)
@@ -1,15 +1,10 @@
-/*
- * soc-io.c  --  ASoC register I/O helpers
- *
- * Copyright 2009-2011 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-io.c  --  ASoC register I/O helpers
+//
+// Copyright 2009-2011 Wolfson Microelectronics PLC.
+//
+// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
index b2b16044ae80327554d3cab9c045f37e122ea85d..c7b990abdbaa62a5182fb475c3e13884ad9f5341 100644 (file)
@@ -1,15 +1,10 @@
-/*
- * soc-jack.c  --  ALSA SoC jack handling
- *
- * Copyright 2008 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-jack.c  --  ALSA SoC jack handling
+//
+// Copyright 2008 Wolfson Microelectronics PLC.
+//
+// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 
 #include <sound/jack.h>
 #include <sound/soc.h>
index 7144a51ddfa9aaa49c917461e1aa9293f26955a4..592efb370c44931854480559ea95851150ec2659 100644 (file)
@@ -1,20 +1,15 @@
-/*
- * soc-ops.c  --  Generic ASoC operations
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- *         with code, comments and ideas from :-
- *         Richard Purdie <richard@openedhand.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-ops.c  --  Generic ASoC operations
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+//         with code, comments and ideas from :-
+//         Richard Purdie <richard@openedhand.com>
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index 5feae9666822204344809c2c93e2d4796231b229..e8b98bfd4cf13bcb56d118a4c87a6e08ce5139e2 100644 (file)
@@ -1,20 +1,14 @@
-/*
- * soc-pcm.c  --  ALSA SoC PCM
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Authors: Liam Girdwood <lrg@ti.com>
- *          Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-pcm.c  --  ALSA SoC PCM
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Authors: Liam Girdwood <lrg@ti.com>
+//          Mark Brown <broonie@opensource.wolfsonmicro.com>
 
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -448,6 +442,29 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
        hw->rate_max = min_not_zero(hw->rate_max, rate_max);
 }
 
+static int soc_pcm_components_close(struct snd_pcm_substream *substream,
+                                   struct snd_soc_component *last)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_rtdcom_list *rtdcom;
+       struct snd_soc_component *component;
+
+       for_each_rtdcom(rtd, rtdcom) {
+               component = rtdcom->component;
+
+               if (component == last)
+                       break;
+
+               if (!component->driver->ops ||
+                   !component->driver->ops->close)
+                       continue;
+
+               component->driver->ops->close(substream);
+       }
+
+       return 0;
+}
+
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
@@ -462,7 +479,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai;
        const char *codec_dai_name = "multicodec";
-       int i, ret = 0, __ret;
+       int i, ret = 0;
 
        pinctrl_pm_select_default_state(cpu_dai->dev);
        for (i = 0; i < rtd->num_codecs; i++)
@@ -486,7 +503,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       ret = 0;
        for_each_rtdcom(rtd, rtdcom) {
                component = rtdcom->component;
 
@@ -494,16 +510,15 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                    !component->driver->ops->open)
                        continue;
 
-               __ret = component->driver->ops->open(substream);
-               if (__ret < 0) {
+               ret = component->driver->ops->open(substream);
+               if (ret < 0) {
                        dev_err(component->dev,
                                "ASoC: can't open component %s: %d\n",
-                               component->name, __ret);
-                       ret = __ret;
+                               component->name, ret);
+                       goto component_err;
                }
        }
-       if (ret < 0)
-               goto component_err;
+       component = NULL;
 
        for (i = 0; i < rtd->num_codecs; i++) {
                codec_dai = rtd->codec_dais[i];
@@ -612,15 +627,7 @@ codec_dai_err:
        }
 
 component_err:
-       for_each_rtdcom(rtd, rtdcom) {
-               component = rtdcom->component;
-
-               if (!component->driver->ops ||
-                   !component->driver->ops->close)
-                       continue;
-
-               component->driver->ops->close(substream);
-       }
+       soc_pcm_components_close(substream, component);
 
        if (cpu_dai->driver->ops->shutdown)
                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
@@ -714,15 +721,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        if (rtd->dai_link->ops->shutdown)
                rtd->dai_link->ops->shutdown(substream);
 
-       for_each_rtdcom(rtd, rtdcom) {
-               component = rtdcom->component;
-
-               if (!component->driver->ops ||
-                   !component->driver->ops->close)
-                       continue;
-
-               component->driver->ops->close(substream);
-       }
+       soc_pcm_components_close(substream, NULL);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
@@ -860,8 +859,20 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
                      struct snd_pcm_hw_params *params,
                      struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        int ret;
 
+       /* perform any topology hw_params fixups before DAI  */
+       if (rtd->dai_link->be_hw_params_fixup) {
+               ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
+               if (ret < 0) {
+                       dev_err(rtd->dev,
+                               "ASoC: hw_params topology fixup failed %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
        if (dai->driver->ops->hw_params) {
                ret = dai->driver->ops->hw_params(substream, params, dai);
                if (ret < 0) {
@@ -874,6 +885,29 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
+                                     struct snd_soc_component *last)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_rtdcom_list *rtdcom;
+       struct snd_soc_component *component;
+
+       for_each_rtdcom(rtd, rtdcom) {
+               component = rtdcom->component;
+
+               if (component == last)
+                       break;
+
+               if (!component->driver->ops ||
+                   !component->driver->ops->hw_free)
+                       continue;
+
+               component->driver->ops->hw_free(substream);
+       }
+
+       return 0;
+}
+
 /*
  * Called by ALSA when the hardware params are set by application. This
  * function can also be called multiple times and can allocate buffers
@@ -886,7 +920,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_component *component;
        struct snd_soc_rtdcom_list *rtdcom;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int i, ret = 0, __ret;
+       int i, ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
        if (rtd->dai_link->ops->hw_params) {
@@ -944,7 +978,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                goto interface_err;
 
-       ret = 0;
        for_each_rtdcom(rtd, rtdcom) {
                component = rtdcom->component;
 
@@ -952,16 +985,15 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                    !component->driver->ops->hw_params)
                        continue;
 
-               __ret = component->driver->ops->hw_params(substream, params);
-               if (__ret < 0) {
+               ret = component->driver->ops->hw_params(substream, params);
+               if (ret < 0) {
                        dev_err(component->dev,
                                "ASoC: %s hw params failed: %d\n",
-                               component->name, __ret);
-                       ret = __ret;
+                               component->name, ret);
+                       goto component_err;
                }
        }
-       if (ret < 0)
-               goto component_err;
+       component = NULL;
 
        /* store the parameters for each DAIs */
        cpu_dai->rate = params_rate(params);
@@ -977,15 +1009,7 @@ out:
        return ret;
 
 component_err:
-       for_each_rtdcom(rtd, rtdcom) {
-               component = rtdcom->component;
-
-               if (!component->driver->ops ||
-                   !component->driver->ops->hw_free)
-                       continue;
-
-               component->driver->ops->hw_free(substream);
-       }
+       soc_pcm_components_hw_free(substream, component);
 
        if (cpu_dai->driver->ops->hw_free)
                cpu_dai->driver->ops->hw_free(substream, cpu_dai);
@@ -1014,8 +1038,6 @@ codec_err:
 static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_component *component;
-       struct snd_soc_rtdcom_list *rtdcom;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai;
        bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
@@ -1052,15 +1074,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
                rtd->dai_link->ops->hw_free(substream);
 
        /* free any component resources */
-       for_each_rtdcom(rtd, rtdcom) {
-               component = rtdcom->component;
-
-               if (!component->driver->ops ||
-                   !component->driver->ops->hw_free)
-                       continue;
-
-               component->driver->ops->hw_free(substream);
-       }
+       soc_pcm_components_hw_free(substream, NULL);
 
        /* now free hw params for the DAIs  */
        for (i = 0; i < rtd->num_codecs; i++) {
@@ -1165,6 +1179,9 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
        snd_pcm_sframes_t codec_delay = 0;
        int i;
 
+       /* clearing the previous total delay */
+       runtime->delay = 0;
+
        for_each_rtdcom(rtd, rtdcom) {
                component = rtdcom->component;
 
@@ -1176,6 +1193,8 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
                offset = component->driver->ops->pointer(substream);
                break;
        }
+       /* base delay if assigned in pointer callback */
+       delay = runtime->delay;
 
        if (cpu_dai->driver->ops->delay)
                delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
@@ -1658,29 +1677,28 @@ unwind:
 }
 
 static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
-                                struct snd_soc_pcm_stream *stream,
-                                u64 formats)
+                                struct snd_soc_pcm_stream *stream)
 {
        runtime->hw.rate_min = stream->rate_min;
        runtime->hw.rate_max = stream->rate_max;
        runtime->hw.channels_min = stream->channels_min;
        runtime->hw.channels_max = stream->channels_max;
        if (runtime->hw.formats)
-               runtime->hw.formats &= formats & stream->formats;
+               runtime->hw.formats &= stream->formats;
        else
-               runtime->hw.formats = formats & stream->formats;
+               runtime->hw.formats = stream->formats;
        runtime->hw.rates = stream->rates;
 }
 
-static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
+static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
+                                     u64 *formats)
 {
        struct snd_soc_pcm_runtime *fe = substream->private_data;
        struct snd_soc_dpcm *dpcm;
-       u64 formats = ULLONG_MAX;
        int stream = substream->stream;
 
        if (!fe->dai_link->dpcm_merged_format)
-               return formats;
+               return;
 
        /*
         * It returns merged BE codec format
@@ -1708,11 +1726,118 @@ static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
                        else
                                codec_stream = &codec_dai_drv->capture;
 
-                       formats &= codec_stream->formats;
+                       *formats &= codec_stream->formats;
                }
        }
+}
+
+static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
+                                   unsigned int *channels_min,
+                                   unsigned int *channels_max)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       struct snd_soc_dpcm *dpcm;
+       int stream = substream->stream;
 
-       return formats;
+       if (!fe->dai_link->dpcm_merged_chan)
+               return;
+
+       /*
+        * It returns merged BE codec channel;
+        * if FE want to use it (= dpcm_merged_chan)
+        */
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_soc_dai_driver *cpu_dai_drv =  be->cpu_dai->driver;
+               struct snd_soc_dai_driver *codec_dai_drv;
+               struct snd_soc_pcm_stream *codec_stream;
+               struct snd_soc_pcm_stream *cpu_stream;
+
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       cpu_stream = &cpu_dai_drv->playback;
+               else
+                       cpu_stream = &cpu_dai_drv->capture;
+
+               *channels_min = max(*channels_min, cpu_stream->channels_min);
+               *channels_max = min(*channels_max, cpu_stream->channels_max);
+
+               /*
+                * chan min/max cannot be enforced if there are multiple CODEC
+                * DAIs connected to a single CPU DAI, use CPU DAI's directly
+                */
+               if (be->num_codecs == 1) {
+                       codec_dai_drv = be->codec_dais[0]->driver;
+
+                       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                               codec_stream = &codec_dai_drv->playback;
+                       else
+                               codec_stream = &codec_dai_drv->capture;
+
+                       *channels_min = max(*channels_min,
+                                           codec_stream->channels_min);
+                       *channels_max = min(*channels_max,
+                                           codec_stream->channels_max);
+               }
+       }
+}
+
+static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
+                                   unsigned int *rates,
+                                   unsigned int *rate_min,
+                                   unsigned int *rate_max)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       struct snd_soc_dpcm *dpcm;
+       int stream = substream->stream;
+
+       if (!fe->dai_link->dpcm_merged_rate)
+               return;
+
+       /*
+        * It returns merged BE codec channel;
+        * if FE want to use it (= dpcm_merged_chan)
+        */
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_soc_dai_driver *cpu_dai_drv =  be->cpu_dai->driver;
+               struct snd_soc_dai_driver *codec_dai_drv;
+               struct snd_soc_pcm_stream *codec_stream;
+               struct snd_soc_pcm_stream *cpu_stream;
+               int i;
+
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       cpu_stream = &cpu_dai_drv->playback;
+               else
+                       cpu_stream = &cpu_dai_drv->capture;
+
+               *rate_min = max(*rate_min, cpu_stream->rate_min);
+               *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
+               *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
+
+               for (i = 0; i < be->num_codecs; i++) {
+                       /*
+                        * Skip CODECs which don't support the current stream
+                        * type. See soc_pcm_init_runtime_hw() for more details
+                        */
+                       if (!snd_soc_dai_stream_valid(be->codec_dais[i],
+                                                     stream))
+                               continue;
+
+                       codec_dai_drv = be->codec_dais[i]->driver;
+                       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                               codec_stream = &codec_dai_drv->playback;
+                       else
+                               codec_stream = &codec_dai_drv->capture;
+
+                       *rate_min = max(*rate_min, codec_stream->rate_min);
+                       *rate_max = min_not_zero(*rate_max,
+                                                codec_stream->rate_max);
+                       *rates = snd_pcm_rate_mask_intersect(*rates,
+                                               codec_stream->rates);
+               }
+       }
 }
 
 static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
@@ -1721,12 +1846,17 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
-       u64 format = dpcm_runtime_base_format(substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback, format);
+               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
        else
-               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture, format);
+               dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
+
+       dpcm_runtime_merge_format(substream, &runtime->hw.formats);
+       dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
+                               &runtime->hw.channels_max);
+       dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
+                               &runtime->hw.rate_min, &runtime->hw.rate_max);
 }
 
 static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
@@ -2551,106 +2681,113 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
        return ret;
 }
 
-/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
- * any DAI links.
- */
-int soc_dpcm_runtime_update(struct snd_soc_card *card)
+static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
 {
-       struct snd_soc_pcm_runtime *fe;
-       int old, new, paths;
+       struct snd_soc_dapm_widget_list *list;
+       int count, paths;
 
-       mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-       list_for_each_entry(fe, &card->rtd_list, list) {
-               struct snd_soc_dapm_widget_list *list;
+       if (!fe->dai_link->dynamic)
+               return 0;
 
-               /* make sure link is FE */
-               if (!fe->dai_link->dynamic)
-                       continue;
+       /* only check active links */
+       if (!fe->cpu_dai->active)
+               return 0;
 
-               /* only check active links */
-               if (!fe->cpu_dai->active)
-                       continue;
+       /* DAPM sync will call this to update DSP paths */
+       dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
+               new ? "new" : "old", fe->dai_link->name);
 
-               /* DAPM sync will call this to update DSP paths */
-               dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n",
-                       fe->dai_link->name);
+       /* skip if FE doesn't have playback capability */
+       if (!fe->cpu_dai->driver->playback.channels_min ||
+           !fe->codec_dai->driver->playback.channels_min)
+               goto capture;
 
-               /* skip if FE doesn't have playback capability */
-               if (!fe->cpu_dai->driver->playback.channels_min
-                   || !fe->codec_dai->driver->playback.channels_min)
-                       goto capture;
-
-               /* skip if FE isn't currently playing */
-               if (!fe->cpu_dai->playback_active
-                   || !fe->codec_dai->playback_active)
-                       goto capture;
-
-               paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
-               if (paths < 0) {
-                       dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
-                                       fe->dai_link->name,  "playback");
-                       mutex_unlock(&card->mutex);
-                       return paths;
-               }
+       /* skip if FE isn't currently playing */
+       if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active)
+               goto capture;
 
-               /* update any new playback paths */
-               new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
-               if (new) {
-                       dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
-                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
-                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
-               }
+       paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
+       if (paths < 0) {
+               dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
+                        fe->dai_link->name,  "playback");
+               return paths;
+       }
 
-               /* update any old playback paths */
-               old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
-               if (old) {
+       /* update any playback paths */
+       count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new);
+       if (count) {
+               if (new)
+                       dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+               else
                        dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
-                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
-                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
-               }
 
-               dpcm_path_put(&list);
+               dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+               dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+       }
+
+       dpcm_path_put(&list);
+
 capture:
-               /* skip if FE doesn't have capture capability */
-               if (!fe->cpu_dai->driver->capture.channels_min
-                   || !fe->codec_dai->driver->capture.channels_min)
-                       continue;
+       /* skip if FE doesn't have capture capability */
+       if (!fe->cpu_dai->driver->capture.channels_min ||
+           !fe->codec_dai->driver->capture.channels_min)
+               return 0;
 
-               /* skip if FE isn't currently capturing */
-               if (!fe->cpu_dai->capture_active
-                   || !fe->codec_dai->capture_active)
-                       continue;
+       /* skip if FE isn't currently capturing */
+       if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active)
+               return 0;
 
-               paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
-               if (paths < 0) {
-                       dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
-                                       fe->dai_link->name,  "capture");
-                       mutex_unlock(&card->mutex);
-                       return paths;
-               }
+       paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
+       if (paths < 0) {
+               dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
+                        fe->dai_link->name,  "capture");
+               return paths;
+       }
 
-               /* update any new capture paths */
-               new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
-               if (new) {
+       /* update any old capture paths */
+       count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new);
+       if (count) {
+               if (new)
                        dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
-                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
-                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
-               }
-
-               /* update any old capture paths */
-               old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
-               if (old) {
+               else
                        dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
-                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
-                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
-               }
 
-               dpcm_path_put(&list);
+               dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+               dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
        }
 
-       mutex_unlock(&card->mutex);
+       dpcm_path_put(&list);
+
        return 0;
 }
+
+/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
+ * any DAI links.
+ */
+int soc_dpcm_runtime_update(struct snd_soc_card *card)
+{
+       struct snd_soc_pcm_runtime *fe;
+       int ret = 0;
+
+       mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       /* shutdown all old paths first */
+       list_for_each_entry(fe, &card->rtd_list, list) {
+               ret = soc_dpcm_fe_runtime_update(fe, 0);
+               if (ret)
+                       goto out;
+       }
+
+       /* bring new paths up */
+       list_for_each_entry(fe, &card->rtd_list, list) {
+               ret = soc_dpcm_fe_runtime_update(fe, 1);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       mutex_unlock(&card->mutex);
+       return ret;
+}
 int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
 {
        struct snd_soc_dpcm *dpcm;
index 53f121a50c97bd6858a2b846b1a3f53e03026dd6..66e77e020745b282983c8c0f994d93485f17210d 100644 (file)
@@ -1,29 +1,24 @@
-/*
- * soc-topology.c  --  ALSA SoC Topology
- *
- * Copyright (C) 2012 Texas Instruments Inc.
- * Copyright (C) 2015 Intel Corporation.
- *
- * Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- *             K, Mythri P <mythri.p.k@intel.com>
- *             Prusty, Subhransu S <subhransu.s.prusty@intel.com>
- *             B, Jayachandran <jayachandran.b@intel.com>
- *             Abdullah, Omair M <omair.m.abdullah@intel.com>
- *             Jin, Yao <yao.jin@intel.com>
- *             Lin, Mengdong <mengdong.lin@intel.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  Add support to read audio firmware topology alongside firmware text. The
- *  topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links,
- *  equalizers, firmware, coefficients etc.
- *
- *  This file only manages the core ALSA and ASoC components, all other bespoke
- *  firmware topology data is passed to component drivers for bespoke handling.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-topology.c  --  ALSA SoC Topology
+//
+// Copyright (C) 2012 Texas Instruments Inc.
+// Copyright (C) 2015 Intel Corporation.
+//
+// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+//             K, Mythri P <mythri.p.k@intel.com>
+//             Prusty, Subhransu S <subhransu.s.prusty@intel.com>
+//             B, Jayachandran <jayachandran.b@intel.com>
+//             Abdullah, Omair M <omair.m.abdullah@intel.com>
+//             Jin, Yao <yao.jin@intel.com>
+//             Lin, Mengdong <mengdong.lin@intel.com>
+//
+//  Add support to read audio firmware topology alongside firmware text. The
+//  topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links,
+//  equalizers, firmware, coefficients etc.
+//
+//  This file only manages the core ALSA and ASoC components, all other bespoke
+//  firmware topology data is passed to component drivers for bespoke handling.
 
 #include <linux/kernel.h>
 #include <linux/export.h>
@@ -259,7 +254,7 @@ static int soc_tplg_vendor_load_(struct soc_tplg *tplg,
        int ret = 0;
 
        if (tplg->comp && tplg->ops && tplg->ops->vendor_load)
-               ret = tplg->ops->vendor_load(tplg->comp, hdr);
+               ret = tplg->ops->vendor_load(tplg->comp, tplg->index, hdr);
        else {
                dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
                        hdr->vendor_type);
@@ -291,7 +286,8 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
        struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
 {
        if (tplg->comp && tplg->ops && tplg->ops->widget_load)
-               return tplg->ops->widget_load(tplg->comp, w, tplg_w);
+               return tplg->ops->widget_load(tplg->comp, tplg->index, w,
+                       tplg_w);
 
        return 0;
 }
@@ -302,27 +298,30 @@ static int soc_tplg_widget_ready(struct soc_tplg *tplg,
        struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
 {
        if (tplg->comp && tplg->ops && tplg->ops->widget_ready)
-               return tplg->ops->widget_ready(tplg->comp, w, tplg_w);
+               return tplg->ops->widget_ready(tplg->comp, tplg->index, w,
+                       tplg_w);
 
        return 0;
 }
 
 /* pass DAI configurations to component driver for extra initialization */
 static int soc_tplg_dai_load(struct soc_tplg *tplg,
-       struct snd_soc_dai_driver *dai_drv)
+       struct snd_soc_dai_driver *dai_drv,
+       struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
 {
        if (tplg->comp && tplg->ops && tplg->ops->dai_load)
-               return tplg->ops->dai_load(tplg->comp, dai_drv);
+               return tplg->ops->dai_load(tplg->comp, tplg->index, dai_drv,
+                       pcm, dai);
 
        return 0;
 }
 
 /* pass link configurations to component driver for extra initialization */
 static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
-       struct snd_soc_dai_link *link)
+       struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg)
 {
        if (tplg->comp && tplg->ops && tplg->ops->link_load)
-               return tplg->ops->link_load(tplg->comp, link);
+               return tplg->ops->link_load(tplg->comp, tplg->index, link, cfg);
 
        return 0;
 }
@@ -643,7 +642,8 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
        struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
 {
        if (tplg->comp && tplg->ops && tplg->ops->control_load)
-               return tplg->ops->control_load(tplg->comp, k, hdr);
+               return tplg->ops->control_load(tplg->comp, tplg->index, k,
+                       hdr);
 
        return 0;
 }
@@ -1100,6 +1100,17 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
        return 0;
 }
 
+/* optionally pass new dynamic kcontrol to component driver. */
+static int soc_tplg_add_route(struct soc_tplg *tplg,
+       struct snd_soc_dapm_route *route)
+{
+       if (tplg->comp && tplg->ops && tplg->ops->dapm_route_load)
+               return tplg->ops->dapm_route_load(tplg->comp, tplg->index,
+                       route);
+
+       return 0;
+}
+
 static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
        struct snd_soc_tplg_hdr *hdr)
 {
@@ -1148,6 +1159,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
                else
                        route.control = elem->control;
 
+               soc_tplg_add_route(tplg, &route);
+
                /* add route, but keep going if some fail */
                snd_soc_dapm_add_routes(dapm, &route, 1);
        }
@@ -1702,7 +1715,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
                dai_drv->compress_new = snd_soc_new_compress;
 
        /* pass control to component driver for optional further init */
-       ret = soc_tplg_dai_load(tplg, dai_drv);
+       ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
        if (ret < 0) {
                dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
                kfree(dai_drv);
@@ -1772,7 +1785,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
                set_link_flags(link, pcm->flag_mask, pcm->flags);
 
        /* pass control to component driver for optional further init */
-       ret = soc_tplg_dai_link_load(tplg, link);
+       ret = soc_tplg_dai_link_load(tplg, link, NULL);
        if (ret < 0) {
                dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
                kfree(link);
@@ -2080,7 +2093,7 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,
                set_link_flags(link, cfg->flag_mask, cfg->flags);
 
        /* pass control to component driver for optional further init */
-       ret = soc_tplg_dai_link_load(tplg, link);
+       ret = soc_tplg_dai_link_load(tplg, link, cfg);
        if (ret < 0) {
                dev_err(tplg->dev, "ASoC: physical link loading failed\n");
                return ret;
@@ -2202,7 +2215,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
                set_dai_flags(dai_drv, d->flag_mask, d->flags);
 
        /* pass control to component driver for optional further init */
-       ret = soc_tplg_dai_load(tplg, dai_drv);
+       ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
        if (ret < 0) {
                dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
                return ret;
@@ -2311,7 +2324,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
 
        /* pass control to component driver for optional further init */
        if (tplg->comp && tplg->ops && tplg->ops->manifest)
-               return tplg->ops->manifest(tplg->comp, _manifest);
+               return tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
 
        if (!abi_match) /* free the duplicated one */
                kfree(_manifest);
index a863bb3f66c21ad8af277cbd6613ea6521a1e702..e0c93496c0cda699cef17f07386ae479b758fc03 100644 (file)
@@ -1,17 +1,11 @@
-/*
- * soc-util.c  --  ALSA SoC Audio Layer utility functions
- *
- * Copyright 2009 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *         Liam Girdwood <lrg@slimlogic.co.uk>
- *         
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-util.c  --  ALSA SoC Audio Layer utility functions
+//
+// Copyright 2009 Wolfson Microelectronics PLC.
+//
+// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+//         Liam Girdwood <lrg@slimlogic.co.uk>
 
 #include <linux/platform_device.h>
 #include <linux/export.h>
index d8b6936e544e3c9e42444130f9087dc31be73357..313dab2857ef9152435649aafb5c0ed744e4e545 100644 (file)
@@ -91,7 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
                        SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);
 
                        /* Stop the player */
-                       snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+                       snd_pcm_stop_xrun(player->substream);
                }
 
                ret = IRQ_HANDLED;
@@ -105,7 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
                SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
 
                /* Stop the player */
-               snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stop_xrun(player->substream);
 
                ret = IRQ_HANDLED;
        }
@@ -138,7 +138,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
                dev_err(player->dev, "Underflow recovery failed\n");
 
                /* Stop the player */
-               snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stop_xrun(player->substream);
 
                ret = IRQ_HANDLED;
        }
index ee0055e608529195fda9b76a4226ebf752ead6e3..7b63d35ef428bc6727178ff0d5900ecf7ea8fd4d 100644 (file)
@@ -65,7 +65,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
        if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
                dev_err(reader->dev, "FIFO error detected\n");
 
-               snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stop_xrun(reader->substream);
 
                ret = IRQ_HANDLED;
        }
index 48f9ddd94016d12cc1b86cbcbee93cba8b6fc214..9b2681397dba72edfb283469c1a181961068f85c 100644 (file)
@@ -6,6 +6,7 @@ config SND_SOC_STM32_SAI
        depends on SND_SOC
        select SND_SOC_GENERIC_DMAENGINE_PCM
        select REGMAP_MMIO
+       select SND_PCM_IEC958
        help
          Say Y if you want to enable SAI for STM32
 
index db73fef3e500715d4eae353f3dab31e69c69389a..706ff005234f34f04bb586d076503855e84d8b08 100644 (file)
@@ -149,7 +149,7 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
        unsigned int old_pos = priv->pos;
        unsigned int cur_size = size;
 
-       dev_dbg(rtd->dev, "%s: buff_add :%p, pos = %d, size = %zu\n",
+       dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n",
                __func__, &pcm_buff[priv->pos], priv->pos, size);
 
        if ((priv->pos + size) > buff_size) {
@@ -269,16 +269,10 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm)
 {
        struct snd_pcm_substream *substream;
-       struct snd_soc_pcm_runtime *rtd;
-       struct stm32_adfsdm_priv *priv;
 
        substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-       if (substream) {
-               rtd = substream->private_data;
-               priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-
+       if (substream)
                snd_pcm_lib_preallocate_free_for_all(pcm);
-       }
 }
 
 static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
index cfeb219e1d78b6d351b239c8533d3f838006eb0e..06fba9650ac4fc8e539ef286a963c1b2c07e2569 100644 (file)
@@ -96,7 +96,8 @@
  * @slot_mask: rx or tx active slots mask. set at init or at runtime
  * @data_size: PCM data width. corresponds to PCM substream width.
  * @spdif_frm_cnt: S/PDIF playback frame counter
- * @spdif_status_bits: S/PDIF status bits
+ * @snd_aes_iec958: iec958 data
+ * @ctrl_lock: control lock
  */
 struct stm32_sai_sub_data {
        struct platform_device *pdev;
@@ -125,7 +126,8 @@ struct stm32_sai_sub_data {
        int slot_mask;
        int data_size;
        unsigned int spdif_frm_cnt;
-       unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES];
+       struct snd_aes_iec958 iec958;
+       struct mutex ctrl_lock; /* protect resources accessed by controls */
 };
 
 enum stm32_sai_fifo_th {
@@ -184,10 +186,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = {
-       0, 0, 0, IEC958_AES3_CON_FS_48000,
-};
-
 static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
        .reg_bits = 32,
        .reg_stride = 4,
@@ -210,6 +208,49 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
        .fast_io = true,
 };
 
+static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int snd_pcm_iec958_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *uctl)
+{
+       struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&sai->ctrl_lock);
+       memcpy(uctl->value.iec958.status, sai->iec958.status, 4);
+       mutex_unlock(&sai->ctrl_lock);
+
+       return 0;
+}
+
+static int snd_pcm_iec958_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *uctl)
+{
+       struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&sai->ctrl_lock);
+       memcpy(sai->iec958.status, uctl->value.iec958.status, 4);
+       mutex_unlock(&sai->ctrl_lock);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new iec958_ctls = {
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+       .info = snd_pcm_iec958_info,
+       .get = snd_pcm_iec958_get,
+       .put = snd_pcm_iec958_put,
+};
+
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
        struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
@@ -259,11 +300,8 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
                status = SNDRV_PCM_STATE_XRUN;
        }
 
-       if (status != SNDRV_PCM_STATE_RUNNING) {
-               snd_pcm_stream_lock(sai->substream);
-               snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
-               snd_pcm_stream_unlock(sai->substream);
-       }
+       if (status != SNDRV_PCM_STATE_RUNNING)
+               snd_pcm_stop_xrun(sai->substream);
 
        return IRQ_HANDLED;
 }
@@ -619,6 +657,59 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
        }
 }
 
+static void stm32_sai_init_iec958_status(struct stm32_sai_sub_data *sai)
+{
+       unsigned char *cs = sai->iec958.status;
+
+       cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+       cs[1] = IEC958_AES1_CON_GENERAL;
+       cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
+       cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;
+}
+
+static void stm32_sai_set_iec958_status(struct stm32_sai_sub_data *sai,
+                                       struct snd_pcm_runtime *runtime)
+{
+       if (!runtime)
+               return;
+
+       /* Force the sample rate according to runtime rate */
+       mutex_lock(&sai->ctrl_lock);
+       switch (runtime->rate) {
+       case 22050:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_22050;
+               break;
+       case 44100:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_44100;
+               break;
+       case 88200:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_88200;
+               break;
+       case 176400:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_176400;
+               break;
+       case 24000:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_24000;
+               break;
+       case 48000:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_48000;
+               break;
+       case 96000:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_96000;
+               break;
+       case 192000:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_192000;
+               break;
+       case 32000:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_32000;
+               break;
+       default:
+               sai->iec958.status[3] = IEC958_AES3_CON_FS_NOTID;
+               break;
+       }
+       mutex_unlock(&sai->ctrl_lock);
+}
+
 static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
                                     struct snd_pcm_hw_params *params)
 {
@@ -709,7 +800,11 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
 
        sai->data_size = params_width(params);
 
-       if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+       if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+               /* Rate not already set in runtime structure */
+               substream->runtime->rate = params_rate(params);
+               stm32_sai_set_iec958_status(sai, substream->runtime);
+       } else {
                ret = stm32_sai_set_slots(cpu_dai);
                if (ret < 0)
                        return ret;
@@ -789,6 +884,20 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
        sai->substream = NULL;
 }
 
+static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd,
+                            struct snd_soc_dai *cpu_dai)
+{
+       struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+
+       if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+               dev_dbg(&sai->pdev->dev, "%s: register iec controls", __func__);
+               return snd_ctl_add(rtd->pcm->card,
+                                  snd_ctl_new1(&iec958_ctls, sai));
+       }
+
+       return 0;
+}
+
 static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
@@ -809,6 +918,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
        else
                snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
 
+       /* Next settings are not relevant for spdif mode */
+       if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
+               return 0;
+
        cr1_mask = SAI_XCR1_RX_TX;
        if (STM_SAI_IS_CAPTURE(sai))
                cr1 |= SAI_XCR1_RX_TX;
@@ -820,10 +933,6 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
                                     sai->synco, sai->synci);
        }
 
-       if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
-               memcpy(sai->spdif_status_bits, default_status_bits,
-                      sizeof(default_status_bits));
-
        cr1_mask |= SAI_XCR1_SYNCEN_MASK;
        cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
 
@@ -861,7 +970,7 @@ static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream,
                /* Set channel status bit */
                byte = frm_cnt >> 3;
                mask = 1 << (frm_cnt - (byte << 3));
-               if (sai->spdif_status_bits[byte] & mask)
+               if (sai->iec958.status[byte] & mask)
                        *ptr |= 0x04000000;
                ptr++;
 
@@ -888,6 +997,7 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
 static struct snd_soc_dai_driver stm32_sai_playback_dai[] = {
 {
                .probe = stm32_sai_dai_probe,
+               .pcm_new = stm32_sai_pcm_new,
                .id = 1, /* avoid call to fmt_single_name() */
                .playback = {
                        .channels_min = 1,
@@ -998,6 +1108,7 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
                        dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n");
                        return -EINVAL;
                }
+               stm32_sai_init_iec958_status(sai);
                sai->spdif = true;
                sai->master = true;
        }
@@ -1114,6 +1225,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
        sai->id = (uintptr_t)of_id->data;
 
        sai->pdev = pdev;
+       mutex_init(&sai->ctrl_lock);
        platform_set_drvdata(pdev, sai);
 
        sai->pdata = dev_get_drvdata(pdev->dev.parent);
index affad46bf1887d08b78fb89394168ca36bef2fcc..682ef33afb5f39efb3a5946d3c76166647049c5b 100644 (file)
@@ -377,7 +377,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ret = clk_prepare_enable(ac97->clk_ac97);
        if (ret) {
                dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
-               goto err;
+               goto err_clk_put;
        }
 
        ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
index 5197d6b18cb6758915c23d50b6f8b8dc7a515d07..98d87801d57a76ec10fa01f901a6009a71f0f5e0 100644 (file)
@@ -190,14 +190,14 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Property 'nvidia,i2s-controller' missing or invalid\n");
                ret = -EINVAL;
-               goto err;
+               goto err_put_codec_of_node;
        }
 
        tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node;
 
        ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
        if (ret)
-               goto err;
+               goto err_put_cpu_of_node;
 
        ret = snd_soc_register_card(card);
        if (ret) {
@@ -210,6 +210,13 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
 
 err_fini_utils:
        tegra_asoc_utils_fini(&alc5632->util_data);
+err_put_cpu_of_node:
+       of_node_put(tegra_alc5632_dai.cpu_of_node);
+       tegra_alc5632_dai.cpu_of_node = NULL;
+       tegra_alc5632_dai.platform_of_node = NULL;
+err_put_codec_of_node:
+       of_node_put(tegra_alc5632_dai.codec_of_node);
+       tegra_alc5632_dai.codec_of_node = NULL;
 err:
        return ret;
 }
@@ -223,6 +230,12 @@ static int tegra_alc5632_remove(struct platform_device *pdev)
 
        tegra_asoc_utils_fini(&machine->util_data);
 
+       of_node_put(tegra_alc5632_dai.cpu_of_node);
+       tegra_alc5632_dai.cpu_of_node = NULL;
+       tegra_alc5632_dai.platform_of_node = NULL;
+       of_node_put(tegra_alc5632_dai.codec_of_node);
+       tegra_alc5632_dai.codec_of_node = NULL;
+
        return 0;
 }
 
index 0e4805c7b4cadb20a0017cda4828d80af753a6fc..7081f15302cc6ca3f31d62be5ebb724a91976220 100644 (file)
@@ -264,13 +264,13 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Property 'nvidia,i2s-controller' missing or invalid\n");
                ret = -EINVAL;
-               goto err;
+               goto err_put_codec_of_node;
        }
        tegra_rt5677_dai.platform_of_node = tegra_rt5677_dai.cpu_of_node;
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
-               goto err;
+               goto err_put_cpu_of_node;
 
        ret = snd_soc_register_card(card);
        if (ret) {
@@ -283,6 +283,13 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
 
 err_fini_utils:
        tegra_asoc_utils_fini(&machine->util_data);
+err_put_cpu_of_node:
+       of_node_put(tegra_rt5677_dai.cpu_of_node);
+       tegra_rt5677_dai.cpu_of_node = NULL;
+       tegra_rt5677_dai.platform_of_node = NULL;
+err_put_codec_of_node:
+       of_node_put(tegra_rt5677_dai.codec_of_node);
+       tegra_rt5677_dai.codec_of_node = NULL;
 err:
        return ret;
 }
@@ -296,6 +303,12 @@ static int tegra_rt5677_remove(struct platform_device *pdev)
 
        tegra_asoc_utils_fini(&machine->util_data);
 
+       tegra_rt5677_dai.platform_of_node = NULL;
+       of_node_put(tegra_rt5677_dai.codec_of_node);
+       tegra_rt5677_dai.codec_of_node = NULL;
+       of_node_put(tegra_rt5677_dai.cpu_of_node);
+       tegra_rt5677_dai.cpu_of_node = NULL;
+
        return 0;
 }
 
index 638cb3fc5f7b1dee22367c52ec3c7c0622459111..9bcba06ba52ea36dc06527561aef739641d99fb2 100644 (file)
@@ -264,6 +264,57 @@ void aio_port_reset(struct uniphier_aio_sub *sub)
        }
 }
 
+/**
+ * aio_port_set_ch - set channels of LPCM
+ * @sub: the AIO substream pointer, PCM substream only
+ * @ch : count of channels
+ *
+ * Set suitable slot selecting to input/output port block of AIO.
+ *
+ * This function may return error if non-PCM substream.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+static int aio_port_set_ch(struct uniphier_aio_sub *sub)
+{
+       struct regmap *r = sub->aio->chip->regmap;
+       u32 slotsel_2ch[] = {
+               0, 0, 0, 0, 0,
+       };
+       u32 slotsel_multi[] = {
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
+       };
+       u32 mode, *slotsel;
+       int i;
+
+       switch (params_channels(&sub->params)) {
+       case 8:
+       case 6:
+               mode = OPORTMXTYSLOTCTR_MODE;
+               slotsel = slotsel_multi;
+               break;
+       case 2:
+               mode = 0;
+               slotsel = slotsel_2ch;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
+               regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
+                                  OPORTMXTYSLOTCTR_MODE, mode);
+               regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
+                                  OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
+       }
+
+       return 0;
+}
+
 /**
  * aio_port_set_rate - set sampling rate of LPCM
  * @sub: the AIO substream pointer, PCM substream only
@@ -276,7 +327,7 @@ void aio_port_reset(struct uniphier_aio_sub *sub)
  *
  * Return: Zero if successful, otherwise a negative value on error.
  */
-int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
+static int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
 {
        struct regmap *r = sub->aio->chip->regmap;
        struct device *dev = &sub->aio->chip->pdev->dev;
@@ -395,7 +446,7 @@ int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
  *
  * Return: Zero if successful, otherwise a negative value on error.
  */
-int aio_port_set_fmt(struct uniphier_aio_sub *sub)
+static int aio_port_set_fmt(struct uniphier_aio_sub *sub)
 {
        struct regmap *r = sub->aio->chip->regmap;
        struct device *dev = &sub->aio->chip->pdev->dev;
@@ -460,7 +511,7 @@ int aio_port_set_fmt(struct uniphier_aio_sub *sub)
  *
  * Return: Zero if successful, otherwise a negative value on error.
  */
-int aio_port_set_clk(struct uniphier_aio_sub *sub)
+static int aio_port_set_clk(struct uniphier_aio_sub *sub)
 {
        struct uniphier_aio_chip *chip = sub->aio->chip;
        struct device *dev = &sub->aio->chip->pdev->dev;
@@ -575,6 +626,10 @@ int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
                        rate = params_rate(params);
                }
 
+               ret = aio_port_set_ch(sub);
+               if (ret)
+                       return ret;
+
                ret = aio_port_set_rate(sub, rate);
                if (ret)
                        return ret;
@@ -731,15 +786,28 @@ void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
 int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
 {
        struct regmap *r = sub->aio->chip->regmap;
-       u32 v;
+       u32 memfmt, v;
 
        if (sub->swm->dir == PORT_DIR_OUTPUT) {
-               if (pass_through)
+               if (pass_through) {
                        v = PBOUTMXCTR0_ENDIAN_0123 |
                                PBOUTMXCTR0_MEMFMT_STREAM;
-               else
-                       v = PBOUTMXCTR0_ENDIAN_3210 |
-                               PBOUTMXCTR0_MEMFMT_2CH;
+               } else {
+                       switch (params_channels(&sub->params)) {
+                       case 2:
+                               memfmt = PBOUTMXCTR0_MEMFMT_2CH;
+                               break;
+                       case 6:
+                               memfmt = PBOUTMXCTR0_MEMFMT_6CH;
+                               break;
+                       case 8:
+                               memfmt = PBOUTMXCTR0_MEMFMT_8CH;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
+               }
 
                regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
                regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
index 2d9b7dde2ffa1dbc4750eda9d2dc5557753bfdc4..ee90e6c3937ce31e0dfb025a1c627b695c35a0a3 100644 (file)
@@ -219,15 +219,10 @@ static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
                                unsigned int freq_out)
 {
        struct uniphier_aio *aio = uniphier_priv(dai);
-       struct device *dev = &aio->chip->pdev->dev;
        int ret;
 
        if (!is_valid_pll(aio->chip, pll_id))
                return -EINVAL;
-       if (!aio->chip->plls[pll_id].enable) {
-               dev_err(dev, "PLL(%d) is not implemented\n", pll_id);
-               return -ENOTSUPP;
-       }
 
        ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
        if (ret < 0)
index ab04d3331be94313748938e5c3f87133b1952eae..de962df245baa450872d5ec9cc87f90d88b3f665 100644 (file)
@@ -286,7 +286,7 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
                        .rates       = SNDRV_PCM_RATE_48000,
                        .channels_min = 2,
-                       .channels_max = 2,
+                       .channels_max = 8,
                },
                .ops = &uniphier_aio_i2s_ops,
        },
index 45fdc6ae358af5dfe5d1022d376d160b53b7a15c..734395dbcffbd22348a62c8435ddc01d1a3be563 100644 (file)
 #define OPORTMXTYVOLGAINSTATUS(n, m)     (0x42108 + 0x400 * (n) + 0x20 * (m))
 #define   OPORTMXTYVOLGAINSTATUS_CUR_MASK  GENMASK(15, 0)
 #define OPORTMXTYSLOTCTR(n, m)           (0x42114 + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXTYSLOTCTR_MODE            BIT(15)
 #define   OPORTMXTYSLOTCTR_SLOTSEL_MASK    GENMASK(11, 8)
 #define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT0   (0x8 << 8)
 #define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT1   (0x9 << 8)
index aa89c2f6fa24014569306a3c63228e27d216d859..ca6ccbae0ee8c2f6f89437ed1d9c18c8986c6607 100644 (file)
@@ -141,6 +141,9 @@ enum IEC61937_PC {
 #define AUD_MIN_FRAGMENT_SIZE    (4 * 1024)
 #define AUD_MAX_FRAGMENT_SIZE    (16 * 1024)
 
+/* max 5 slots, 10 channels, 2 channel in 1 slot */
+#define AUD_MAX_SLOTSEL    5
+
 /*
  * This is a selector for virtual register map of AIO.
  *
@@ -322,9 +325,6 @@ int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
 void aio_chip_init(struct uniphier_aio_chip *chip);
 int aio_init(struct uniphier_aio_sub *sub);
 void aio_port_reset(struct uniphier_aio_sub *sub);
-int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate);
-int aio_port_set_fmt(struct uniphier_aio_sub *sub);
-int aio_port_set_clk(struct uniphier_aio_sub *sub);
 int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
                       const struct snd_pcm_hw_params *params);
 void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
index dc955272f58b07350b042852e20209c9fc9fb08a..389272eeba9a6caad7e5d9074dff8c17a725ad82 100644 (file)
@@ -144,8 +144,8 @@ static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
 #define ZX_TDM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
 
 #define ZX_TDM_FMTBIT \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \
-       SNDRV_PCM_FORMAT_A_LAW)
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_MU_LAW | \
+       SNDRV_PCM_FMTBIT_A_LAW)
 
 static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
 {