aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/ak4104.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/ak4118.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/audio-graph-card.txt205
-rw-r--r--Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/cs4270.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/dmic.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-sai.txt8
-rw-r--r--Documentation/devicetree/bindings/sound/omap-mcpdm.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/pcm3060.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6asm.txt27
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt395
-rw-r--r--Documentation/devicetree/bindings/sound/rt5631.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/rt5663.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/simple-amplifier.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt137
-rw-r--r--Documentation/devicetree/bindings/sound/simple-scu-card.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/xlnx,i2s.txt28
-rw-r--r--MAINTAINERS18
-rw-r--r--arch/arm/configs/davinci_all_defconfig5
-rw-r--r--arch/arm/configs/omap1_defconfig2
-rw-r--r--arch/arm/configs/omap2plus_defconfig14
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c4
-rw-r--r--arch/arm/mach-omap1/Makefile2
-rw-r--r--arch/arm/mach-omap2/Makefile2
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c4
-rw-r--r--drivers/leds/trigger/Kconfig7
-rw-r--r--drivers/leds/trigger/Makefile1
-rw-r--r--drivers/leds/trigger/ledtrig-audio.c44
-rw-r--r--drivers/platform/x86/Kconfig21
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/dell-laptop.c27
-rw-r--r--drivers/platform/x86/huawei-wmi.c208
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c67
-rw-r--r--include/dt-bindings/sound/qcom,q6afe.h1
-rw-r--r--include/linux/dell-led.h7
-rw-r--r--include/linux/leds.h20
-rw-r--r--include/linux/platform_data/davinci_asp.h1
-rw-r--r--include/linux/thinkpad_acpi.h16
-rw-r--r--include/sound/compress_driver.h19
-rw-r--r--include/sound/hda_codec.h1
-rw-r--r--include/sound/hda_component.h11
-rw-r--r--include/sound/hdaudio.h14
-rw-r--r--include/sound/simple_card_utils.h6
-rw-r--r--include/sound/soc-acpi-intel-match.h1
-rw-r--r--include/sound/soc-acpi.h15
-rw-r--r--include/sound/soc.h14
-rw-r--r--include/uapi/sound/firewire.h20
-rw-r--r--sound/aoa/fabrics/layout.c6
-rw-r--r--sound/aoa/soundbus/core.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c6
-rw-r--r--sound/aoa/soundbus/sysfs.c34
-rw-r--r--sound/core/compress_offload.c18
-rw-r--r--sound/core/control.c123
-rw-r--r--sound/core/pcm.c2
-rw-r--r--sound/firewire/Kconfig2
-rw-r--r--sound/firewire/amdtp-stream-trace.h4
-rw-r--r--sound/firewire/amdtp-stream.c4
-rw-r--r--sound/firewire/bebob/bebob.c2
-rw-r--r--sound/firewire/fireface/Makefile3
-rw-r--r--sound/firewire/fireface/ff-pcm.c35
-rw-r--r--sound/firewire/fireface/ff-proc.c193
-rw-r--r--sound/firewire/fireface/ff-protocol-ff400.c341
-rw-r--r--sound/firewire/fireface/ff-protocol-ff800.c143
-rw-r--r--sound/firewire/fireface/ff-stream.c126
-rw-r--r--sound/firewire/fireface/ff-transaction.c157
-rw-r--r--sound/firewire/fireface/ff.c25
-rw-r--r--sound/firewire/fireface/ff.h42
-rw-r--r--sound/firewire/oxfw/oxfw.c8
-rw-r--r--sound/firewire/tascam/amdtp-tascam.c51
-rw-r--r--sound/firewire/tascam/tascam-hwdep.c115
-rw-r--r--sound/firewire/tascam/tascam.h9
-rw-r--r--sound/hda/hdac_bus.c7
-rw-r--r--sound/hda/hdac_component.c39
-rw-r--r--sound/hda/hdac_device.c17
-rw-r--r--sound/pci/asihpi/asihpi.c2
-rw-r--r--sound/pci/emu10k1/emufx.c5
-rw-r--r--sound/pci/hda/Kconfig62
-rw-r--r--sound/pci/hda/dell_wmi_helper.c48
-rw-r--r--sound/pci/hda/hda_codec.c16
-rw-r--r--sound/pci/hda/hda_controller.c11
-rw-r--r--sound/pci/hda/hda_controller.h8
-rw-r--r--sound/pci/hda/hda_generic.c31
-rw-r--r--sound/pci/hda/hda_generic.h2
-rw-r--r--sound/pci/hda/hda_intel.c274
-rw-r--r--sound/pci/hda/hda_jack.c56
-rw-r--r--sound/pci/hda/hda_jack.h12
-rw-r--r--sound/pci/hda/hda_tegra.c22
-rw-r--r--sound/pci/hda/patch_ca0132.c207
-rw-r--r--sound/pci/hda/patch_conexant.c1
-rw-r--r--sound/pci/hda/patch_hdmi.c14
-rw-r--r--sound/pci/hda/patch_realtek.c106
-rw-r--r--sound/pci/hda/thinkpad_helper.c43
-rw-r--r--sound/pci/rme9652/hdsp.c10
-rw-r--r--sound/ppc/pmac.c4
-rw-r--r--sound/ppc/tumbler.c4
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/amd/Kconfig6
-rw-r--r--sound/soc/amd/Makefile1
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c2
-rw-r--r--sound/soc/amd/acp-pcm-dma.c22
-rw-r--r--sound/soc/amd/acp.h2
-rw-r--r--sound/soc/amd/raven/Makefile6
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c777
-rw-r--r--sound/soc/amd/raven/acp3x.h58
-rw-r--r--sound/soc/amd/raven/chip_offset_byte.h639
-rw-r--r--sound/soc/amd/raven/pci-acp3x.c156
-rw-r--r--sound/soc/codecs/Kconfig6
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak4104.c22
-rw-r--r--sound/soc/codecs/ak4118.c438
-rw-r--r--sound/soc/codecs/ak4458.c2
-rw-r--r--sound/soc/codecs/ak5558.c19
-rw-r--r--sound/soc/codecs/cs4270.c23
-rw-r--r--sound/soc/codecs/dmic.c40
-rw-r--r--sound/soc/codecs/hdac_hda.c2
-rw-r--r--sound/soc/codecs/hdac_hdmi.c87
-rw-r--r--sound/soc/codecs/max98373.c35
-rw-r--r--sound/soc/codecs/max9867.c505
-rw-r--r--sound/soc/codecs/max9867.h41
-rw-r--r--sound/soc/codecs/nau8540.c2
-rw-r--r--sound/soc/codecs/nau8822.c26
-rw-r--r--sound/soc/codecs/nau8822.h9
-rw-r--r--sound/soc/codecs/nau8825.c4
-rw-r--r--sound/soc/codecs/pcm3060.c28
-rw-r--r--sound/soc/codecs/pcm3060.h3
-rw-r--r--sound/soc/codecs/pcm3168a.c40
-rw-r--r--sound/soc/codecs/pcm512x.c121
-rw-r--r--sound/soc/codecs/pcm512x.h2
-rw-r--r--sound/soc/codecs/rt5660.c1
-rw-r--r--sound/soc/codecs/rt5663.c75
-rw-r--r--sound/soc/codecs/simple-amplifier.c4
-rw-r--r--sound/soc/codecs/tas6424.c2
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c2
-rw-r--r--sound/soc/codecs/tlv320aic3x.c10
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/wm8998.c2
-rw-r--r--sound/soc/codecs/wm9705.c10
-rw-r--r--sound/soc/codecs/wm9712.c10
-rw-r--r--sound/soc/codecs/wm9713.c10
-rw-r--r--sound/soc/codecs/wm_adsp.c14
-rw-r--r--sound/soc/davinci/Kconfig106
-rw-r--r--sound/soc/davinci/Makefile16
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c6
-rw-r--r--sound/soc/fsl/fsl_ssi_dbg.c14
-rw-r--r--sound/soc/generic/Kconfig4
-rw-r--r--sound/soc/generic/audio-graph-card.c465
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c262
-rw-r--r--sound/soc/generic/simple-card-utils.c45
-rw-r--r--sound/soc/generic/simple-card.c402
-rw-r--r--sound/soc/generic/simple-scu-card.c264
-rw-r--r--sound/soc/intel/Kconfig79
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_loader.c8
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c4
-rw-r--r--sound/soc/intel/boards/Kconfig26
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c33
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c6
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c14
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c6
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c2
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c14
-rw-r--r--sound/soc/intel/boards/kbl_rt5660.c543
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c14
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c10
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c22
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c14
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c14
-rw-r--r--sound/soc/intel/common/Makefile2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-bxt-match.c36
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c32
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-kbl-match.c10
-rw-r--r--sound/soc/intel/skylake/skl-messages.c8
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c3
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c50
-rw-r--r--sound/soc/intel/skylake/skl.c202
-rw-r--r--sound/soc/intel/skylake/skl.h3
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c2
-rw-r--r--sound/soc/meson/Kconfig9
-rw-r--r--sound/soc/meson/Makefile2
-rw-r--r--sound/soc/meson/axg-fifo.h3
-rw-r--r--sound/soc/meson/axg-spdifin.c521
-rw-r--r--sound/soc/meson/axg-toddr.c15
-rw-r--r--sound/soc/omap/Kconfig129
-rw-r--r--sound/soc/omap/Makefile32
-rw-r--r--sound/soc/omap/am3517evm.c141
-rw-r--r--sound/soc/omap/mcbsp.c1104
-rw-r--r--sound/soc/pxa/Kconfig26
-rw-r--r--sound/soc/pxa/Makefile1
-rw-r--r--sound/soc/pxa/raumfeld.c318
-rw-r--r--sound/soc/qcom/Kconfig2
-rw-r--r--sound/soc/qcom/lpass-platform.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c30
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c4
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c372
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c5
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c9
-rw-r--r--sound/soc/qcom/sdm845.c186
-rw-r--r--sound/soc/sh/rcar/adg.c38
-rw-r--r--sound/soc/sh/rcar/cmd.c11
-rw-r--r--sound/soc/sh/rcar/core.c256
-rw-r--r--sound/soc/sh/rcar/ctu.c138
-rw-r--r--sound/soc/sh/rcar/dma.c84
-rw-r--r--sound/soc/sh/rcar/dvc.c21
-rw-r--r--sound/soc/sh/rcar/gen.c49
-rw-r--r--sound/soc/sh/rcar/mix.c3
-rw-r--r--sound/soc/sh/rcar/rsnd.h382
-rw-r--r--sound/soc/sh/rcar/src.c67
-rw-r--r--sound/soc/sh/rcar/ssi.c269
-rw-r--r--sound/soc/sh/rcar/ssiu.c300
-rw-r--r--sound/soc/soc-core.c13
-rw-r--r--sound/soc/stm/stm32_sai.c8
-rw-r--r--sound/soc/stm/stm32_sai_sub.c3
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c2
-rw-r--r--sound/soc/ti/Kconfig209
-rw-r--r--sound/soc/ti/Makefile44
-rw-r--r--sound/soc/ti/ams-delta.c (renamed from sound/soc/omap/ams-delta.c)0
-rw-r--r--sound/soc/ti/davinci-evm.c (renamed from sound/soc/davinci/davinci-evm.c)4
-rw-r--r--sound/soc/ti/davinci-i2s.c (renamed from sound/soc/davinci/davinci-i2s.c)0
-rw-r--r--sound/soc/ti/davinci-i2s.h (renamed from sound/soc/davinci/davinci-i2s.h)0
-rw-r--r--sound/soc/ti/davinci-mcasp.c (renamed from sound/soc/davinci/davinci-mcasp.c)123
-rw-r--r--sound/soc/ti/davinci-mcasp.h (renamed from sound/soc/davinci/davinci-mcasp.h)30
-rw-r--r--sound/soc/ti/davinci-vcif.c (renamed from sound/soc/davinci/davinci-vcif.c)0
-rw-r--r--sound/soc/ti/edma-pcm.c (renamed from sound/soc/davinci/edma-pcm.c)0
-rw-r--r--sound/soc/ti/edma-pcm.h (renamed from sound/soc/davinci/edma-pcm.h)4
-rw-r--r--sound/soc/ti/n810.c (renamed from sound/soc/omap/n810.c)0
-rw-r--r--sound/soc/ti/omap-abe-twl6040.c (renamed from sound/soc/omap/omap-abe-twl6040.c)0
-rw-r--r--sound/soc/ti/omap-dmic.c (renamed from sound/soc/omap/omap-dmic.c)0
-rw-r--r--sound/soc/ti/omap-dmic.h (renamed from sound/soc/omap/omap-dmic.h)0
-rw-r--r--sound/soc/ti/omap-hdmi.c (renamed from sound/soc/omap/omap-hdmi-audio.c)0
-rw-r--r--sound/soc/ti/omap-mcbsp-priv.h (renamed from sound/soc/omap/mcbsp.h)126
-rw-r--r--sound/soc/ti/omap-mcbsp-st.c516
-rw-r--r--sound/soc/ti/omap-mcbsp.c (renamed from sound/soc/omap/omap-mcbsp.c)857
-rw-r--r--sound/soc/ti/omap-mcbsp.h (renamed from sound/soc/omap/omap-mcbsp.h)8
-rw-r--r--sound/soc/ti/omap-mcpdm.c (renamed from sound/soc/omap/omap-mcpdm.c)0
-rw-r--r--sound/soc/ti/omap-mcpdm.h (renamed from sound/soc/omap/omap-mcpdm.h)0
-rw-r--r--sound/soc/ti/omap-twl4030.c (renamed from sound/soc/omap/omap-twl4030.c)0
-rw-r--r--sound/soc/ti/omap3pandora.c (renamed from sound/soc/omap/omap3pandora.c)0
-rw-r--r--sound/soc/ti/osk5912.c (renamed from sound/soc/omap/osk5912.c)0
-rw-r--r--sound/soc/ti/rx51.c (renamed from sound/soc/omap/rx51.c)0
-rw-r--r--sound/soc/ti/sdma-pcm.c (renamed from sound/soc/omap/sdma-pcm.c)0
-rw-r--r--sound/soc/ti/sdma-pcm.h (renamed from sound/soc/omap/sdma-pcm.h)4
-rw-r--r--sound/soc/xilinx/Kconfig8
-rw-r--r--sound/soc/xilinx/Makefile2
-rw-r--r--sound/soc/xilinx/xlnx_i2s.c185
-rw-r--r--sound/synth/emux/emux_hwdep.c7
-rw-r--r--sound/usb/quirks.c129
254 files changed, 11685 insertions, 5080 deletions
diff --git a/Documentation/devicetree/bindings/sound/ak4104.txt b/Documentation/devicetree/bindings/sound/ak4104.txt
index deca5e18f304..ae5f7f057dc3 100644
--- a/Documentation/devicetree/bindings/sound/ak4104.txt
+++ b/Documentation/devicetree/bindings/sound/ak4104.txt
@@ -12,8 +12,8 @@ Required properties:
Optional properties:
- - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
- deasserted before communication to the device starts.
+ - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+ deasserted before communication to the device starts.
Example:
diff --git a/Documentation/devicetree/bindings/sound/ak4118.txt b/Documentation/devicetree/bindings/sound/ak4118.txt
new file mode 100644
index 000000000000..6e11a2f7404c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ak4118.txt
@@ -0,0 +1,22 @@
+AK4118 S/PDIF transceiver
+
+This device supports I2C mode.
+
+Required properties:
+
+- compatible : "asahi-kasei,ak4118"
+- reg : The I2C address of the device for I2C
+- reset-gpios: A GPIO specifier for the reset pin
+- irq-gpios: A GPIO specifier for the IRQ pin
+
+Example:
+
+&i2c {
+ ak4118: ak4118@13 {
+ #sound-dai-cells = <0>;
+ compatible = "asahi-kasei,ak4118";
+ reg = <0x13>;
+ reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>
+ irq-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt
new file mode 100644
index 000000000000..2e6cb7d9b202
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt
@@ -0,0 +1,22 @@
+* Amlogic Audio SPDIF Input
+
+Required properties:
+- compatible: 'amlogic,axg-spdifin'
+- interrupts: interrupt specifier for the spdif input.
+- clocks: list of clock phandle, one for each entry clock-names.
+- clock-names: should contain the following:
+ * "pclk" : peripheral clock.
+ * "refclk" : spdif input reference clock
+- #sound-dai-cells: must be 0.
+
+Example on the A113 SoC:
+
+spdifin: audio-controller@400 {
+ compatible = "amlogic,axg-spdifin";
+ reg = <0x0 0x400 0x0 0x30>;
+ #sound-dai-cells = <0>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
+ <&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
+ clock-names = "pclk", "refclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-card.txt
index 7e63e53a901c..269682619a70 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph-card.txt
+++ b/Documentation/devicetree/bindings/sound/audio-graph-card.txt
@@ -32,7 +32,9 @@ Required properties:
Optional properties:
- pa-gpios: GPIO used to control external amplifier.
+-----------------------
Example: Single DAI case
+-----------------------
sound_card {
compatible = "audio-graph-card";
@@ -61,7 +63,9 @@ Example: Single DAI case
};
};
+-----------------------
Example: Multi DAI case
+-----------------------
sound-card {
compatible = "audio-graph-card";
@@ -130,3 +134,204 @@ Example: Multi DAI case
};
};
+
+-----------------------
+Example: Sampling Rate Conversion
+-----------------------
+
+ sound_card {
+ compatible = "audio-graph-card";
+
+ label = "sound-card";
+ prefix = "codec";
+ routing = "codec Playback", "DAI0 Playback",
+ "DAI0 Capture", "codec Capture";
+ convert-rate = <48000>;
+
+ dais = <&cpu_port>;
+ };
+
+ audio-codec {
+ ...
+ port {
+ codec_endpoint: endpoint {
+ remote-endpoint = <&cpu_endpoint>;
+ };
+ };
+ };
+
+ dai-controller {
+ ...
+ cpu_port: port {
+ cpu_endpoint: endpoint {
+ remote-endpoint = <&codec_endpoint>;
+
+ dai-format = "left_j";
+ ...
+ };
+ };
+ };
+
+-----------------------
+Example: 2 CPU 1 Codec (Mixing)
+-----------------------
+
+ sound_card {
+ compatible = "audio-graph-card";
+
+ label = "sound-card";
+ routing = "codec Playback", "DAI0 Playback",
+ "codec Playback", "DAI1 Playback",
+ "DAI0 Capture", "codec Capture";
+
+ dais = <&cpu_port>;
+ };
+
+ audio-codec {
+ ...
+
+ audio-graph-card,prefix = "codec";
+ audio-graph-card,convert-rate = <48000>;
+ port {
+ reg = <0>;
+ codec_endpoint0: endpoint@0 {
+ remote-endpoint = <&cpu_endpoint0>;
+ };
+ codec_endpoint1: endpoint@1 {
+ remote-endpoint = <&cpu_endpoint1>;
+ };
+ };
+ };
+
+ dai-controller {
+ ...
+ cpu_port: port {
+ cpu_endpoint0: endpoint@0 {
+ remote-endpoint = <&codec_endpoint0>;
+
+ dai-format = "left_j";
+ ...
+ };
+ cpu_endpoint1: endpoint@1 {
+ remote-endpoint = <&codec_endpoint1>;
+
+ dai-format = "left_j";
+ ...
+ };
+ };
+ };
+
+-----------------------
+Example: Multi DAI with DPCM
+-----------------------
+
+ CPU0 ------ ak4613
+ CPU1 ------ HDMI
+ CPU2 ------ PCM3168A-p /* DPCM 1ch/2ch */
+ CPU3 --/ /* DPCM 3ch/4ch */
+ CPU4 --/ /* DPCM 5ch/6ch */
+ CPU5 --/ /* DPCM 7ch/8ch */
+ CPU6 ------ PCM3168A-c
+
+ sound_card: sound {
+ compatible = "audio-graph-card";
+
+ label = "sound-card";
+
+ routing = "pcm3168a Playback", "DAI2 Playback",
+ "pcm3168a Playback", "DAI3 Playback",
+ "pcm3168a Playback", "DAI4 Playback",
+ "pcm3168a Playback", "DAI5 Playback";
+
+ dais = <&snd_port0 /* ak4613 */
+ &snd_port1 /* HDMI0 */
+ &snd_port2 /* pcm3168a playback */
+ &snd_port3 /* pcm3168a capture */
+ >;
+ };
+
+ ak4613: codec@10 {
+ ...
+ port {
+ ak4613_endpoint: endpoint {
+ remote-endpoint = <&rsnd_endpoint0>;
+ };
+ };
+ };
+
+ pcm3168a: audio-codec@44 {
+ ...
+ audio-graph-card,prefix = "pcm3168a";
+ audio-graph-card,convert-channels = <8>; /* TDM Split */
+ ports {
+ port@0 {
+ reg = <0>;
+ pcm3168a_endpoint_p1: endpoint@1 {
+ remote-endpoint = <&rsnd_endpoint2>;
+ ...
+ };
+ pcm3168a_endpoint_p2: endpoint@2 {
+ remote-endpoint = <&rsnd_endpoint3>;
+ ...
+ };
+ pcm3168a_endpoint_p3: endpoint@3 {
+ remote-endpoint = <&rsnd_endpoint4>;
+ ...
+ };
+ pcm3168a_endpoint_p4: endpoint@4 {
+ remote-endpoint = <&rsnd_endpoint5>;
+ ...
+ };
+ };
+ port@1 {
+ reg = <1>;
+ pcm3168a_endpoint_c: endpoint {
+ remote-endpoint = <&rsnd_endpoint6>;
+ ...
+ };
+ };
+ };
+ };
+
+ &sound {
+ ports {
+ snd_port0: port@0 {
+ rsnd_endpoint0: endpoint {
+ remote-endpoint = <&ak4613_endpoint>;
+ ...
+ };
+ };
+ snd_port1: port@1 {
+ rsnd_endpoint1: endpoint {
+ remote-endpoint = <&dw_hdmi0_snd_in>;
+ ...
+ };
+ };
+ snd_port2: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rsnd_endpoint2: endpoint@2 {
+ remote-endpoint = <&pcm3168a_endpoint_p1>;
+ ...
+ };
+ rsnd_endpoint3: endpoint@3 {
+ remote-endpoint = <&pcm3168a_endpoint_p2>;
+ ...
+ };
+ rsnd_endpoint4: endpoint@4 {
+ remote-endpoint = <&pcm3168a_endpoint_p3>;
+ ...
+ };
+ rsnd_endpoint5: endpoint@5 {
+ remote-endpoint = <&pcm3168a_endpoint_p4>;
+ ...
+ };
+ };
+ snd_port3: port@6 {
+ rsnd_endpoint6: endpoint {
+ remote-endpoint = <&pcm3168a_endpoint_c>;
+ ...
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
index 441dd6f29df1..62d42768a00b 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
+++ b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
@@ -77,11 +77,9 @@ Example 2. 2 CPU 1 Codec (Mixing)
compatible = "audio-graph-scu-card";
label = "sound-card";
- prefix = "codec";
routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback",
"DAI0 Capture", "codec Capture";
- convert-rate = <48000>;
dais = <&cpu_port0
&cpu_port1>;
@@ -90,6 +88,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
audio-codec {
...
+ audio-graph-card,prefix = "codec";
+ audio-graph-card,convert-rate = <48000>;
port {
codec_endpoint0: endpoint {
remote-endpoint = <&cpu_endpoint0>;
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt
index 6b222f9b8ef5..c33770ec4c3c 100644
--- a/Documentation/devicetree/bindings/sound/cs4270.txt
+++ b/Documentation/devicetree/bindings/sound/cs4270.txt
@@ -10,8 +10,8 @@ Required properties:
Optional properties:
- - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
- deasserted before communication to the codec starts.
+ - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+ deasserted before communication to the codec starts.
Example:
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
index 46bc9829c71a..b279b6072bd5 100644
--- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
@@ -30,6 +30,11 @@ Optional properties:
- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
- tx-num-evt : FIFO levels.
- rx-num-evt : FIFO levels.
+- dismod : Specify the drive on TX pin during inactive slots
+ 0 : 3-state
+ 2 : logic low
+ 3 : logic high
+ Defaults to 'logic low' when the property is not present
- sram-size-playback : size of sram to be allocated during playback
- sram-size-capture : size of sram to be allocated during capture
- interrupts : Interrupt numbers for McASP
diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt
index e957b4136716..32e871037269 100644
--- a/Documentation/devicetree/bindings/sound/dmic.txt
+++ b/Documentation/devicetree/bindings/sound/dmic.txt
@@ -9,6 +9,7 @@ Optional properties:
- dmicen-gpios: GPIO specifier for dmic to control start and stop
- num-channels: Number of microphones on this DAI
- wakeup-delay-ms: Delay (in ms) after enabling the DMIC
+ - modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
Example node:
@@ -17,4 +18,5 @@ Example node:
dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
num-channels = <1>;
wakeup-delay-ms <50>;
+ modeswitch-delay-ms <35>;
};
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt
index dd9e59738e08..2e726b983845 100644
--- a/Documentation/devicetree/bindings/sound/fsl-sai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt
@@ -35,13 +35,13 @@ Required properties:
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
that SAI will work in the synchronous mode (sync Tx
- with Rx) which means both the transimitter and the
+ with Rx) which means both the transmitter and the
receiver will send and receive data by following
receiver's bit clocks and frame sync clocks.
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
that SAI will work in the asynchronous mode, which
- means both transimitter and receiver will send and
+ means both transmitter and receiver will send and
receive data by following their own bit clocks and
frame sync clocks separately.
@@ -58,8 +58,8 @@ Optional properties (for mx6ul):
Note:
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
default synchronous mode (sync Rx with Tx) will be used, which means both
- transimitter and receiver will send and receive data by following clocks
- of transimitter.
+ transmitter and receiver will send and receive data by following clocks
+ of transmitter.
- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
Example:
diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
index 5f4e68ca228c..ff98a0cb5b3f 100644
--- a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
+++ b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
@@ -7,6 +7,8 @@ Required properties:
<L3 interconnect address, size>;
- interrupts: Interrupt number for McPDM
- ti,hwmods: Name of the hwmod associated to the McPDM
+- clocks: phandle for the pdmclk provider, likely <&twl6040>
+- clock-names: Must be "pdmclk"
Example:
@@ -18,3 +20,11 @@ mcpdm: mcpdm@40132000 {
interrupt-parent = <&gic>;
ti,hwmods = "mcpdm";
};
+
+In board DTS file the pdmclk needs to be added:
+
+&mcpdm {
+ clocks = <&twl6040>;
+ clock-names = "pdmclk";
+ status = "okay";
+};
diff --git a/Documentation/devicetree/bindings/sound/pcm3060.txt b/Documentation/devicetree/bindings/sound/pcm3060.txt
index 90fcb8523099..97de66932d44 100644
--- a/Documentation/devicetree/bindings/sound/pcm3060.txt
+++ b/Documentation/devicetree/bindings/sound/pcm3060.txt
@@ -9,9 +9,15 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
+Optional properties:
+
+- ti,out-single-ended: "true" if output is single-ended;
+ "false" or not specified if output is differential.
+
Examples:
pcm3060: pcm3060@46 {
compatible = "ti,pcm3060";
reg = <0x46>;
+ ti,out-single-ended = "true";
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt
index f9c7bd8c1bc0..9f5378c51686 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt
@@ -27,6 +27,28 @@ used by the apr service device.
Value type: <u32>
Definition: Must be 1
+== ASM DAI is subnode of "dais" and represent a dai, it includes board specific
+configuration of each dai. Must contain the following properties.
+
+- reg
+ Usage: required
+ Value type: <u32>
+ Definition: Must be dai id
+
+- direction:
+ Usage: Required for Compress offload dais
+ Value type: <u32>
+ Definition: Specifies the direction of the dai stream
+ 0 for both tx and rx
+ 1 for only tx (Capture/Encode)
+ 2 for only rx (Playback/Decode)
+
+- is-compress-dai:
+ Usage: Required for Compress offload dais
+ Value type: <boolean>
+ Definition: present for Compress offload dais
+
+
= EXAMPLE
q6asm@7 {
@@ -35,5 +57,10 @@ q6asm@7 {
q6asmdai: dais {
compatible = "qcom,q6asm-dais";
#sound-dai-cells = <1>;
+ mm@0 {
+ reg = <0>;
+ direction = <2>;
+ is-compress-dai;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index d92b705e7917..648d43e1b1e9 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -39,15 +39,7 @@ This is example of
Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
- &rcar_sound {
- ...
- rcar_sound,dai {
- dai0 {
- playback = <&ssi0 &src2 &dvc0>;
- capture = <&ssi1 &src3 &dvc1>;
- };
- };
- };
+see "Example: simple sound card"
You can use below.
${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
@@ -83,29 +75,8 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
** Asynchronous mode
------------------
-You need to use "simple-scu-audio-card" sound card for it.
-example)
-
- sound {
- compatible = "simple-scu-audio-card";
- ...
- /*
- * SRC Asynchronous mode setting
- * Playback:
- * All input data will be converted to 48kHz
- * Capture:
- * Inputed 48kHz data will be converted to
- * system specified Hz
- */
- simple-audio-card,convert-rate = <48000>;
- ...
- simple-audio-card,cpu {
- sound-dai = <&rcar_sound>;
- };
- simple-audio-card,codec {
- ...
- };
- };
+You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
+see "Example: simple sound card for Asynchronous mode"
------------------
** Synchronous mode
@@ -141,26 +112,8 @@ For more detail information, see below
${LINUX}/sound/soc/sh/rcar/ctu.c
- comment of header
-You need to use "simple-scu-audio-card" sound card for it.
-example)
-
- sound {
- compatible = "simple-scu-audio-card";
- ...
- /*
- * CTU setting
- * All input data will be converted to 2ch
- * as output data
- */
- simple-audio-card,convert-channels = <2>;
- ...
- simple-audio-card,cpu {
- sound-dai = <&rcar_sound>;
- };
- simple-audio-card,codec {
- ...
- };
- };
+You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
+see "Example: simple sound card for channel convert"
Ex) Exchange output channel
Input -> Output
@@ -190,42 +143,13 @@ and these sounds will be merged by MIX.
aplay -D plughw:0,0 xxxx.wav &
aplay -D plughw:0,1 yyyy.wav
-You need to use "simple-scu-audio-card" sound card for it.
+You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
Ex)
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
[MEM] -> [SRC2] -> [CTU03] -+
- sound {
- #address-cells = <1>;
- #size-cells = <0>;
-
- compatible = "simple-scu-audio-card";
- ...
- simple-audio-card,cpu@0 {
- reg = <0>;
- sound-dai = <&rcar_sound 0>;
- };
- simple-audio-card,cpu@1 {
- reg = <1>;
- sound-dai = <&rcar_sound 1>;
- };
- simple-audio-card,codec {
- ...
- };
- };
-
- &rcar_sound {
- ...
- rcar_sound,dai {
- dai0 {
- playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
- };
- dai1 {
- playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
- };
- };
- };
+see "Example: simple sound card for MIXer"
=============================================
* DVC (Digital Volume and Mute Function)
@@ -257,15 +181,31 @@ Volume Ramp
* SSIU (Serial Sound Interface Unit)
=============================================
-There is no DT settings for SSIU, because SSIU will be automatically
-selected via SSI.
SSIU can avoid some under/over run error, because it has some buffer.
But you can't use it if SSI was PIO mode.
-In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
+In DMA mode, you can select not to use SSIU by using "no-busif" via SSI.
- &ssi0 {
- no-busif;
- };
+SSIU handles BUSIF which will be used for TDM Split mode.
+This driver is assuming that audio-graph card will be used.
+
+TDM Split mode merges 4 sounds. You can see 4 sound interface on system,
+and these sounds will be merged SSIU/SSI.
+
+ aplay -D plughw:0,0 xxxx.wav &
+ aplay -D plughw:0,1 xxxx.wav &
+ aplay -D plughw:0,2 xxxx.wav &
+ aplay -D plughw:0,3 xxxx.wav
+
+ 2ch 8ch
+ [MEM] -> [SSIU 30] -+-> [SSIU 3] --> [Codec]
+ 2ch |
+ [MEM] -> [SSIU 31] -+
+ 2ch |
+ [MEM] -> [SSIU 32] -+
+ 2ch |
+ [MEM] -> [SSIU 33] -+
+
+see "Example: simple sound card for TDM Split"
=============================================
* SSI (Serial Sound Interface)
@@ -304,14 +244,7 @@ This is example if SSI1 want to share WS pin with SSI0
You can use Multi-SSI.
This is example of SSI0/SSI1/SSI2 (= for 6ch)
- &rcar_sound {
- ...
- rcar_sound,dai {
- dai0 {
- playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
- };
- };
- };
+see "Example: simple sound card for Multi channel"
** TDM-SSI
@@ -319,19 +252,7 @@ You can use TDM with SSI.
This is example of TDM 6ch.
Driver can automatically switches TDM <-> stereo mode in this case.
- rsnd_tdm: sound {
- compatible = "simple-audio-card";
- ...
- simple-audio-card,cpu {
- /* system can use TDM 6ch */
- dai-tdm-slot-num = <6>;
- sound-dai = <&rcar_sound>;
- };
- simple-audio-card,codec {
- ...
- };
- };
-
+see "Example: simple sound card for TDM"
=============================================
Required properties:
@@ -346,6 +267,7 @@ Required properties:
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
+ - "renesas,rcar_sound-r8a774c0" (RZ/G2E)
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
- "renesas,rcar_sound-r8a7779" (R-Car H1)
- "renesas,rcar_sound-r8a7790" (R-Car H2)
@@ -356,6 +278,7 @@ Required properties:
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
- "renesas,rcar_sound-r8a77990" (R-Car E3)
+ - "renesas,rcar_sound-r8a77995" (R-Car D3)
- reg : Should contain the register physical address.
required register is
SRU/ADG/SSI if generation1
@@ -363,6 +286,9 @@ Required properties:
- rcar_sound,ssi : Should contain SSI feature.
The number of SSI subnode should be same as HW.
see below for detail.
+- rcar_sound,ssiu : Should contain SSIU feature.
+ The number of SSIU subnode should be same as HW.
+ see below for detail.
- rcar_sound,src : Should contain SRC feature.
The number of SRC subnode should be same as HW.
see below for detail.
@@ -402,8 +328,13 @@ SSI subnode properties:
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
- dma : Should contain Audio DMAC entry
- dma-names : SSI case "rx" (=playback), "tx" (=capture)
+ Deprecated: see SSIU subnode properties
SSIU case "rxu" (=playback), "txu" (=capture)
+SSIU subnode properties:
+- dma : Should contain Audio DMAC entry
+- dma-names : "rx" (=playback), "tx" (=capture)
+
SRC subnode properties:
- dma : Should contain Audio DMAC entry
- dma-names : "rx" (=playback), "tx" (=capture)
@@ -532,56 +463,55 @@ rcar_sound: sound@ec500000 {
};
};
+ rcar_sound,ssiu {
+ ssiu00: ssiu-0 {
+ dmas = <&audma0 0x15>, <&audma1 0x16>;
+ dma-names = "rx", "tx";
+ };
+ ssiu01: ssiu-1 {
+ dmas = <&audma0 0x35>, <&audma1 0x36>;
+ dma-names = "rx", "tx";
+ };
+
+ ...
+
+ ssiu95: ssiu-49 {
+ dmas = <&audma0 0xA5>, <&audma1 0xA6>;
+ dma-names = "rx", "tx";
+ };
+ ssiu96: ssiu-50 {
+ dmas = <&audma0 0xA7>, <&audma1 0xA8>;
+ dma-names = "rx", "tx";
+ };
+ ssiu97: ssiu-51 {
+ dmas = <&audma0 0xA9>, <&audma1 0xAA>;
+ dma-names = "rx", "tx";
+ };
+ };
+
rcar_sound,ssi {
ssi0: ssi-0 {
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
- dma-names = "rx", "tx", "rxu", "txu";
+ dmas = <&audma0 0x01>, <&audma1 0x02>;
+ dma-names = "rx", "tx";
};
ssi1: ssi-1 {
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
- dma-names = "rx", "tx", "rxu", "txu";
- };
- ssi2: ssi-2 {
- interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
- dma-names = "rx", "tx", "rxu", "txu";
- };
- ssi3: ssi-3 {
- interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
- dma-names = "rx", "tx", "rxu", "txu";
- };
- ssi4: ssi-4 {
- interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
- dma-names = "rx", "tx", "rxu", "txu";
- };
- ssi5: ssi-5 {
- interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
- dma-names = "rx", "tx", "rxu", "txu";
- };
- ssi6: ssi-6 {
- interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
- dma-names = "rx", "tx", "rxu", "txu";
- };
- ssi7: ssi-7 {
- interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
- dma-names = "rx", "tx", "rxu", "txu";
+ dmas = <&audma0 0x03>, <&audma1 0x04>;
+ dma-names = "rx", "tx";
};
+
+ ...
+
ssi8: ssi-8 {
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
- dma-names = "rx", "tx", "rxu", "txu";
+ dmas = <&audma0 0x11>, <&audma1 0x12>;
+ dma-names = "rx", "tx";
};
ssi9: ssi-9 {
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
- dma-names = "rx", "tx", "rxu", "txu";
+ dmas = <&audma0 0x13>, <&audma1 0x14>;
+ dma-names = "rx", "tx";
};
};
@@ -647,25 +577,174 @@ Example: simple sound card
};
=============================================
+Example: simple sound card for Asynchronous mode
+=============================================
+
+sound {
+ compatible = "simple-scu-audio-card";
+ ...
+ /*
+ * SRC Asynchronous mode setting
+ * Playback:
+ * All input data will be converted to 48kHz
+ * Capture:
+ * Inputed 48kHz data will be converted to
+ * system specified Hz
+ */
+ simple-audio-card,convert-rate = <48000>;
+ ...
+ simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+ simple-audio-card,codec {
+ ...
+ };
+};
+
+=============================================
+Example: simple sound card for channel convert
+=============================================
+
+sound {
+ compatible = "simple-scu-audio-card";
+ ...
+ /*
+ * CTU setting
+ * All input data will be converted to 2ch
+ * as output data
+ */
+ simple-audio-card,convert-channels = <2>;
+ ...
+ simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+ simple-audio-card,codec {
+ ...
+ };
+};
+
+=============================================
+Example: simple sound card for MIXer
+=============================================
+
+sound {
+ compatible = "simple-scu-audio-card";
+ ...
+ simple-audio-card,cpu@0 {
+ sound-dai = <&rcar_sound 0>;
+ };
+ simple-audio-card,cpu@1 {
+ sound-dai = <&rcar_sound 1>;
+ };
+ simple-audio-card,codec {
+ ...
+ };
+};
+
+&rcar_sound {
+ ...
+ rcar_sound,dai {
+ dai0 {
+ playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
+ };
+ dai1 {
+ playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
+ };
+ };
+};
+
+=============================================
Example: simple sound card for TDM
=============================================
- rsnd_tdm: sound {
- compatible = "simple-audio-card";
+rsnd_tdm: sound {
+ compatible = "simple-audio-card";
- simple-audio-card,format = "left_j";
- simple-audio-card,bitclock-master = <&sndcodec>;
- simple-audio-card,frame-master = <&sndcodec>;
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcodec>;
+ simple-audio-card,frame-master = <&sndcodec>;
- sndcpu: simple-audio-card,cpu {
- sound-dai = <&rcar_sound>;
- dai-tdm-slot-num = <6>;
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ dai-tdm-slot-num = <6>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&xxx>;
+ };
+};
+
+=============================================
+Example: simple sound card for TDM Split
+=============================================
+
+sound_card: sound {
+ compatible = "audio-graph-scu-card";
+ prefix = "xxxx";
+ routing = "xxxx Playback", "DAI0 Playback",
+ "xxxx Playback", "DAI1 Playback",
+ "xxxx Playback", "DAI2 Playback",
+ "xxxx Playback", "DAI3 Playback";
+ convert-channels = <8>; /* TDM Split */
+
+ dais = <&rsnd_port0 /* playback ch1/ch2 */
+ &rsnd_port1 /* playback ch3/ch4 */
+ &rsnd_port2 /* playback ch5/ch6 */
+ &rsnd_port3 /* playback ch7/ch8 */
+ >;
+};
+
+audio-codec {
+ ...
+ port {
+ codec_0: endpoint@1 {
+ remote-endpoint = <&rsnd_ep0>;
+ };
+ codec_1: endpoint@2 {
+ remote-endpoint = <&rsnd_ep1>;
+ };
+ codec_2: endpoint@3 {
+ remote-endpoint = <&rsnd_ep2>;
+ };
+ codec_3: endpoint@4 {
+ remote-endpoint = <&rsnd_ep3>;
};
+ };
+};
- sndcodec: simple-audio-card,codec {
- sound-dai = <&xxx>;
+&rcar_sound {
+ ...
+ ports {
+ rsnd_port0: port@0 {
+ rsnd_ep0: endpoint {
+ remote-endpoint = <&codec_0>;
+ ...
+ playback = <&ssiu30 &ssi3>;
+ };
+ };
+ rsnd_port1: port@1 {
+ rsnd_ep1: endpoint {
+ remote-endpoint = <&codec_1>;
+ ...
+ playback = <&ssiu31 &ssi3>;
+ };
+ };
+ rsnd_port2: port@2 {
+ rsnd_ep2: endpoint {
+ remote-endpoint = <&codec_2>;
+ ...
+ playback = <&ssiu32 &ssi3>;
+ };
+ };
+ rsnd_port3: port@3 {
+ rsnd_ep3: endpoint {
+ remote-endpoint = <&codec_3>;
+ ...
+ playback = <&ssiu33 &ssi3>;
+ };
};
};
+};
=============================================
Example: simple sound card for Multi channel
diff --git a/Documentation/devicetree/bindings/sound/rt5631.txt b/Documentation/devicetree/bindings/sound/rt5631.txt
index 92b986ca337b..56bc85232c49 100644
--- a/Documentation/devicetree/bindings/sound/rt5631.txt
+++ b/Documentation/devicetree/bindings/sound/rt5631.txt
@@ -35,14 +35,14 @@ Pins on the device (for linking into audio routes):
Example:
-alc5631: alc5631@1a {
+alc5631: audio-codec@1a {
compatible = "realtek,alc5631";
reg = <0x1a>;
};
or
-rt5631: rt5631@1a {
+rt5631: audio-codec@1a {
compatible = "realtek,rt5631";
reg = <0x1a>;
};
diff --git a/Documentation/devicetree/bindings/sound/rt5663.txt b/Documentation/devicetree/bindings/sound/rt5663.txt
index 23386446c63d..2a55e9133408 100644
--- a/Documentation/devicetree/bindings/sound/rt5663.txt
+++ b/Documentation/devicetree/bindings/sound/rt5663.txt
@@ -10,6 +10,10 @@ Required properties:
- interrupts : The CODEC's interrupt output.
+- avdd-supply: Power supply for AVDD, providing 1.8V.
+
+- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
+
Optional properties:
- "realtek,dc_offset_l_manual"
@@ -51,4 +55,6 @@ rt5663: codec@12 {
compatible = "realtek,rt5663";
reg = <0x12>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ avdd-supply = <&pp1800_a_alc5662>;
+ cpvdd-supply = <&pp3500_a_alc5662>;
};
diff --git a/Documentation/devicetree/bindings/sound/simple-amplifier.txt b/Documentation/devicetree/bindings/sound/simple-amplifier.txt
index 8647edae7af0..7182ac4f1e65 100644
--- a/Documentation/devicetree/bindings/sound/simple-amplifier.txt
+++ b/Documentation/devicetree/bindings/sound/simple-amplifier.txt
@@ -4,9 +4,14 @@ Required properties:
- compatible : "dioo,dio2125" or "simple-audio-amplifier"
- enable-gpios : the gpio connected to the enable pin of the simple amplifier
+Optional properties:
+- VCC-supply : power supply for the device, as covered
+ in Documentation/devicetree/bindings/regulator/regulator.txt
+
Example:
amp: analog-amplifier {
compatible = "simple-audio-amplifier";
+ VCC-supply = <&regulator>;
enable-gpios = <&gpio GPIOH_3 0>;
};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index a4c72d09cd45..4629c8f8a6b6 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -95,7 +95,9 @@ Optional CPU/CODEC subnodes properties:
initialization. It is useful for some aCPUs with
fixed clocks.
+-------------------------------------------
Example 1 - single DAI link:
+-------------------------------------------
sound {
compatible = "simple-audio-card";
@@ -138,7 +140,9 @@ sh_fsi2: sh_fsi2@ec230000 {
interrupts = <0 146 0x4>;
};
+-------------------------------------------
Example 2 - many DAI links:
+-------------------------------------------
sound {
compatible = "simple-audio-card";
@@ -176,8 +180,10 @@ sound {
};
};
+-------------------------------------------
Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
through TPA6130A2 amplifier to headphones:
+-------------------------------------------
&i2c0 {
codec: tlv320dac3100@18 {
@@ -210,3 +216,134 @@ sound {
clocks = ...
};
};
+
+-------------------------------------------
+Example 4. Sampling Rate Conversion
+-------------------------------------------
+
+sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,name = "rsnd-ak4643";
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcodec>;
+ simple-audio-card,frame-master = <&sndcodec>;
+
+ simple-audio-card,convert-rate = <48000>;
+
+ simple-audio-card,prefix = "ak4642";
+ simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+ "DAI0 Capture", "ak4642 Capture";
+
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4643>;
+ system-clock-frequency = <11289600>;
+ };
+};
+
+-------------------------------------------
+Example 5. 2 CPU 1 Codec (Mixing)
+-------------------------------------------
+sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,name = "rsnd-ak4643";
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&dpcmcpu>;
+ simple-audio-card,frame-master = <&dpcmcpu>;
+
+ simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+ "ak4642 Playback", "DAI1 Playback";
+
+ dpcmcpu: cpu@0 {
+ sound-dai = <&rcar_sound 0>;
+ };
+
+ cpu@1 {
+ sound-dai = <&rcar_sound 1>;
+ };
+
+ codec {
+ prefix = "ak4642";
+ sound-dai = <&ak4643>;
+ clocks = <&audio_clock>;
+ };
+};
+
+-------------------------------------------
+Example 6 - many DAI links with DPCM:
+-------------------------------------------
+
+CPU0 ------ ak4613
+CPU1 ------ PCM3168A-p /* DPCM 1ch/2ch */
+CPU2 --/ /* DPCM 3ch/4ch */
+CPU3 --/ /* DPCM 5ch/6ch */
+CPU4 --/ /* DPCM 7ch/8ch */
+CPU5 ------ PCM3168A-c
+
+sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,routing =
+ "pcm3168a Playback", "DAI1 Playback",
+ "pcm3168a Playback", "DAI2 Playback",
+ "pcm3168a Playback", "DAI3 Playback",
+ "pcm3168a Playback", "DAI4 Playback";
+
+ simple-audio-card,dai-link@0 {
+ format = "left_j";
+ bitclock-master = <&sndcpu0>;
+ frame-master = <&sndcpu0>;
+
+ sndcpu0: cpu {
+ sound-dai = <&rcar_sound 0>;
+ };
+ codec {
+ sound-dai = <&ak4613>;
+ };
+ };
+ simple-audio-card,dai-link@1 {
+ format = "i2s";
+ bitclock-master = <&sndcpu1>;
+ frame-master = <&sndcpu1>;
+
+ convert-channels = <8>; /* TDM Split */
+
+ sndcpu1: cpu@0 {
+ sound-dai = <&rcar_sound 1>;
+ };
+ cpu@1 {
+ sound-dai = <&rcar_sound 2>;
+ };
+ cpu@2 {
+ sound-dai = <&rcar_sound 3>;
+ };
+ cpu@3 {
+ sound-dai = <&rcar_sound 4>;
+ };
+ codec {
+ mclk-fs = <512>;
+ prefix = "pcm3168a";
+ dai-tdm-slot-num = <8>;
+ sound-dai = <&pcm3168a 0>;
+ };
+ };
+ simple-audio-card,dai-link@2 {
+ format = "i2s";
+ bitclock-master = <&sndcpu2>;
+ frame-master = <&sndcpu2>;
+
+ sndcpu2: cpu {
+ sound-dai = <&rcar_sound 5>;
+ };
+ codec {
+ mclk-fs = <512>;
+ prefix = "pcm3168a";
+ sound-dai = <&pcm3168a 1>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
index 32f8dbce5241..3a2f71616cda 100644
--- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
@@ -75,7 +75,6 @@ sound {
simple-audio-card,bitclock-master = <&dpcmcpu>;
simple-audio-card,frame-master = <&dpcmcpu>;
- simple-audio-card,prefix = "ak4642";
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
"ak4642 Playback", "DAI1 Playback";
@@ -88,6 +87,7 @@ sound {
};
codec {
+ prefix = "ak4642";
sound-dai = <&ak4643>;
clocks = <&audio_clock>;
};
diff --git a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt
index 4f8ad0e04d20..056a098495cc 100644
--- a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt
+++ b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt
@@ -4,9 +4,11 @@ Required properties:
- compatible: must be one of the following compatibles:
- "allwinner,sun50i-a64-codec-analog"
- reg: must contain the registers location and length
+- cpvdd-supply: Regulator supply for the headphone amplifier
Example:
codec_analog: codec-analog@1f015c0 {
compatible = "allwinner,sun50i-a64-codec-analog";
reg = <0x01f015c0 0x4>;
+ cpvdd-supply = <&reg_eldo1>;
};
diff --git a/Documentation/devicetree/bindings/sound/xlnx,i2s.txt b/Documentation/devicetree/bindings/sound/xlnx,i2s.txt
new file mode 100644
index 000000000000..5e7c7d5bb60a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/xlnx,i2s.txt
@@ -0,0 +1,28 @@
+Device-Tree bindings for Xilinx I2S PL block
+
+The IP supports I2S based playback/capture audio
+
+Required property:
+ - compatible: "xlnx,i2s-transmitter-1.0" for playback and
+ "xlnx,i2s-receiver-1.0" for capture
+
+Required property common to both I2S playback and capture:
+ - reg: Base address and size of the IP core instance.
+ - xlnx,dwidth: sample data width. Can be any of 16, 24.
+ - xlnx,num-channels: Number of I2S streams. Can be any of 1, 2, 3, 4.
+ supported channels = 2 * xlnx,num-channels
+
+Example:
+
+ i2s_receiver@a0080000 {
+ compatible = "xlnx,i2s-receiver-1.0";
+ reg = <0x0 0xa0080000 0x0 0x10000>;
+ xlnx,dwidth = <0x18>;
+ xlnx,num-channels = <1>;
+ };
+ i2s_transmitter@a0090000 {
+ compatible = "xlnx,i2s-transmitter-1.0";
+ reg = <0x0 0xa0090000 0x0 0x10000>;
+ xlnx,dwidth = <0x18>;
+ xlnx,num-channels = <1>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index e3bf2cbeba04..f436ff2185f7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1310,6 +1310,13 @@ F: drivers/pinctrl/meson/
F: drivers/mmc/host/meson*
N: meson
+ARM/Amlogic Meson SoC Sound Drivers
+M: Jerome Brunet <jbrunet@baylibre.com>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/meson/
+F: Documentation/devicetree/bindings/sound/amlogic*
+
ARM/Annapurna Labs ALPINE ARCHITECTURE
M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
M: Antoine Tenart <antoine.tenart@bootlin.com>
@@ -10862,7 +10869,10 @@ M: Jarkko Nikula <jarkko.nikula@bitmer.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
L: linux-omap@vger.kernel.org
S: Maintained
-F: sound/soc/omap/
+F: sound/soc/ti/omap*
+F: sound/soc/ti/rx51.c
+F: sound/soc/ti/n810.c
+F: sound/soc/ti/sdma-pcm.*
OMAP CLOCK FRAMEWORK SUPPORT
M: Paul Walmsley <paul@pwsan.com>
@@ -14927,6 +14937,12 @@ F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
F: drivers/clk/keystone/sci-clk.c
F: drivers/reset/reset-ti-sci.c
+Texas Instruments ASoC drivers
+M: Peter Ujfalusi <peter.ujfalusi@ti.com>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/ti/
+
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index 07b2eadac3dd..207962a656a2 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -167,8 +167,9 @@ CONFIG_SOUND=m
CONFIG_SND=m
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=m
-CONFIG_SND_EDMA_SOC=m
-CONFIG_SND_DA850_SOC_EVM=m
+CONFIG_SND_SOC_TLV320AIC3X=m
+CONFIG_SND_SOC_DAVINCI_MCASP=m
+CONFIG_SND_SOC_DAVINCI_EVM=m
CONFIG_SND_SIMPLE_CARD=m
CONFIG_HID=m
CONFIG_HID_A4TECH=m
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index 72f4bc83f467..cfc00b0961ec 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -175,8 +175,6 @@ CONFIG_SND_PCM_OSS=y
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_DUMMY=y
CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
# CONFIG_USB_HID is not set
CONFIG_USB=y
CONFIG_USB_PHY=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 6491419b1dad..2274e45623f9 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -381,13 +381,13 @@ CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=m
-CONFIG_SND_EDMA_SOC=m
-CONFIG_SND_AM33XX_SOC_EVM=m
-CONFIG_SND_OMAP_SOC=m
-CONFIG_SND_OMAP_SOC_HDMI_AUDIO=m
-CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
-CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
-CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
+CONFIG_SND_SOC_TLV320AIC3X=m
+CONFIG_SND_SOC_DAVINCI_MCASP=m
+CONFIG_SND_SOC_NOKIA_RX51=m
+CONFIG_SND_SOC_OMAP_HDMI=m
+CONFIG_SND_SOC_OMAP_ABE_TWL6040=m
+CONFIG_SND_SOC_OMAP3_PANDORA=m
+CONFIG_SND_SOC_OMAP3_TWL4030=m
CONFIG_SND_SOC_CPCAP=m
CONFIG_SND_SIMPLE_CARD=m
CONFIG_SND_AUDIO_GRAPH_CARD=m
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 8143756ff38b..09e439d4abf5 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -794,9 +794,9 @@ static __init void dm365_evm_init(void)
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
+#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
dm365_init_asp();
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
+#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
dm365_init_vc();
#endif
dm365_init_rtc();
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index e8ccf51c6f29..a7e9c6d19fb5 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -8,7 +8,7 @@ obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
serial.o devices.o dma.o fb.o
obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
-ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
+ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
obj-y += mcbsp.o
endif
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 01377c292db4..899c60fac159 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -24,7 +24,7 @@ obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common)
obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
-ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
+ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
obj-y += mcbsp.o
endif
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 9fec5f84bf77..8a5b6ed4ec36 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -524,7 +524,7 @@ void omap_auxdata_legacy_init(struct device *dev)
dev->platform_data = &twl_gpio_auxdata;
}
-#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
+#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
static struct omap_mcbsp_platform_data mcbsp_pdata;
static void __init omap3_mcbsp_init(void)
{
@@ -572,7 +572,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
&am35xx_emac_pdata),
/* McBSP modules with sidetone core */
-#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
+#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata),
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49024000, "49024000.mcbsp", &mcbsp_pdata),
#endif
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index b76fc3cdc8f8..23cc85e2e0e5 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -136,4 +136,11 @@ config LEDS_TRIGGER_PATTERN
which is a series of tuples, of brightness and duration (ms).
If unsure, say N
+config LEDS_TRIGGER_AUDIO
+ tristate "Audio Mute LED Trigger"
+ help
+ This allows LEDs to be controlled by audio drivers for following
+ the audio mute and mic-mute changes.
+ If unsure, say N
+
endif # LEDS_TRIGGERS
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
index 9bcb64ee8123..733a83e2a718 100644
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
+obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o
diff --git a/drivers/leds/trigger/ledtrig-audio.c b/drivers/leds/trigger/ledtrig-audio.c
new file mode 100644
index 000000000000..f76621e88482
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-audio.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Audio Mute LED trigger
+//
+
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+
+static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS];
+static enum led_brightness audio_state[NUM_AUDIO_LEDS];
+
+enum led_brightness ledtrig_audio_get(enum led_audio type)
+{
+ return audio_state[type];
+}
+EXPORT_SYMBOL_GPL(ledtrig_audio_get);
+
+void ledtrig_audio_set(enum led_audio type, enum led_brightness state)
+{
+ audio_state[type] = state;
+ led_trigger_event(ledtrig_audio[type], state);
+}
+EXPORT_SYMBOL_GPL(ledtrig_audio_set);
+
+static int __init ledtrig_audio_init(void)
+{
+ led_trigger_register_simple("audio-mute",
+ &ledtrig_audio[LED_AUDIO_MUTE]);
+ led_trigger_register_simple("audio-micmute",
+ &ledtrig_audio[LED_AUDIO_MICMUTE]);
+ return 0;
+}
+module_init(ledtrig_audio_init);
+
+static void __exit ledtrig_audio_exit(void)
+{
+ led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MUTE]);
+ led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MICMUTE]);
+}
+module_exit(ledtrig_audio_exit);
+
+MODULE_DESCRIPTION("LED trigger for audio mute control");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 54f6a40c75c6..45ef4d22f14c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -177,6 +177,8 @@ config DELL_LAPTOP
select POWER_SUPPLY
select LEDS_CLASS
select NEW_LEDS
+ select LEDS_TRIGGERS
+ select LEDS_TRIGGER_AUDIO
---help---
This driver adds support for rfkill and backlight control to Dell
laptops (except for some models covered by the Compal driver).
@@ -493,6 +495,8 @@ config THINKPAD_ACPI
select NVRAM
select NEW_LEDS
select LEDS_CLASS
+ select LEDS_TRIGGERS
+ select LEDS_TRIGGER_AUDIO
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -1288,6 +1292,23 @@ config INTEL_ATOMISP2_PM
To compile this driver as a module, choose M here: the module
will be called intel_atomisp2_pm.
+config HUAWEI_WMI
+ tristate "Huawei WMI hotkeys driver"
+ depends on ACPI_WMI
+ depends on INPUT
+ select INPUT_SPARSEKMAP
+ select LEDS_CLASS
+ select LEDS_TRIGGERS
+ select LEDS_TRIGGER_AUDIO
+ select NEW_LEDS
+ help
+ This driver provides support for Huawei WMI hotkeys.
+ It enables the missing keys and adds support to the micmute
+ LED found on some of these laptops.
+
+ To compile this driver as a module, choose M here: the module
+ will be called huawei-wmi.
+
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 39ae94135406..d841c550e3cc 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
+obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o
obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 63121fd22c2e..95e6ca116e00 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -29,7 +29,6 @@
#include <linux/mm.h>
#include <linux/i8042.h>
#include <linux/debugfs.h>
-#include <linux/dell-led.h>
#include <linux/seq_file.h>
#include <acpi/video.h>
#include "dell-rbtn.h"
@@ -2111,17 +2110,17 @@ static struct notifier_block dell_laptop_notifier = {
.notifier_call = dell_laptop_notifier_call,
};
-int dell_micmute_led_set(int state)
+static int micmute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
struct calling_interface_buffer buffer;
struct calling_interface_token *token;
+ int state = brightness != LED_OFF;
if (state == 0)
token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
- else if (state == 1)
- token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
else
- return -EINVAL;
+ token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
if (!token)
return -ENODEV;
@@ -2129,9 +2128,15 @@ int dell_micmute_led_set(int state)
dell_fill_request(&buffer, token->location, token->value, 0, 0);
dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
- return state;
+ return 0;
}
-EXPORT_SYMBOL_GPL(dell_micmute_led_set);
+
+static struct led_classdev micmute_led_cdev = {
+ .name = "platform::micmute",
+ .max_brightness = 1,
+ .brightness_set_blocking = micmute_led_set,
+ .default_trigger = "audio-micmute",
+};
static int __init dell_init(void)
{
@@ -2177,6 +2182,11 @@ static int __init dell_init(void)
dell_laptop_register_notifier(&dell_laptop_notifier);
+ micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
+ ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev);
+ if (ret < 0)
+ goto fail_led;
+
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
return 0;
@@ -2222,6 +2232,8 @@ static int __init dell_init(void)
fail_get_brightness:
backlight_device_unregister(dell_backlight_device);
fail_backlight:
+ led_classdev_unregister(&micmute_led_cdev);
+fail_led:
dell_cleanup_rfkill();
fail_rfkill:
platform_device_del(platform_device);
@@ -2241,6 +2253,7 @@ static void __exit dell_exit(void)
touchpad_led_exit();
kbd_led_exit();
backlight_device_unregister(dell_backlight_device);
+ led_classdev_unregister(&micmute_led_cdev);
dell_cleanup_rfkill();
if (platform_device) {
platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
new file mode 100644
index 000000000000..59872f87b741
--- /dev/null
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Huawei WMI hotkeys
+ *
+ * Copyright (C) 2018 Ayman Bagabas <ayman.bagabas@gmail.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+
+/*
+ * Huawei WMI GUIDs
+ */
+#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
+#define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
+
+#define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
+
+struct huawei_wmi_priv {
+ struct input_dev *idev;
+ struct led_classdev cdev;
+ acpi_handle handle;
+ char *acpi_method;
+};
+
+static const struct key_entry huawei_wmi_keymap[] = {
+ { KE_KEY, 0x281, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x282, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x284, { KEY_MUTE } },
+ { KE_KEY, 0x285, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 0x286, { KEY_VOLUMEUP } },
+ { KE_KEY, 0x287, { KEY_MICMUTE } },
+ { KE_KEY, 0x289, { KEY_WLAN } },
+ // Huawei |M| key
+ { KE_KEY, 0x28a, { KEY_CONFIG } },
+ // Keyboard backlight
+ { KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
+ { KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
+ { KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
+ { KE_END, 0 }
+};
+
+static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent);
+ acpi_status status;
+ union acpi_object args[3];
+ struct acpi_object_list arg_list = {
+ .pointer = args,
+ .count = ARRAY_SIZE(args),
+ };
+
+ args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
+ args[1].integer.value = 0x04;
+
+ if (strcmp(priv->acpi_method, "SPIN") == 0) {
+ args[0].integer.value = 0;
+ args[2].integer.value = brightness ? 1 : 0;
+ } else if (strcmp(priv->acpi_method, "WPIN") == 0) {
+ args[0].integer.value = 1;
+ args[2].integer.value = brightness ? 0 : 1;
+ } else {
+ return -EINVAL;
+ }
+
+ status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENXIO;
+
+ return 0;
+}
+
+static int huawei_wmi_leds_setup(struct wmi_device *wdev)
+{
+ struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+
+ priv->handle = ec_get_handle();
+ if (!priv->handle)
+ return 0;
+
+ if (acpi_has_method(priv->handle, "SPIN"))
+ priv->acpi_method = "SPIN";
+ else if (acpi_has_method(priv->handle, "WPIN"))
+ priv->acpi_method = "WPIN";
+ else
+ return 0;
+
+ priv->cdev.name = "platform::micmute";
+ priv->cdev.max_brightness = 1;
+ priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
+ priv->cdev.default_trigger = "audio-micmute";
+ priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
+ priv->cdev.dev = &wdev->dev;
+ priv->cdev.flags = LED_CORE_SUSPENDRESUME;
+
+ return devm_led_classdev_register(&wdev->dev, &priv->cdev);
+}
+
+static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
+{
+ struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+ const struct key_entry *key;
+
+ /*
+ * WMI0 uses code 0x80 to indicate a hotkey event.
+ * The actual key is fetched from the method WQ00
+ * using WMI0_EXPENSIVE_GUID.
+ */
+ if (code == 0x80) {
+ struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+
+ status = wmi_query_block(WMI0_EXPENSIVE_GUID, 0, &response);
+ if (ACPI_FAILURE(status))
+ return;
+
+ obj = (union acpi_object *)response.pointer;
+ if (obj && obj->type == ACPI_TYPE_INTEGER)
+ code = obj->integer.value;
+
+ kfree(response.pointer);
+ }
+
+ key = sparse_keymap_entry_from_scancode(priv->idev, code);
+ if (!key) {
+ dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code);
+ return;
+ }
+
+ sparse_keymap_report_entry(priv->idev, key, 1, true);
+}
+
+static void huawei_wmi_notify(struct wmi_device *wdev,
+ union acpi_object *obj)
+{
+ if (obj->type == ACPI_TYPE_INTEGER)
+ huawei_wmi_process_key(wdev, obj->integer.value);
+ else
+ dev_info(&wdev->dev, "Bad response type %d\n", obj->type);
+}
+
+static int huawei_wmi_input_setup(struct wmi_device *wdev)
+{
+ struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+ int err;
+
+ priv->idev = devm_input_allocate_device(&wdev->dev);
+ if (!priv->idev)
+ return -ENOMEM;
+
+ priv->idev->name = "Huawei WMI hotkeys";
+ priv->idev->phys = "wmi/input0";
+ priv->idev->id.bustype = BUS_HOST;
+ priv->idev->dev.parent = &wdev->dev;
+
+ err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL);
+ if (err)
+ return err;
+
+ return input_register_device(priv->idev);
+}
+
+static int huawei_wmi_probe(struct wmi_device *wdev)
+{
+ struct huawei_wmi_priv *priv;
+ int err;
+
+ priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&wdev->dev, priv);
+
+ err = huawei_wmi_input_setup(wdev);
+ if (err)
+ return err;
+
+ return huawei_wmi_leds_setup(wdev);
+}
+
+static const struct wmi_device_id huawei_wmi_id_table[] = {
+ { .guid_string = WMI0_EVENT_GUID },
+ { .guid_string = AMW0_EVENT_GUID },
+ { }
+};
+
+static struct wmi_driver huawei_wmi_driver = {
+ .driver = {
+ .name = "huawei-wmi",
+ },
+ .id_table = huawei_wmi_id_table,
+ .probe = huawei_wmi_probe,
+ .notify = huawei_wmi_notify,
+};
+
+module_wmi_driver(huawei_wmi_driver);
+
+MODULE_ALIAS("wmi:"WMI0_EVENT_GUID);
+MODULE_ALIAS("wmi:"AMW0_EVENT_GUID);
+MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
+MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index f5773cdfdebc..726341f2b638 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -81,7 +81,6 @@
#include <linux/acpi.h>
#include <linux/pci_ids.h>
#include <linux/power_supply.h>
-#include <linux/thinkpad_acpi.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
@@ -9131,6 +9130,7 @@ static struct ibm_struct fan_driver_data = {
* Mute LED subdriver
*/
+#define TPACPI_LED_MAX 2
struct tp_led_table {
acpi_string name;
@@ -9139,13 +9139,13 @@ struct tp_led_table {
int state;
};
-static struct tp_led_table led_tables[] = {
- [TPACPI_LED_MUTE] = {
+static struct tp_led_table led_tables[TPACPI_LED_MAX] = {
+ [LED_AUDIO_MUTE] = {
.name = "SSMS",
.on_value = 1,
.off_value = 0,
},
- [TPACPI_LED_MICMUTE] = {
+ [LED_AUDIO_MICMUTE] = {
.name = "MMTS",
.on_value = 2,
.off_value = 0,
@@ -9170,31 +9170,64 @@ static int mute_led_on_off(struct tp_led_table *t, bool state)
return state;
}
-int tpacpi_led_set(int whichled, bool on)
+static int tpacpi_led_set(int whichled, bool on)
{
struct tp_led_table *t;
- if (whichled < 0 || whichled >= TPACPI_LED_MAX)
- return -EINVAL;
-
t = &led_tables[whichled];
if (t->state < 0 || t->state == on)
return t->state;
return mute_led_on_off(t, on);
}
-EXPORT_SYMBOL_GPL(tpacpi_led_set);
+
+static int tpacpi_led_mute_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ return tpacpi_led_set(LED_AUDIO_MUTE, brightness != LED_OFF);
+}
+
+static int tpacpi_led_micmute_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ return tpacpi_led_set(LED_AUDIO_MICMUTE, brightness != LED_OFF);
+}
+
+static struct led_classdev mute_led_cdev[TPACPI_LED_MAX] = {
+ [LED_AUDIO_MUTE] = {
+ .name = "platform::mute",
+ .max_brightness = 1,
+ .brightness_set_blocking = tpacpi_led_mute_set,
+ .default_trigger = "audio-mute",
+ },
+ [LED_AUDIO_MICMUTE] = {
+ .name = "platform::micmute",
+ .max_brightness = 1,
+ .brightness_set_blocking = tpacpi_led_micmute_set,
+ .default_trigger = "audio-micmute",
+ },
+};
static int mute_led_init(struct ibm_init_struct *iibm)
{
acpi_handle temp;
- int i;
+ int i, err;
for (i = 0; i < TPACPI_LED_MAX; i++) {
struct tp_led_table *t = &led_tables[i];
- if (ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp)))
- mute_led_on_off(t, false);
- else
+ if (ACPI_FAILURE(acpi_get_handle(hkey_handle, t->name, &temp))) {
t->state = -ENODEV;
+ continue;
+ }
+
+ mute_led_cdev[i].brightness = ledtrig_audio_get(i);
+ err = led_classdev_register(&tpacpi_pdev->dev, &mute_led_cdev[i]);
+ if (err < 0) {
+ while (i--) {
+ if (led_tables[i].state >= 0)
+ led_classdev_unregister(&mute_led_cdev[i]);
+ }
+ return err;
+ }
}
return 0;
}
@@ -9203,8 +9236,12 @@ static void mute_led_exit(void)
{
int i;
- for (i = 0; i < TPACPI_LED_MAX; i++)
- tpacpi_led_set(i, false);
+ for (i = 0; i < TPACPI_LED_MAX; i++) {
+ if (led_tables[i].state >= 0) {
+ led_classdev_unregister(&mute_led_cdev[i]);
+ tpacpi_led_set(i, false);
+ }
+ }
}
static void mute_led_resume(void)
diff --git a/include/dt-bindings/sound/qcom,q6afe.h b/include/dt-bindings/sound/qcom,q6afe.h
index e2d3892240b8..1df06f8ad5c3 100644
--- a/include/dt-bindings/sound/qcom,q6afe.h
+++ b/include/dt-bindings/sound/qcom,q6afe.h
@@ -106,6 +106,7 @@
#define QUINARY_TDM_TX_6 101
#define QUINARY_TDM_RX_7 102
#define QUINARY_TDM_TX_7 103
+#define DISPLAY_PORT_RX 104
#endif /* __DT_BINDINGS_Q6_AFE_H__ */
diff --git a/include/linux/dell-led.h b/include/linux/dell-led.h
deleted file mode 100644
index 92521471517f..000000000000
--- a/include/linux/dell-led.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __DELL_LED_H__
-#define __DELL_LED_H__
-
-int dell_micmute_led_set(int on);
-
-#endif
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 7393a316d9fa..580cbaef789a 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -487,4 +487,24 @@ struct led_pattern {
int brightness;
};
+enum led_audio {
+ LED_AUDIO_MUTE, /* master mute LED */
+ LED_AUDIO_MICMUTE, /* mic mute LED */
+ NUM_AUDIO_LEDS
+};
+
+#if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO)
+enum led_brightness ledtrig_audio_get(enum led_audio type);
+void ledtrig_audio_set(enum led_audio type, enum led_brightness state);
+#else
+static inline enum led_brightness ledtrig_audio_get(enum led_audio type)
+{
+ return LED_OFF;
+}
+static inline void ledtrig_audio_set(enum led_audio type,
+ enum led_brightness state)
+{
+}
+#endif
+
#endif /* __LINUX_LEDS_H_INCLUDED */
diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h
index 85ad68f9206a..7fe80f1c7e08 100644
--- a/include/linux/platform_data/davinci_asp.h
+++ b/include/linux/platform_data/davinci_asp.h
@@ -79,6 +79,7 @@ struct davinci_mcasp_pdata {
/* McASP specific fields */
int tdm_slots;
u8 op_mode;
+ u8 dismod;
u8 num_serializer;
u8 *serial_dir;
u8 version;
diff --git a/include/linux/thinkpad_acpi.h b/include/linux/thinkpad_acpi.h
deleted file mode 100644
index 9fb317970c01..000000000000
--- a/include/linux/thinkpad_acpi.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __THINKPAD_ACPI_H__
-#define __THINKPAD_ACPI_H__
-
-/* These two functions return 0 if success, or negative error code
- (e g -ENODEV if no led present) */
-
-enum {
- TPACPI_LED_MUTE,
- TPACPI_LED_MICMUTE,
- TPACPI_LED_MAX,
-};
-
-int tpacpi_led_set(int whichled, bool on);
-
-#endif
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index ea8c93bbb0e0..0cdc3999ecfa 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -23,6 +23,7 @@ struct snd_compr_ops;
* struct snd_compr_runtime: runtime stream description
* @state: stream state
* @ops: pointer to DSP callbacks
+ * @dma_buffer_p: runtime dma buffer pointer
* @buffer: pointer to kernel buffer, valid only when not in mmap mode or
* DSP doesn't implement copy
* @buffer_size: size of the above buffer
@@ -37,6 +38,7 @@ struct snd_compr_ops;
struct snd_compr_runtime {
snd_pcm_state_t state;
struct snd_compr_ops *ops;
+ struct snd_dma_buffer *dma_buffer_p;
void *buffer;
u64 buffer_size;
u32 fragment_size;
@@ -175,6 +177,23 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
wake_up(&stream->runtime->sleep);
}
+/**
+ * snd_compr_set_runtime_buffer - Set the Compress runtime buffer
+ * @substream: compress substream to set
+ * @bufp: the buffer information, NULL to clear
+ *
+ * Copy the buffer information to runtime buffer when @bufp is non-NULL.
+ * Otherwise it clears the current buffer information.
+ */
+static inline void snd_compr_set_runtime_buffer(
+ struct snd_compr_stream *substream,
+ struct snd_dma_buffer *bufp)
+{
+ struct snd_compr_runtime *runtime = substream->runtime;
+
+ runtime->dma_buffer_p = bufp;
+}
+
int snd_compr_stop_error(struct snd_compr_stream *stream,
snd_pcm_state_t state);
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
index 0d98bb9068b1..7fa48b100936 100644
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -236,6 +236,7 @@ struct hda_codec {
/* misc flags */
unsigned int in_freeing:1; /* being released */
unsigned int registered:1; /* codec was registered */
+ unsigned int display_power_control:1; /* needs display power */
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
* status change
* (e.g. Realtek codecs)
diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h
index 78626cde7081..2ec31b358950 100644
--- a/include/sound/hda_component.h
+++ b/include/sound/hda_component.h
@@ -5,10 +5,15 @@
#define __SOUND_HDA_COMPONENT_H
#include <drm/drm_audio_component.h>
+#include <sound/hdaudio.h>
+
+/* virtual idx for controller */
+#define HDA_CODEC_IDX_CONTROLLER HDA_MAX_CODECS
#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);
+void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx,
+ 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,
@@ -25,9 +30,9 @@ 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)
+static inline void snd_hdac_display_power(struct hdac_bus *bus,
+ unsigned int idx, 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)
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index cd1773d0e08f..b4fa1c775251 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -79,7 +79,6 @@ struct hdac_device {
/* misc flags */
atomic_t in_pm; /* suspend/resume being performed */
- bool link_power_control:1;
/* sysfs */
struct hdac_widget_tree *widgets;
@@ -99,6 +98,12 @@ enum {
HDA_DEV_ASOC,
};
+enum {
+ SND_SKL_PCI_BIND_AUTO, /* automatic selection based on pci class */
+ SND_SKL_PCI_BIND_LEGACY,/* bind only with legacy driver */
+ SND_SKL_PCI_BIND_ASOC /* bind only with ASoC driver */
+};
+
/* direction */
enum {
HDA_INPUT, HDA_OUTPUT
@@ -237,8 +242,6 @@ struct hdac_bus_ops {
/* get a response from the last command */
int (*get_response)(struct hdac_bus *bus, unsigned int addr,
unsigned int *res);
- /* control the link power */
- int (*link_power)(struct hdac_bus *bus, bool enable);
};
/*
@@ -363,7 +366,8 @@ struct hdac_bus {
/* DRM component interface */
struct drm_audio_component *audio_component;
- int drm_power_refcount;
+ long display_power_status;
+ bool display_power_active;
/* parameters required for enhanced capabilities */
int num_streams;
@@ -389,6 +393,7 @@ void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
void snd_hdac_bus_remove_device(struct hdac_bus *bus,
struct hdac_device *codec);
+void snd_hdac_bus_process_unsol_events(struct work_struct *work);
static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
{
@@ -404,7 +409,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
unsigned int *res);
int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus);
-int snd_hdac_link_power(struct hdac_device *codec, bool enable);
bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index fb0318f9b10f..6d69ed2bd7b1 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -116,12 +116,12 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card);
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
struct snd_pcm_hw_params *params);
-void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+void asoc_simple_card_parse_convert(struct device *dev,
+ struct device_node *np, char *prefix,
struct asoc_simple_card_data *data);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
- char *prefix,
- int optional);
+ char *prefix);
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
char *prefix);
diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h
index f48f59e5b7b0..bb5e1e4ce8bf 100644
--- a/include/sound/soc-acpi-intel-match.h
+++ b/include/sound/soc-acpi-intel-match.h
@@ -24,6 +24,7 @@ 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[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with
diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h
index e45b2330d16a..266e64e3c24c 100644
--- a/include/sound/soc-acpi.h
+++ b/include/sound/soc-acpi.h
@@ -38,6 +38,20 @@ struct snd_soc_acpi_mach *
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines);
/**
+ * snd_soc_acpi_mach_params: interface for machine driver configuration
+ *
+ * @acpi_ipc_irq_index: used for BYT-CR detection
+ * @platform: string used for HDaudio codec support
+ * @codec_mask: used for HDAudio support
+ */
+struct snd_soc_acpi_mach_params {
+ u32 acpi_ipc_irq_index;
+ const char *platform;
+ u32 codec_mask;
+ u32 dmic_num;
+};
+
+/**
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
* related to the hardware, except for the firmware and topology file names.
* A platform supported by legacy and Sound Open Firmware (SOF) would expose
@@ -68,6 +82,7 @@ struct snd_soc_acpi_mach {
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
const void *quirk_data;
void *pdata;
+ struct snd_soc_acpi_mach_params mach_params;
const char *sof_fw_filename;
const char *sof_tplg_filename;
const char *asoc_plat_name;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 70c10a8f3e90..8ec1de856ee7 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
}
#endif
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
unsigned int id, unsigned int id_mask);
void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
+#ifdef CONFIG_SND_SOC_AC97_BUS
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev);
@@ -1477,10 +1477,20 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *rx_mask,
unsigned int *slots,
unsigned int *slot_width);
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+void snd_soc_of_parse_node_prefix(struct device_node *np,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
const char *propname);
+static inline
+void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+ struct snd_soc_codec_conf *codec_conf,
+ struct device_node *of_node,
+ const char *propname)
+{
+ snd_soc_of_parse_node_prefix(card->dev->of_node,
+ codec_conf, of_node, propname);
+}
+
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
index f0a547d86679..ae12826ed641 100644
--- a/include/uapi/sound/firewire.h
+++ b/include/uapi/sound/firewire.h
@@ -12,6 +12,7 @@
#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475
#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
#define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
+#define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL 0x7473636d
struct snd_firewire_event_common {
unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -53,12 +54,24 @@ struct snd_firewire_event_motu_notification {
__u32 message; /* MOTU-specific bits. */
};
+struct snd_firewire_tascam_change {
+ unsigned int index;
+ __be32 before;
+ __be32 after;
+};
+
+struct snd_firewire_event_tascam_control {
+ unsigned int type;
+ struct snd_firewire_tascam_change changes[0];
+};
+
union snd_firewire_event {
struct snd_firewire_event_common common;
struct snd_firewire_event_lock_status lock_status;
struct snd_firewire_event_dice_notification dice_notification;
struct snd_firewire_event_efw_response efw_response;
struct snd_firewire_event_digi00x_message digi00x_message;
+ struct snd_firewire_event_tascam_control tascam_control;
struct snd_firewire_event_motu_notification motu_notification;
};
@@ -66,6 +79,7 @@ union snd_firewire_event {
#define SNDRV_FIREWIRE_IOCTL_GET_INFO _IOR('H', 0xf8, struct snd_firewire_get_info)
#define SNDRV_FIREWIRE_IOCTL_LOCK _IO('H', 0xf9)
#define SNDRV_FIREWIRE_IOCTL_UNLOCK _IO('H', 0xfa)
+#define SNDRV_FIREWIRE_IOCTL_TASCAM_STATE _IOR('H', 0xfb, struct snd_firewire_tascam_state)
#define SNDRV_FIREWIRE_TYPE_DICE 1
#define SNDRV_FIREWIRE_TYPE_FIREWORKS 2
@@ -88,4 +102,10 @@ struct snd_firewire_get_info {
* Returns -EBUSY if the driver is already streaming.
*/
+#define SNDRV_FIREWIRE_TASCAM_STATE_COUNT 64
+
+struct snd_firewire_tascam_state {
+ __be32 data[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
+};
+
#endif /* _UAPI_SOUND_FIREWIRE_H_INCLUDED */
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index 1eddf8fa188f..8797d42e2b76 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -776,7 +776,7 @@ static int check_codec(struct aoa_codec *codec,
struct codec_connection *cc;
/* if the codec has a 'codec' node, we require a reference */
- if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
+ if (of_node_name_eq(codec->node, "codec")) {
snprintf(propname, sizeof(propname),
"platform-%s-codec-ref", codec->name);
ref = of_get_property(ldev->sound, propname, NULL);
@@ -1008,8 +1008,8 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
return -ENODEV;
/* by breaking out we keep a reference */
- while ((sound = of_get_next_child(sdev->ofdev.dev.of_node, sound))) {
- if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
+ for_each_child_of_node(sdev->ofdev.dev.of_node, sound) {
+ if (of_node_is_type(sound, "soundchip"))
break;
}
if (!sound)
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 70bcaa7f93dd..065d3a55725e 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -74,11 +74,11 @@ static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
of = &soundbus_dev->ofdev;
/* stuff we want to pass to /sbin/hotplug */
- retval = add_uevent_var(env, "OF_NAME=%s", of->dev.of_node->name);
+ retval = add_uevent_var(env, "OF_NAME=%pOFn", of->dev.of_node);
if (retval)
return retval;
- retval = add_uevent_var(env, "OF_TYPE=%s", of->dev.of_node->type);
+ retval = add_uevent_var(env, "OF_TYPE=%s", of_node_get_device_type(of->dev.of_node));
if (retval)
return retval;
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index bd7c5029fc59..c3f57a3fb1a5 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -154,7 +154,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
struct device_node *np)
{
struct i2sbus_dev *dev;
- struct device_node *child = NULL, *sound = NULL;
+ struct device_node *child, *sound = NULL;
struct resource *r;
int i, layout = 0, rlen, ok = force;
char node_name[6];
@@ -177,8 +177,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
return 0;
i = 0;
- while ((child = of_get_next_child(np, child))) {
- if (strcmp(child->name, "sound") == 0) {
+ for_each_child_of_node(np, child) {
+ if (of_node_name_eq(child, "sound")) {
i++;
sound = child;
}
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
index 81da020bddef..a2d55e15afbb 100644
--- a/sound/aoa/soundbus/sysfs.c
+++ b/sound/aoa/soundbus/sysfs.c
@@ -1,18 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/stat.h>
/* FIX UP */
#include "soundbus.h"
-#define soundbus_config_of_attr(field, format_string) \
-static ssize_t \
-field##_show (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- struct soundbus_dev *mdev = to_soundbus_device (dev); \
- return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \
-}
-
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -25,17 +17,33 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
strcat(buf, "\n");
length = strlen(buf);
} else {
- length = sprintf(buf, "of:N%sT%s\n",
- of->dev.of_node->name, of->dev.of_node->type);
+ length = sprintf(buf, "of:N%pOFn%c%s\n",
+ of->dev.of_node, 'T',
+ of_node_get_device_type(of->dev.of_node));
}
return length;
}
static DEVICE_ATTR_RO(modalias);
-soundbus_config_of_attr (name, "%s\n");
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct soundbus_dev *sdev = to_soundbus_device(dev);
+ struct platform_device *of = &sdev->ofdev;
+
+ return sprintf(buf, "%pOFn\n", of->dev.of_node);
+}
static DEVICE_ATTR_RO(name);
-soundbus_config_of_attr (type, "%s\n");
+
+static ssize_t type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct soundbus_dev *sdev = to_soundbus_device(dev);
+ struct platform_device *of = &sdev->ofdev;
+
+ return sprintf(buf, "%s\n", of_node_get_device_type(of->dev.of_node));
+}
static DEVICE_ATTR_RO(type);
struct attribute *soundbus_dev_attrs[] = {
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 26b5e245b074..a5b09e75e787 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
}
data->stream.ops->free(&data->stream);
- kfree(data->stream.runtime->buffer);
+ if (!data->stream.runtime->dma_buffer_p)
+ kfree(data->stream.runtime->buffer);
kfree(data->stream.runtime);
kfree(data);
return 0;
@@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
struct snd_compr_params *params)
{
unsigned int buffer_size;
- void *buffer;
+ void *buffer = NULL;
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
if (stream->ops->copy) {
@@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
* the data from core
*/
} else {
- buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (stream->runtime->dma_buffer_p) {
+
+ if (buffer_size > stream->runtime->dma_buffer_p->bytes)
+ dev_err(&stream->device->dev,
+ "Not enough DMA buffer");
+ else
+ buffer = stream->runtime->dma_buffer_p->area;
+
+ } else {
+ buffer = kmalloc(buffer_size, GFP_KERNEL);
+ }
+
if (!buffer)
return -ENOMEM;
}
diff --git a/sound/core/control.c b/sound/core/control.c
index 649d3217590e..fad7db402443 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -348,22 +348,41 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
return 0;
}
-/* add a new kcontrol object; call with card->controls_rwsem locked */
-static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+enum snd_ctl_add_mode {
+ CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE,
+};
+
+/* add/replace a new kcontrol object; call with card->controls_rwsem locked */
+static int __snd_ctl_add_replace(struct snd_card *card,
+ struct snd_kcontrol *kcontrol,
+ enum snd_ctl_add_mode mode)
{
struct snd_ctl_elem_id id;
unsigned int idx;
unsigned int count;
+ struct snd_kcontrol *old;
+ int err;
id = kcontrol->id;
if (id.index > UINT_MAX - kcontrol->count)
return -EINVAL;
- if (snd_ctl_find_id(card, &id)) {
- dev_err(card->dev,
- "control %i:%i:%i:%s:%i is already present\n",
- id.iface, id.device, id.subdevice, id.name, id.index);
- return -EBUSY;
+ old = snd_ctl_find_id(card, &id);
+ if (!old) {
+ if (mode == CTL_REPLACE)
+ return -EINVAL;
+ } else {
+ if (mode == CTL_ADD_EXCLUSIVE) {
+ dev_err(card->dev,
+ "control %i:%i:%i:%s:%i is already present\n",
+ id.iface, id.device, id.subdevice, id.name,
+ id.index);
+ return -EBUSY;
+ }
+
+ err = snd_ctl_remove(card, old);
+ if (err < 0)
+ return err;
}
if (snd_ctl_find_hole(card, kcontrol->count) < 0)
@@ -382,21 +401,9 @@ static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
return 0;
}
-/**
- * snd_ctl_add - add the control instance to the card
- * @card: the card instance
- * @kcontrol: the control instance to add
- *
- * Adds the control instance created via snd_ctl_new() or
- * snd_ctl_new1() to the given card. Assigns also an unique
- * numid used for fast search.
- *
- * It frees automatically the control which cannot be added.
- *
- * Return: Zero if successful, or a negative error code on failure.
- *
- */
-int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+static int snd_ctl_add_replace(struct snd_card *card,
+ struct snd_kcontrol *kcontrol,
+ enum snd_ctl_add_mode mode)
{
int err = -EINVAL;
@@ -406,7 +413,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
goto error;
down_write(&card->controls_rwsem);
- err = __snd_ctl_add(card, kcontrol);
+ err = __snd_ctl_add_replace(card, kcontrol, mode);
up_write(&card->controls_rwsem);
if (err < 0)
goto error;
@@ -416,6 +423,25 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
snd_ctl_free_one(kcontrol);
return err;
}
+
+/**
+ * snd_ctl_add - add the control instance to the card
+ * @card: the card instance
+ * @kcontrol: the control instance to add
+ *
+ * Adds the control instance created via snd_ctl_new() or
+ * snd_ctl_new1() to the given card. Assigns also an unique
+ * numid used for fast search.
+ *
+ * It frees automatically the control which cannot be added.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ *
+ */
+int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+{
+ return snd_ctl_add_replace(card, kcontrol, CTL_ADD_EXCLUSIVE);
+}
EXPORT_SYMBOL(snd_ctl_add);
/**
@@ -435,53 +461,8 @@ EXPORT_SYMBOL(snd_ctl_add);
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
bool add_on_replace)
{
- struct snd_ctl_elem_id id;
- unsigned int count;
- unsigned int idx;
- struct snd_kcontrol *old;
- int ret;
-
- if (!kcontrol)
- return -EINVAL;
- if (snd_BUG_ON(!card || !kcontrol->info)) {
- ret = -EINVAL;
- goto error;
- }
- id = kcontrol->id;
- down_write(&card->controls_rwsem);
- old = snd_ctl_find_id(card, &id);
- if (!old) {
- if (add_on_replace)
- goto add;
- up_write(&card->controls_rwsem);
- ret = -EINVAL;
- goto error;
- }
- ret = snd_ctl_remove(card, old);
- if (ret < 0) {
- up_write(&card->controls_rwsem);
- goto error;
- }
-add:
- if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
- up_write(&card->controls_rwsem);
- ret = -ENOMEM;
- goto error;
- }
- list_add_tail(&kcontrol->list, &card->controls);
- card->controls_count += kcontrol->count;
- kcontrol->id.numid = card->last_numid + 1;
- card->last_numid += kcontrol->count;
- id = kcontrol->id;
- count = kcontrol->count;
- up_write(&card->controls_rwsem);
- for (idx = 0; idx < count; idx++, id.index++, id.numid++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
- return 0;
-
-error:
- snd_ctl_free_one(kcontrol);
- return ret;
+ return snd_ctl_add_replace(card, kcontrol,
+ add_on_replace ? CTL_ADD_ON_REPLACE : CTL_REPLACE);
}
EXPORT_SYMBOL(snd_ctl_replace);
@@ -1369,7 +1350,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
/* This function manage to free the instance on failure. */
down_write(&card->controls_rwsem);
- err = __snd_ctl_add(card, kctl);
+ err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
if (err < 0) {
snd_ctl_free_one(kctl);
goto unlock;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index fdb9b92fc8d6..01b9d62eef14 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -25,6 +25,7 @@
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/device.h>
+#include <linux/nospec.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/pcm.h>
@@ -129,6 +130,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
return -EFAULT;
if (stream < 0 || stream > 1)
return -EINVAL;
+ stream = array_index_nospec(stream, 2);
if (get_user(subdevice, &info->subdevice))
return -EFAULT;
mutex_lock(&register_mutex);
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index 8a146b039276..052e00590259 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -41,6 +41,7 @@ config SND_OXFW
* Mackie(Loud) U.420/U.420d
* TASCAM FireOne
* Stanton Controllers & Systems 1 Deck/Mixer
+ * APOGEE duet FireWire
To compile this driver as a module, choose M here: the module
will be called snd-oxfw.
@@ -161,5 +162,6 @@ config SND_FIREFACE
help
Say Y here to include support for RME fireface series.
* Fireface 400
+ * Fireface 800
endif # SND_FIREWIRE
diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h
index 54cdd4ffa9ce..ac20acf48fc6 100644
--- a/sound/firewire/amdtp-stream-trace.h
+++ b/sound/firewire/amdtp-stream-trace.h
@@ -131,7 +131,7 @@ TRACE_EVENT(in_packet_without_header,
__entry->index = index;
),
TP_printk(
- "%02u %04u %04x %04x %02d %03u %3u %3u %02u %01u %02u",
+ "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
__entry->second,
__entry->cycle,
__entry->src,
@@ -169,7 +169,7 @@ TRACE_EVENT(out_packet_without_header,
__entry->dest = fw_parent_device(s->unit)->node_id;
__entry->payload_quadlets = payload_length / 4;
__entry->data_blocks = data_blocks,
- __entry->data_blocks = s->data_block_counter,
+ __entry->data_block_counter = s->data_block_counter,
__entry->packet_index = s->packet_index;
__entry->irq = !!in_interrupt();
__entry->index = index;
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 9be76c808fcc..3ada55ed5381 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -654,15 +654,17 @@ end:
}
static int handle_in_packet_without_header(struct amdtp_stream *s,
- unsigned int payload_quadlets, unsigned int cycle,
+ unsigned int payload_length, unsigned int cycle,
unsigned int index)
{
__be32 *buffer;
+ unsigned int payload_quadlets;
unsigned int data_blocks;
struct snd_pcm_substream *pcm;
unsigned int pcm_frames;
buffer = s->buffer.packets[s->packet_index].buffer;
+ payload_quadlets = payload_length / 4;
data_blocks = payload_quadlets / s->data_block_quadlets;
trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks,
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index 672d13488454..d91874275d2c 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -408,7 +408,7 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* Apogee Electronics, DA/AD/DD-16X (X-FireWire card) */
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00010048, &spec_normal),
/* Apogee Electronics, Ensemble */
- SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00001eee, &spec_normal),
+ SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal),
/* ESI, Quatafire610 */
SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal),
/* AcousticReality, eARMasterOne */
diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile
index 8f807284ba54..79a7d6d99d72 100644
--- a/sound/firewire/fireface/Makefile
+++ b/sound/firewire/fireface/Makefile
@@ -1,3 +1,4 @@
snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
- ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o
+ ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \
+ ff-protocol-ff800.o
obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index bf47f9ec8703..d0bc96b20a65 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -8,11 +8,6 @@
#include "ff.h"
-static inline unsigned int get_multiplier_mode_with_index(unsigned int index)
-{
- return ((int)index - 1) / 2;
-}
-
static int hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -24,10 +19,16 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_interval t = {
.min = UINT_MAX, .max = 0, .integer = 1
};
- unsigned int i, mode;
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
- mode = get_multiplier_mode_with_index(i);
+ enum snd_ff_stream_mode mode;
+ int err;
+
+ err = snd_ff_stream_get_multiplier_mode(i, &mode);
+ if (err < 0)
+ continue;
+
if (!snd_interval_test(c, pcm_channels[mode]))
continue;
@@ -49,10 +50,16 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
struct snd_interval t = {
.min = UINT_MAX, .max = 0, .integer = 1
};
- unsigned int i, mode;
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
- mode = get_multiplier_mode_with_index(i);
+ enum snd_ff_stream_mode mode;
+ int err;
+
+ err = snd_ff_stream_get_multiplier_mode(i, &mode);
+ if (err < 0)
+ continue;
+
if (!snd_interval_test(r, amdtp_rate_table[i]))
continue;
@@ -66,7 +73,6 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
const unsigned int *pcm_channels)
{
- unsigned int mode;
unsigned int rate, channels;
int i;
@@ -76,7 +82,12 @@ static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
hw->rate_max = 0;
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
- mode = get_multiplier_mode_with_index(i);
+ enum snd_ff_stream_mode mode;
+ int err;
+
+ err = snd_ff_stream_get_multiplier_mode(i, &mode);
+ if (err < 0)
+ continue;
channels = pcm_channels[mode];
if (pcm_channels[mode] == 0)
@@ -141,7 +152,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
goto release_lock;
- err = ff->spec->protocol->get_clock(ff, &rate, &src);
+ err = snd_ff_transaction_get_clock(ff, &rate, &src);
if (err < 0)
goto release_lock;
diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c
index 40ccbfd8ef89..a0c550dabe9a 100644
--- a/sound/firewire/fireface/ff-proc.c
+++ b/sound/firewire/fireface/ff-proc.c
@@ -12,16 +12,205 @@ static void proc_dump_clock_config(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_ff *ff = entry->private_data;
+ __le32 reg;
+ u32 data;
+ unsigned int rate;
+ const char *src;
+ int err;
- ff->spec->protocol->dump_clock_config(ff, buffer);
+ err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
+ SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return;
+
+ data = le32_to_cpu(reg);
+
+ snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
+ (data & 0x20) ? "Professional" : "Consumer",
+ (data & 0x40) ? "on" : "off");
+
+ snd_iprintf(buffer, "Optical output interface format: %s\n",
+ ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
+
+ snd_iprintf(buffer, "Word output single speed: %s\n",
+ ((data >> 8) & 0x20) ? "on" : "off");
+
+ snd_iprintf(buffer, "S/PDIF input interface: %s\n",
+ ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
+
+ switch ((data >> 1) & 0x03) {
+ case 0x01:
+ rate = 32000;
+ break;
+ case 0x00:
+ rate = 44100;
+ break;
+ case 0x03:
+ rate = 48000;
+ break;
+ case 0x02:
+ default:
+ return;
+ }
+
+ if (data & 0x08)
+ rate *= 2;
+ else if (data & 0x10)
+ rate *= 4;
+
+ snd_iprintf(buffer, "Sampling rate: %d\n", rate);
+
+ if (data & 0x01) {
+ src = "Internal";
+ } else {
+ switch ((data >> 10) & 0x07) {
+ case 0x00:
+ src = "ADAT1";
+ break;
+ case 0x01:
+ src = "ADAT2";
+ break;
+ case 0x03:
+ src = "S/PDIF";
+ break;
+ case 0x04:
+ src = "Word";
+ break;
+ case 0x05:
+ src = "LTC";
+ break;
+ default:
+ return;
+ }
+ }
+
+ snd_iprintf(buffer, "Sync to clock source: %s\n", src);
}
static void proc_dump_sync_status(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_ff *ff = entry->private_data;
+ __le32 reg;
+ u32 data;
+ int err;
+
+ err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+ SND_FF_REG_SYNC_STATUS, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return;
+
+ data = le32_to_cpu(reg);
+
+ snd_iprintf(buffer, "External source detection:\n");
+
+ snd_iprintf(buffer, "Word Clock:");
+ if ((data >> 24) & 0x20) {
+ if ((data >> 24) & 0x40)
+ snd_iprintf(buffer, "sync\n");
+ else
+ snd_iprintf(buffer, "lock\n");
+ } else {
+ snd_iprintf(buffer, "none\n");
+ }
+
+ snd_iprintf(buffer, "S/PDIF:");
+ if ((data >> 16) & 0x10) {
+ if ((data >> 16) & 0x04)
+ snd_iprintf(buffer, "sync\n");
+ else
+ snd_iprintf(buffer, "lock\n");
+ } else {
+ snd_iprintf(buffer, "none\n");
+ }
+
+ snd_iprintf(buffer, "ADAT1:");
+ if ((data >> 8) & 0x04) {
+ if ((data >> 8) & 0x10)
+ snd_iprintf(buffer, "sync\n");
+ else
+ snd_iprintf(buffer, "lock\n");
+ } else {
+ snd_iprintf(buffer, "none\n");
+ }
+
+ snd_iprintf(buffer, "ADAT2:");
+ if ((data >> 8) & 0x08) {
+ if ((data >> 8) & 0x20)
+ snd_iprintf(buffer, "sync\n");
+ else
+ snd_iprintf(buffer, "lock\n");
+ } else {
+ snd_iprintf(buffer, "none\n");
+ }
+
+ snd_iprintf(buffer, "\nUsed external source:\n");
+
+ if (((data >> 22) & 0x07) == 0x07) {
+ snd_iprintf(buffer, "None\n");
+ } else {
+ switch ((data >> 22) & 0x07) {
+ case 0x00:
+ snd_iprintf(buffer, "ADAT1:");
+ break;
+ case 0x01:
+ snd_iprintf(buffer, "ADAT2:");
+ break;
+ case 0x03:
+ snd_iprintf(buffer, "S/PDIF:");
+ break;
+ case 0x04:
+ snd_iprintf(buffer, "Word:");
+ break;
+ case 0x07:
+ snd_iprintf(buffer, "Nothing:");
+ break;
+ case 0x02:
+ case 0x05:
+ case 0x06:
+ default:
+ snd_iprintf(buffer, "unknown:");
+ break;
+ }
+
+ if ((data >> 25) & 0x07) {
+ switch ((data >> 25) & 0x07) {
+ case 0x01:
+ snd_iprintf(buffer, "32000\n");
+ break;
+ case 0x02:
+ snd_iprintf(buffer, "44100\n");
+ break;
+ case 0x03:
+ snd_iprintf(buffer, "48000\n");
+ break;
+ case 0x04:
+ snd_iprintf(buffer, "64000\n");
+ break;
+ case 0x05:
+ snd_iprintf(buffer, "88200\n");
+ break;
+ case 0x06:
+ snd_iprintf(buffer, "96000\n");
+ break;
+ case 0x07:
+ snd_iprintf(buffer, "128000\n");
+ break;
+ case 0x08:
+ snd_iprintf(buffer, "176400\n");
+ break;
+ case 0x09:
+ snd_iprintf(buffer, "192000\n");
+ break;
+ case 0x00:
+ snd_iprintf(buffer, "unknown\n");
+ break;
+ }
+ }
+ }
- ff->spec->protocol->dump_sync_status(ff, buffer);
+ snd_iprintf(buffer, "Multiplied:");
+ snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
}
static void add_node(struct snd_ff *ff, struct snd_info_entry *root,
diff --git a/sound/firewire/fireface/ff-protocol-ff400.c b/sound/firewire/fireface/ff-protocol-ff400.c
index 654a50319198..2280fab9b3c7 100644
--- a/sound/firewire/fireface/ff-protocol-ff400.c
+++ b/sound/firewire/fireface/ff-protocol-ff400.c
@@ -14,85 +14,60 @@
#define FF400_ISOC_COMM_START 0x000080100508ull
#define FF400_TX_PACKET_FORMAT 0x00008010050cull
#define FF400_ISOC_COMM_STOP 0x000080100510ull
-#define FF400_SYNC_STATUS 0x0000801c0000ull
-#define FF400_FETCH_PCM_FRAMES 0x0000801c0000ull /* For block request. */
-#define FF400_CLOCK_CONFIG 0x0000801c0004ull
-#define FF400_MIDI_HIGH_ADDR 0x0000801003f4ull
-#define FF400_MIDI_RX_PORT_0 0x000080180000ull
-#define FF400_MIDI_RX_PORT_1 0x000080190000ull
-
-static int ff400_get_clock(struct snd_ff *ff, unsigned int *rate,
- enum snd_ff_clock_src *src)
+/*
+ * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
+ * we can allocate between 0 and 7 channel.
+ */
+static int keep_resources(struct snd_ff *ff, unsigned int rate)
{
- __le32 reg;
- u32 data;
+ enum snd_ff_stream_mode mode;
+ int i;
int err;
- err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
- FF400_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+ // Check whether the given value is supported or not.
+ for (i = 0; i < CIP_SFC_COUNT; i++) {
+ if (amdtp_rate_table[i] == rate)
+ break;
+ }
+ if (i >= CIP_SFC_COUNT)
+ return -EINVAL;
+
+ err = snd_ff_stream_get_multiplier_mode(i, &mode);
if (err < 0)
return err;
- data = le32_to_cpu(reg);
- /* Calculate sampling rate. */
- switch ((data >> 1) & 0x03) {
- case 0x01:
- *rate = 32000;
- break;
- case 0x00:
- *rate = 44100;
- break;
- case 0x03:
- *rate = 48000;
- break;
- case 0x02:
- default:
- return -EIO;
- }
-
- if (data & 0x08)
- *rate *= 2;
- else if (data & 0x10)
- *rate *= 4;
+ /* Keep resources for in-stream. */
+ ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
+ err = fw_iso_resources_allocate(&ff->tx_resources,
+ amdtp_stream_get_max_payload(&ff->tx_stream),
+ fw_parent_device(ff->unit)->max_speed);
+ if (err < 0)
+ return err;
- /* Calculate source of clock. */
- if (data & 0x01) {
- *src = SND_FF_CLOCK_SRC_INTERNAL;
- } else {
- /* TODO: 0x00, 0x01, 0x02, 0x06, 0x07? */
- switch ((data >> 10) & 0x07) {
- case 0x03:
- *src = SND_FF_CLOCK_SRC_SPDIF;
- break;
- case 0x04:
- *src = SND_FF_CLOCK_SRC_WORD;
- break;
- case 0x05:
- *src = SND_FF_CLOCK_SRC_LTC;
- break;
- case 0x00:
- default:
- *src = SND_FF_CLOCK_SRC_ADAT;
- break;
- }
- }
+ /* Keep resources for out-stream. */
+ err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
+ ff->spec->pcm_playback_channels[mode]);
+ if (err < 0)
+ return err;
+ ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
+ err = fw_iso_resources_allocate(&ff->rx_resources,
+ amdtp_stream_get_max_payload(&ff->rx_stream),
+ fw_parent_device(ff->unit)->max_speed);
+ if (err < 0)
+ fw_iso_resources_free(&ff->tx_resources);
- return 0;
+ return err;
}
static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
{
__le32 reg;
- int i, err;
+ int err;
- /* Check whether the given value is supported or not. */
- for (i = 0; i < CIP_SFC_COUNT; i++) {
- if (amdtp_rate_table[i] == rate)
- break;
- }
- if (i == CIP_SFC_COUNT)
- return -EINVAL;
+ err = keep_resources(ff, rate);
+ if (err < 0)
+ return err;
/* Set the number of data blocks transferred in a second. */
reg = cpu_to_le32(rate);
@@ -142,233 +117,45 @@ static void ff400_finish_session(struct snd_ff *ff)
FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
}
-static int ff400_switch_fetching_mode(struct snd_ff *ff, bool enable)
+static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
{
- __le32 *reg;
int i;
- int err;
- reg = kcalloc(18, sizeof(__le32), GFP_KERNEL);
- if (reg == NULL)
- return -ENOMEM;
+ for (i = 0; i < length / 4; i++) {
+ u32 quad = le32_to_cpu(buf[i]);
+ u8 byte;
+ unsigned int index;
+ struct snd_rawmidi_substream *substream;
- if (enable) {
+ /* Message in first port. */
/*
- * Each quadlet is corresponding to data channels in a data
- * blocks in reverse order. Precisely, quadlets for available
- * data channels should be enabled. Here, I take second best
- * to fetch PCM frames from all of data channels regardless of
- * stf.
+ * This value may represent the index of this unit when the same
+ * units are on the same IEEE 1394 bus. This driver doesn't use
+ * it.
*/
- for (i = 0; i < 18; ++i)
- reg[i] = cpu_to_le32(0x00000001);
- }
-
- err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
- FF400_FETCH_PCM_FRAMES, reg,
- sizeof(__le32) * 18, 0);
- kfree(reg);
- return err;
-}
-
-static void ff400_dump_sync_status(struct snd_ff *ff,
- struct snd_info_buffer *buffer)
-{
- __le32 reg;
- u32 data;
- int err;
-
- err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
- FF400_SYNC_STATUS, &reg, sizeof(reg), 0);
- if (err < 0)
- return;
-
- data = le32_to_cpu(reg);
-
- snd_iprintf(buffer, "External source detection:\n");
-
- snd_iprintf(buffer, "Word Clock:");
- if ((data >> 24) & 0x20) {
- if ((data >> 24) & 0x40)
- snd_iprintf(buffer, "sync\n");
- else
- snd_iprintf(buffer, "lock\n");
- } else {
- snd_iprintf(buffer, "none\n");
- }
-
- snd_iprintf(buffer, "S/PDIF:");
- if ((data >> 16) & 0x10) {
- if ((data >> 16) & 0x04)
- snd_iprintf(buffer, "sync\n");
- else
- snd_iprintf(buffer, "lock\n");
- } else {
- snd_iprintf(buffer, "none\n");
- }
-
- snd_iprintf(buffer, "ADAT:");
- if ((data >> 8) & 0x04) {
- if ((data >> 8) & 0x10)
- snd_iprintf(buffer, "sync\n");
- else
- snd_iprintf(buffer, "lock\n");
- } else {
- snd_iprintf(buffer, "none\n");
- }
-
- snd_iprintf(buffer, "\nUsed external source:\n");
-
- if (((data >> 22) & 0x07) == 0x07) {
- snd_iprintf(buffer, "None\n");
- } else {
- switch ((data >> 22) & 0x07) {
- case 0x00:
- snd_iprintf(buffer, "ADAT:");
- break;
- case 0x03:
- snd_iprintf(buffer, "S/PDIF:");
- break;
- case 0x04:
- snd_iprintf(buffer, "Word:");
- break;
- case 0x07:
- snd_iprintf(buffer, "Nothing:");
- break;
- case 0x01:
- case 0x02:
- case 0x05:
- case 0x06:
- default:
- snd_iprintf(buffer, "unknown:");
- break;
- }
-
- if ((data >> 25) & 0x07) {
- switch ((data >> 25) & 0x07) {
- case 0x01:
- snd_iprintf(buffer, "32000\n");
- break;
- case 0x02:
- snd_iprintf(buffer, "44100\n");
- break;
- case 0x03:
- snd_iprintf(buffer, "48000\n");
- break;
- case 0x04:
- snd_iprintf(buffer, "64000\n");
- break;
- case 0x05:
- snd_iprintf(buffer, "88200\n");
- break;
- case 0x06:
- snd_iprintf(buffer, "96000\n");
- break;
- case 0x07:
- snd_iprintf(buffer, "128000\n");
- break;
- case 0x08:
- snd_iprintf(buffer, "176400\n");
- break;
- case 0x09:
- snd_iprintf(buffer, "192000\n");
- break;
- case 0x00:
- snd_iprintf(buffer, "unknown\n");
- break;
+ index = (quad >> 8) & 0xff;
+ if (index > 0) {
+ substream = READ_ONCE(ff->tx_midi_substreams[0]);
+ if (substream != NULL) {
+ byte = quad & 0xff;
+ snd_rawmidi_receive(substream, &byte, 1);
}
}
- }
-
- snd_iprintf(buffer, "Multiplied:");
- snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
-}
-static void ff400_dump_clock_config(struct snd_ff *ff,
- struct snd_info_buffer *buffer)
-{
- __le32 reg;
- u32 data;
- unsigned int rate;
- const char *src;
- int err;
-
- err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
- FF400_CLOCK_CONFIG, &reg, sizeof(reg), 0);
- if (err < 0)
- return;
-
- data = le32_to_cpu(reg);
-
- snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
- (data & 0x20) ? "Professional" : "Consumer",
- (data & 0x40) ? "on" : "off");
-
- snd_iprintf(buffer, "Optical output interface format: %s\n",
- ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
-
- snd_iprintf(buffer, "Word output single speed: %s\n",
- ((data >> 8) & 0x20) ? "on" : "off");
-
- snd_iprintf(buffer, "S/PDIF input interface: %s\n",
- ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
-
- switch ((data >> 1) & 0x03) {
- case 0x01:
- rate = 32000;
- break;
- case 0x00:
- rate = 44100;
- break;
- case 0x03:
- rate = 48000;
- break;
- case 0x02:
- default:
- return;
- }
-
- if (data & 0x08)
- rate *= 2;
- else if (data & 0x10)
- rate *= 4;
-
- snd_iprintf(buffer, "Sampling rate: %d\n", rate);
-
- if (data & 0x01) {
- src = "Internal";
- } else {
- switch ((data >> 10) & 0x07) {
- case 0x00:
- src = "ADAT";
- break;
- case 0x03:
- src = "S/PDIF";
- break;
- case 0x04:
- src = "Word";
- break;
- case 0x05:
- src = "LTC";
- break;
- default:
- return;
+ /* Message in second port. */
+ index = (quad >> 24) & 0xff;
+ if (index > 0) {
+ substream = READ_ONCE(ff->tx_midi_substreams[1]);
+ if (substream != NULL) {
+ byte = (quad >> 16) & 0xff;
+ snd_rawmidi_receive(substream, &byte, 1);
+ }
}
}
-
- snd_iprintf(buffer, "Sync to clock source: %s\n", src);
}
const struct snd_ff_protocol snd_ff_protocol_ff400 = {
- .get_clock = ff400_get_clock,
+ .handle_midi_msg = ff400_handle_midi_msg,
.begin_session = ff400_begin_session,
.finish_session = ff400_finish_session,
- .switch_fetching_mode = ff400_switch_fetching_mode,
-
- .dump_sync_status = ff400_dump_sync_status,
- .dump_clock_config = ff400_dump_clock_config,
-
- .midi_high_addr_reg = FF400_MIDI_HIGH_ADDR,
- .midi_rx_port_0_reg = FF400_MIDI_RX_PORT_0,
- .midi_rx_port_1_reg = FF400_MIDI_RX_PORT_1,
};
diff --git a/sound/firewire/fireface/ff-protocol-ff800.c b/sound/firewire/fireface/ff-protocol-ff800.c
new file mode 100644
index 000000000000..2acbf6039770
--- /dev/null
+++ b/sound/firewire/fireface/ff-protocol-ff800.c
@@ -0,0 +1,143 @@
+/*
+ * ff-protocol-ff800.c - a part of driver for RME Fireface series
+ *
+ * Copyright (c) 2018 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/delay.h>
+
+#include "ff.h"
+
+#define FF800_STF 0x0000fc88f000
+#define FF800_RX_PACKET_FORMAT 0x0000fc88f004
+#define FF800_ALLOC_TX_STREAM 0x0000fc88f008
+#define FF800_ISOC_COMM_START 0x0000fc88f00c
+#define FF800_TX_S800_FLAG 0x00000800
+#define FF800_ISOC_COMM_STOP 0x0000fc88f010
+
+#define FF800_TX_PACKET_ISOC_CH 0x0000801c0008
+
+static int allocate_rx_resources(struct snd_ff *ff)
+{
+ u32 data;
+ __le32 reg;
+ int err;
+
+ // Controllers should allocate isochronous resources for rx stream.
+ err = fw_iso_resources_allocate(&ff->rx_resources,
+ amdtp_stream_get_max_payload(&ff->rx_stream),
+ fw_parent_device(ff->unit)->max_speed);
+ if (err < 0)
+ return err;
+
+ // Set isochronous channel and the number of quadlets of rx packets.
+ data = ff->rx_stream.data_block_quadlets << 3;
+ data = (data << 8) | ff->rx_resources.channel;
+ reg = cpu_to_le32(data);
+ return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
+}
+
+static int allocate_tx_resources(struct snd_ff *ff)
+{
+ __le32 reg;
+ unsigned int count;
+ unsigned int tx_isoc_channel;
+ int err;
+
+ reg = cpu_to_le32(ff->tx_stream.data_block_quadlets);
+ err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF800_ALLOC_TX_STREAM, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ // Wait till the format of tx packet is available.
+ count = 0;
+ while (count++ < 10) {
+ u32 data;
+ err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+ FF800_TX_PACKET_ISOC_CH, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ data = le32_to_cpu(reg);
+ if (data != 0xffffffff) {
+ tx_isoc_channel = data;
+ break;
+ }
+
+ msleep(50);
+ }
+ if (count >= 10)
+ return -ETIMEDOUT;
+
+ // NOTE: this is a makeshift to start OHCI 1394 IR context in the
+ // channel. On the other hand, 'struct fw_iso_resources.allocated' is
+ // not true and it's not deallocated at stop.
+ ff->tx_resources.channel = tx_isoc_channel;
+
+ return 0;
+}
+
+static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
+{
+ __le32 reg;
+ int err;
+
+ reg = cpu_to_le32(rate);
+ err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF800_STF, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+
+ // If starting isochronous communication immediately, change of STF has
+ // no effect. In this case, the communication runs based on former STF.
+ // Let's sleep for a bit.
+ msleep(100);
+
+ err = allocate_rx_resources(ff);
+ if (err < 0)
+ return err;
+
+ err = allocate_tx_resources(ff);
+ if (err < 0)
+ return err;
+
+ reg = cpu_to_le32(0x80000000);
+ reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);
+ if (fw_parent_device(ff->unit)->max_speed == SCODE_800)
+ reg |= cpu_to_le32(FF800_TX_S800_FLAG);
+ return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF800_ISOC_COMM_START, &reg, sizeof(reg), 0);
+}
+
+static void ff800_finish_session(struct snd_ff *ff)
+{
+ __le32 reg;
+
+ reg = cpu_to_le32(0x80000000);
+ snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+ FF800_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
+}
+
+static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
+{
+ int i;
+
+ for (i = 0; i < length / 4; i++) {
+ u8 byte = le32_to_cpu(buf[i]) & 0xff;
+ struct snd_rawmidi_substream *substream;
+
+ substream = READ_ONCE(ff->tx_midi_substreams[0]);
+ if (substream)
+ snd_rawmidi_receive(substream, &byte, 1);
+ }
+}
+
+const struct snd_ff_protocol snd_ff_protocol_ff800 = {
+ .handle_midi_msg = ff800_handle_midi_msg,
+ .begin_session = ff800_begin_session,
+ .finish_session = ff800_finish_session,
+};
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index 78880922120e..a490e4553721 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -10,73 +10,71 @@
#define CALLBACK_TIMEOUT_MS 200
-static int get_rate_mode(unsigned int rate, unsigned int *mode)
+int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
+ enum snd_ff_stream_mode *mode)
{
- int i;
-
- for (i = 0; i < CIP_SFC_COUNT; i++) {
- if (amdtp_rate_table[i] == rate)
- break;
- }
-
- if (i == CIP_SFC_COUNT)
+ static const enum snd_ff_stream_mode modes[] = {
+ [CIP_SFC_32000] = SND_FF_STREAM_MODE_LOW,
+ [CIP_SFC_44100] = SND_FF_STREAM_MODE_LOW,
+ [CIP_SFC_48000] = SND_FF_STREAM_MODE_LOW,
+ [CIP_SFC_88200] = SND_FF_STREAM_MODE_MID,
+ [CIP_SFC_96000] = SND_FF_STREAM_MODE_MID,
+ [CIP_SFC_176400] = SND_FF_STREAM_MODE_HIGH,
+ [CIP_SFC_192000] = SND_FF_STREAM_MODE_HIGH,
+ };
+
+ if (sfc >= CIP_SFC_COUNT)
return -EINVAL;
- *mode = ((int)i - 1) / 2;
+ *mode = modes[sfc];
return 0;
}
-/*
- * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
- * we can allocate between 0 and 7 channel.
- */
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+static void release_resources(struct snd_ff *ff)
{
- int mode;
- int err;
-
- err = get_rate_mode(rate, &mode);
- if (err < 0)
- return err;
+ fw_iso_resources_free(&ff->tx_resources);
+ fw_iso_resources_free(&ff->rx_resources);
+}
- /* Keep resources for in-stream. */
- err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
- ff->spec->pcm_capture_channels[mode]);
- if (err < 0)
- return err;
- ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
- err = fw_iso_resources_allocate(&ff->tx_resources,
- amdtp_stream_get_max_payload(&ff->tx_stream),
- fw_parent_device(ff->unit)->max_speed);
- if (err < 0)
- return err;
+static int switch_fetching_mode(struct snd_ff *ff, bool enable)
+{
+ unsigned int count;
+ __le32 *reg;
+ int i;
+ int err;
- /* Keep resources for out-stream. */
- err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
- ff->spec->pcm_playback_channels[mode]);
- if (err < 0)
- return err;
- ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
- err = fw_iso_resources_allocate(&ff->rx_resources,
- amdtp_stream_get_max_payload(&ff->rx_stream),
- fw_parent_device(ff->unit)->max_speed);
- if (err < 0)
- fw_iso_resources_free(&ff->tx_resources);
+ count = 0;
+ for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
+ count = max(count, ff->spec->pcm_playback_channels[i]);
+
+ reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ if (!enable) {
+ /*
+ * Each quadlet is corresponding to data channels in a data
+ * blocks in reverse order. Precisely, quadlets for available
+ * data channels should be enabled. Here, I take second best
+ * to fetch PCM frames from all of data channels regardless of
+ * stf.
+ */
+ for (i = 0; i < count; ++i)
+ reg[i] = cpu_to_le32(0x00000001);
+ }
+ err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
+ SND_FF_REG_FETCH_PCM_FRAMES, reg,
+ sizeof(__le32) * count, 0);
+ kfree(reg);
return err;
}
-static void release_resources(struct snd_ff *ff)
-{
- fw_iso_resources_free(&ff->tx_resources);
- fw_iso_resources_free(&ff->rx_resources);
-}
-
static inline void finish_session(struct snd_ff *ff)
{
ff->spec->protocol->finish_session(ff);
- ff->spec->protocol->switch_fetching_mode(ff, false);
+ switch_fetching_mode(ff, false);
}
static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
@@ -149,7 +147,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
if (ff->substreams_counter == 0)
return 0;
- err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
+ err = snd_ff_transaction_get_clock(ff, &curr_rate, &src);
if (err < 0)
return err;
if (curr_rate != rate ||
@@ -168,9 +166,29 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
* packets. Then, the device transfers packets.
*/
if (!amdtp_stream_running(&ff->rx_stream)) {
- err = keep_resources(ff, rate);
+ enum snd_ff_stream_mode mode;
+ int i;
+
+ for (i = 0; i < CIP_SFC_COUNT; ++i) {
+ if (amdtp_rate_table[i] == rate)
+ break;
+ }
+ if (i >= CIP_SFC_COUNT)
+ return -EINVAL;
+
+ err = snd_ff_stream_get_multiplier_mode(i, &mode);
if (err < 0)
- goto error;
+ return err;
+
+ err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
+ ff->spec->pcm_capture_channels[mode]);
+ if (err < 0)
+ return err;
+
+ err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
+ ff->spec->pcm_playback_channels[mode]);
+ if (err < 0)
+ return err;
err = ff->spec->protocol->begin_session(ff, rate);
if (err < 0)
@@ -188,7 +206,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
goto error;
}
- err = ff->spec->protocol->switch_fetching_mode(ff, true);
+ err = switch_fetching_mode(ff, true);
if (err < 0)
goto error;
}
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 332b29f8ed75..5f4ddfd55403 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -8,6 +8,72 @@
#include "ff.h"
+#define SND_FF_REG_MIDI_RX_PORT_0 0x000080180000ull
+#define SND_FF_REG_MIDI_RX_PORT_1 0x000080190000ull
+
+int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
+ enum snd_ff_clock_src *src)
+{
+ __le32 reg;
+ u32 data;
+ int err;
+
+ err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+ SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+ if (err < 0)
+ return err;
+ data = le32_to_cpu(reg);
+
+ /* Calculate sampling rate. */
+ switch ((data >> 1) & 0x03) {
+ case 0x01:
+ *rate = 32000;
+ break;
+ case 0x00:
+ *rate = 44100;
+ break;
+ case 0x03:
+ *rate = 48000;
+ break;
+ case 0x02:
+ default:
+ return -EIO;
+ }
+
+ if (data & 0x08)
+ *rate *= 2;
+ else if (data & 0x10)
+ *rate *= 4;
+
+ /* Calculate source of clock. */
+ if (data & 0x01) {
+ *src = SND_FF_CLOCK_SRC_INTERNAL;
+ } else {
+ /* TODO: 0x02, 0x06, 0x07? */
+ switch ((data >> 10) & 0x07) {
+ case 0x00:
+ *src = SND_FF_CLOCK_SRC_ADAT1;
+ break;
+ case 0x01:
+ *src = SND_FF_CLOCK_SRC_ADAT2;
+ break;
+ case 0x03:
+ *src = SND_FF_CLOCK_SRC_SPDIF;
+ break;
+ case 0x04:
+ *src = SND_FF_CLOCK_SRC_WORD;
+ break;
+ case 0x05:
+ *src = SND_FF_CLOCK_SRC_LTC;
+ break;
+ default:
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
int rcode)
{
@@ -90,10 +156,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
fill_midi_buf(ff, port, i, buf[i]);
if (port == 0) {
- addr = ff->spec->protocol->midi_rx_port_0_reg;
+ addr = SND_FF_REG_MIDI_RX_PORT_0;
callback = finish_transmit_midi0_msg;
} else {
- addr = ff->spec->protocol->midi_rx_port_1_reg;
+ addr = SND_FF_REG_MIDI_RX_PORT_1;
callback = finish_transmit_midi1_msg;
}
@@ -140,42 +206,10 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
{
struct snd_ff *ff = callback_data;
__le32 *buf = data;
- u32 quad;
- u8 byte;
- unsigned int index;
- struct snd_rawmidi_substream *substream;
- int i;
fw_send_response(card, request, RCODE_COMPLETE);
- for (i = 0; i < length / 4; i++) {
- quad = le32_to_cpu(buf[i]);
-
- /* Message in first port. */
- /*
- * This value may represent the index of this unit when the same
- * units are on the same IEEE 1394 bus. This driver doesn't use
- * it.
- */
- index = (quad >> 8) & 0xff;
- if (index > 0) {
- substream = READ_ONCE(ff->tx_midi_substreams[0]);
- if (substream != NULL) {
- byte = quad & 0xff;
- snd_rawmidi_receive(substream, &byte, 1);
- }
- }
-
- /* Message in second port. */
- index = (quad >> 24) & 0xff;
- if (index > 0) {
- substream = READ_ONCE(ff->tx_midi_substreams[1]);
- if (substream != NULL) {
- byte = (quad >> 16) & 0xff;
- snd_rawmidi_receive(substream, &byte, 1);
- }
- }
- }
+ ff->spec->protocol->handle_midi_msg(ff, buf, length);
}
static int allocate_own_address(struct snd_ff *ff, int i)
@@ -203,36 +237,33 @@ static int allocate_own_address(struct snd_ff *ff, int i)
}
/*
- * The configuration to start asynchronous transactions for MIDI messages is in
- * 0x'0000'8010'051c. This register includes the other options, thus this driver
- * doesn't touch it and leaves the decision to userspace. The userspace MUST add
- * 0x04000000 to write transactions to the register to receive any MIDI
- * messages.
- *
- * Here, I just describe MIDI-related offsets of the register, in little-endian
- * order.
- *
* Controllers are allowed to register higher 4 bytes of address to receive
- * the transactions. The register is 0x'0000'8010'03f4. On the other hand, the
- * controllers are not allowed to register lower 4 bytes of the address. They
- * are forced to select from 4 options by writing corresponding bits to
- * 0x'0000'8010'051c.
+ * the transactions. Different models have different registers for this purpose;
+ * e.g. 0x'0000'8010'03f4 for Fireface 400.
+ * The controllers are not allowed to register lower 4 bytes of the address.
+ * They are forced to select one of 4 options for the part of address by writing
+ * corresponding bits to 0x'0000'8010'051f.
+ *
+ * The 3rd-6th bits of this register are flags to indicate lower 4 bytes of
+ * address to which the device transferrs the transactions. In short:
+ * - 0x20: 0x'....'....'0000'0180
+ * - 0x10: 0x'....'....'0000'0100
+ * - 0x08: 0x'....'....'0000'0080
+ * - 0x04: 0x'....'....'0000'0000
*
- * The 3rd-6th bits in MSB of this register are used to indicate lower 4 bytes
- * of address to which the device transferrs the transactions.
- * - 6th: 0x'....'....'0000'0180
- * - 5th: 0x'....'....'0000'0100
- * - 4th: 0x'....'....'0000'0080
- * - 3rd: 0x'....'....'0000'0000
+ * This driver configure 0x'....'....'0000'0000 to receive MIDI messages from
+ * units. The 3rd bit of the register should be configured, however this driver
+ * deligates this task to userspace applications due to a restriction that this
+ * register is write-only and the other bits have own effects.
*
- * This driver configure 0x'....'....'0000'0000 for units to receive MIDI
- * messages. 3rd bit of the register should be configured, however this driver
- * deligates this task to user space applications due to a restriction that
- * this register is write-only and the other bits have own effects.
+ * Unlike Fireface 800, Fireface 400 cancels transferring asynchronous
+ * transactions when the 1st and 2nd of the register stand. These two bits have
+ * the same effect.
+ * - 0x02, 0x01: cancel transferring
*
- * The 1st and 2nd bits in LSB of this register are used to cancel transferring
- * asynchronous transactions. These two bits have the same effect.
- * - 1st/2nd: cancel transferring
+ * On the other hand, the bits have no effect on Fireface 800. This model
+ * cancels asynchronous transactions when the higher 4 bytes of address is
+ * overwritten with zero.
*/
int snd_ff_transaction_reregister(struct snd_ff *ff)
{
@@ -247,7 +278,7 @@ int snd_ff_transaction_reregister(struct snd_ff *ff)
addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32);
reg = cpu_to_le32(addr);
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
- ff->spec->protocol->midi_high_addr_reg,
+ ff->spec->midi_high_addr,
&reg, sizeof(reg), 0);
}
@@ -288,7 +319,7 @@ void snd_ff_transaction_unregister(struct snd_ff *ff)
/* Release higher 4 bytes of address. */
reg = cpu_to_le32(0x00000000);
snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
- ff->spec->protocol->midi_high_addr_reg,
+ ff->spec->midi_high_addr,
&reg, sizeof(reg), 0);
fw_core_remove_address_handler(&ff->async_handler);
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index 3f61cfeace69..36575f4159d1 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -145,6 +145,16 @@ static void snd_ff_remove(struct fw_unit *unit)
fw_unit_put(ff->unit);
}
+static const struct snd_ff_spec spec_ff800 = {
+ .name = "Fireface800",
+ .pcm_capture_channels = {28, 20, 12},
+ .pcm_playback_channels = {28, 20, 12},
+ .midi_in_ports = 1,
+ .midi_out_ports = 1,
+ .protocol = &snd_ff_protocol_ff800,
+ .midi_high_addr = 0x000200000320ull,
+};
+
static const struct snd_ff_spec spec_ff400 = {
.name = "Fireface400",
.pcm_capture_channels = {18, 14, 10},
@@ -152,9 +162,22 @@ static const struct snd_ff_spec spec_ff400 = {
.midi_in_ports = 2,
.midi_out_ports = 2,
.protocol = &snd_ff_protocol_ff400,
+ .midi_high_addr = 0x0000801003f4ull,
};
static const struct ieee1394_device_id snd_ff_id_table[] = {
+ /* Fireface 800 */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_RME,
+ .specifier_id = OUI_RME,
+ .version = 0x000001,
+ .model_id = 0x101800,
+ .driver_data = (kernel_ulong_t)&spec_ff800,
+ },
/* Fireface 400 */
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
@@ -162,7 +185,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
IEEE1394_MATCH_VERSION |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = OUI_RME,
- .specifier_id = 0x000a35,
+ .specifier_id = OUI_RME,
.version = 0x000002,
.model_id = 0x101800,
.driver_data = (kernel_ulong_t)&spec_ff400,
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 64df44beb950..7dfc7745a914 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -31,23 +31,34 @@
#include "../amdtp-stream.h"
#include "../iso-resources.h"
-#define SND_FF_STREAM_MODES 3
-
#define SND_FF_MAXIMIM_MIDI_QUADS 9
#define SND_FF_IN_MIDI_PORTS 2
#define SND_FF_OUT_MIDI_PORTS 2
+#define SND_FF_REG_SYNC_STATUS 0x0000801c0000ull
+/* For block write request. */
+#define SND_FF_REG_FETCH_PCM_FRAMES 0x0000801c0000ull
+#define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull
+
+enum snd_ff_stream_mode {
+ SND_FF_STREAM_MODE_LOW = 0,
+ SND_FF_STREAM_MODE_MID,
+ SND_FF_STREAM_MODE_HIGH,
+ SND_FF_STREAM_MODE_COUNT,
+};
+
struct snd_ff_protocol;
struct snd_ff_spec {
const char *const name;
- const unsigned int pcm_capture_channels[SND_FF_STREAM_MODES];
- const unsigned int pcm_playback_channels[SND_FF_STREAM_MODES];
+ const unsigned int pcm_capture_channels[SND_FF_STREAM_MODE_COUNT];
+ const unsigned int pcm_playback_channels[SND_FF_STREAM_MODE_COUNT];
unsigned int midi_in_ports;
unsigned int midi_out_ports;
const struct snd_ff_protocol *protocol;
+ u64 midi_high_addr;
};
struct snd_ff {
@@ -89,31 +100,24 @@ struct snd_ff {
enum snd_ff_clock_src {
SND_FF_CLOCK_SRC_INTERNAL,
SND_FF_CLOCK_SRC_SPDIF,
- SND_FF_CLOCK_SRC_ADAT,
+ SND_FF_CLOCK_SRC_ADAT1,
+ SND_FF_CLOCK_SRC_ADAT2,
SND_FF_CLOCK_SRC_WORD,
SND_FF_CLOCK_SRC_LTC,
- /* TODO: perhaps ADAT2 and TCO exists. */
+ /* TODO: perhaps TCO exists. */
};
struct snd_ff_protocol {
- int (*get_clock)(struct snd_ff *ff, unsigned int *rate,
- enum snd_ff_clock_src *src);
+ void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
int (*begin_session)(struct snd_ff *ff, unsigned int rate);
void (*finish_session)(struct snd_ff *ff);
- int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
-
- void (*dump_sync_status)(struct snd_ff *ff,
- struct snd_info_buffer *buffer);
- void (*dump_clock_config)(struct snd_ff *ff,
- struct snd_info_buffer *buffer);
-
- u64 midi_high_addr_reg;
- u64 midi_rx_port_0_reg;
- u64 midi_rx_port_1_reg;
};
+extern const struct snd_ff_protocol snd_ff_protocol_ff800;
extern const struct snd_ff_protocol snd_ff_protocol_ff400;
+int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
+ enum snd_ff_clock_src *src);
int snd_ff_transaction_register(struct snd_ff *ff);
int snd_ff_transaction_reregister(struct snd_ff *ff);
void snd_ff_transaction_unregister(struct snd_ff *ff);
@@ -125,6 +129,8 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s,
int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir);
+int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
+ enum snd_ff_stream_mode *mode);
int snd_ff_stream_init_duplex(struct snd_ff *ff);
void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index afb78d90384b..3d27f3378d5d 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -20,6 +20,7 @@
#define VENDOR_LACIE 0x00d04b
#define VENDOR_TASCAM 0x00022e
#define OUI_STANTON 0x001260
+#define OUI_APOGEE 0x0003db
#define MODEL_SATELLITE 0x00200f
@@ -397,6 +398,13 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
.vendor_id = OUI_STANTON,
.model_id = 0x002000,
},
+ // APOGEE, duet FireWire
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_APOGEE,
+ .model_id = 0x01dddd,
+ },
{ }
};
MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c
index ab482423c165..a52d1f76c610 100644
--- a/sound/firewire/tascam/amdtp-tascam.c
+++ b/sound/firewire/tascam/amdtp-tascam.c
@@ -117,6 +117,55 @@ int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
return amdtp_stream_add_pcm_hw_constraints(s, runtime);
}
+static void read_status_messages(struct amdtp_stream *s,
+ __be32 *buffer, unsigned int data_blocks)
+{
+ struct snd_tscm *tscm = container_of(s, struct snd_tscm, tx_stream);
+ bool used = READ_ONCE(tscm->hwdep->used);
+ int i;
+
+ for (i = 0; i < data_blocks; i++) {
+ unsigned int index;
+ __be32 before;
+ __be32 after;
+
+ index = be32_to_cpu(buffer[0]) % SNDRV_FIREWIRE_TASCAM_STATE_COUNT;
+ before = tscm->state[index];
+ after = buffer[s->data_block_quadlets - 1];
+
+ if (used && index > 4 && index < 16) {
+ __be32 mask;
+
+ if (index == 5)
+ mask = cpu_to_be32(~0x0000ffff);
+ else if (index == 6)
+ mask = cpu_to_be32(~0x0000ffff);
+ else if (index == 8)
+ mask = cpu_to_be32(~0x000f0f00);
+ else
+ mask = cpu_to_be32(~0x00000000);
+
+ if ((before ^ after) & mask) {
+ struct snd_firewire_tascam_change *entry =
+ &tscm->queue[tscm->push_pos];
+
+ spin_lock_irq(&tscm->lock);
+ entry->index = index;
+ entry->before = before;
+ entry->after = after;
+ if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
+ tscm->push_pos = 0;
+ spin_unlock_irq(&tscm->lock);
+
+ wake_up(&tscm->hwdep_wait);
+ }
+ }
+
+ tscm->state[index] = after;
+ buffer += s->data_block_quadlets;
+ }
+}
+
static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
__be32 *buffer,
unsigned int data_blocks,
@@ -128,7 +177,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
if (data_blocks > 0 && pcm)
read_pcm_s32(s, pcm, buffer, data_blocks);
- /* A place holder for control messages. */
+ read_status_messages(s, buffer, data_blocks);
return data_blocks;
}
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 4e4c1e9020e8..0414abf5daa8 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -16,18 +16,93 @@
#include "tascam.h"
+static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
+ long count, loff_t *offset)
+{
+ struct snd_firewire_event_lock_status event = {
+ .type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
+ };
+
+ event.status = (tscm->dev_lock_count > 0);
+ tscm->dev_lock_changed = false;
+ count = min_t(long, count, sizeof(event));
+
+ spin_unlock_irq(&tscm->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
+ long remained, loff_t *offset)
+{
+ char __user *pos = buf;
+ unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
+ struct snd_firewire_tascam_change *entries = tscm->queue;
+ long count;
+
+ // At least, one control event can be copied.
+ if (remained < sizeof(type) + sizeof(*entries)) {
+ spin_unlock_irq(&tscm->lock);
+ return -EINVAL;
+ }
+
+ // Copy the type field later.
+ count = sizeof(type);
+ remained -= sizeof(type);
+ pos += sizeof(type);
+
+ while (true) {
+ unsigned int head_pos;
+ unsigned int tail_pos;
+ unsigned int length;
+
+ if (tscm->pull_pos == tscm->push_pos)
+ break;
+ else if (tscm->pull_pos < tscm->push_pos)
+ tail_pos = tscm->push_pos;
+ else
+ tail_pos = SND_TSCM_QUEUE_COUNT;
+ head_pos = tscm->pull_pos;
+
+ length = (tail_pos - head_pos) * sizeof(*entries);
+ if (remained < length)
+ length = rounddown(remained, sizeof(*entries));
+ if (length == 0)
+ break;
+
+ spin_unlock_irq(&tscm->lock);
+ if (copy_to_user(pos, &entries[head_pos], length))
+ return -EFAULT;
+
+ spin_lock_irq(&tscm->lock);
+
+ tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;
+
+ count += length;
+ remained -= length;
+ pos += length;
+ }
+
+ spin_unlock_irq(&tscm->lock);
+
+ if (copy_to_user(buf, &type, sizeof(type)))
+ return -EFAULT;
+
+ return count;
+}
+
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
loff_t *offset)
{
struct snd_tscm *tscm = hwdep->private_data;
DEFINE_WAIT(wait);
- union snd_firewire_event event = {
- .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
- };
spin_lock_irq(&tscm->lock);
- while (!tscm->dev_lock_changed) {
+ while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) {
prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
spin_unlock_irq(&tscm->lock);
schedule();
@@ -37,15 +112,15 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
spin_lock_irq(&tscm->lock);
}
- event.lock_status.status = (tscm->dev_lock_count > 0);
- tscm->dev_lock_changed = false;
-
- spin_unlock_irq(&tscm->lock);
-
- count = min_t(long, count, sizeof(event.lock_status));
-
- if (copy_to_user(buf, &event, count))
- return -EFAULT;
+ // NOTE: The acquired lock should be released in callee side.
+ if (tscm->dev_lock_changed) {
+ count = tscm_hwdep_read_locked(tscm, buf, count, offset);
+ } else if (tscm->push_pos != tscm->pull_pos) {
+ count = tscm_hwdep_read_queue(tscm, buf, count, offset);
+ } else {
+ spin_unlock_irq(&tscm->lock);
+ count = 0;
+ }
return count;
}
@@ -59,7 +134,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_wait(file, &tscm->hwdep_wait, wait);
spin_lock_irq(&tscm->lock);
- if (tscm->dev_lock_changed)
+ if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
events = EPOLLIN | EPOLLRDNORM;
else
events = 0;
@@ -123,6 +198,14 @@ static int hwdep_unlock(struct snd_tscm *tscm)
return err;
}
+static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg)
+{
+ if (copy_to_user(arg, tscm->state, sizeof(tscm->state)))
+ return -EFAULT;
+
+ return 0;
+}
+
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_tscm *tscm = hwdep->private_data;
@@ -147,6 +230,8 @@ static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
return hwdep_lock(tscm);
case SNDRV_FIREWIRE_IOCTL_UNLOCK:
return hwdep_unlock(tscm);
+ case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE:
+ return tscm_hwdep_state(tscm, (void __user *)arg);
default:
return -ENOIOCTLCMD;
}
@@ -185,5 +270,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
hwdep->private_data = tscm;
hwdep->exclusive = true;
+ tscm->hwdep = hwdep;
+
return err;
}
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index a5bd167eb5d9..6a411ee0dcf1 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -62,6 +62,8 @@ struct snd_fw_async_midi_port {
int consume_bytes;
};
+#define SND_TSCM_QUEUE_COUNT 16
+
struct snd_tscm {
struct snd_card *card;
struct fw_unit *unit;
@@ -89,6 +91,13 @@ struct snd_tscm {
/* For MIDI message outgoing transactions. */
struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
+
+ // A cache of status information in tx isoc packets.
+ __be32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
+ struct snd_hwdep *hwdep;
+ struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT];
+ unsigned int pull_pos;
+ unsigned int push_pos;
};
#define TSCM_ADDR_BASE 0xffff00000000ull
diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c
index 714a51721a31..012305177f68 100644
--- a/sound/hda/hdac_bus.c
+++ b/sound/hda/hdac_bus.c
@@ -9,8 +9,6 @@
#include <sound/hdaudio.h>
#include "trace.h"
-static void process_unsol_events(struct work_struct *work);
-
static const struct hdac_bus_ops default_ops = {
.command = snd_hdac_bus_send_cmd,
.get_response = snd_hdac_bus_get_response,
@@ -37,7 +35,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
bus->io_ops = io_ops;
INIT_LIST_HEAD(&bus->stream_list);
INIT_LIST_HEAD(&bus->codec_list);
- INIT_WORK(&bus->unsol_work, process_unsol_events);
+ INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
spin_lock_init(&bus->reg_lock);
mutex_init(&bus->cmd_mutex);
bus->irq = -1;
@@ -148,7 +146,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event);
/*
* process queued unsolicited events
*/
-static void process_unsol_events(struct work_struct *work)
+void snd_hdac_bus_process_unsol_events(struct work_struct *work)
{
struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work);
struct hdac_device *codec;
@@ -171,6 +169,7 @@ static void process_unsol_events(struct work_struct *work)
drv->unsol_event(codec, res);
}
}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events);
/**
* snd_hdac_bus_add_device - Add a codec to bus
diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c
index 6e46a9c73aed..a6d37b9d6413 100644
--- a/sound/hda/hdac_component.c
+++ b/sound/hda/hdac_component.c
@@ -54,41 +54,44 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
/**
* snd_hdac_display_power - Power up / down the power refcount
* @bus: HDA core bus
+ * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller
* @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 is used by either HD-audio controller or codec driver that
+ * needs the interaction with graphics driver.
*
- * This function manages a refcount and calls the get_power() and
+ * This function updates the power status, 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)
+void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, 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)
+ set_bit(idx, &bus->display_power_status);
+ else
+ clear_bit(idx, &bus->display_power_status);
- if (enable) {
- if (!bus->drm_power_refcount++) {
+ if (!acomp || !acomp->ops)
+ return;
+
+ if (bus->display_power_status) {
+ if (!bus->display_power_active) {
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);
+ bus->display_power_active = true;
}
} else {
- WARN_ON(!bus->drm_power_refcount);
- if (!--bus->drm_power_refcount)
+ if (bus->display_power_active) {
if (acomp->ops->put_power)
acomp->ops->put_power(acomp->dev);
+ bus->display_power_active = false;
+ }
}
-
- return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
@@ -321,10 +324,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus)
if (!acomp)
return 0;
- WARN_ON(bus->drm_power_refcount);
- if (bus->drm_power_refcount > 0 && acomp->ops)
+ if (WARN_ON(bus->display_power_active) && acomp->ops)
acomp->ops->put_power(acomp->dev);
+ bus->display_power_active = false;
+ bus->display_power_status = 0;
+
component_master_del(dev, &hdac_component_master_ops);
bus->audio_component = NULL;
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index dbf02a3a8d2f..95b073ee4b32 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec)
EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
#endif
-/**
- * snd_hdac_link_power - Enable/disable the link power for a codec
- * @codec: the codec object
- * @bool: enable or disable the link power
- */
-int snd_hdac_link_power(struct hdac_device *codec, bool enable)
-{
- if (!codec->link_power_control)
- return 0;
-
- if (codec->bus->ops->link_power)
- return codec->bus->ops->link_power(codec->bus, enable);
- else
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_link_power);
-
/* codec vendor labels */
struct hda_vendor_id {
unsigned int id;
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index a31fe1550903..aad74e809797 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1183,7 +1183,7 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
u32 h_stream)
{
- struct hpi_format hpi_format;
+ struct hpi_format hpi_format;
u16 format;
u16 err;
u32 h_control;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 6ebe817801ea..1f25e6d029d8 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -36,6 +36,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/moduleparam.h>
+#include <linux/nospec.h>
#include <sound/core.h>
#include <sound/tlv.h>
@@ -1026,6 +1027,8 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
return -EINVAL;
+ ipcm->substream = array_index_nospec(ipcm->substream,
+ EMU10K1_FX8010_PCM_COUNT);
if (ipcm->channels > 32)
return -EINVAL;
pcm = &emu->fx8010.pcm[ipcm->substream];
@@ -1072,6 +1075,8 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
return -EINVAL;
+ ipcm->substream = array_index_nospec(ipcm->substream,
+ EMU10K1_FX8010_PCM_COUNT);
pcm = &emu->fx8010.pcm[ipcm->substream];
mutex_lock(&emu->fx8010.lock);
spin_lock_irq(&emu->reg_lock);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 4235907b7858..0d38c006e182 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -226,6 +226,68 @@ config SND_HDA_POWER_SAVE_DEFAULT
The default time-out value in seconds for HD-audio automatic
power-save mode. 0 means to disable the power-save mode.
+if SND_HDA_INTEL
+
+# The options below should not be enabled by distributions or
+# users. They are selected by Intel/Skylake or SOF drivers when they
+# register for a PCI ID which is also handled by the HDAudio legacy
+# driver. When this option is selected and the DSP is detected based on
+# the PCI class/subclass/prog-if, the probe of the HDAudio legacy
+# aborts. This mechanism removes the need for distributions to use
+# blacklists. It can be bypassed with module parameters should the
+# Intel/Skylake or SOF drivers fail to handle a specific platform.
+
+config SND_HDA_INTEL_DSP_DETECTION_SKL
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ Skylake machines.
+
+config SND_HDA_INTEL_DSP_DETECTION_APL
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ Broxton/ApolloLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_KBL
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ KabyLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_GLK
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ GeminiLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_CNL
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ CannonLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_CFL
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ CoffeeLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_ICL
+ bool
+ help
+ This option is selected by SOF or SST drivers, not users or distros.
+ It enables DSP detection based on PCI class information for
+ IceLake machines
+
+endif ## SND_HDA_INTEL
+
endif
endmenu
diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c
deleted file mode 100644
index bbd6c87a4ed6..000000000000
--- a/sound/pci/hda/dell_wmi_helper.c
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Helper functions for Dell Mic Mute LED control;
- * to be included from codec driver
- */
-
-#if IS_ENABLED(CONFIG_DELL_LAPTOP)
-#include <linux/dell-led.h>
-
-static int (*dell_micmute_led_set_func)(int);
-
-static void dell_micmute_update(struct hda_codec *codec)
-{
- struct hda_gen_spec *spec = codec->spec;
-
- dell_micmute_led_set_func(spec->micmute_led.led_value);
-}
-
-static void alc_fixup_dell_wmi(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- bool removefunc = false;
-
- if (action == HDA_FIXUP_ACT_PROBE) {
- if (!dell_micmute_led_set_func)
- dell_micmute_led_set_func = symbol_request(dell_micmute_led_set);
- if (!dell_micmute_led_set_func) {
- codec_warn(codec, "Failed to find dell wmi symbol dell_micmute_led_set\n");
- return;
- }
-
- removefunc = (dell_micmute_led_set_func(false) < 0) ||
- (snd_hda_gen_add_micmute_led(codec,
- dell_micmute_update) < 0);
- }
-
- if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
- symbol_put(dell_micmute_led_set);
- dell_micmute_led_set_func = NULL;
- }
-}
-
-#else /* CONFIG_DELL_LAPTOP */
-static void alc_fixup_dell_wmi(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
-}
-
-#endif /* CONFIG_DELL_LAPTOP */
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 0957813939e5..9f8d59e7e89f 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -36,6 +36,7 @@
#include "hda_beep.h"
#include "hda_jack.h"
#include <sound/hda_hwdep.h>
+#include <sound/hda_component.h>
#define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core)
#define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core)
@@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state);
+/* enable/disable display power per codec */
+static void codec_display_power(struct hda_codec *codec, bool enable)
+{
+ if (codec->display_power_control)
+ snd_hdac_display_power(&codec->bus->core, codec->addr, enable);
+}
+
/* also called from hda_bind.c */
void snd_hda_codec_register(struct hda_codec *codec)
{
@@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
return;
if (device_is_registered(hda_codec_dev(codec))) {
snd_hda_register_beep_device(codec);
- snd_hdac_link_power(&codec->core, true);
+ codec_display_power(codec, true);
pm_runtime_enable(hda_codec_dev(codec));
/* it was powered up in snd_hda_codec_new(), now all done */
snd_hda_power_down(codec);
@@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
codec->in_freeing = 1;
snd_hdac_device_unregister(&codec->core);
- snd_hdac_link_power(&codec->core, false);
+ codec_display_power(codec, false);
put_device(hda_codec_dev(codec));
return 0;
}
@@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
(codec_has_clkstop(codec) && codec_has_epss(codec) &&
(state & AC_PWRST_CLK_STOP_OK)))
snd_hdac_codec_link_down(&codec->core);
- snd_hdac_link_power(&codec->core, false);
+ codec_display_power(codec, false);
return 0;
}
@@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
- snd_hdac_link_power(&codec->core, true);
+ codec_display_power(codec, true);
snd_hdac_codec_link_up(&codec->core);
hda_call_codec_resume(codec);
pm_runtime_mark_last_busy(dev);
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index fe2506672a72..532e081f8b8a 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -989,20 +989,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,
return azx_rirb_get_response(bus, addr, res);
}
-static int azx_link_power(struct hdac_bus *bus, bool enable)
-{
- struct azx *chip = bus_to_azx(bus);
-
- if (chip->ops->link_power)
- return chip->ops->link_power(chip, enable);
- else
- return -EINVAL;
-}
-
static const struct hdac_bus_ops bus_core_ops = {
.command = azx_send_cmd,
.get_response = azx_get_response,
- .link_power = azx_link_power,
};
#ifdef CONFIG_SND_HDA_DSP_LOADER
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index c95097bb5a0c..e0c3fcbaa028 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -37,7 +37,7 @@
#else
#define AZX_DCAPS_I915_COMPONENT 0 /* NOP */
#endif
-/* 14 unused */
+#define AZX_DCAPS_INTEL_SHARED (1 << 14) /* shared with ASoC */
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
/* 17 unused */
@@ -50,11 +50,7 @@
/* 24 unused */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
-#ifdef CONFIG_SND_HDA_I915
-#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */
-#else
-#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */
-#endif
+/* 27 unused */
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 276150f29cda..4095cd7c56c6 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -29,6 +29,7 @@
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/module.h>
+#include <linux/leds.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/tlv.h>
@@ -4035,6 +4036,36 @@ int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
+#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
+static void call_ledtrig_micmute(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ ledtrig_audio_set(LED_AUDIO_MICMUTE,
+ spec->micmute_led.led_value ? LED_ON : LED_OFF);
+}
+#endif
+
+/**
+ * snd_hda_gen_fixup_micmute_led - A fixup for mic-mute LED trigger
+ *
+ * Pass this function to the quirk entry if another driver supports the
+ * audio mic-mute LED trigger. Then this will bind the mixer capture switch
+ * change with the LED.
+ *
+ * Note that this fixup has to be called after other fixup that sets
+ * cap_sync_hook. Otherwise the chaining wouldn't work.
+ */
+void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
+ if (action == HDA_FIXUP_ACT_PROBE)
+ snd_hda_gen_add_micmute_led(codec, call_ledtrig_micmute);
+#endif
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_fixup_micmute_led);
+
/*
* parse digital I/Os and set up NIDs in BIOS auto-parse mode
*/
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 10123664fa61..78d77042b05a 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -357,5 +357,7 @@ int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
void (*hook)(struct hda_codec *));
+void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 76f03abd15ab..e42cc2230977 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -172,6 +172,9 @@ module_param_array(beep_mode, bool, NULL, 0444);
MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
"(0=off, 1=on) (default=1).");
#endif
+static int skl_pci_binding;
+module_param_named(pci_binding, skl_pci_binding, int, 0444);
+MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
#ifdef CONFIG_PM
static int param_set_xint(const char *val, const struct kernel_param *kp);
@@ -310,31 +313,28 @@ enum {
#define AZX_DCAPS_INTEL_HASWELL \
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
- AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH))
+ AZX_DCAPS_SNOOP_TYPE(SCH))
/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
#define AZX_DCAPS_INTEL_BROADWELL \
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
- AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH))
+ AZX_DCAPS_SNOOP_TYPE(SCH))
#define AZX_DCAPS_INTEL_BAYTRAIL \
- (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\
- AZX_DCAPS_I915_POWERWELL)
+ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
#define AZX_DCAPS_INTEL_BRASWELL \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
- AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL)
+ AZX_DCAPS_I915_COMPONENT)
#define AZX_DCAPS_INTEL_SKYLAKE \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
- AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\
- AZX_DCAPS_I915_POWERWELL)
+ AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
#define AZX_DCAPS_INTEL_BROXTON \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
- AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\
- AZX_DCAPS_I915_POWERWELL)
+ AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
@@ -360,6 +360,7 @@ enum {
AZX_DCAPS_NO_64BIT |\
AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
+#define AZX_DCAPS_INTEL_DSP_DETECTION(conf) (IS_ENABLED(CONFIG_SND_HDA_INTEL_DSP_DETECTION_##conf) ? AZX_DCAPS_INTEL_SHARED : 0)
/*
* vga_switcheroo support
*/
@@ -591,8 +592,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
struct pci_dev *pci = chip->pci;
u32 val;
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- snd_hdac_set_codec_wakeup(bus, true);
+ snd_hdac_set_codec_wakeup(bus, true);
if (chip->driver_type == AZX_DRIVER_SKL) {
pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
@@ -604,8 +604,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
val = val | INTEL_HDA_CGCTL_MISCBDCGE;
pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
}
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- snd_hdac_set_codec_wakeup(bus, false);
+
+ snd_hdac_set_codec_wakeup(bus, false);
/* reduce dma latency to avoid noise */
if (IS_BXT(pci))
@@ -667,13 +667,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
return 0;
}
-/* Enable/disable i915 display power for the link */
-static int azx_intel_link_power(struct azx *chip, bool enable)
-{
- struct hdac_bus *bus = azx_bus(chip);
-
- return snd_hdac_display_power(bus, enable);
-}
+#define display_power(chip, enable) \
+ snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable)
/*
* Check whether the current DMA position is acceptable for updating
@@ -930,35 +925,75 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
mutex_unlock(&card_list_lock);
return 0;
}
-#else
-#define azx_add_card_list(chip) /* NOP */
-#define azx_del_card_list(chip) /* NOP */
-#endif /* CONFIG_PM */
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
-static int azx_suspend(struct device *dev)
+static bool azx_is_pm_ready(struct snd_card *card)
{
- struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
struct hda_intel *hda;
- struct hdac_bus *bus;
if (!card)
- return 0;
-
+ return false;
chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip);
if (chip->disabled || hda->init_failed || !chip->running)
+ return false;
+ return true;
+}
+
+static void __azx_runtime_suspend(struct azx *chip)
+{
+ azx_stop_chip(chip);
+ azx_enter_link_reset(chip);
+ azx_clear_irq_pending(chip);
+ display_power(chip, false);
+}
+
+static void __azx_runtime_resume(struct azx *chip)
+{
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hdac_bus *bus = azx_bus(chip);
+ struct hda_codec *codec;
+ int status;
+
+ display_power(chip, true);
+ if (hda->need_i915_power)
+ snd_hdac_i915_set_bclk(bus);
+
+ /* Read STATESTS before controller reset */
+ status = azx_readw(chip, STATESTS);
+
+ azx_init_pci(chip);
+ hda_intel_init_chip(chip, true);
+
+ if (status) {
+ list_for_each_codec(codec, &chip->bus)
+ if (status & (1 << codec->addr))
+ schedule_delayed_work(&codec->jackpoll_work,
+ codec->jackpoll_interval);
+ }
+
+ /* power down again for link-controlled chips */
+ if (!hda->need_i915_power)
+ display_power(chip, false);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int azx_suspend(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip;
+ struct hdac_bus *bus;
+
+ if (!azx_is_pm_ready(card))
return 0;
+ chip = card->private_data;
bus = azx_bus(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- azx_clear_irq_pending(chip);
- azx_stop_chip(chip);
- azx_enter_link_reset(chip);
+ __azx_runtime_suspend(chip);
if (bus->irq >= 0) {
free_irq(bus->irq, chip);
bus->irq = -1;
@@ -966,9 +1001,6 @@ static int azx_suspend(struct device *dev)
if (chip->msi)
pci_disable_msi(chip->pci);
- if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- && hda->need_i915_power)
- snd_hdac_display_power(bus, false);
trace_azx_suspend(chip);
return 0;
@@ -976,41 +1008,19 @@ static int azx_suspend(struct device *dev)
static int azx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
- struct hda_intel *hda;
- struct hdac_bus *bus;
- if (!card)
+ if (!azx_is_pm_ready(card))
return 0;
chip = card->private_data;
- hda = container_of(chip, struct hda_intel, chip);
- bus = azx_bus(chip);
- if (chip->disabled || hda->init_failed || !chip->running)
- return 0;
-
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- snd_hdac_display_power(bus, true);
- if (hda->need_i915_power)
- snd_hdac_i915_set_bclk(bus);
- }
-
if (chip->msi)
- if (pci_enable_msi(pci) < 0)
+ if (pci_enable_msi(chip->pci) < 0)
chip->msi = 0;
if (azx_acquire_irq(chip, 1) < 0)
return -EIO;
- azx_init_pci(chip);
-
- hda_intel_init_chip(chip, true);
-
- /* power down again for link-controlled chips */
- if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
- !hda->need_i915_power)
- snd_hdac_display_power(bus, false);
-
+ __azx_runtime_resume(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
trace_azx_resume(chip);
@@ -1045,21 +1055,14 @@ static int azx_thaw_noirq(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM
static int azx_runtime_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
- struct hda_intel *hda;
- if (!card)
+ if (!azx_is_pm_ready(card))
return 0;
-
chip = card->private_data;
- hda = container_of(chip, struct hda_intel, chip);
- if (chip->disabled || hda->init_failed)
- return 0;
-
if (!azx_has_pm_runtime(chip))
return 0;
@@ -1067,13 +1070,7 @@ static int azx_runtime_suspend(struct device *dev)
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
STATESTS_INT_MASK);
- azx_stop_chip(chip);
- azx_enter_link_reset(chip);
- azx_clear_irq_pending(chip);
- if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- && hda->need_i915_power)
- snd_hdac_display_power(azx_bus(chip), false);
-
+ __azx_runtime_suspend(chip);
trace_azx_runtime_suspend(chip);
return 0;
}
@@ -1082,51 +1079,18 @@ static int azx_runtime_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
- struct hda_intel *hda;
- struct hdac_bus *bus;
- struct hda_codec *codec;
- int status;
- if (!card)
+ if (!azx_is_pm_ready(card))
return 0;
-
chip = card->private_data;
- hda = container_of(chip, struct hda_intel, chip);
- bus = azx_bus(chip);
- if (chip->disabled || hda->init_failed)
- return 0;
-
if (!azx_has_pm_runtime(chip))
return 0;
-
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- snd_hdac_display_power(bus, true);
- if (hda->need_i915_power)
- snd_hdac_i915_set_bclk(bus);
- }
-
- /* Read STATESTS before controller reset */
- status = azx_readw(chip, STATESTS);
-
- azx_init_pci(chip);
- hda_intel_init_chip(chip, true);
-
- if (status) {
- list_for_each_codec(codec, &chip->bus)
- if (status & (1 << codec->addr))
- schedule_delayed_work(&codec->jackpoll_work,
- codec->jackpoll_interval);
- }
+ __azx_runtime_resume(chip);
/* disable controller Wake Up event*/
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
~STATESTS_INT_MASK);
- /* power down again for link-controlled chips */
- if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
- !hda->need_i915_power)
- snd_hdac_display_power(bus, false);
-
trace_azx_runtime_resume(chip);
return 0;
}
@@ -1167,6 +1131,8 @@ static const struct dev_pm_ops azx_pm = {
#define AZX_PM_OPS &azx_pm
#else
+#define azx_add_card_list(chip) /* NOP */
+#define azx_del_card_list(chip) /* NOP */
#define AZX_PM_OPS NULL
#endif /* CONFIG_PM */
@@ -1374,11 +1340,8 @@ static int azx_free(struct azx *chip)
#ifdef CONFIG_SND_HDA_PATCH_LOADER
release_firmware(chip->fw);
#endif
+ display_power(chip, false);
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- if (hda->need_i915_power)
- snd_hdac_display_power(bus, false);
- }
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
snd_hdac_i915_exit(bus);
kfree(hda);
@@ -1935,8 +1898,7 @@ static int azx_first_init(struct azx *chip)
/* initialize chip */
azx_init_pci(chip);
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- snd_hdac_i915_set_bclk(bus);
+ snd_hdac_i915_set_bclk(bus);
hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0);
@@ -2078,7 +2040,6 @@ static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq,
.pcm_mmap_prepare = pcm_mmap_prepare,
.position_check = azx_position_check,
- .link_power = azx_intel_link_power,
};
static int azx_probe(struct pci_dev *pci,
@@ -2091,6 +2052,28 @@ static int azx_probe(struct pci_dev *pci,
bool schedule_probe;
int err;
+ /* check if this driver can be used on SKL+ Intel platforms */
+ if (pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) {
+ switch (skl_pci_binding) {
+ case SND_SKL_PCI_BIND_AUTO:
+ if (pci->class != 0x040300) {
+ dev_info(&pci->dev, "The DSP is enabled on this platform, aborting probe\n");
+ return -ENODEV;
+ }
+ dev_info(&pci->dev, "No DSP detected, continuing HDaudio legacy probe\n");
+ break;
+ case SND_SKL_PCI_BIND_LEGACY:
+ dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, bypassed detection logic\n");
+ break;
+ case SND_SKL_PCI_BIND_ASOC:
+ dev_info(&pci->dev, "Module parameter forced binding with SKL+ ASoC driver, aborting probe\n");
+ return -ENODEV;
+ default:
+ dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
+ break;
+ }
+ }
+
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
@@ -2245,10 +2228,13 @@ static int azx_probe_continue(struct azx *chip)
goto out_free;
} else {
/* don't bother any longer */
- chip->driver_caps &=
- ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL);
+ chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
}
}
+
+ /* HSW/BDW controllers need this power */
+ if (CONTROLLER_IN_GPU(pci))
+ hda->need_i915_power = 1;
}
/* Request display power well for the HDA controller or codec. For
@@ -2256,18 +2242,7 @@ static int azx_probe_continue(struct azx *chip)
* this power. For other platforms, like Baytrail/Braswell, only the
* display codec needs the power and it can be released after probe.
*/
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- /* HSW/BDW controllers need this power */
- if (CONTROLLER_IN_GPU(pci))
- hda->need_i915_power = 1;
-
- err = snd_hdac_display_power(bus, true);
- if (err < 0) {
- dev_err(chip->card->dev,
- "Cannot turn on display power on i915\n");
- goto i915_power_fail;
- }
- }
+ display_power(chip, true);
err = azx_first_init(chip);
if (err < 0)
@@ -2315,11 +2290,8 @@ static int azx_probe_continue(struct azx *chip)
pm_runtime_put_autosuspend(&pci->dev);
out_free:
- if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- && !hda->need_i915_power)
- snd_hdac_display_power(bus, false);
-
-i915_power_fail:
+ if (err < 0 || !hda->need_i915_power)
+ display_power(chip, false);
if (err < 0)
hda->init_failed = 1;
complete_all(&hda->probe_wait);
@@ -2408,34 +2380,48 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+ AZX_DCAPS_INTEL_DSP_DETECTION(SKL)
+ },
/* Kabylake */
{ PCI_DEVICE(0x8086, 0xa171),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
/* Kabylake-LP */
{ PCI_DEVICE(0x8086, 0x9d71),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+ AZX_DCAPS_INTEL_DSP_DETECTION(KBL)
+ },
/* Kabylake-H */
{ PCI_DEVICE(0x8086, 0xa2f0),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
/* Coffelake */
{ PCI_DEVICE(0x8086, 0xa348),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+ AZX_DCAPS_INTEL_DSP_DETECTION(CFL)
+ },
/* Cannonlake */
{ PCI_DEVICE(0x8086, 0x9dc8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+ AZX_DCAPS_INTEL_DSP_DETECTION(CNL)
+ },
/* Icelake */
{ PCI_DEVICE(0x8086, 0x34c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+ AZX_DCAPS_INTEL_DSP_DETECTION(ICL)
+ },
/* Broxton-P(Apollolake) */
{ PCI_DEVICE(0x8086, 0x5a98),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON |
+ AZX_DCAPS_INTEL_DSP_DETECTION(APL)
+ },
/* Broxton-T */
{ PCI_DEVICE(0x8086, 0x1a98),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
/* Gemini-Lake */
{ PCI_DEVICE(0x8086, 0x3198),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON |
+ AZX_DCAPS_INTEL_DSP_DETECTION(GLK)
+ },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index c499727920e6..74b46952fc98 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -339,9 +339,15 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
if (jack->nid) {
if (!jack->jack || jack->block_report)
continue;
- state = get_jack_plug_state(jack->pin_sense);
- snd_jack_report(jack->jack,
- state ? jack->type : 0);
+ state = jack->button_state;
+ if (get_jack_plug_state(jack->pin_sense))
+ state |= jack->type;
+ snd_jack_report(jack->jack, state);
+ if (jack->button_state) {
+ snd_jack_report(jack->jack,
+ state & ~jack->button_state);
+ jack->button_state = 0; /* button released */
+ }
}
}
EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync);
@@ -379,15 +385,19 @@ static void hda_free_jack_priv(struct snd_jack *jack)
* @nid: pin NID to assign
* @name: string name for the jack
* @phantom_jack: flag to deal as a phantom jack
+ * @type: jack type bits to be reported, 0 for guessing from pincfg
+ * @keymap: optional jack / key mapping
*
* This assigns a jack-detection kctl to the given pin. The kcontrol
* will have the given name and index.
*/
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
- const char *name, bool phantom_jack)
+ const char *name, bool phantom_jack,
+ int type, const struct hda_jack_keymap *keymap)
{
struct hda_jack_tbl *jack;
- int err, state, type;
+ const struct hda_jack_keymap *map;
+ int err, state, buttons;
jack = snd_hda_jack_tbl_new(codec, nid);
if (!jack)
@@ -395,16 +405,30 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
if (jack->jack)
return 0; /* already created */
- type = get_input_jack_type(codec, nid);
- err = snd_jack_new(codec->card, name, type,
+ if (!type)
+ type = get_input_jack_type(codec, nid);
+
+ buttons = 0;
+ if (keymap) {
+ for (map = keymap; map->type; map++)
+ buttons |= map->type;
+ }
+
+ err = snd_jack_new(codec->card, name, type | buttons,
&jack->jack, true, phantom_jack);
if (err < 0)
return err;
jack->phantom_jack = !!phantom_jack;
jack->type = type;
+ jack->button_state = 0;
jack->jack->private_data = jack;
jack->jack->private_free = hda_free_jack_priv;
+ if (keymap) {
+ for (map = keymap; map->type; map++)
+ snd_jack_set_key(jack->jack, map->type, map->key);
+ }
+
state = snd_hda_jack_detect(codec, nid);
snd_jack_report(jack->jack, state ? jack->type : 0);
@@ -437,7 +461,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
if (phantom_jack)
/* Example final name: "Internal Mic Phantom Jack" */
strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
- err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
+ err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL);
if (err < 0)
return err;
@@ -508,19 +532,25 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls);
-static void call_jack_callback(struct hda_codec *codec,
+static void call_jack_callback(struct hda_codec *codec, unsigned int res,
struct hda_jack_tbl *jack)
{
struct hda_jack_callback *cb;
- for (cb = jack->callback; cb; cb = cb->next)
+ for (cb = jack->callback; cb; cb = cb->next) {
+ cb->jack = jack;
+ cb->unsol_res = res;
cb->func(codec, cb);
+ }
if (jack->gated_jack) {
struct hda_jack_tbl *gated =
snd_hda_jack_tbl_get(codec, jack->gated_jack);
if (gated) {
- for (cb = gated->callback; cb; cb = cb->next)
+ for (cb = gated->callback; cb; cb = cb->next) {
+ cb->jack = gated;
+ cb->unsol_res = res;
cb->func(codec, cb);
+ }
}
}
}
@@ -540,7 +570,7 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
return;
event->jack_dirty = 1;
- call_jack_callback(codec, event);
+ call_jack_callback(codec, res, event);
snd_hda_jack_report_sync(codec);
}
EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event);
@@ -566,7 +596,7 @@ void snd_hda_jack_poll_all(struct hda_codec *codec)
if (old_sense == get_jack_plug_state(jack->pin_sense))
continue;
changes = 1;
- call_jack_callback(codec, jack);
+ call_jack_callback(codec, 0, jack);
}
if (changes)
snd_hda_jack_report_sync(codec);
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index e9814c0168ea..1d713201c160 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -13,6 +13,7 @@
#define __SOUND_HDA_JACK_H
#include <linux/err.h>
+#include <sound/jack.h>
struct auto_pin_cfg;
struct hda_jack_tbl;
@@ -24,6 +25,8 @@ struct hda_jack_callback {
hda_nid_t nid;
hda_jack_callback_fn func;
unsigned int private_data; /* arbitrary data */
+ unsigned int unsol_res; /* unsolicited event bits */
+ struct hda_jack_tbl *jack; /* associated jack entry */
struct hda_jack_callback *next;
};
@@ -40,9 +43,15 @@ struct hda_jack_tbl {
hda_nid_t gating_jack; /* valid when gating jack plugged */
hda_nid_t gated_jack; /* gated is dependent on this jack */
int type;
+ int button_state;
struct snd_jack *jack;
};
+struct hda_jack_keymap {
+ enum snd_jack_types type;
+ int key;
+};
+
struct hda_jack_tbl *
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
struct hda_jack_tbl *
@@ -82,7 +91,8 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
- const char *name, bool phantom_jack);
+ const char *name, bool phantom_jack,
+ int type, const struct hda_jack_keymap *keymap);
int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg);
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index dd7d4242d6d2..83befd8d43e8 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -31,6 +31,7 @@
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <sound/initval.h>
@@ -344,6 +345,8 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
int err;
unsigned short gcap;
int irq_id = platform_get_irq(pdev, 0);
+ const char *sname;
+ struct device_node *root;
err = hda_tegra_init_chip(chip, pdev);
if (err)
@@ -401,8 +404,23 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
return -ENODEV;
}
+ /* driver name */
strcpy(card->driver, "tegra-hda");
- strcpy(card->shortname, "tegra-hda");
+
+ root = of_find_node_by_path("/");
+ sname = of_get_property(root, "compatible", NULL);
+ of_node_put(root);
+ if (!sname) {
+ dev_err(card->dev,
+ "failed to get compatible property from root node\n");
+ return -ENODEV;
+ }
+ /* shortname for card */
+ if (strlen(sname) > sizeof(card->shortname))
+ dev_info(card->dev, "truncating shortname for card\n");
+ strncpy(card->shortname, sname, sizeof(card->shortname));
+
+ /* longname for card */
snprintf(card->longname, sizeof(card->longname),
"%s at 0x%lx irq %i",
card->shortname, bus->addr, bus->irq);
@@ -513,7 +531,7 @@ static void hda_tegra_probe_work(struct work_struct *work)
goto out_free;
/* create codec instances */
- err = azx_probe_codecs(chip, 0);
+ err = azx_probe_codecs(chip, 8);
if (err < 0)
goto out_free;
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 0a567634e5fa..e5bdbc245682 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1081,6 +1081,18 @@ enum {
QUIRK_AE5,
};
+#ifdef CONFIG_PCI
+#define ca0132_quirk(spec) ((spec)->quirk)
+#define ca0132_use_pci_mmio(spec) ((spec)->use_pci_mmio)
+#define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions)
+#define ca0132_use_alt_controls(spec) ((spec)->use_alt_controls)
+#else
+#define ca0132_quirk(spec) ({ (void)(spec); QUIRK_NONE; })
+#define ca0132_use_alt_functions(spec) ({ (void)(spec); false; })
+#define ca0132_use_pci_mmio(spec) ({ (void)(spec); false; })
+#define ca0132_use_alt_controls(spec) ({ (void)(spec); false; })
+#endif
+
static const struct hda_pintbl alienware_pincfgs[] = {
{ 0x0b, 0x90170110 }, /* Builtin Speaker */
{ 0x0c, 0x411111f0 }, /* N/A */
@@ -3101,7 +3113,7 @@ static void dspload_post_setup(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
codec_dbg(codec, "---- dspload_post_setup ------\n");
- if (!spec->use_alt_functions) {
+ if (!ca0132_use_alt_functions(spec)) {
/*set DSP speaker to 2.0 configuration*/
chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000);
@@ -3333,7 +3345,7 @@ static void ca0132_gpio_init(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_AE5:
snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
@@ -3344,6 +3356,8 @@ static void ca0132_gpio_init(struct hda_codec *codec)
snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B);
break;
+ default:
+ break;
}
}
@@ -3353,7 +3367,7 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DIRECTION, 0x07);
@@ -3372,6 +3386,8 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, 0x0C);
break;
+ default:
+ break;
}
}
@@ -4172,7 +4188,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
switch (spec->cur_out_type) {
case SPEAKER_OUT:
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
ca0113_mmio_gpio_set(codec, 7, false);
ca0113_mmio_gpio_set(codec, 4, true);
@@ -4203,10 +4219,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
chipio_set_control_param(codec, 0x0d, 0xa4);
chipio_write(codec, 0x18b03c, 0x00000012);
break;
+ default:
+ break;
}
break;
case HEADPHONE_OUT:
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
ca0113_mmio_gpio_set(codec, 7, true);
ca0113_mmio_gpio_set(codec, 4, true);
@@ -4238,10 +4256,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
chipio_set_control_param(codec, 0x0d, 0xa1);
chipio_write(codec, 0x18b03c, 0x00000012);
break;
+ default:
+ break;
}
break;
case SURROUND_OUT:
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
ca0113_mmio_gpio_set(codec, 7, false);
ca0113_mmio_gpio_set(codec, 4, true);
@@ -4272,6 +4292,8 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
chipio_set_control_param(codec, 0x0d, 0xa4);
chipio_write(codec, 0x18b03c, 0x00000012);
break;
+ default:
+ break;
}
break;
}
@@ -4446,7 +4468,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
struct hda_jack_tbl *jack;
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(spec->codec);
else
ca0132_select_out(spec->codec);
@@ -4530,14 +4552,14 @@ static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
if (spec->in_enum_val == REAR_LINE_IN)
tmp = FLOAT_ZERO;
else {
- if (spec->quirk == QUIRK_SBZ)
+ if (ca0132_quirk(spec) == QUIRK_SBZ)
tmp = FLOAT_THREE;
else
tmp = FLOAT_ONE;
@@ -4549,7 +4571,7 @@ static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
codec_dbg(codec, "%s: on.", __func__);
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
chipio_set_conn_rate(codec, 0x0F, SR_16_000);
if (spec->effects_switch[VOICE_FOCUS - EFFECT_START_NID])
@@ -4645,7 +4667,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
switch (spec->cur_mic_type) {
case REAR_MIC:
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_R3D:
ca0113_mmio_gpio_set(codec, 0, false);
@@ -4669,14 +4691,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
chipio_write(codec, 0x18B098, 0x0000000C);
chipio_write(codec, 0x18B09C, 0x0000000C);
@@ -4689,12 +4711,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_write(codec, 0x18B098, 0x0000000C);
chipio_write(codec, 0x18B09C, 0x0000004C);
break;
+ default:
+ break;
}
ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
break;
case REAR_LINE_IN:
ca0132_mic_boost_set(codec, 0);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_R3D:
ca0113_mmio_gpio_set(codec, 0, false);
@@ -4705,28 +4729,32 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
case QUIRK_AE5:
ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
break;
+ default:
+ break;
}
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
tmp = FLOAT_ZERO;
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_AE5:
chipio_write(codec, 0x18B098, 0x00000000);
chipio_write(codec, 0x18B09C, 0x00000000);
break;
+ default:
+ break;
}
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
break;
case FRONT_MIC:
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_R3D:
ca0113_mmio_gpio_set(codec, 0, true);
@@ -4748,7 +4776,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
@@ -4756,7 +4784,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
chipio_write(codec, 0x18B098, 0x0000000C);
chipio_write(codec, 0x18B09C, 0x000000CC);
@@ -4765,6 +4793,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_write(codec, 0x18B098, 0x0000000C);
chipio_write(codec, 0x18B09C, 0x0000004C);
break;
+ default:
+ break;
}
ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
break;
@@ -4859,7 +4889,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
val = 0;
/* If Voice Focus on SBZ, set to two channel. */
- if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio)
+ if ((nid == VOICE_FOCUS) && ca0132_use_pci_mmio(spec)
&& (spec->cur_mic_type != REAR_LINE_IN)) {
if (spec->effects_switch[CRYSTAL_VOICE -
EFFECT_START_NID]) {
@@ -4878,7 +4908,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
* For SBZ noise reduction, there's an extra command
* to module ID 0x47. No clue why.
*/
- if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio)
+ if ((nid == NOISE_REDUCTION) && ca0132_use_pci_mmio(spec)
&& (spec->cur_mic_type != REAR_LINE_IN)) {
if (spec->effects_switch[CRYSTAL_VOICE -
EFFECT_START_NID]) {
@@ -4894,7 +4924,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
}
/* If rear line in disable effects. */
- if (spec->use_alt_functions &&
+ if (ca0132_use_alt_functions(spec) &&
spec->in_enum_val == REAR_LINE_IN)
val = 0;
}
@@ -4924,7 +4954,7 @@ static int ca0132_pe_switch_set(struct hda_codec *codec)
codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec);
i = OUT_EFFECT_START_NID - EFFECT_START_NID;
@@ -4984,7 +5014,7 @@ static int ca0132_cvoice_switch_set(struct hda_codec *codec)
/* set correct vipsource */
oldval = stop_mic1(codec);
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ret |= ca0132_alt_set_vipsource(codec, 1);
else
ret |= ca0132_set_vipsource(codec, 1);
@@ -5053,7 +5083,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
auto_jack =
spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
if (!auto_jack) {
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec);
else
ca0132_select_out(codec);
@@ -5070,7 +5100,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
}
if (nid == VNID_HP_ASEL) {
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_select_out(codec);
else
ca0132_select_out(codec);
@@ -5784,7 +5814,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
/* mic boost */
if (nid == spec->input_pins[0]) {
spec->cur_mic_boost = *valp;
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
if (spec->in_enum_val != REAR_LINE_IN)
changed = ca0132_mic_boost_set(codec, *valp);
} else {
@@ -6080,7 +6110,7 @@ static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
/* If using alt_controls, add FX: prefix. But, don't add FX:
* prefix to OutFX or InFX enable controls.
*/
- if ((spec->use_alt_controls) && (nid <= IN_EFFECT_END_NID))
+ if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
else
sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
@@ -6357,7 +6387,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
return err;
}
/* Setup vmaster with surround slaves for desktop ca0132 devices */
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
spec->tlv);
snd_hda_add_vmaster(codec, "Master Playback Volume",
@@ -6377,7 +6407,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
for (i = 0; i < num_fx; i++) {
/* Desktop cards break if Echo Cancellation is used. */
- if (spec->use_pci_mmio) {
+ if (ca0132_use_pci_mmio(spec)) {
if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
OUT_EFFECTS_COUNT))
continue;
@@ -6394,7 +6424,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
* EQ presets, and Smart Volume presets. Also, change names to add FX
* prefix, and change PlayEnhancement and CrystalVoice to match.
*/
- if (spec->use_alt_controls) {
+ if (ca0132_use_alt_controls(spec)) {
err = ca0132_alt_add_svm_enum(codec);
if (err < 0)
return err;
@@ -6448,7 +6478,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
* to select the new outputs and inputs, plus add the new mic boost
* setting control.
*/
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
err = ca0132_alt_add_output_enum(codec);
if (err < 0)
return err;
@@ -6459,14 +6489,14 @@ static int ca0132_build_controls(struct hda_codec *codec)
* ZxR only has microphone input, there is no front panel
* header on the card, and aux-in is handled by the DBPro board.
*/
- if (spec->quirk != QUIRK_ZXR) {
+ if (ca0132_quirk(spec) != QUIRK_ZXR) {
err = ca0132_alt_add_input_enum(codec);
if (err < 0)
return err;
}
}
- if (spec->quirk == QUIRK_AE5) {
+ if (ca0132_quirk(spec) == QUIRK_AE5) {
err = ae5_add_headphone_gain_enum(codec);
if (err < 0)
return err;
@@ -6475,7 +6505,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
return err;
}
- if (spec->quirk == QUIRK_ZXR) {
+ if (ca0132_quirk(spec) == QUIRK_ZXR) {
err = zxr_add_headphone_gain_switch(codec);
if (err < 0)
return err;
@@ -6505,7 +6535,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
return err;
}
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_add_chmap_ctls(codec);
return 0;
@@ -6583,7 +6613,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
if (!info)
return -ENOMEM;
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
info->own_chmap = true;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap
= ca0132_alt_chmaps;
@@ -6597,7 +6627,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
/* With the DSP enabled, desktops don't use this ADC. */
- if (!spec->use_alt_functions) {
+ if (!ca0132_use_alt_functions(spec)) {
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
if (!info)
return -ENOMEM;
@@ -6795,7 +6825,7 @@ static void ca0132_init_dmic(struct hda_codec *codec)
* Bit 6: set to select Data2, clear for Data1
* Bit 7: set to enable DMic, clear for AMic
*/
- if (spec->quirk == QUIRK_ALIENWARE_M17XR4)
+ if (ca0132_quirk(spec) == QUIRK_ALIENWARE_M17XR4)
val = 0x33;
else
val = 0x23;
@@ -6877,7 +6907,7 @@ static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
/* Mic 1 Setup */
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- if (spec->quirk == QUIRK_R3DI) {
+ if (ca0132_quirk(spec) == QUIRK_R3DI) {
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
tmp = FLOAT_ONE;
} else
@@ -6887,7 +6917,7 @@ static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
/* Mic 2 setup (not present on desktop cards) */
chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
tmp = FLOAT_ZERO;
dspio_set_uint_param(codec, 0x80, 0x01, tmp);
@@ -6949,7 +6979,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
chipio_set_stream_channels(codec, 0x0C, 6);
chipio_set_stream_control(codec, 0x0C, 1);
/* No clue what these control */
- if (spec->quirk == QUIRK_SBZ) {
+ if (ca0132_quirk(spec) == QUIRK_SBZ) {
chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
@@ -6962,7 +6992,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
- } else if (spec->quirk == QUIRK_ZXR) {
+ } else if (ca0132_quirk(spec) == QUIRK_ZXR) {
chipio_write_no_mutex(codec, 0x190038, 0x000140c2);
chipio_write_no_mutex(codec, 0x19003c, 0x000141c3);
chipio_write_no_mutex(codec, 0x190040, 0x000150c4);
@@ -6992,7 +7022,7 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
* why this is, but multiple tests have confirmed it.
*/
for (i = 0; i < 2; i++) {
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_AE5:
tmp = 0x00000003;
@@ -7021,6 +7051,8 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
tmp = 0x00000000;
dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
break;
+ default:
+ break;
}
msleep(100);
}
@@ -7043,7 +7075,7 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
chipio_write(codec, 0x18b098, 0x0000000c);
chipio_write(codec, 0x18b09C, 0x0000000c);
@@ -7052,6 +7084,8 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
chipio_write(codec, 0x18b098, 0x0000000c);
chipio_write(codec, 0x18b09c, 0x0000004c);
break;
+ default:
+ break;
}
}
@@ -7273,7 +7307,7 @@ static void r3d_setup_defaults(struct hda_codec *codec)
/* Set speaker source? */
dspio_set_uint_param(codec, 0x32, 0x00, tmp);
- if (spec->quirk == QUIRK_R3DI)
+ if (ca0132_quirk(spec) == QUIRK_R3DI)
r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
/* Setup effect defaults */
@@ -7420,7 +7454,7 @@ static void ca0132_init_flags(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, 1);
chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, 1);
chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, 1);
@@ -7453,7 +7487,7 @@ static void ca0132_init_params(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
chipio_set_conn_rate(codec, 0x0B, SR_48_000);
chipio_set_control_param(codec, CONTROL_PARAM_SPDIF1_SOURCE, 0);
@@ -7490,7 +7524,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
* can use the default firmware, but I'll leave the option in case
* it needs it again.
*/
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_R3D:
case QUIRK_AE5:
@@ -7564,7 +7598,7 @@ static void ca0132_download_dsp(struct hda_codec *codec)
}
/* For codecs using alt functions, this is already done earlier */
- if (spec->dsp_state == DSP_DOWNLOADED && (!spec->use_alt_functions))
+ if (spec->dsp_state == DSP_DOWNLOADED && !ca0132_use_alt_functions(spec))
ca0132_set_dsp_msr(codec, true);
}
@@ -7601,7 +7635,7 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
{
struct ca0132_spec *spec = codec->spec;
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_select_in(codec);
else
ca0132_select_mic(codec);
@@ -7616,7 +7650,7 @@ static void ca0132_init_unsol(struct hda_codec *codec)
snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
ca0132_process_dsp_response);
/* Front headphone jack detection */
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
snd_hda_jack_detect_enable_callback(codec,
spec->unsol_tag_front_hp, hp_callback);
}
@@ -7706,7 +7740,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
mutex_init(&spec->chipio_mutex);
spec->cur_out_type = SPEAKER_OUT;
- if (!spec->use_alt_functions)
+ if (!ca0132_use_alt_functions(spec))
spec->cur_mic_type = DIGITAL_MIC;
else
spec->cur_mic_type = REAR_MIC;
@@ -7732,7 +7766,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
* Sets defaults for the effect slider controls, only for alternative
* ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
*/
- if (spec->use_alt_controls) {
+ if (ca0132_use_alt_controls(spec)) {
spec->xbass_xover_freq = 8;
for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
spec->fx_ctl_val[i] = effect_slider_defaults[i];
@@ -7747,7 +7781,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
* the daughter board. So, there is no input enum control, and we need
* to make sure that spec->in_enum_val is set properly.
*/
- if (spec->quirk == QUIRK_ZXR)
+ if (ca0132_quirk(spec) == QUIRK_ZXR)
spec->in_enum_val = REAR_MIC;
#ifdef ENABLE_TUNING_CONTROLS
@@ -8088,27 +8122,27 @@ static void ca0132_mmio_init(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00000001, spec->mem_base + 0x400);
else
writel(0x00000000, spec->mem_base + 0x400);
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00000001, spec->mem_base + 0x408);
else
writel(0x00000000, spec->mem_base + 0x408);
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00000001, spec->mem_base + 0x40c);
else
writel(0x00000000, spec->mem_base + 0x40C);
- if (spec->quirk == QUIRK_ZXR)
+ if (ca0132_quirk(spec) == QUIRK_ZXR)
writel(0x00880640, spec->mem_base + 0x01C);
else
writel(0x00880680, spec->mem_base + 0x01C);
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00000080, spec->mem_base + 0xC0C);
else
writel(0x00000083, spec->mem_base + 0xC0C);
@@ -8116,7 +8150,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
writel(0x00000030, spec->mem_base + 0xC00);
writel(0x00000000, spec->mem_base + 0xC04);
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00000000, spec->mem_base + 0xC0C);
else
writel(0x00000003, spec->mem_base + 0xC0C);
@@ -8125,7 +8159,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
writel(0x00000003, spec->mem_base + 0xC0C);
writel(0x00000003, spec->mem_base + 0xC0C);
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
writel(0x00000001, spec->mem_base + 0xC08);
else
writel(0x000000C1, spec->mem_base + 0xC08);
@@ -8136,7 +8170,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
writel(0x000000C1, spec->mem_base + 0xC08);
writel(0x00000080, spec->mem_base + 0xC04);
- if (spec->quirk == QUIRK_AE5) {
+ if (ca0132_quirk(spec) == QUIRK_AE5) {
writel(0x00000000, spec->mem_base + 0x42c);
writel(0x00000000, spec->mem_base + 0x46c);
writel(0x00000000, spec->mem_base + 0x4ac);
@@ -8211,7 +8245,7 @@ static void ca0132_alt_init(struct hda_codec *codec)
ca0132_alt_vol_setup(codec);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
codec_dbg(codec, "SBZ alt_init");
ca0132_gpio_init(codec);
@@ -8248,6 +8282,8 @@ static void ca0132_alt_init(struct hda_codec *codec)
snd_hda_sequence_write(codec, spec->chip_init_verbs);
snd_hda_sequence_write(codec, spec->desktop_init_verbs);
break;
+ default:
+ break;
}
}
@@ -8274,7 +8310,7 @@ static int ca0132_init(struct hda_codec *codec)
spec->dsp_reload = true;
spec->dsp_state = DSP_DOWNLOAD_INIT;
} else {
- if (spec->quirk == QUIRK_SBZ)
+ if (ca0132_quirk(spec) == QUIRK_SBZ)
sbz_dsp_startup_check(codec);
return 0;
}
@@ -8284,12 +8320,12 @@ static int ca0132_init(struct hda_codec *codec)
spec->dsp_state = DSP_DOWNLOAD_INIT;
spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
- if (spec->use_pci_mmio)
+ if (ca0132_use_pci_mmio(spec))
ca0132_mmio_init(codec);
snd_hda_power_up_pm(codec);
- if (spec->quirk == QUIRK_AE5)
+ if (ca0132_quirk(spec) == QUIRK_AE5)
ae5_register_set(codec);
ca0132_init_unsol(codec);
@@ -8298,14 +8334,14 @@ static int ca0132_init(struct hda_codec *codec)
snd_hda_sequence_write(codec, spec->base_init_verbs);
- if (spec->use_alt_functions)
+ if (ca0132_use_alt_functions(spec))
ca0132_alt_init(codec);
ca0132_download_dsp(codec);
ca0132_refresh_widget_caps(codec);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_R3DI:
case QUIRK_R3D:
r3d_setup_defaults(codec);
@@ -8334,7 +8370,7 @@ static int ca0132_init(struct hda_codec *codec)
init_input(codec, cfg->dig_in_pin, spec->dig_in);
- if (!spec->use_alt_functions) {
+ if (!ca0132_use_alt_functions(spec)) {
snd_hda_sequence_write(codec, spec->chip_init_verbs);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D);
@@ -8342,11 +8378,11 @@ static int ca0132_init(struct hda_codec *codec)
VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20);
}
- if (spec->quirk == QUIRK_SBZ)
+ if (ca0132_quirk(spec) == QUIRK_SBZ)
ca0132_gpio_setup(codec);
snd_hda_sequence_write(codec, spec->spec_init_verbs);
- if (spec->use_alt_functions) {
+ if (ca0132_use_alt_functions(spec)) {
ca0132_alt_select_out(codec);
ca0132_alt_select_in(codec);
} else {
@@ -8391,7 +8427,7 @@ static void ca0132_free(struct hda_codec *codec)
cancel_delayed_work_sync(&spec->unsol_hp_work);
snd_hda_power_up(codec);
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
sbz_exit_chip(codec);
break;
@@ -8407,13 +8443,15 @@ static void ca0132_free(struct hda_codec *codec)
case QUIRK_R3DI:
r3di_gpio_shutdown(codec);
break;
+ default:
+ break;
}
snd_hda_sequence_write(codec, spec->base_exit_verbs);
ca0132_exit_chip(codec);
snd_hda_power_down(codec);
- if (spec->mem_base)
+ if (IS_ENABLED(CONFIG_PCI) && spec->mem_base)
pci_iounmap(codec->bus->pci, spec->mem_base);
kfree(spec->spec_init_verbs);
kfree(codec->spec);
@@ -8461,12 +8499,12 @@ static void ca0132_config(struct hda_codec *codec)
spec->multiout.dac_nids = spec->dacs;
spec->multiout.num_dacs = 3;
- if (!spec->use_alt_functions)
+ if (!ca0132_use_alt_functions(spec))
spec->multiout.max_channels = 2;
else
spec->multiout.max_channels = 6;
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_ALIENWARE:
codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
snd_hda_apply_pincfgs(codec, alienware_pincfgs);
@@ -8491,9 +8529,11 @@ static void ca0132_config(struct hda_codec *codec)
codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
snd_hda_apply_pincfgs(codec, ae5_pincfgs);
break;
+ default:
+ break;
}
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_ALIENWARE:
spec->num_outputs = 2;
spec->out_pins[0] = 0x0b; /* speaker out */
@@ -8654,7 +8694,7 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
* Since desktop cards use pci_mmio, this can be used to determine
* whether or not to use these verbs instead of a separate bool.
*/
- if (spec->use_pci_mmio)
+ if (ca0132_use_pci_mmio(spec))
spec->desktop_init_verbs = ca0132_init_verbs1;
spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
sizeof(struct hda_verb),
@@ -8729,11 +8769,10 @@ static int patch_ca0132(struct hda_codec *codec)
spec->quirk = quirk->value;
else
spec->quirk = QUIRK_NONE;
-
- if (spec->quirk == QUIRK_SBZ)
+ if (ca0132_quirk(spec) == QUIRK_SBZ)
sbz_detect_quirk(codec);
- if (spec->quirk == QUIRK_ZXR_DBPRO)
+ if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
codec->patch_ops = dbpro_patch_ops;
else
codec->patch_ops = ca0132_patch_ops;
@@ -8746,7 +8785,7 @@ static int patch_ca0132(struct hda_codec *codec)
spec->num_mixers = 1;
/* Set which mixers each quirk uses. */
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
spec->mixers[0] = desktop_mixer;
snd_hda_codec_set_name(codec, "Sound Blaster Z");
@@ -8775,7 +8814,7 @@ static int patch_ca0132(struct hda_codec *codec)
}
/* Setup whether or not to use alt functions/controls/pci_mmio */
- switch (spec->quirk) {
+ switch (ca0132_quirk(spec)) {
case QUIRK_SBZ:
case QUIRK_R3D:
case QUIRK_AE5:
@@ -8796,6 +8835,7 @@ static int patch_ca0132(struct hda_codec *codec)
break;
}
+#ifdef CONFIG_PCI
if (spec->use_pci_mmio) {
spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
if (spec->mem_base == NULL) {
@@ -8803,6 +8843,7 @@ static int patch_ca0132(struct hda_codec *codec)
spec->quirk = QUIRK_NONE;
}
}
+#endif
spec->base_init_verbs = ca0132_base_init_verbs;
spec->base_exit_verbs = ca0132_base_exit_verbs;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 950e02e71766..51cc6589443f 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -923,6 +923,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
+ SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 67099cbb6be2..46f88dc7b7e8 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -2142,7 +2142,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
strncat(hdmi_str, " Phantom",
sizeof(hdmi_str) - strlen(hdmi_str) - 1);
ret = snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str,
- phantom_jack);
+ phantom_jack, 0, NULL);
if (ret < 0)
return ret;
jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
@@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid)
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
- /* For Haswell/Broadwell, the controller is also in the power well and
- * can cover the codec power request, and so need not set this flag.
- */
- if (!is_haswell(codec) && !is_broadwell(codec))
- codec->core.link_power_control = 1;
+ codec->display_power_control = 1;
codec->patch_ops.set_power_state = haswell_set_power_state;
codec->depop_delay = 0;
@@ -2656,7 +2652,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
/* For Valleyview/Cherryview, only the display codec is in the display
* power well and can use link_power ops to request/release the power.
*/
- codec->core.link_power_control = 1;
+ codec->display_power_control = 1;
codec->depop_delay = 0;
codec->auto_runtime_pm = 1;
@@ -3834,6 +3830,10 @@ HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 15021c839372..a4f4a9dd488d 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5380,6 +5380,66 @@ static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
snd_hda_override_wcaps(codec, 0x03, 0);
}
+static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
+ { SND_JACK_BTN_0, KEY_PLAYPAUSE },
+ { SND_JACK_BTN_1, KEY_VOICECOMMAND },
+ { SND_JACK_BTN_2, KEY_VOLUMEUP },
+ { SND_JACK_BTN_3, KEY_VOLUMEDOWN },
+ {}
+};
+
+static void alc_headset_btn_callback(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ int report = 0;
+
+ if (jack->unsol_res & (7 << 13))
+ report |= SND_JACK_BTN_0;
+
+ if (jack->unsol_res & (1 << 16 | 3 << 8))
+ report |= SND_JACK_BTN_1;
+
+ /* Volume up key */
+ if (jack->unsol_res & (7 << 23))
+ report |= SND_JACK_BTN_2;
+
+ /* Volume down key */
+ if (jack->unsol_res & (7 << 10))
+ report |= SND_JACK_BTN_3;
+
+ jack->jack->button_state = report;
+}
+
+static void alc_fixup_headset_jack(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_jack_detect_enable_callback(codec, 0x55,
+ alc_headset_btn_callback);
+ snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
+ SND_JACK_HEADSET, alc_headset_btn_keymap);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ switch (codec->core.vendor_id) {
+ case 0x10ec0225:
+ case 0x10ec0295:
+ case 0x10ec0299:
+ alc_write_coef_idx(codec, 0x48, 0xd011);
+ alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+ alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
+ break;
+ case 0x10ec0236:
+ case 0x10ec0256:
+ alc_write_coef_idx(codec, 0x48, 0xd011);
+ alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+ break;
+ }
+ break;
+ }
+}
+
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
@@ -5390,9 +5450,6 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
hda_fixup_thinkpad_acpi(codec, fix, action);
}
-/* for dell wmi mic mute led */
-#include "dell_wmi_helper.c"
-
/* for alc295_fixup_hp_top_speakers */
#include "hp_x360_helper.c"
@@ -5470,7 +5527,7 @@ enum {
ALC292_FIXUP_TPT440_DOCK,
ALC292_FIXUP_TPT440,
ALC283_FIXUP_HEADSET_MIC,
- ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
+ ALC255_FIXUP_MIC_MUTE_LED,
ALC282_FIXUP_ASPIRE_V5_PINS,
ALC280_FIXUP_HP_GPIO4,
ALC286_FIXUP_HP_GPIO_LED,
@@ -5515,6 +5572,7 @@ enum {
ALC298_FIXUP_TPT470_DOCK,
ALC255_FIXUP_DUMMY_LINEOUT_VERB,
ALC255_FIXUP_DELL_HEADSET_MIC,
+ ALC256_FIXUP_HUAWEI_MBXP_PINS,
ALC295_FIXUP_HP_X360,
ALC221_FIXUP_HP_HEADSET_MIC,
ALC285_FIXUP_LENOVO_HEADPHONE_NOISE,
@@ -5523,6 +5581,7 @@ enum {
ALC294_FIXUP_ASUS_MIC,
ALC294_FIXUP_ASUS_HEADSET_MIC,
ALC294_FIXUP_ASUS_SPK,
+ ALC225_FIXUP_HEADSET_JACK,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -5770,7 +5829,7 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode,
.chained = true,
- .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+ .chain_id = ALC255_FIXUP_MIC_MUTE_LED
},
[ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
.type = HDA_FIXUP_FUNC,
@@ -5794,6 +5853,24 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MIC
},
+ [ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x12, 0x90a60130},
+ {0x13, 0x40000000},
+ {0x14, 0x90170110},
+ {0x18, 0x411111f0},
+ {0x19, 0x04a11040},
+ {0x1a, 0x411111f0},
+ {0x1b, 0x90170112},
+ {0x1d, 0x40759a05},
+ {0x1e, 0x411111f0},
+ {0x21, 0x04211020},
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+ },
[ALC269_FIXUP_ASUS_X101_FUNC] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_x101_headset_mic,
@@ -5996,7 +6073,7 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_alc255,
.chained = true,
- .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+ .chain_id = ALC255_FIXUP_MIC_MUTE_LED
},
[ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
.type = HDA_FIXUP_FUNC,
@@ -6031,9 +6108,9 @@ static const struct hda_fixup alc269_fixups[] = {
{ },
},
},
- [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = {
+ [ALC255_FIXUP_MIC_MUTE_LED] = {
.type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_dell_wmi,
+ .v.func = snd_hda_gen_fixup_micmute_led,
},
[ALC282_FIXUP_ASPIRE_V5_PINS] = {
.type = HDA_FIXUP_PINS,
@@ -6092,7 +6169,7 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_dell_alc288,
.chained = true,
- .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+ .chain_id = ALC255_FIXUP_MIC_MUTE_LED
},
[ALC288_FIXUP_DELL1_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
@@ -6441,6 +6518,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
},
+ [ALC225_FIXUP_HEADSET_JACK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_jack,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6573,6 +6654,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -6680,6 +6762,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+ SND_PCI_QUIRK(0x19e5, 0x3200, "Huawei MBX", ALC255_FIXUP_MIC_MUTE_LED),
+ SND_PCI_QUIRK(0x19e5, 0x3201, "Huawei MBX", ALC255_FIXUP_MIC_MUTE_LED),
+ SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
#if 0
@@ -6805,7 +6890,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
{.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
{.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
- {.id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, .name = "alc255-dell-mute"},
+ {.id = ALC255_FIXUP_MIC_MUTE_LED, .name = "alc255-dell-mute"},
{.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
{.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
{.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
@@ -6844,6 +6929,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
{.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
{.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
+ {.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-sense-combo"},
{}
};
#define ALC225_STANDARD_PINS \
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
index 568575b72f2f..4089feb8c68e 100644
--- a/sound/pci/hda/thinkpad_helper.c
+++ b/sound/pci/hda/thinkpad_helper.c
@@ -3,12 +3,11 @@
* to be included from codec driver
*/
-#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
+#if IS_ENABLED(CONFIG_THINKPAD_ACPI) && IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
#include <linux/acpi.h>
-#include <linux/thinkpad_acpi.h>
+#include <linux/leds.h>
-static int (*led_set_func)(int, bool);
static void (*old_vmaster_hook)(void *, int);
static bool is_thinkpad(struct hda_codec *codec)
@@ -23,50 +22,20 @@ static void update_tpacpi_mute_led(void *private_data, int enabled)
if (old_vmaster_hook)
old_vmaster_hook(private_data, enabled);
- if (led_set_func)
- led_set_func(TPACPI_LED_MUTE, !enabled);
-}
-
-static void update_tpacpi_micmute(struct hda_codec *codec)
-{
- struct hda_gen_spec *spec = codec->spec;
-
- led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
+ ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
}
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct hda_gen_spec *spec = codec->spec;
- bool removefunc = false;
if (action == HDA_FIXUP_ACT_PROBE) {
if (!is_thinkpad(codec))
return;
- if (!led_set_func)
- led_set_func = symbol_request(tpacpi_led_set);
- if (!led_set_func) {
- codec_warn(codec,
- "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
- return;
- }
-
- removefunc = true;
- if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
- old_vmaster_hook = spec->vmaster_mute.hook;
- spec->vmaster_mute.hook = update_tpacpi_mute_led;
- removefunc = false;
- }
- if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
- !snd_hda_gen_add_micmute_led(codec,
- update_tpacpi_micmute))
- removefunc = false;
- }
-
- if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
- symbol_put(tpacpi_led_set);
- led_set_func = NULL;
- old_vmaster_hook = NULL;
+ old_vmaster_hook = spec->vmaster_mute.hook;
+ spec->vmaster_mute.hook = update_tpacpi_mute_led;
+ snd_hda_gen_fixup_micmute_led(codec, fix, action);
}
}
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 1bff4b1b39cd..ba99ff0e93e0 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -30,6 +30,7 @@
#include <linux/math64.h>
#include <linux/vmalloc.h>
#include <linux/io.h>
+#include <linux/nospec.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -4092,15 +4093,16 @@ static int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info *info)
{
struct hdsp *hdsp = snd_pcm_substream_chip(substream);
- int mapped_channel;
+ unsigned int channel = info->channel;
- if (snd_BUG_ON(info->channel >= hdsp->max_channels))
+ if (snd_BUG_ON(channel >= hdsp->max_channels))
return -EINVAL;
+ channel = array_index_nospec(channel, hdsp->max_channels);
- if ((mapped_channel = hdsp->channel_map[info->channel]) < 0)
+ if (hdsp->channel_map[channel] < 0)
return -EINVAL;
- info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES;
+ info->offset = hdsp->channel_map[channel] * HDSP_CHANNEL_BUFFER_BYTES;
info->first = 0;
info->step = 32;
return 0;
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 48dd44f8e914..d692e4070167 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -908,7 +908,7 @@ static void detect_byte_swap(struct snd_pmac *chip)
/* if seems that Keylargo can't byte-swap */
for (mio = chip->node->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0) {
+ if (of_node_name_eq(mio, "mac-io")) {
if (of_device_is_compatible(mio, "Keylargo"))
chip->can_byte_swap = 0;
break;
@@ -1313,7 +1313,7 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
} else if (chip->is_pbook_G3) {
struct device_node* mio;
for (mio = chip->node->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0) {
+ if (of_node_name_eq(mio, "mac-io")) {
struct resource r;
if (of_address_to_resource(mio, 0, &r) == 0)
chip->macio_base =
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 0779a2912237..6d7ffffcce95 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1365,8 +1365,8 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip)
mix->anded_reset = 0;
mix->reset_on_sleep = 1;
- for (np = chip->node->child; np; np = np->sibling) {
- if (!strcmp(np->name, "sound")) {
+ for_each_child_of_node(chip->node, np) {
+ if (of_node_name_eq(np, "sound")) {
if (of_get_property(np, "has-anded-reset", NULL))
mix->anded_reset = 1;
if (of_get_property(np, "layout-id", NULL))
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 1cf11cf51e1d..6592a422a047 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
source "sound/soc/cirrus/Kconfig"
-source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/hisilicon/Kconfig"
source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
-source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
@@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
+source "sound/soc/ti/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/uniphier/Kconfig"
source "sound/soc/ux500/Kconfig"
+source "sound/soc/xilinx/Kconfig"
source "sound/soc/xtensa/Kconfig"
source "sound/soc/zte/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 62a5f87c3cfc..48c48c1c893c 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += cirrus/
-obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += hisilicon/
@@ -41,7 +40,6 @@ 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/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
@@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/
obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
+obj-$(CONFIG_SND_SOC) += ti/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += uniphier/
obj-$(CONFIG_SND_SOC) += ux500/
+obj-$(CONFIG_SND_SOC) += xilinx/
obj-$(CONFIG_SND_SOC) += xtensa/
obj-$(CONFIG_SND_SOC) += zte/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 58c1dcb4d255..33ebec990c2f 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -19,3 +19,9 @@ config SND_SOC_AMD_CZ_RT5645_MACH
depends on SND_SOC_AMD_ACP && I2C
help
This option enables machine driver for rt5645.
+
+config SND_SOC_AMD_ACP3x
+ tristate "AMD Audio Coprocessor-v3.x support"
+ depends on X86 && PCI
+ help
+ This option enables ACP v3.x I2S support on AMD platform
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 79b0622fa5d3..8e1c571c3161 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -5,3 +5,4 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index 3f813ea5210a..a5daad973ce5 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -403,7 +403,7 @@ static struct regulator_config acp_da7219_cfg = {
static struct regulator_ops acp_da7219_ops = {
};
-static struct regulator_desc acp_da7219_desc = {
+static const struct regulator_desc acp_da7219_desc = {
.name = "reg-fixed-1.8V",
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index cdebab2f8ce5..f4011bebc7ec 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -303,11 +303,10 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
}
/* Create page table entries in ACP SRAM for the allocated memory */
-static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
+static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr,
u16 num_of_pages, u32 pte_offset)
{
u16 page_idx;
- u64 addr;
u32 low;
u32 high;
u32 offset;
@@ -317,7 +316,6 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
/* Load the low address of page int ACP SRAM through SRBM */
acp_reg_write((offset + (page_idx * 8)),
acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
- addr = page_to_phys(pg);
low = lower_32_bits(addr);
high = upper_32_bits(addr);
@@ -333,7 +331,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
/* Move to next physically contiguos page */
- pg++;
+ addr += PAGE_SIZE;
}
}
@@ -343,7 +341,7 @@ static void config_acp_dma(void __iomem *acp_mmio,
{
u16 ch_acp_sysmem, ch_acp_i2s;
- acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
+ acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages,
rtd->pte_offset);
if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -850,7 +848,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
int status;
uint64_t size;
u32 val = 0;
- struct page *pg;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -986,16 +983,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
- pg = virt_to_page(substream->dma_buffer.area);
- if (pg) {
+ if (substream->dma_buffer.area) {
acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
/* Save for runtime private data */
- rtd->pg = pg;
+ rtd->dma_addr = substream->dma_buffer.addr;
rtd->order = get_order(size);
/* Fill the page table entries in ACP SRAM */
- rtd->pg = pg;
rtd->size = size;
rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
rtd->direction = substream->stream;
@@ -1151,18 +1146,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
DRV_NAME);
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
+ struct device *parent = component->dev->parent;
switch (adata->asic_type) {
case CHIP_STONEY:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
- NULL, ST_MIN_BUFFER,
+ parent,
+ ST_MIN_BUFFER,
ST_MAX_BUFFER);
break;
default:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
- NULL, MIN_BUFFER,
+ parent,
+ MIN_BUFFER,
MAX_BUFFER);
break;
}
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index dbbb1a85638d..e5ab6c6040a6 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -123,7 +123,7 @@ enum acp_dma_priority_level {
};
struct audio_substream_data {
- struct page *pg;
+ dma_addr_t dma_addr;
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile
new file mode 100644
index 000000000000..108d1acf189b
--- /dev/null
+++ b/sound/soc/amd/raven/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Raven Ridge platform Support
+snd-pci-acp3x-objs := pci-acp3x.o
+snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
new file mode 100644
index 000000000000..022a8912c8a2
--- /dev/null
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// AMD ALSA SoC PCM Driver
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "acp3x.h"
+
+#define DRV_NAME "acp3x-i2s-audio"
+
+struct i2s_dev_data {
+ bool tdm_mode;
+ unsigned int i2s_irq;
+ u32 tdm_fmt;
+ void __iomem *acp3x_base;
+ struct snd_pcm_substream *play_stream;
+ struct snd_pcm_substream *capture_stream;
+};
+
+struct i2s_stream_instance {
+ u16 num_pages;
+ u16 channels;
+ u32 xfer_resolution;
+ struct page *pg;
+ void __iomem *acp3x_base;
+};
+
+static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
+
+static int acp3x_power_on(void __iomem *acp3x_base, bool on)
+{
+ u16 val, mask;
+ u32 timeout;
+
+ if (on == true) {
+ val = 1;
+ mask = ACP3x_POWER_ON;
+ } else {
+ val = 0;
+ mask = ACP3x_POWER_OFF;
+ }
+
+ rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL);
+ timeout = 0;
+ while (true) {
+ val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
+ if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask)
+ break;
+ if (timeout > 100) {
+ pr_err("ACP3x power state change failure\n");
+ return -ENODEV;
+ }
+ timeout++;
+ cpu_relax();
+ }
+ return 0;
+}
+
+static int acp3x_reset(void __iomem *acp3x_base)
+{
+ u32 val, timeout;
+
+ rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
+ timeout = 0;
+ while (true) {
+ val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+ if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) ||
+ timeout > 100) {
+ if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
+ break;
+ return -ENODEV;
+ }
+ timeout++;
+ cpu_relax();
+ }
+
+ rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
+ timeout = 0;
+ while (true) {
+ val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+ if (!val || timeout > 100) {
+ if (!val)
+ break;
+ return -ENODEV;
+ }
+ timeout++;
+ cpu_relax();
+ }
+ return 0;
+}
+
+static int acp3x_init(void __iomem *acp3x_base)
+{
+ int ret;
+
+ /* power on */
+ ret = acp3x_power_on(acp3x_base, true);
+ if (ret) {
+ pr_err("ACP3x power on failed\n");
+ return ret;
+ }
+ /* Reset */
+ ret = acp3x_reset(acp3x_base);
+ if (ret) {
+ pr_err("ACP3x reset failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int acp3x_deinit(void __iomem *acp3x_base)
+{
+ int ret;
+
+ /* Reset */
+ ret = acp3x_reset(acp3x_base);
+ if (ret) {
+ pr_err("ACP3x reset failed\n");
+ return ret;
+ }
+ /* power off */
+ ret = acp3x_power_on(acp3x_base, false);
+ if (ret) {
+ pr_err("ACP3x power off failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
+{
+ u16 play_flag, cap_flag;
+ u32 val;
+ struct i2s_dev_data *rv_i2s_data = dev_id;
+
+ if (!rv_i2s_data)
+ return IRQ_NONE;
+
+ play_flag = 0;
+ cap_flag = 0;
+ val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
+ if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) {
+ rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base +
+ mmACP_EXTERNAL_INTR_STAT);
+ snd_pcm_period_elapsed(rv_i2s_data->play_stream);
+ play_flag = 1;
+ }
+
+ if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) {
+ rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base +
+ mmACP_EXTERNAL_INTR_STAT);
+ snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
+ cap_flag = 1;
+ }
+
+ if (play_flag | cap_flag)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
+{
+ u16 page_idx;
+ u64 addr;
+ u32 low, high, val, acp_fifo_addr;
+ struct page *pg = rtd->pg;
+
+ /* 8 scratch registers used to map one 64 bit address */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ val = 0;
+ else
+ val = rtd->num_pages * 8;
+
+ /* Group Enable */
+ rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
+ mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
+ rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base +
+ mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
+
+ for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
+ /* Load the low address of page int ACP SRAM through SRBM */
+ addr = page_to_phys(pg);
+ low = lower_32_bits(addr);
+ high = upper_32_bits(addr);
+
+ rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val);
+ high |= BIT(31);
+ rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val
+ + 4);
+ /* Move to next physically contiguos page */
+ val += 8;
+ pg++;
+ }
+
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* Config ringbuffer */
+ rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
+ mmACP_BT_TX_RINGBUFADDR);
+ rv_writel(MAX_BUFFER, rtd->acp3x_base +
+ mmACP_BT_TX_RINGBUFSIZE);
+ rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
+
+ /* Config audio fifo */
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
+ + PLAYBACK_FIFO_ADDR_OFFSET;
+ rv_writel(acp_fifo_addr, rtd->acp3x_base +
+ mmACP_BT_TX_FIFOADDR);
+ rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
+ } else {
+ /* Config ringbuffer */
+ rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
+ mmACP_BT_RX_RINGBUFADDR);
+ rv_writel(MAX_BUFFER, rtd->acp3x_base +
+ mmACP_BT_RX_RINGBUFSIZE);
+ rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
+
+ /* Config audio fifo */
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+ (rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
+ rv_writel(acp_fifo_addr, rtd->acp3x_base +
+ mmACP_BT_RX_FIFOADDR);
+ rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
+ }
+
+ /* Enable watermark/period interrupt to host */
+ rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
+ rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
+}
+
+static int acp3x_dma_open(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+ DRV_NAME);
+ struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
+
+ struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
+ GFP_KERNEL);
+ if (!i2s_data)
+ return -EINVAL;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = acp3x_pcm_hardware_playback;
+ else
+ runtime->hw = acp3x_pcm_hardware_capture;
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ dev_err(component->dev, "set integer constraint failed\n");
+ kfree(i2s_data);
+ return ret;
+ }
+
+ if (!adata->play_stream && !adata->capture_stream)
+ rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ adata->play_stream = substream;
+ else
+ adata->capture_stream = substream;
+
+ i2s_data->acp3x_base = adata->acp3x_base;
+ runtime->private_data = i2s_data;
+ return 0;
+}
+
+static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int status;
+ u64 size;
+ struct page *pg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct i2s_stream_instance *rtd = runtime->private_data;
+
+ if (!rtd)
+ return -EINVAL;
+
+ size = params_buffer_bytes(params);
+ status = snd_pcm_lib_malloc_pages(substream, size);
+ if (status < 0)
+ return status;
+
+ memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+ pg = virt_to_page(substream->dma_buffer.area);
+ if (pg) {
+ rtd->pg = pg;
+ rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
+ config_acp3x_dma(rtd, substream->stream);
+ status = 0;
+ } else {
+ status = -ENOMEM;
+ }
+ return status;
+}
+
+static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
+{
+ u32 pos = 0;
+ struct i2s_stream_instance *rtd = substream->runtime->private_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pos = rv_readl(rtd->acp3x_base +
+ mmACP_BT_TX_LINKPOSITIONCNTR);
+ else
+ pos = rv_readl(rtd->acp3x_base +
+ mmACP_BT_RX_LINKPOSITIONCNTR);
+
+ if (pos >= MAX_BUFFER)
+ pos = 0;
+
+ return bytes_to_frames(substream->runtime, pos);
+}
+
+static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
+{
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+ SNDRV_DMA_TYPE_DEV,
+ NULL, MIN_BUFFER,
+ MAX_BUFFER);
+}
+
+static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static int acp3x_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct i2s_stream_instance *rtd = substream->runtime->private_data;
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+ DRV_NAME);
+ struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ adata->play_stream = NULL;
+ else
+ adata->capture_stream = NULL;
+
+ /* Disable ACP irq, when the current stream is being closed and
+ * another stream is also not active.
+ */
+ if (!adata->play_stream && !adata->capture_stream)
+ rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+ kfree(rtd);
+ return 0;
+}
+
+static struct snd_pcm_ops acp3x_dma_ops = {
+ .open = acp3x_dma_open,
+ .close = acp3x_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = acp3x_dma_hw_params,
+ .hw_free = acp3x_dma_hw_free,
+ .pointer = acp3x_dma_pointer,
+ .mmap = acp3x_dma_mmap,
+};
+
+
+static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+
+ struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ adata->tdm_mode = false;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ adata->tdm_mode = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int acp3x_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ u32 val = 0;
+ u16 slot_len;
+
+ struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
+
+ switch (slot_width) {
+ case SLOT_WIDTH_8:
+ slot_len = 8;
+ break;
+ case SLOT_WIDTH_16:
+ slot_len = 16;
+ break;
+ case SLOT_WIDTH_24:
+ slot_len = 24;
+ break;
+ case SLOT_WIDTH_32:
+ slot_len = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
+ rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER);
+ val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
+ rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER);
+
+ val = (FRM_LEN | (slots << 15) | (slot_len << 18));
+ rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT);
+ rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT);
+
+ adata->tdm_fmt = val;
+ return 0;
+}
+
+static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ u32 val = 0;
+ struct i2s_stream_instance *rtd = substream->runtime->private_data;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
+ case SNDRV_PCM_FORMAT_S8:
+ rtd->xfer_resolution = 0x0;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ rtd->xfer_resolution = 0x02;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ rtd->xfer_resolution = 0x04;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ rtd->xfer_resolution = 0x05;
+ break;
+ default:
+ return -EINVAL;
+ }
+ val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
+ val = val | (rtd->xfer_resolution << 3);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
+ else
+ rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
+
+ return 0;
+}
+
+static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ struct i2s_stream_instance *rtd = substream->runtime->private_data;
+ u32 val, period_bytes;
+
+ period_bytes = frames_to_bytes(substream->runtime,
+ substream->runtime->period_size);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ rv_writel(period_bytes, rtd->acp3x_base +
+ mmACP_BT_TX_INTR_WATERMARK_SIZE);
+ val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
+ val = val | BIT(0);
+ rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
+ } else {
+ rv_writel(period_bytes, rtd->acp3x_base +
+ mmACP_BT_RX_INTR_WATERMARK_SIZE);
+ val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
+ val = val | BIT(0);
+ rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
+ }
+ rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
+ val = val & ~BIT(0);
+ rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
+ } else {
+ val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
+ val = val & ~BIT(0);
+ rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
+ }
+ rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+struct snd_soc_dai_ops acp3x_dai_i2s_ops = {
+ .hw_params = acp3x_dai_i2s_hwparams,
+ .trigger = acp3x_dai_i2s_trigger,
+ .set_fmt = acp3x_dai_i2s_set_fmt,
+ .set_tdm_slot = acp3x_dai_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver acp3x_i2s_dai_driver = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &acp3x_dai_i2s_ops,
+};
+
+static const struct snd_soc_component_driver acp3x_i2s_component = {
+ .name = DRV_NAME,
+ .ops = &acp3x_dma_ops,
+ .pcm_new = acp3x_dma_new,
+};
+
+static int acp3x_audio_probe(struct platform_device *pdev)
+{
+ int status;
+ struct resource *res;
+ struct i2s_dev_data *adata;
+ unsigned int irqflags;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "platform_data not retrieved\n");
+ return -ENODEV;
+ }
+ irqflags = *((unsigned int *)(pdev->dev.platform_data));
+
+ adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
+ GFP_KERNEL);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ return -ENODEV;
+ }
+
+ adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ return -ENODEV;
+ }
+
+ adata->i2s_irq = res->start;
+ adata->play_stream = NULL;
+ adata->capture_stream = NULL;
+
+ dev_set_drvdata(&pdev->dev, adata);
+ /* Initialize ACP */
+ status = acp3x_init(adata->acp3x_base);
+ if (status)
+ return -ENODEV;
+ status = devm_snd_soc_register_component(&pdev->dev,
+ &acp3x_i2s_component,
+ &acp3x_i2s_dai_driver, 1);
+ if (status) {
+ dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
+ goto dev_err;
+ }
+ status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
+ irqflags, "ACP3x_I2S_IRQ", adata);
+ if (status) {
+ dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n");
+ goto dev_err;
+ }
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ return 0;
+dev_err:
+ status = acp3x_deinit(adata->acp3x_base);
+ if (status)
+ dev_err(&pdev->dev, "ACP de-init failed\n");
+ else
+ dev_info(&pdev->dev, "ACP de-initialized\n");
+ /*ignore device status and return driver probe error*/
+ return -ENODEV;
+}
+
+static int acp3x_audio_remove(struct platform_device *pdev)
+{
+ int ret;
+ struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev);
+
+ ret = acp3x_deinit(adata->acp3x_base);
+ if (ret)
+ dev_err(&pdev->dev, "ACP de-init failed\n");
+ else
+ dev_info(&pdev->dev, "ACP de-initialized\n");
+
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static int acp3x_resume(struct device *dev)
+{
+ int status;
+ u32 val;
+ struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+ status = acp3x_init(adata->acp3x_base);
+ if (status)
+ return -ENODEV;
+
+ if (adata->play_stream && adata->play_stream->runtime) {
+ struct i2s_stream_instance *rtd =
+ adata->play_stream->runtime->private_data;
+ config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+ rv_writel((rtd->xfer_resolution << 3),
+ rtd->acp3x_base + mmACP_BTTDM_ITER);
+ if (adata->tdm_mode == true) {
+ rv_writel(adata->tdm_fmt, adata->acp3x_base +
+ mmACP_BTTDM_TXFRMT);
+ val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
+ rv_writel((val | 0x2), adata->acp3x_base +
+ mmACP_BTTDM_ITER);
+ }
+ }
+
+ if (adata->capture_stream && adata->capture_stream->runtime) {
+ struct i2s_stream_instance *rtd =
+ adata->capture_stream->runtime->private_data;
+ config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+ rv_writel((rtd->xfer_resolution << 3),
+ rtd->acp3x_base + mmACP_BTTDM_IRER);
+ if (adata->tdm_mode == true) {
+ rv_writel(adata->tdm_fmt, adata->acp3x_base +
+ mmACP_BTTDM_RXFRMT);
+ val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
+ rv_writel((val | 0x2), adata->acp3x_base +
+ mmACP_BTTDM_IRER);
+ }
+ }
+
+ rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+
+static int acp3x_pcm_runtime_suspend(struct device *dev)
+{
+ int status;
+ struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+ status = acp3x_deinit(adata->acp3x_base);
+ if (status)
+ dev_err(dev, "ACP de-init failed\n");
+ else
+ dev_info(dev, "ACP de-initialized\n");
+
+ rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+
+ return 0;
+}
+
+static int acp3x_pcm_runtime_resume(struct device *dev)
+{
+ int status;
+ struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+ status = acp3x_init(adata->acp3x_base);
+ if (status)
+ return -ENODEV;
+ rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+static const struct dev_pm_ops acp3x_pm_ops = {
+ .runtime_suspend = acp3x_pcm_runtime_suspend,
+ .runtime_resume = acp3x_pcm_runtime_resume,
+ .resume = acp3x_resume,
+};
+
+static struct platform_driver acp3x_dma_driver = {
+ .probe = acp3x_audio_probe,
+ .remove = acp3x_audio_remove,
+ .driver = {
+ .name = "acp3x_rv_i2s",
+ .pm = &acp3x_pm_ops,
+ },
+};
+
+module_platform_driver(acp3x_dma_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h
new file mode 100644
index 000000000000..4f2cadd90a87
--- /dev/null
+++ b/sound/soc/amd/raven/acp3x.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ALSA SoC PCM Driver
+ *
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#include "chip_offset_byte.h"
+
+#define ACP3x_PHY_BASE_ADDRESS 0x1240000
+#define ACP3x_I2S_MODE 0
+#define ACP3x_REG_START 0x1240000
+#define ACP3x_REG_END 0x1250200
+#define I2S_MODE 0x04
+#define BT_TX_THRESHOLD 26
+#define BT_RX_THRESHOLD 25
+#define ACP3x_POWER_ON 0x00
+#define ACP3x_POWER_ON_IN_PROGRESS 0x01
+#define ACP3x_POWER_OFF 0x02
+#define ACP3x_POWER_OFF_IN_PROGRESS 0x03
+#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001
+
+#define ACP_SRAM_PTE_OFFSET 0x02050000
+#define PAGE_SIZE_4K_ENABLE 0x2
+#define MEM_WINDOW_START 0x4000000
+#define PLAYBACK_FIFO_ADDR_OFFSET 0x400
+#define CAPTURE_FIFO_ADDR_OFFSET 0x500
+
+#define PLAYBACK_MIN_NUM_PERIODS 2
+#define PLAYBACK_MAX_NUM_PERIODS 8
+#define PLAYBACK_MAX_PERIOD_SIZE 16384
+#define PLAYBACK_MIN_PERIOD_SIZE 4096
+#define CAPTURE_MIN_NUM_PERIODS 2
+#define CAPTURE_MAX_NUM_PERIODS 8
+#define CAPTURE_MAX_PERIOD_SIZE 16384
+#define CAPTURE_MIN_PERIOD_SIZE 4096
+
+#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define MIN_BUFFER MAX_BUFFER
+#define FIFO_SIZE 0x100
+#define DMA_SIZE 0x40
+#define FRM_LEN 0x100
+
+#define SLOT_WIDTH_8 0x08
+#define SLOT_WIDTH_16 0x10
+#define SLOT_WIDTH_24 0x18
+#define SLOT_WIDTH_32 0x20
+
+
+static inline u32 rv_readl(void __iomem *base_addr)
+{
+ return readl(base_addr - ACP3x_PHY_BASE_ADDRESS);
+}
+
+static inline void rv_writel(u32 val, void __iomem *base_addr)
+{
+ writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS);
+}
diff --git a/sound/soc/amd/raven/chip_offset_byte.h b/sound/soc/amd/raven/chip_offset_byte.h
new file mode 100644
index 000000000000..9c1fac58fb2a
--- /dev/null
+++ b/sound/soc/amd/raven/chip_offset_byte.h
@@ -0,0 +1,639 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ACP 3.0 Register Documentation
+ *
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _acp_ip_OFFSET_HEADER
+#define _acp_ip_OFFSET_HEADER
+// Registers from ACP_DMA block
+
+#define mmACP_DMA_CNTL_0 0x1240000
+#define mmACP_DMA_CNTL_1 0x1240004
+#define mmACP_DMA_CNTL_2 0x1240008
+#define mmACP_DMA_CNTL_3 0x124000C
+#define mmACP_DMA_CNTL_4 0x1240010
+#define mmACP_DMA_CNTL_5 0x1240014
+#define mmACP_DMA_CNTL_6 0x1240018
+#define mmACP_DMA_CNTL_7 0x124001C
+#define mmACP_DMA_DSCR_STRT_IDX_0 0x1240020
+#define mmACP_DMA_DSCR_STRT_IDX_1 0x1240024
+#define mmACP_DMA_DSCR_STRT_IDX_2 0x1240028
+#define mmACP_DMA_DSCR_STRT_IDX_3 0x124002C
+#define mmACP_DMA_DSCR_STRT_IDX_4 0x1240030
+#define mmACP_DMA_DSCR_STRT_IDX_5 0x1240034
+#define mmACP_DMA_DSCR_STRT_IDX_6 0x1240038
+#define mmACP_DMA_DSCR_STRT_IDX_7 0x124003C
+#define mmACP_DMA_DSCR_CNT_0 0x1240040
+#define mmACP_DMA_DSCR_CNT_1 0x1240044
+#define mmACP_DMA_DSCR_CNT_2 0x1240048
+#define mmACP_DMA_DSCR_CNT_3 0x124004C
+#define mmACP_DMA_DSCR_CNT_4 0x1240050
+#define mmACP_DMA_DSCR_CNT_5 0x1240054
+#define mmACP_DMA_DSCR_CNT_6 0x1240058
+#define mmACP_DMA_DSCR_CNT_7 0x124005C
+#define mmACP_DMA_PRIO_0 0x1240060
+#define mmACP_DMA_PRIO_1 0x1240064
+#define mmACP_DMA_PRIO_2 0x1240068
+#define mmACP_DMA_PRIO_3 0x124006C
+#define mmACP_DMA_PRIO_4 0x1240070
+#define mmACP_DMA_PRIO_5 0x1240074
+#define mmACP_DMA_PRIO_6 0x1240078
+#define mmACP_DMA_PRIO_7 0x124007C
+#define mmACP_DMA_CUR_DSCR_0 0x1240080
+#define mmACP_DMA_CUR_DSCR_1 0x1240084
+#define mmACP_DMA_CUR_DSCR_2 0x1240088
+#define mmACP_DMA_CUR_DSCR_3 0x124008C
+#define mmACP_DMA_CUR_DSCR_4 0x1240090
+#define mmACP_DMA_CUR_DSCR_5 0x1240094
+#define mmACP_DMA_CUR_DSCR_6 0x1240098
+#define mmACP_DMA_CUR_DSCR_7 0x124009C
+#define mmACP_DMA_CUR_TRANS_CNT_0 0x12400A0
+#define mmACP_DMA_CUR_TRANS_CNT_1 0x12400A4
+#define mmACP_DMA_CUR_TRANS_CNT_2 0x12400A8
+#define mmACP_DMA_CUR_TRANS_CNT_3 0x12400AC
+#define mmACP_DMA_CUR_TRANS_CNT_4 0x12400B0
+#define mmACP_DMA_CUR_TRANS_CNT_5 0x12400B4
+#define mmACP_DMA_CUR_TRANS_CNT_6 0x12400B8
+#define mmACP_DMA_CUR_TRANS_CNT_7 0x12400BC
+#define mmACP_DMA_ERR_STS_0 0x12400C0
+#define mmACP_DMA_ERR_STS_1 0x12400C4
+#define mmACP_DMA_ERR_STS_2 0x12400C8
+#define mmACP_DMA_ERR_STS_3 0x12400CC
+#define mmACP_DMA_ERR_STS_4 0x12400D0
+#define mmACP_DMA_ERR_STS_5 0x12400D4
+#define mmACP_DMA_ERR_STS_6 0x12400D8
+#define mmACP_DMA_ERR_STS_7 0x12400DC
+#define mmACP_DMA_DESC_BASE_ADDR 0x12400E0
+#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4
+#define mmACP_DMA_CH_STS 0x12400E8
+#define mmACP_DMA_CH_GROUP 0x12400EC
+#define mmACP_DMA_CH_RST_STS 0x12400F0
+
+
+// Registers from ACP_AXI2AXIATU block
+
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C
+#define mmACPAXI2AXI_ATU_CTRL 0x1240C40
+
+
+// Registers from ACP_CLKRST block
+
+#define mmACP_SOFT_RESET 0x1241000
+#define mmACP_CONTROL 0x1241004
+#define mmACP_STATUS 0x1241008
+#define mmACP_DSP0_OCD_HALT_ON_RST 0x124100C
+#define mmACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010
+
+
+// Registers from ACP_MISC block
+
+#define mmACP_EXTERNAL_INTR_ENB 0x1241800
+#define mmACP_EXTERNAL_INTR_CNTL 0x1241804
+#define mmACP_EXTERNAL_INTR_STAT 0x1241808
+#define mmACP_DSP0_INTR_CNTL 0x124180C
+#define mmACP_DSP0_INTR_STAT 0x1241810
+#define mmACP_DSP_SW_INTR_CNTL 0x1241814
+#define mmACP_DSP_SW_INTR_STAT 0x1241818
+#define mmACP_SW_INTR_TRIG 0x124181C
+#define mmACP_SMU_MAILBOX 0x1241820
+#define mmDSP_INTERRUPT_ROUTING_CTRL 0x1241824
+#define mmACP_DSP0_WATCHDOG_TIMER_CNTL 0x1241828
+#define mmACP_DSP0_EXT_TIMER1_CNTL 0x124182C
+#define mmACP_DSP0_EXT_TIMER2_CNTL 0x1241830
+#define mmACP_DSP0_EXT_TIMER3_CNTL 0x1241834
+#define mmACP_DSP0_EXT_TIMER4_CNTL 0x1241838
+#define mmACP_DSP0_EXT_TIMER5_CNTL 0x124183C
+#define mmACP_DSP0_EXT_TIMER6_CNTL 0x1241840
+#define mmACP_DSP0_EXT_TIMER1_CURR_VALUE 0x1241844
+#define mmACP_DSP0_EXT_TIMER2_CURR_VALUE 0x1241848
+#define mmACP_DSP0_EXT_TIMER3_CURR_VALUE 0x124184C
+#define mmACP_DSP0_EXT_TIMER4_CURR_VALUE 0x1241850
+#define mmACP_DSP0_EXT_TIMER5_CURR_VALUE 0x1241854
+#define mmACP_DSP0_EXT_TIMER6_CURR_VALUE 0x1241858
+#define mmACP_FW_STATUS 0x124185C
+#define mmACP_TIMER 0x1241874
+#define mmACP_TIMER_CNTL 0x1241878
+#define mmACP_PGMEM_CTRL 0x12418C0
+#define mmACP_ERROR_STATUS 0x12418C4
+#define mmACP_SW_I2S_ERROR_REASON 0x12418C8
+#define mmACP_MEM_PG_STS 0x12418CC
+
+
+// Registers from ACP_PGFSM block
+
+#define mmACP_I2S_PIN_CONFIG 0x1241400
+#define mmACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404
+#define mmACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408
+#define mmACP_SW_PAD_KEEPER_EN 0x124140C
+#define mmACP_SW_WAKE_EN 0x1241410
+#define mmACP_I2S_WAKE_EN 0x1241414
+#define mmACP_PME_EN 0x1241418
+#define mmACP_PGFSM_CONTROL 0x124141C
+#define mmACP_PGFSM_STATUS 0x1241420
+
+
+// Registers from ACP_SCRATCH block
+
+#define mmACP_SCRATCH_REG_0 0x1250000
+#define mmACP_SCRATCH_REG_1 0x1250004
+#define mmACP_SCRATCH_REG_2 0x1250008
+#define mmACP_SCRATCH_REG_3 0x125000C
+#define mmACP_SCRATCH_REG_4 0x1250010
+#define mmACP_SCRATCH_REG_5 0x1250014
+#define mmACP_SCRATCH_REG_6 0x1250018
+#define mmACP_SCRATCH_REG_7 0x125001C
+#define mmACP_SCRATCH_REG_8 0x1250020
+#define mmACP_SCRATCH_REG_9 0x1250024
+#define mmACP_SCRATCH_REG_10 0x1250028
+#define mmACP_SCRATCH_REG_11 0x125002C
+#define mmACP_SCRATCH_REG_12 0x1250030
+#define mmACP_SCRATCH_REG_13 0x1250034
+#define mmACP_SCRATCH_REG_14 0x1250038
+#define mmACP_SCRATCH_REG_15 0x125003C
+#define mmACP_SCRATCH_REG_16 0x1250040
+#define mmACP_SCRATCH_REG_17 0x1250044
+#define mmACP_SCRATCH_REG_18 0x1250048
+#define mmACP_SCRATCH_REG_19 0x125004C
+#define mmACP_SCRATCH_REG_20 0x1250050
+#define mmACP_SCRATCH_REG_21 0x1250054
+#define mmACP_SCRATCH_REG_22 0x1250058
+#define mmACP_SCRATCH_REG_23 0x125005C
+#define mmACP_SCRATCH_REG_24 0x1250060
+#define mmACP_SCRATCH_REG_25 0x1250064
+#define mmACP_SCRATCH_REG_26 0x1250068
+#define mmACP_SCRATCH_REG_27 0x125006C
+#define mmACP_SCRATCH_REG_28 0x1250070
+#define mmACP_SCRATCH_REG_29 0x1250074
+#define mmACP_SCRATCH_REG_30 0x1250078
+#define mmACP_SCRATCH_REG_31 0x125007C
+#define mmACP_SCRATCH_REG_32 0x1250080
+#define mmACP_SCRATCH_REG_33 0x1250084
+#define mmACP_SCRATCH_REG_34 0x1250088
+#define mmACP_SCRATCH_REG_35 0x125008C
+#define mmACP_SCRATCH_REG_36 0x1250090
+#define mmACP_SCRATCH_REG_37 0x1250094
+#define mmACP_SCRATCH_REG_38 0x1250098
+#define mmACP_SCRATCH_REG_39 0x125009C
+#define mmACP_SCRATCH_REG_40 0x12500A0
+#define mmACP_SCRATCH_REG_41 0x12500A4
+#define mmACP_SCRATCH_REG_42 0x12500A8
+#define mmACP_SCRATCH_REG_43 0x12500AC
+#define mmACP_SCRATCH_REG_44 0x12500B0
+#define mmACP_SCRATCH_REG_45 0x12500B4
+#define mmACP_SCRATCH_REG_46 0x12500B8
+#define mmACP_SCRATCH_REG_47 0x12500BC
+#define mmACP_SCRATCH_REG_48 0x12500C0
+#define mmACP_SCRATCH_REG_49 0x12500C4
+#define mmACP_SCRATCH_REG_50 0x12500C8
+#define mmACP_SCRATCH_REG_51 0x12500CC
+#define mmACP_SCRATCH_REG_52 0x12500D0
+#define mmACP_SCRATCH_REG_53 0x12500D4
+#define mmACP_SCRATCH_REG_54 0x12500D8
+#define mmACP_SCRATCH_REG_55 0x12500DC
+#define mmACP_SCRATCH_REG_56 0x12500E0
+#define mmACP_SCRATCH_REG_57 0x12500E4
+#define mmACP_SCRATCH_REG_58 0x12500E8
+#define mmACP_SCRATCH_REG_59 0x12500EC
+#define mmACP_SCRATCH_REG_60 0x12500F0
+#define mmACP_SCRATCH_REG_61 0x12500F4
+#define mmACP_SCRATCH_REG_62 0x12500F8
+#define mmACP_SCRATCH_REG_63 0x12500FC
+#define mmACP_SCRATCH_REG_64 0x1250100
+#define mmACP_SCRATCH_REG_65 0x1250104
+#define mmACP_SCRATCH_REG_66 0x1250108
+#define mmACP_SCRATCH_REG_67 0x125010C
+#define mmACP_SCRATCH_REG_68 0x1250110
+#define mmACP_SCRATCH_REG_69 0x1250114
+#define mmACP_SCRATCH_REG_70 0x1250118
+#define mmACP_SCRATCH_REG_71 0x125011C
+#define mmACP_SCRATCH_REG_72 0x1250120
+#define mmACP_SCRATCH_REG_73 0x1250124
+#define mmACP_SCRATCH_REG_74 0x1250128
+#define mmACP_SCRATCH_REG_75 0x125012C
+#define mmACP_SCRATCH_REG_76 0x1250130
+#define mmACP_SCRATCH_REG_77 0x1250134
+#define mmACP_SCRATCH_REG_78 0x1250138
+#define mmACP_SCRATCH_REG_79 0x125013C
+#define mmACP_SCRATCH_REG_80 0x1250140
+#define mmACP_SCRATCH_REG_81 0x1250144
+#define mmACP_SCRATCH_REG_82 0x1250148
+#define mmACP_SCRATCH_REG_83 0x125014C
+#define mmACP_SCRATCH_REG_84 0x1250150
+#define mmACP_SCRATCH_REG_85 0x1250154
+#define mmACP_SCRATCH_REG_86 0x1250158
+#define mmACP_SCRATCH_REG_87 0x125015C
+#define mmACP_SCRATCH_REG_88 0x1250160
+#define mmACP_SCRATCH_REG_89 0x1250164
+#define mmACP_SCRATCH_REG_90 0x1250168
+#define mmACP_SCRATCH_REG_91 0x125016C
+#define mmACP_SCRATCH_REG_92 0x1250170
+#define mmACP_SCRATCH_REG_93 0x1250174
+#define mmACP_SCRATCH_REG_94 0x1250178
+#define mmACP_SCRATCH_REG_95 0x125017C
+#define mmACP_SCRATCH_REG_96 0x1250180
+#define mmACP_SCRATCH_REG_97 0x1250184
+#define mmACP_SCRATCH_REG_98 0x1250188
+#define mmACP_SCRATCH_REG_99 0x125018C
+#define mmACP_SCRATCH_REG_100 0x1250190
+#define mmACP_SCRATCH_REG_101 0x1250194
+#define mmACP_SCRATCH_REG_102 0x1250198
+#define mmACP_SCRATCH_REG_103 0x125019C
+#define mmACP_SCRATCH_REG_104 0x12501A0
+#define mmACP_SCRATCH_REG_105 0x12501A4
+#define mmACP_SCRATCH_REG_106 0x12501A8
+#define mmACP_SCRATCH_REG_107 0x12501AC
+#define mmACP_SCRATCH_REG_108 0x12501B0
+#define mmACP_SCRATCH_REG_109 0x12501B4
+#define mmACP_SCRATCH_REG_110 0x12501B8
+#define mmACP_SCRATCH_REG_111 0x12501BC
+#define mmACP_SCRATCH_REG_112 0x12501C0
+#define mmACP_SCRATCH_REG_113 0x12501C4
+#define mmACP_SCRATCH_REG_114 0x12501C8
+#define mmACP_SCRATCH_REG_115 0x12501CC
+#define mmACP_SCRATCH_REG_116 0x12501D0
+#define mmACP_SCRATCH_REG_117 0x12501D4
+#define mmACP_SCRATCH_REG_118 0x12501D8
+#define mmACP_SCRATCH_REG_119 0x12501DC
+#define mmACP_SCRATCH_REG_120 0x12501E0
+#define mmACP_SCRATCH_REG_121 0x12501E4
+#define mmACP_SCRATCH_REG_122 0x12501E8
+#define mmACP_SCRATCH_REG_123 0x12501EC
+#define mmACP_SCRATCH_REG_124 0x12501F0
+#define mmACP_SCRATCH_REG_125 0x12501F4
+#define mmACP_SCRATCH_REG_126 0x12501F8
+#define mmACP_SCRATCH_REG_127 0x12501FC
+#define mmACP_SCRATCH_REG_128 0x1250200
+
+
+// Registers from ACP_SW_ACLK block
+
+#define mmSW_CORB_Base_Address 0x1243200
+#define mmSW_CORB_Write_Pointer 0x1243204
+#define mmSW_CORB_Read_Pointer 0x1243208
+#define mmSW_CORB_Control 0x124320C
+#define mmSW_CORB_Size 0x1243214
+#define mmSW_RIRB_Base_Address 0x1243218
+#define mmSW_RIRB_Write_Pointer 0x124321C
+#define mmSW_RIRB_Response_Interrupt_Count 0x1243220
+#define mmSW_RIRB_Control 0x1243224
+#define mmSW_RIRB_Size 0x1243228
+#define mmSW_RIRB_FIFO_MIN_THDL 0x124322C
+#define mmSW_imm_cmd_UPPER_WORD 0x1243230
+#define mmSW_imm_cmd_LOWER_QWORD 0x1243234
+#define mmSW_imm_resp_UPPER_WORD 0x1243238
+#define mmSW_imm_resp_LOWER_QWORD 0x124323C
+#define mmSW_imm_cmd_sts 0x1243240
+#define mmSW_BRA_BASE_ADDRESS 0x1243244
+#define mmSW_BRA_TRANSFER_SIZE 0x1243248
+#define mmSW_BRA_DMA_BUSY 0x124324C
+#define mmSW_BRA_RESP 0x1243250
+#define mmSW_BRA_RESP_FRAME_ADDR 0x1243254
+#define mmSW_BRA_CURRENT_TRANSFER_SIZE 0x1243258
+#define mmSW_STATE_CHANGE_STATUS_0TO7 0x124325C
+#define mmSW_STATE_CHANGE_STATUS_8TO11 0x1243260
+#define mmSW_STATE_CHANGE_STATUS_MASK_0to7 0x1243264
+#define mmSW_STATE_CHANGE_STATUS_MASK_8to11 0x1243268
+#define mmSW_CLK_FREQUENCY_CTRL 0x124326C
+#define mmSW_ERROR_INTR_MASK 0x1243270
+#define mmSW_PHY_TEST_MODE_DATA_OFF 0x1243274
+
+
+// Registers from ACP_SW_SWCLK block
+
+#define mmACP_SW_EN 0x1243000
+#define mmACP_SW_EN_STATUS 0x1243004
+#define mmACP_SW_FRAMESIZE 0x1243008
+#define mmACP_SW_SSP_Counter 0x124300C
+#define mmACP_SW_Audio_TX_EN 0x1243010
+#define mmACP_SW_Audio_TX_EN_STATUS 0x1243014
+#define mmACP_SW_Audio_TX_Frame_Format 0x1243018
+#define mmACP_SW_Audio_TX_SampleInterval 0x124301C
+#define mmACP_SW_Audio_TX_Hctrl_DP0 0x1243020
+#define mmACP_SW_Audio_TX_Hctrl_DP1 0x1243024
+#define mmACP_SW_Audio_TX_Hctrl_DP2 0x1243028
+#define mmACP_SW_Audio_TX_Hctrl_DP3 0x124302C
+#define mmACP_SW_Audio_TX_offset_DP0 0x1243030
+#define mmACP_SW_Audio_TX_offset_DP1 0x1243034
+#define mmACP_SW_Audio_TX_offset_DP2 0x1243038
+#define mmACP_SW_Audio_TX_offset_DP3 0x124303C
+#define mmACP_SW_Audio_TX_Channel_Enable_DP0 0x1243040
+#define mmACP_SW_Audio_TX_Channel_Enable_DP1 0x1243044
+#define mmACP_SW_Audio_TX_Channel_Enable_DP2 0x1243048
+#define mmACP_SW_Audio_TX_Channel_Enable_DP3 0x124304C
+#define mmACP_SW_BT_TX_EN 0x1243050
+#define mmACP_SW_BT_TX_EN_STATUS 0x1243054
+#define mmACP_SW_BT_TX_Frame_Format 0x1243058
+#define mmACP_SW_BT_TX_SampleInterval 0x124305C
+#define mmACP_SW_BT_TX_Hctrl 0x1243060
+#define mmACP_SW_BT_TX_offset 0x1243064
+#define mmACP_SW_BT_TX_Channel_Enable_DP0 0x1243068
+#define mmACP_SW_Headset_TX_EN 0x124306C
+#define mmACP_SW_Headset_TX_EN_STATUS 0x1243070
+#define mmACP_SW_Headset_TX_Frame_Format 0x1243074
+#define mmACP_SW_Headset_TX_SampleInterval 0x1243078
+#define mmACP_SW_Headset_TX_Hctrl 0x124307C
+#define mmACP_SW_Headset_TX_offset 0x1243080
+#define mmACP_SW_Headset_TX_Channel_Enable_DP0 0x1243084
+#define mmACP_SW_Audio_RX_EN 0x1243088
+#define mmACP_SW_Audio_RX_EN_STATUS 0x124308C
+#define mmACP_SW_Audio_RX_Frame_Format 0x1243090
+#define mmACP_SW_Audio_RX_SampleInterval 0x1243094
+#define mmACP_SW_Audio_RX_Hctrl_DP0 0x1243098
+#define mmACP_SW_Audio_RX_Hctrl_DP1 0x124309C
+#define mmACP_SW_Audio_RX_Hctrl_DP2 0x1243100
+#define mmACP_SW_Audio_RX_Hctrl_DP3 0x1243104
+#define mmACP_SW_Audio_RX_offset_DP0 0x1243108
+#define mmACP_SW_Audio_RX_offset_DP1 0x124310C
+#define mmACP_SW_Audio_RX_offset_DP2 0x1243110
+#define mmACP_SW_Audio_RX_offset_DP3 0x1243114
+#define mmACP_SW_Audio_RX_Channel_Enable_DP0 0x1243118
+#define mmACP_SW_Audio_RX_Channel_Enable_DP1 0x124311C
+#define mmACP_SW_Audio_RX_Channel_Enable_DP2 0x1243120
+#define mmACP_SW_Audio_RX_Channel_Enable_DP3 0x1243124
+#define mmACP_SW_BT_RX_EN 0x1243128
+#define mmACP_SW_BT_RX_EN_STATUS 0x124312C
+#define mmACP_SW_BT_RX_Frame_Format 0x1243130
+#define mmACP_SW_BT_RX_SampleInterval 0x1243134
+#define mmACP_SW_BT_RX_Hctrl 0x1243138
+#define mmACP_SW_BT_RX_offset 0x124313C
+#define mmACP_SW_BT_RX_Channel_Enable_DP0 0x1243140
+#define mmACP_SW_Headset_RX_EN 0x1243144
+#define mmACP_SW_Headset_RX_EN_STATUS 0x1243148
+#define mmACP_SW_Headset_RX_Frame_Format 0x124314C
+#define mmACP_SW_Headset_RX_SampleInterval 0x1243150
+#define mmACP_SW_Headset_RX_Hctrl 0x1243154
+#define mmACP_SW_Headset_RX_offset 0x1243158
+#define mmACP_SW_Headset_RX_Channel_Enable_DP0 0x124315C
+#define mmACP_SW_BPT_PORT_EN 0x1243160
+#define mmACP_SW_BPT_PORT_EN_STATUS 0x1243164
+#define mmACP_SW_BPT_PORT_Frame_Format 0x1243168
+#define mmACP_SW_BPT_PORT_SampleInterval 0x124316C
+#define mmACP_SW_BPT_PORT_Hctrl 0x1243170
+#define mmACP_SW_BPT_PORT_offset 0x1243174
+#define mmACP_SW_BPT_PORT_Channel_Enable 0x1243178
+#define mmACP_SW_BPT_PORT_First_byte_addr 0x124317C
+#define mmACP_SW_CLK_RESUME_CTRL 0x1243180
+#define mmACP_SW_CLK_RESUME_Delay_Cntr 0x1243184
+#define mmACP_SW_BUS_RESET_CTRL 0x1243188
+#define mmACP_SW_PRBS_ERR_STATUS 0x124318C
+
+
+// Registers from ACP_AUDIO_BUFFERS block
+
+#define mmACP_I2S_RX_RINGBUFADDR 0x1242000
+#define mmACP_I2S_RX_RINGBUFSIZE 0x1242004
+#define mmACP_I2S_RX_LINKPOSITIONCNTR 0x1242008
+#define mmACP_I2S_RX_FIFOADDR 0x124200C
+#define mmACP_I2S_RX_FIFOSIZE 0x1242010
+#define mmACP_I2S_RX_DMA_SIZE 0x1242014
+#define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018
+#define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C
+#define mmACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020
+#define mmACP_I2S_TX_RINGBUFADDR 0x1242024
+#define mmACP_I2S_TX_RINGBUFSIZE 0x1242028
+#define mmACP_I2S_TX_LINKPOSITIONCNTR 0x124202C
+#define mmACP_I2S_TX_FIFOADDR 0x1242030
+#define mmACP_I2S_TX_FIFOSIZE 0x1242034
+#define mmACP_I2S_TX_DMA_SIZE 0x1242038
+#define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C
+#define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040
+#define mmACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044
+#define mmACP_BT_RX_RINGBUFADDR 0x1242048
+#define mmACP_BT_RX_RINGBUFSIZE 0x124204C
+#define mmACP_BT_RX_LINKPOSITIONCNTR 0x1242050
+#define mmACP_BT_RX_FIFOADDR 0x1242054
+#define mmACP_BT_RX_FIFOSIZE 0x1242058
+#define mmACP_BT_RX_DMA_SIZE 0x124205C
+#define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060
+#define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064
+#define mmACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068
+#define mmACP_BT_TX_RINGBUFADDR 0x124206C
+#define mmACP_BT_TX_RINGBUFSIZE 0x1242070
+#define mmACP_BT_TX_LINKPOSITIONCNTR 0x1242074
+#define mmACP_BT_TX_FIFOADDR 0x1242078
+#define mmACP_BT_TX_FIFOSIZE 0x124207C
+#define mmACP_BT_TX_DMA_SIZE 0x1242080
+#define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084
+#define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088
+#define mmACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C
+#define mmACP_HS_RX_RINGBUFADDR 0x1242090
+#define mmACP_HS_RX_RINGBUFSIZE 0x1242094
+#define mmACP_HS_RX_LINKPOSITIONCNTR 0x1242098
+#define mmACP_HS_RX_FIFOADDR 0x124209C
+#define mmACP_HS_RX_FIFOSIZE 0x12420A0
+#define mmACP_HS_RX_DMA_SIZE 0x12420A4
+#define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8
+#define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC
+#define mmACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0
+#define mmACP_HS_TX_RINGBUFADDR 0x12420B4
+#define mmACP_HS_TX_RINGBUFSIZE 0x12420B8
+#define mmACP_HS_TX_LINKPOSITIONCNTR 0x12420BC
+#define mmACP_HS_TX_FIFOADDR 0x12420C0
+#define mmACP_HS_TX_FIFOSIZE 0x12420C4
+#define mmACP_HS_TX_DMA_SIZE 0x12420C8
+#define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC
+#define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0
+#define mmACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4
+
+
+// Registers from ACP_I2S_TDM block
+
+#define mmACP_I2STDM_IER 0x1242400
+#define mmACP_I2STDM_IRER 0x1242404
+#define mmACP_I2STDM_RXFRMT 0x1242408
+#define mmACP_I2STDM_ITER 0x124240C
+#define mmACP_I2STDM_TXFRMT 0x1242410
+
+
+// Registers from ACP_BT_TDM block
+
+#define mmACP_BTTDM_IER 0x1242800
+#define mmACP_BTTDM_IRER 0x1242804
+#define mmACP_BTTDM_RXFRMT 0x1242808
+#define mmACP_BTTDM_ITER 0x124280C
+#define mmACP_BTTDM_TXFRMT 0x1242810
+
+
+// Registers from AZALIA_IP block
+
+#define mmAudio_Az_Global_Capabilities 0x1200000
+#define mmAudio_Az_Minor_Version 0x1200002
+#define mmAudio_Az_Major_Version 0x1200003
+#define mmAudio_Az_Output_Payload_Capability 0x1200004
+#define mmAudio_Az_Input_Payload_Capability 0x1200006
+#define mmAudio_Az_Global_Control 0x1200008
+#define mmAudio_Az_Wake_Enable 0x120000C
+#define mmAudio_Az_State_Change_Status 0x120000E
+#define mmAudio_Az_Global_Status 0x1200010
+#define mmAudio_Az_Linked_List_Capability_Header 0x1200014
+#define mmAudio_Az_Output_Stream_Payload_Capability 0x1200018
+#define mmAudio_Az_Input_Stream_Payload_Capability 0x120001A
+#define mmAudio_Az_Interrupt_Control 0x1200020
+#define mmAudio_Az_Interrupt_Status 0x1200024
+#define mmAudio_Az_Wall_Clock_Counter 0x1200030
+#define mmAudio_Az_Stream_Synchronization 0x1200038
+#define mmAudio_Az_CORB_Lower_Base_Address 0x1200040
+#define mmAudio_Az_CORB_Upper_Base_Address 0x1200044
+#define mmAudio_Az_CORB_Write_Pointer 0x1200048
+#define mmAudio_Az_CORB_Read_Pointer 0x120004A
+#define mmAudio_Az_CORB_Control 0x120004C
+#define mmAudio_Az_CORB_Status 0x120004D
+#define mmAudio_Az_CORB_Size 0x120004E
+#define mmAudio_Az_RIRB_Lower_Base_Address 0x1200050
+#define mmAudio_Az_RIRB_Upper_Base_Address 0x1200054
+#define mmAudio_Az_RIRB_Write_Pointer 0x1200058
+#define mmAudio_Az_RIRB_Response_Interrupt_Count 0x120005A
+#define mmAudio_Az_RIRB_Control 0x120005C
+#define mmAudio_Az_RIRB_Status 0x120005D
+#define mmAudio_Az_RIRB_Size 0x120005E
+#define mmAudio_Az_Immediate_Command_Output_Interface 0x1200060
+#define mmAudio_Az_Immediate_Response_Input_Interface 0x1200064
+#define mmAudio_Az_Immediate_Command_Status 0x1200068
+#define mmAudio_Az_DPLBASE 0x1200070
+#define mmAudio_Az_DPUBASE 0x1200074
+#define mmAudio_Az_Input_SD0CTL_and_STS 0x1200080
+#define mmAudio_Az_Input_SD0LPIB 0x1200084
+#define mmAudio_Az_Input_SD0CBL 0x1200088
+#define mmAudio_Az_Input_SD0LVI 0x120008C
+#define mmAudio_Az_Input_SD0FIFOS 0x1200090
+#define mmAudio_Az_Input_SD0FMT 0x1200092
+#define mmAudio_Az_Input_SD0BDPL 0x1200098
+#define mmAudio_Az_Input_SD0BDPU 0x120009C
+#define mmAudio_Az_Input_SD1CTL_and_STS 0x12000A0
+#define mmAudio_Az_Input_SD1LPIB 0x12000A4
+#define mmAudio_Az_Input_SD1CBL 0x12000A8
+#define mmAudio_Az_Input_SD1LVI 0x12000AC
+#define mmAudio_Az_Input_SD1FIFOS 0x12000B0
+#define mmAudio_Az_Input_SD1FMT 0x12000B2
+#define mmAudio_Az_Input_SD1BDPL 0x12000B8
+#define mmAudio_Az_Input_SD1BDPU 0x12000BC
+#define mmAudio_Az_Input_SD2CTL_and_STS 0x12000C0
+#define mmAudio_Az_Input_SD2LPIB 0x12000C4
+#define mmAudio_Az_Input_SD2CBL 0x12000C8
+#define mmAudio_Az_Input_SD2LVI 0x12000CC
+#define mmAudio_Az_Input_SD2FIFOS 0x12000D0
+#define mmAudio_Az_Input_SD2FMT 0x12000D2
+#define mmAudio_Az_Input_SD2BDPL 0x12000D8
+#define mmAudio_Az_Input_SD2BDPU 0x12000DC
+#define mmAudio_Az_Input_SD3CTL_and_STS 0x12000E0
+#define mmAudio_Az_Input_SD3LPIB 0x12000E4
+#define mmAudio_Az_Input_SD3CBL 0x12000E8
+#define mmAudio_Az_Input_SD3LVI 0x12000EC
+#define mmAudio_Az_Input_SD3FIFOS 0x12000F0
+#define mmAudio_Az_Input_SD3FMT 0x12000F2
+#define mmAudio_Az_Input_SD3BDPL 0x12000F8
+#define mmAudio_Az_Input_SD3BDPU 0x12000FC
+#define mmAudio_Az_Output_SD0CTL_and_STS 0x1200100
+#define mmAudio_Az_Output_SD0LPIB 0x1200104
+#define mmAudio_Az_Output_SD0CBL 0x1200108
+#define mmAudio_Az_Output_SD0LVI 0x120010C
+#define mmAudio_Az_Output_SD0FIFOS 0x1200110
+#define mmAudio_Az_Output_SD0FMT 0x1200112
+#define mmAudio_Az_Output_SD0BDPL 0x1200118
+#define mmAudio_Az_Output_SD0BDPU 0x120011C
+#define mmAudio_Az_Output_SD1CTL_and_STS 0x1200120
+#define mmAudio_Az_Output_SD1LPIB 0x1200124
+#define mmAudio_Az_Output_SD1CBL 0x1200128
+#define mmAudio_Az_Output_SD1LVI 0x120012C
+#define mmAudio_Az_Output_SD1FIFOS 0x1200130
+#define mmAudio_Az_Output_SD1FMT 0x1200132
+#define mmAudio_Az_Output_SD1BDPL 0x1200138
+#define mmAudio_Az_Output_SD1BDPU 0x120013C
+#define mmAudio_Az_Output_SD2CTL_and_STS 0x1200140
+#define mmAudio_Az_Output_SD2LPIB 0x1200144
+#define mmAudio_Az_Output_SD2CBL 0x1200148
+#define mmAudio_Az_Output_SD2LVI 0x120014C
+#define mmAudio_Az_Output_SD2FIFOS 0x1200150
+#define mmAudio_Az_Output_SD2FMT 0x1200152
+#define mmAudio_Az_Output_SD2BDPL 0x1200158
+#define mmAudio_Az_Output_SD2BDPU 0x120015C
+#define mmAudio_Az_Output_SD3CTL_and_STS 0x1200160
+#define mmAudio_Az_Output_SD3LPIB 0x1200164
+#define mmAudio_Az_Output_SD3CBL 0x1200168
+#define mmAudio_Az_Output_SD3LVI 0x120016C
+#define mmAudio_Az_Output_SD3FIFOS 0x1200170
+#define mmAudio_Az_Output_SD3FMT 0x1200172
+#define mmAudio_Az_Output_SD3BDPL 0x1200178
+#define mmAudio_Az_Output_SD3BDPU 0x120017C
+#define mmAudioAZ_Misc_Control_Register_1 0x1200180
+#define mmAudioAZ_Misc_Control_Register_2 0x1200182
+#define mmAudioAZ_Misc_Control_Register_3 0x1200183
+#define mmAudio_AZ_Multiple_Links_Capability_Header 0x1200200
+#define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204
+#define mmAudio_AZ_Link0_Capabilities 0x1200240
+#define mmAudio_AZ_Link0_Control 0x1200244
+#define mmAudio_AZ_Link0_Output_Stream_ID 0x1200248
+#define mmAudio_AZ_Link0_SDI_Identifier 0x120024C
+#define mmAudio_AZ_Link0_Per_Stream_Overhead 0x1200250
+#define mmAudio_AZ_Link0_Wall_Frame_Counter 0x1200258
+#define mmAudio_AZ_Link0_Output_Payload_Capability_L 0x1200260
+#define mmAudio_AZ_Link0_Output_Payload_Capability_U 0x1200264
+#define mmAudio_AZ_Link0_Input_Payload_Capability_L 0x1200270
+#define mmAudio_AZ_Link0_Input_Payload_Capability_U 0x1200274
+#define mmAudio_Az_Input_SD0LICBA 0x1202084
+#define mmAudio_Az_Input_SD1LICBA 0x12020A4
+#define mmAudio_Az_Input_SD2LICBA 0x12020C4
+#define mmAudio_Az_Input_SD3LICBA 0x12020E4
+#define mmAudio_Az_Output_SD0LICBA 0x1202104
+#define mmAudio_Az_Output_SD1LICBA 0x1202124
+#define mmAudio_Az_Output_SD2LICBA 0x1202144
+#define mmAudio_Az_Output_SD3LICBA 0x1202164
+#define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL 0x1204000
+#define mmAUDIO_AZ_IOC_SOFTRST_CONTROL 0x1204004
+#define mmAUDIO_AZ_IOC_CLKGATE_CONTROL 0x1204008
+
+
+// Registers from ACP_AZALIA block
+
+#define mmACP_AZ_PAGE0_LBASE_ADDR 0x1243800
+#define mmACP_AZ_PAGE0_UBASE_ADDR 0x1243804
+#define mmACP_AZ_PAGE0_PGEN_SIZE 0x1243808
+#define mmACP_AZ_PAGE0_OFFSET 0x124380C
+#define mmACP_AZ_PAGE1_LBASE_ADDR 0x1243810
+#define mmACP_AZ_PAGE1_UBASE_ADDR 0x1243814
+#define mmACP_AZ_PAGE1_PGEN_SIZE 0x1243818
+#define mmACP_AZ_PAGE1_OFFSET 0x124381C
+#define mmACP_AZ_PAGE2_LBASE_ADDR 0x1243820
+#define mmACP_AZ_PAGE2_UBASE_ADDR 0x1243824
+#define mmACP_AZ_PAGE2_PGEN_SIZE 0x1243828
+#define mmACP_AZ_PAGE2_OFFSET 0x124382C
+#define mmACP_AZ_PAGE3_LBASE_ADDR 0x1243830
+#define mmACP_AZ_PAGE3_UBASE_ADDR 0x1243834
+#define mmACP_AZ_PAGE3_PGEN_SIZE 0x1243838
+#define mmACP_AZ_PAGE3_OFFSET 0x124383C
+#define mmACP_AZ_PAGE4_LBASE_ADDR 0x1243840
+#define mmACP_AZ_PAGE4_UBASE_ADDR 0x1243844
+#define mmACP_AZ_PAGE4_PGEN_SIZE 0x1243848
+#define mmACP_AZ_PAGE4_OFFSET 0x124384C
+#define mmACP_AZ_PAGE5_LBASE_ADDR 0x1243850
+#define mmACP_AZ_PAGE5_UBASE_ADDR 0x1243854
+#define mmACP_AZ_PAGE5_PGEN_SIZE 0x1243858
+#define mmACP_AZ_PAGE5_OFFSET 0x124385C
+#define mmACP_AZ_PAGE6_LBASE_ADDR 0x1243860
+#define mmACP_AZ_PAGE6_UBASE_ADDR 0x1243864
+#define mmACP_AZ_PAGE6_PGEN_SIZE 0x1243868
+#define mmACP_AZ_PAGE6_OFFSET 0x124386C
+#define mmACP_AZ_PAGE7_LBASE_ADDR 0x1243870
+#define mmACP_AZ_PAGE7_UBASE_ADDR 0x1243874
+#define mmACP_AZ_PAGE7_PGEN_SIZE 0x1243878
+#define mmACP_AZ_PAGE7_OFFSET 0x124387C
+
+
+#endif
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
new file mode 100644
index 000000000000..facec2472b34
--- /dev/null
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// AMD ACP PCI Driver
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include "acp3x.h"
+
+struct acp3x_dev_data {
+ void __iomem *acp3x_base;
+ bool acp3x_audio_mode;
+ struct resource *res;
+ struct platform_device *pdev;
+};
+
+static int snd_acp3x_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ int ret;
+ u32 addr, val;
+ struct acp3x_dev_data *adata;
+ struct platform_device_info pdevinfo;
+ unsigned int irqflags;
+
+ if (pci_enable_device(pci)) {
+ dev_err(&pci->dev, "pci_enable_device failed\n");
+ return -ENODEV;
+ }
+
+ ret = pci_request_regions(pci, "AMD ACP3x audio");
+ if (ret < 0) {
+ dev_err(&pci->dev, "pci_request_regions failed\n");
+ goto disable_pci;
+ }
+
+ adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
+ GFP_KERNEL);
+ if (!adata) {
+ ret = -ENOMEM;
+ goto release_regions;
+ }
+
+ /* check for msi interrupt support */
+ ret = pci_enable_msi(pci);
+ if (ret)
+ /* msi is not enabled */
+ irqflags = IRQF_SHARED;
+ else
+ /* msi is enabled */
+ irqflags = 0;
+
+ addr = pci_resource_start(pci, 0);
+ adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
+ if (!adata->acp3x_base) {
+ ret = -ENOMEM;
+ goto release_regions;
+ }
+ pci_set_master(pci);
+ pci_set_drvdata(pci, adata);
+
+ val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
+ switch (val) {
+ case I2S_MODE:
+ adata->res = devm_kzalloc(&pci->dev,
+ sizeof(struct resource) * 2,
+ GFP_KERNEL);
+ if (!adata->res) {
+ ret = -ENOMEM;
+ goto unmap_mmio;
+ }
+
+ adata->res[0].name = "acp3x_i2s_iomem";
+ adata->res[0].flags = IORESOURCE_MEM;
+ adata->res[0].start = addr;
+ adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
+
+ adata->res[1].name = "acp3x_i2s_irq";
+ adata->res[1].flags = IORESOURCE_IRQ;
+ adata->res[1].start = pci->irq;
+ adata->res[1].end = pci->irq;
+
+ adata->acp3x_audio_mode = ACP3x_I2S_MODE;
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.name = "acp3x_rv_i2s";
+ pdevinfo.id = 0;
+ pdevinfo.parent = &pci->dev;
+ pdevinfo.num_res = 2;
+ pdevinfo.res = adata->res;
+ pdevinfo.data = &irqflags;
+ pdevinfo.size_data = sizeof(irqflags);
+
+ adata->pdev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->pdev)) {
+ dev_err(&pci->dev, "cannot register %s device\n",
+ pdevinfo.name);
+ ret = PTR_ERR(adata->pdev);
+ goto unmap_mmio;
+ }
+ break;
+ default:
+ dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
+ ret = -ENODEV;
+ goto unmap_mmio;
+ }
+ return 0;
+
+unmap_mmio:
+ pci_disable_msi(pci);
+ iounmap(adata->acp3x_base);
+release_regions:
+ pci_release_regions(pci);
+disable_pci:
+ pci_disable_device(pci);
+
+ return ret;
+}
+
+static void snd_acp3x_remove(struct pci_dev *pci)
+{
+ struct acp3x_dev_data *adata = pci_get_drvdata(pci);
+
+ platform_device_unregister(adata->pdev);
+ iounmap(adata->acp3x_base);
+
+ pci_disable_msi(pci);
+ pci_release_regions(pci);
+ pci_disable_device(pci);
+}
+
+static const struct pci_device_id snd_acp3x_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
+ .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
+ .class_mask = 0xffffff },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
+
+static struct pci_driver acp3x_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = snd_acp3x_ids,
+ .probe = snd_acp3x_probe,
+ .remove = snd_acp3x_remove,
+};
+
+module_pci_driver(acp3x_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_DESCRIPTION("AMD ACP3x PCI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9cc4f1848c9b..62bdb7e333b8 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ADAU7002
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
+ select SND_SOC_AK4118 if I2C
select SND_SOC_AK4458 if I2C
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4554
@@ -392,6 +393,11 @@ config SND_SOC_AK4104
tristate "AKM AK4104 CODEC"
depends on SPI_MASTER
+config SND_SOC_AK4118
+ tristate "AKM AK4118 CODEC"
+ depends on I2C
+ select REGMAP_I2C
+
config SND_SOC_AK4458
tristate "AKM AK4458 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8ffab8c8dbfa..66f55d185620 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o
snd-soc-adav803-objs := adav803.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
+snd-soc-ak4118-objs := ak4118.o
snd-soc-ak4458-objs := ak4458.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4554-objs := ak4554.o
@@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
+obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o
obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 32bc545c19cf..6dec8a65eafc 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = {
static int ak4104_spi_probe(struct spi_device *spi)
{
- struct device_node *np = spi->dev.of_node;
struct ak4104_private *ak4104;
+ struct gpio_desc *reset_gpiod;
unsigned int val;
int ret;
@@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi)
return ret;
}
- if (np) {
- enum of_gpio_flags flags;
- int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
-
- if (gpio_is_valid(gpio)) {
- ret = devm_gpio_request_one(&spi->dev, gpio,
- flags & OF_GPIO_ACTIVE_LOW ?
- GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
- "ak4104 reset");
- if (ret < 0)
- return ret;
- }
- }
+ reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpiod) &&
+ PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
/* read the 'reserved' register - according to the datasheet, it
* should contain 0x5b. Not a good way to verify the presence of
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
new file mode 100644
index 000000000000..238ab29f2bf4
--- /dev/null
+++ b/sound/soc/codecs/ak4118.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ak4118.c -- Asahi Kasei ALSA Soc Audio driver
+ *
+ * Copyright 2018 DEVIALET
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#define AK4118_REG_CLK_PWR_CTL 0x00
+#define AK4118_REG_FORMAT_CTL 0x01
+#define AK4118_REG_IO_CTL0 0x02
+#define AK4118_REG_IO_CTL1 0x03
+#define AK4118_REG_INT0_MASK 0x04
+#define AK4118_REG_INT1_MASK 0x05
+#define AK4118_REG_RCV_STATUS0 0x06
+#define AK4118_REG_RCV_STATUS1 0x07
+#define AK4118_REG_RXCHAN_STATUS0 0x08
+#define AK4118_REG_RXCHAN_STATUS1 0x09
+#define AK4118_REG_RXCHAN_STATUS2 0x0a
+#define AK4118_REG_RXCHAN_STATUS3 0x0b
+#define AK4118_REG_RXCHAN_STATUS4 0x0c
+#define AK4118_REG_TXCHAN_STATUS0 0x0d
+#define AK4118_REG_TXCHAN_STATUS1 0x0e
+#define AK4118_REG_TXCHAN_STATUS2 0x0f
+#define AK4118_REG_TXCHAN_STATUS3 0x10
+#define AK4118_REG_TXCHAN_STATUS4 0x11
+#define AK4118_REG_BURST_PREAMB_PC0 0x12
+#define AK4118_REG_BURST_PREAMB_PC1 0x13
+#define AK4118_REG_BURST_PREAMB_PD0 0x14
+#define AK4118_REG_BURST_PREAMB_PD1 0x15
+#define AK4118_REG_QSUB_CTL 0x16
+#define AK4118_REG_QSUB_TRACK 0x17
+#define AK4118_REG_QSUB_INDEX 0x18
+#define AK4118_REG_QSUB_MIN 0x19
+#define AK4118_REG_QSUB_SEC 0x1a
+#define AK4118_REG_QSUB_FRAME 0x1b
+#define AK4118_REG_QSUB_ZERO 0x1c
+#define AK4118_REG_QSUB_ABS_MIN 0x1d
+#define AK4118_REG_QSUB_ABS_SEC 0x1e
+#define AK4118_REG_QSUB_ABS_FRAME 0x1f
+#define AK4118_REG_GPE 0x20
+#define AK4118_REG_GPDR 0x21
+#define AK4118_REG_GPSCR 0x22
+#define AK4118_REG_GPLR 0x23
+#define AK4118_REG_DAT_MASK_DTS 0x24
+#define AK4118_REG_RX_DETECT 0x25
+#define AK4118_REG_STC_DAT_DETECT 0x26
+#define AK4118_REG_RXCHAN_STATUS5 0x27
+#define AK4118_REG_TXCHAN_STATUS5 0x28
+#define AK4118_REG_MAX 0x29
+
+#define AK4118_REG_FORMAT_CTL_DIF0 (1 << 4)
+#define AK4118_REG_FORMAT_CTL_DIF1 (1 << 5)
+#define AK4118_REG_FORMAT_CTL_DIF2 (1 << 6)
+
+struct ak4118_priv {
+ struct regmap *regmap;
+ struct gpio_desc *reset;
+ struct gpio_desc *irq;
+ struct snd_soc_component *component;
+};
+
+static const struct reg_default ak4118_reg_defaults[] = {
+ {AK4118_REG_CLK_PWR_CTL, 0x43},
+ {AK4118_REG_FORMAT_CTL, 0x6a},
+ {AK4118_REG_IO_CTL0, 0x88},
+ {AK4118_REG_IO_CTL1, 0x48},
+ {AK4118_REG_INT0_MASK, 0xee},
+ {AK4118_REG_INT1_MASK, 0xb5},
+ {AK4118_REG_RCV_STATUS0, 0x00},
+ {AK4118_REG_RCV_STATUS1, 0x10},
+ {AK4118_REG_TXCHAN_STATUS0, 0x00},
+ {AK4118_REG_TXCHAN_STATUS1, 0x00},
+ {AK4118_REG_TXCHAN_STATUS2, 0x00},
+ {AK4118_REG_TXCHAN_STATUS3, 0x00},
+ {AK4118_REG_TXCHAN_STATUS4, 0x00},
+ {AK4118_REG_GPE, 0x77},
+ {AK4118_REG_GPDR, 0x00},
+ {AK4118_REG_GPSCR, 0x00},
+ {AK4118_REG_GPLR, 0x00},
+ {AK4118_REG_DAT_MASK_DTS, 0x3f},
+ {AK4118_REG_RX_DETECT, 0x00},
+ {AK4118_REG_STC_DAT_DETECT, 0x00},
+ {AK4118_REG_TXCHAN_STATUS5, 0x00},
+};
+
+static const char * const ak4118_input_select_txt[] = {
+ "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
+};
+static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
+ ak4118_input_select_txt);
+
+static const struct snd_kcontrol_new ak4118_input_mux_controls =
+ SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
+
+static const char * const ak4118_iec958_fs_txt[] = {
+ "44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
+ "8000", "96000", "64000", "176400", "192000",
+};
+
+static const int ak4118_iec958_fs_val[] = {
+ 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
+ 0x4, 0x4, ak4118_iec958_fs_txt,
+ ak4118_iec958_fs_val);
+
+static struct snd_kcontrol_new ak4118_iec958_controls[] = {
+ SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
+ SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
+ SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
+ SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
+ SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
+};
+
+static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("INRX0"),
+ SND_SOC_DAPM_INPUT("INRX1"),
+ SND_SOC_DAPM_INPUT("INRX2"),
+ SND_SOC_DAPM_INPUT("INRX3"),
+ SND_SOC_DAPM_INPUT("INRX4"),
+ SND_SOC_DAPM_INPUT("INRX5"),
+ SND_SOC_DAPM_INPUT("INRX6"),
+ SND_SOC_DAPM_INPUT("INRX7"),
+ SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+ &ak4118_input_mux_controls),
+};
+
+static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
+ {"Input Mux", "RX0", "INRX0"},
+ {"Input Mux", "RX1", "INRX1"},
+ {"Input Mux", "RX2", "INRX2"},
+ {"Input Mux", "RX3", "INRX3"},
+ {"Input Mux", "RX4", "INRX4"},
+ {"Input Mux", "RX5", "INRX5"},
+ {"Input Mux", "RX6", "INRX6"},
+ {"Input Mux", "RX7", "INRX7"},
+};
+
+
+static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118,
+ unsigned int format)
+{
+ int dif;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dif = AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return dif;
+}
+
+static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118,
+ unsigned int format)
+{
+ int dif;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
+ AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return dif;
+}
+
+static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+ int dif;
+ int ret = 0;
+
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* component is master */
+ dif = ak4118_set_dai_fmt_master(ak4118, format);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /*component is slave */
+ dif = ak4118_set_dai_fmt_slave(ak4118, format);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ /* format not supported */
+ if (dif < 0) {
+ ret = dif;
+ goto exit;
+ }
+
+ ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
+ AK4118_REG_FORMAT_CTL_DIF0 |
+ AK4118_REG_FORMAT_CTL_DIF1 |
+ AK4118_REG_FORMAT_CTL_DIF2, dif);
+ if (ret < 0)
+ goto exit;
+
+exit:
+ return ret;
+}
+
+static int ak4118_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static const struct snd_soc_dai_ops ak4118_dai_ops = {
+ .hw_params = ak4118_hw_params,
+ .set_fmt = ak4118_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ak4118_dai = {
+ .name = "ak4118-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_22050 | 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_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE
+ },
+ .ops = &ak4118_dai_ops,
+};
+
+static irqreturn_t ak4118_irq_handler(int irq, void *data)
+{
+ struct ak4118_priv *ak4118 = data;
+ struct snd_soc_component *component = ak4118->component;
+ struct snd_kcontrol_new *kctl_new;
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_id *id;
+ unsigned int i;
+
+ if (!component)
+ return IRQ_NONE;
+
+ for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
+ kctl_new = &ak4118_iec958_controls[i];
+ kctl = snd_soc_card_get_kcontrol(component->card,
+ kctl_new->name);
+ if (!kctl)
+ continue;
+ id = &kctl->id;
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, id);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ak4118_probe(struct snd_soc_component *component)
+{
+ struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ ak4118->component = component;
+
+ /* release reset */
+ gpiod_set_value(ak4118->reset, 0);
+
+ /* unmask all int1 sources */
+ ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "failed to write regmap 0x%x 0x%x: %d\n",
+ AK4118_REG_INT1_MASK, 0x00, ret);
+ return ret;
+ }
+
+ /* rx detect enable on all channels */
+ ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "failed to write regmap 0x%x 0x%x: %d\n",
+ AK4118_REG_RX_DETECT, 0xff, ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
+ ARRAY_SIZE(ak4118_iec958_controls));
+ if (ret) {
+ dev_err(component->dev,
+ "failed to add component kcontrols: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ak4118_remove(struct snd_soc_component *component)
+{
+ struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+
+ /* hold reset */
+ gpiod_set_value(ak4118->reset, 1);
+}
+
+static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
+ .probe = ak4118_probe,
+ .remove = ak4118_remove,
+ .dapm_widgets = ak4118_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ak4118_dapm_widgets),
+ .dapm_routes = ak4118_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ak4118_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static const struct regmap_config ak4118_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .reg_defaults = ak4118_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
+
+ .cache_type = REGCACHE_NONE,
+ .max_register = AK4118_REG_MAX - 1,
+};
+
+static int ak4118_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct ak4118_priv *ak4118;
+ int ret;
+
+ ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
+ GFP_KERNEL);
+ if (ak4118 == NULL)
+ return -ENOMEM;
+
+ ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
+ if (IS_ERR(ak4118->regmap))
+ return PTR_ERR(ak4118->regmap);
+
+ i2c_set_clientdata(i2c, ak4118);
+
+ ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ak4118->reset)) {
+ ret = PTR_ERR(ak4118->reset);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&i2c->dev, "Failed to get reset: %d\n", ret);
+ return ret;
+ }
+
+ ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
+ if (IS_ERR(ak4118->irq)) {
+ ret = PTR_ERR(ak4118->irq);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
+ NULL, ak4118_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "ak4118-irq", ak4118);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118,
+ &ak4118_dai, 1);
+}
+
+static int ak4118_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_component(&i2c->dev);
+ return 0;
+}
+
+static const struct of_device_id ak4118_of_match[] = {
+ { .compatible = "asahi-kasei,ak4118", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ak4118_of_match);
+
+static const struct i2c_device_id ak4118_id_table[] = {
+ { "ak4118", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
+
+static struct i2c_driver ak4118_i2c_driver = {
+ .driver = {
+ .name = "ak4118",
+ .of_match_table = of_match_ptr(ak4118_of_match),
+ },
+ .id_table = ak4118_id_table,
+ .probe = ak4118_i2c_probe,
+ .remove = ak4118_i2c_remove,
+};
+
+module_i2c_driver(ak4118_i2c_driver);
+
+MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
+MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 299ada4dfaa0..70d4c89bd6fc 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_dai_ops ak4458_dai_ops = {
+static const struct snd_soc_dai_ops ak4458_dai_ops = {
.startup = ak4458_startup,
.hw_params = ak4458_hw_params,
.set_fmt = ak4458_set_dai_fmt,
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 448bb90c9c8e..8179512129d3 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream,
u8 bits;
int pcm_width = max(params_physical_width(params), ak5558->slot_width);
- /* set master/slave audio interface */
- bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
- bits &= ~AK5558_BITS;
-
switch (pcm_width) {
case 16:
- bits |= AK5558_DIF_24BIT_MODE;
+ bits = AK5558_DIF_24BIT_MODE;
break;
case 32:
- bits |= AK5558_DIF_32BIT_MODE;
+ bits = AK5558_DIF_32BIT_MODE;
break;
default:
return -EINVAL;
@@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
/* set master/slave audio interface */
- format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
- format &= ~AK5558_DIF;
-
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- format |= AK5558_DIF_I2S_MODE;
+ format = AK5558_DIF_I2S_MODE;
break;
case SND_SOC_DAIFMT_LEFT_J:
- format |= AK5558_DIF_MSB_MODE;
+ format = AK5558_DIF_MSB_MODE;
break;
case SND_SOC_DAIFMT_DSP_B:
- format |= AK5558_DIF_MSB_MODE;
+ format = AK5558_DIF_MSB_MODE;
break;
default:
return -EINVAL;
@@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream,
&ak5558_rate_constraints);
}
-static struct snd_soc_dai_ops ak5558_dai_ops = {
+static const struct snd_soc_dai_ops ak5558_dai_ops = {
.startup = ak5558_startup,
.hw_params = ak5558_hw_params,
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 3c266eeb89bf..33d74f163bd7 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -29,8 +29,8 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
/*
* The codec isn't really big-endian or little-endian, since the I2S
@@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = {
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
- struct device_node *np = i2c_client->dev.of_node;
struct cs4270_private *cs4270;
+ struct gpio_desc *reset_gpiod;
unsigned int val;
int ret, i;
@@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
if (ret < 0)
return ret;
- /* See if we have a way to bring the codec out of reset */
- if (np) {
- enum of_gpio_flags flags;
- int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
-
- if (gpio_is_valid(gpio)) {
- ret = devm_gpio_request_one(&i2c_client->dev, gpio,
- flags & OF_GPIO_ACTIVE_LOW ?
- GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
- "cs4270 reset");
- if (ret < 0)
- return ret;
- }
- }
+ reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpiod) &&
+ PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
if (IS_ERR(cs4270->regmap))
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 71322e0410ee..da921da50ef0 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -30,9 +30,39 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#define MAX_MODESWITCH_DELAY 70
+static int modeswitch_delay;
+module_param(modeswitch_delay, uint, 0644);
+
+static int wakeup_delay;
+module_param(wakeup_delay, uint, 0644);
+
struct dmic {
struct gpio_desc *gpio_en;
int wakeup_delay;
+ /* Delay after DMIC mode switch */
+ int modeswitch_delay;
+};
+
+int dmic_daiops_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct dmic *dmic = snd_soc_component_get_drvdata(component);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (dmic->modeswitch_delay)
+ mdelay(dmic->modeswitch_delay);
+
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+ .trigger = dmic_daiops_trigger,
};
static int dmic_aif_event(struct snd_soc_dapm_widget *w,
@@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
+ .ops = &dmic_dai_ops,
};
static int dmic_component_probe(struct snd_soc_component *component)
@@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component)
device_property_read_u32(component->dev, "wakeup-delay-ms",
&dmic->wakeup_delay);
+ device_property_read_u32(component->dev, "modeswitch-delay-ms",
+ &dmic->modeswitch_delay);
+ if (wakeup_delay)
+ dmic->wakeup_delay = wakeup_delay;
+ if (modeswitch_delay)
+ dmic->modeswitch_delay = modeswitch_delay;
+
+ if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY)
+ dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
snd_soc_component_set_drvdata(component, dmic);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 2aaa83028e55..ffecdaaa8cf2 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai);
-static struct snd_soc_dai_ops hdac_hda_dai_ops = {
+static const struct snd_soc_dai_ops hdac_hda_dai_ops = {
.startup = hdac_hda_dai_open,
.shutdown = hdac_hda_dai_close,
.prepare = hdac_hda_dai_prepare,
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index e63d6e33df48..3ab2949c1dfa 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt;
};
+/*
+ * pin to port mapping table where the value indicate the pin number and
+ * the index indicate the port number with 1 base.
+ */
+static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb};
+
struct hdac_hdmi_drv_data {
unsigned int vendor_nid;
+ const int *port_map; /* pin to port mapping table */
+ int port_num;
};
struct hdac_hdmi_priv {
@@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
return 0;
}
-#define INTEL_VENDOR_NID 0x08
-#define INTEL_GLK_VENDOR_NID 0x0b
+#define INTEL_VENDOR_NID_0x2 0x02
+#define INTEL_VENDOR_NID_0x8 0x08
+#define INTEL_VENDOR_NID_0xb 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
-#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
+#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
@@ -1538,7 +1547,26 @@ free_widgets:
static int hdac_hdmi_pin2port(void *aptr, int pin)
{
- return pin - 4; /* map NID 0x05 -> port #1 */
+ struct hdac_device *hdev = aptr;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+ const int *map = hdmi->drv_data->port_map;
+ int i;
+
+ if (!hdmi->drv_data->port_num)
+ return pin - 4; /* map NID 0x05 -> port #1 */
+
+ /*
+ * looking for the pin number in the mapping table and return
+ * the index which indicate the port number
+ */
+ for (i = 0; i < hdmi->drv_data->port_num; i++) {
+ if (pin == map[i])
+ return i + 1;
+ }
+
+ /* return -1 if pin number exceeds our expectation */
+ dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin);
+ return -1;
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_component *component = hdmi->component;
int i;
-
- /* Don't know how this mapping is derived */
- hda_nid_t pin_nid = port + 0x04;
+ hda_nid_t pin_nid;
+
+ if (!hdmi->drv_data->port_num) {
+ /* for legacy platforms */
+ pin_nid = port + 0x04;
+ } else if (port < hdmi->drv_data->port_num) {
+ /* get pin number from the pin2port mapping table */
+ pin_nid = hdmi->drv_data->port_map[port - 1];
+ } else {
+ dev_err(&hdev->dev, "Can't find the pin for port %d\n", port);
+ return;
+ }
dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
@@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
return port->eld.info.spk_alloc;
}
+static struct hdac_hdmi_drv_data intel_icl_drv_data = {
+ .vendor_nid = INTEL_VENDOR_NID_0x2,
+ .port_map = icl_pin2port_map,
+ .port_num = ARRAY_SIZE(icl_pin2port_map),
+};
+
static struct hdac_hdmi_drv_data intel_glk_drv_data = {
- .vendor_nid = INTEL_GLK_VENDOR_NID,
+ .vendor_nid = INTEL_VENDOR_NID_0xb,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
- .vendor_nid = INTEL_VENDOR_NID,
+ .vendor_nid = INTEL_VENDOR_NID_0x8,
};
static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
@@ -2031,13 +2074,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
* Turned off in the runtime_suspend during the first explicit
* pm_runtime_suspend call.
*/
- ret = snd_hdac_display_power(hdev->bus, true);
- if (ret < 0) {
- dev_err(&hdev->dev,
- "Cannot turn on display power on i915 err: %d\n",
- ret);
- return ret;
- }
+ snd_hdac_display_power(hdev->bus, hdev->addr, true);
ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais);
if (ret < 0) {
@@ -2065,6 +2102,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
struct hdac_hdmi_port *port, *port_next;
int i;
+ snd_hdac_display_power(hdev->bus, hdev->addr, false);
+
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
pcm->cvt = NULL;
if (list_empty(&pcm->port_list))
@@ -2170,7 +2209,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink = NULL;
- int err;
dev_dbg(dev, "Enter: %s\n", __func__);
@@ -2196,11 +2234,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
snd_hdac_ext_bus_link_put(bus, hlink);
- err = snd_hdac_display_power(bus, false);
- if (err < 0)
- dev_err(dev, "Cannot turn off display power on i915\n");
+ snd_hdac_display_power(bus, hdev->addr, false);
- return err;
+ return 0;
}
static int hdac_hdmi_runtime_resume(struct device *dev)
@@ -2208,7 +2244,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink = NULL;
- int err;
dev_dbg(dev, "Enter: %s\n", __func__);
@@ -2224,11 +2259,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
snd_hdac_ext_bus_link_get(bus, hlink);
- err = snd_hdac_display_power(bus, true);
- if (err < 0) {
- dev_err(dev, "Cannot turn on display power on i915\n");
- return err;
- }
+ snd_hdac_display_power(bus, hdev->addr, true);
hdac_hdmi_skl_enable_all_pins(hdev);
hdac_hdmi_skl_enable_dp12(hdev);
@@ -2258,6 +2289,8 @@ static const struct hda_device_id hdmi_list[] = {
&intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
+ HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI",
+ &intel_icl_drv_data),
{}
};
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index a09d01318f79..9c8616a7b61c 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = {
}
};
+static void max98373_reset(struct max98373_priv *max98373, struct device *dev)
+{
+ int ret, reg, count;
+
+ /* Software Reset */
+ ret = regmap_update_bits(max98373->regmap,
+ MAX98373_R2000_SW_RESET,
+ MAX98373_SOFT_RESET,
+ MAX98373_SOFT_RESET);
+ if (ret)
+ dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
+
+ count = 0;
+ while (count < 3) {
+ usleep_range(10000, 11000);
+ /* Software Reset Verification */
+ ret = regmap_read(max98373->regmap,
+ MAX98373_R21FF_REV_ID, &reg);
+ if (!ret) {
+ dev_info(dev, "Reset completed (retry:%d)\n", count);
+ return;
+ }
+ count++;
+ }
+ dev_err(dev, "Reset failed. (ret:%d)\n", ret);
+}
+
static int max98373_probe(struct snd_soc_component *component)
{
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
/* Software Reset */
- regmap_write(max98373->regmap,
- MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
- usleep_range(10000, 11000);
+ max98373_reset(max98373, component->dev);
/* IV default slot configuration */
regmap_write(max98373->regmap,
@@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
- regmap_write(max98373->regmap,
- MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
- usleep_range(10000, 11000);
+ max98373_reset(max98373, dev);
regcache_cache_only(max98373->regmap, false);
regcache_sync(max98373->regmap);
return 0;
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 4ea3287162ad..8600c5439e1e 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -1,12 +1,10 @@
-/*
- * max9867.c -- max9867 ALSA SoC Audio driver
- *
- * Copyright 2013-15 Maxim Integrated Products
- *
- * 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
+//
+// MAX9867 ALSA SoC codec driver
+//
+// Copyright 2013-2015 Maxim Integrated Products
+// Copyright 2018 Ladislav Michl <ladis@linux-mips.org>
+//
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -23,254 +21,237 @@ static const char *const max9867_spmode[] = {
"Stereo Single", "Mono Single",
"Stereo Single Fast", "Mono Single Fast"
};
-static const char *const max9867_sidetone_text[] = {
- "None", "Left", "Right", "LeftRight", "LeftRightDiv2",
-};
static const char *const max9867_filter_text[] = {"IIR", "FIR"};
static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7,
max9867_filter_text);
static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0,
max9867_spmode);
-static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6,
- max9867_sidetone_text);
-static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
-static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
-static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
-static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
-static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
- 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv,
+ 0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1),
+ 3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0),
+ 18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0),
+ 26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0),
+ 35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0),
+);
+static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0);
+static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv,
+ 0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1),
+ 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
);
static const struct snd_kcontrol_new max9867_snd_controls[] = {
- SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
- MAX9867_RIGHTVOL, 0, 63, 1),
- SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN,
- MAX9867_RIGHTMICGAIN,
- 0, 15, 1, max9860_capture_tlv),
- SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN,
- MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv),
- SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN,
- MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv),
- SOC_ENUM("Digital Sidetone Src", max9867_sidetone),
- SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1),
- SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0),
- SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1),
- SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL,
- 4, 15, 1, max9860_adc_left_tlv),
- SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL,
- 0, 15, 1, max9860_adc_right_tlv),
+ SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL,
+ MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv),
+ SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL,
+ MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv),
+ SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN,
+ MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv),
+ SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN,
+ MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv),
+ SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1),
+ SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1,
+ max9867_dac_tlv),
+ SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0,
+ max9867_dacboost_tlv),
+ SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1,
+ max9867_adc_tlv),
SOC_ENUM("Speaker Mode", max9867_spkmode),
SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0),
- SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0),
+ SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0),
SOC_ENUM("DSP Filter", max9867_filter),
};
-static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"};
+/* Input mixer */
+static const struct snd_kcontrol_new max9867_input_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0),
+ SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0),
+};
+
+/* Output mixer */
+static const struct snd_kcontrol_new max9867_output_mixer_controls[] = {
+ SOC_DAPM_DOUBLE_R("Line Bypass Switch",
+ MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1),
+};
-static SOC_ENUM_SINGLE_DECL(max9867_mux_enum,
- MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT,
- max9867_mux);
+/* Sidetone mixer */
+static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0),
+};
-static const struct snd_kcontrol_new max9867_dapm_mux_controls =
- SOC_DAPM_ENUM("Route", max9867_mux_enum);
+/* Line out switch */
+static const struct snd_kcontrol_new max9867_line_out_control =
+ SOC_DAPM_DOUBLE_R("Switch",
+ MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1);
-static const struct snd_kcontrol_new max9867_left_dapm_control =
- SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0);
-static const struct snd_kcontrol_new max9867_right_dapm_control =
- SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0);
-static const struct snd_kcontrol_new max9867_line_dapm_control =
- SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1);
static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = {
- SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0),
- SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0),
- SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_OUTPUT("HPOUT"),
-
- SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
- SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
- SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
- &max9867_dapm_mux_controls),
-
- SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1,
- &max9867_left_dapm_control),
- SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1,
- &max9867_right_dapm_control),
- SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0,
- &max9867_line_dapm_control),
- SND_SOC_DAPM_INPUT("LINE_IN"),
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("MICR"),
+ SND_SOC_DAPM_INPUT("LINL"),
+ SND_SOC_DAPM_INPUT("LINR"),
+
+ SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
+ max9867_input_mixer_controls,
+ ARRAY_SIZE(max9867_input_mixer_controls)),
+ SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
+ SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
+
+ SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0,
+ max9867_sidetone_mixer_controls,
+ ARRAY_SIZE(max9867_sidetone_mixer_controls)),
+ SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0,
+ max9867_output_mixer_controls,
+ ARRAY_SIZE(max9867_output_mixer_controls)),
+ SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0),
+ SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0),
+ SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0,
+ &max9867_line_out_control),
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
};
static const struct snd_soc_dapm_route max9867_audio_map[] = {
- {"Left DAC", NULL, "DAI_OUT"},
- {"Right DAC", NULL, "DAI_OUT"},
- {"Output Mixer", NULL, "Left DAC"},
- {"Output Mixer", NULL, "Right DAC"},
- {"HPOUT", NULL, "Output Mixer"},
-
- {"Left ADC", NULL, "DAI_IN"},
- {"Right ADC", NULL, "DAI_IN"},
- {"Input Mixer", NULL, "Left ADC"},
- {"Input Mixer", NULL, "Right ADC"},
- {"Input Mux", "Line", "Input Mixer"},
- {"Input Mux", "Mic", "Input Mixer"},
- {"Input Mux", "Mic_Line", "Input Mixer"},
- {"Right Line", "Switch", "Input Mux"},
- {"Left Line", "Switch", "Input Mux"},
- {"LINE_IN", NULL, "Left Line"},
- {"LINE_IN", NULL, "Right Line"},
+ {"Left Line Input", NULL, "LINL"},
+ {"Right Line Input", NULL, "LINR"},
+ {"Input Mixer", "Mic Capture Switch", "MICL"},
+ {"Input Mixer", "Mic Capture Switch", "MICR"},
+ {"Input Mixer", "Line Capture Switch", "Left Line Input"},
+ {"Input Mixer", "Line Capture Switch", "Right Line Input"},
+ {"ADCL", NULL, "Input Mixer"},
+ {"ADCR", NULL, "Input Mixer"},
+
+ {"Digital", "Sidetone Switch", "ADCL"},
+ {"Digital", "Sidetone Switch", "ADCR"},
+ {"DACL", NULL, "Digital"},
+ {"DACR", NULL, "Digital"},
+
+ {"Output Mixer", "Line Bypass Switch", "Left Line Input"},
+ {"Output Mixer", "Line Bypass Switch", "Right Line Input"},
+ {"Output Mixer", NULL, "DACL"},
+ {"Output Mixer", NULL, "DACR"},
+ {"Master Playback", "Switch", "Output Mixer"},
+ {"LOUT", NULL, "Master Playback"},
+ {"ROUT", NULL, "Master Playback"},
+};
+
+static const unsigned int max9867_rates_44k1[] = {
+ 11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = {
+ .list = max9867_rates_44k1,
+ .count = ARRAY_SIZE(max9867_rates_44k1),
};
-enum rates {
- pcm_rate_8, pcm_rate_16, pcm_rate_24,
- pcm_rate_32, pcm_rate_44,
- pcm_rate_48, max_pcm_rate,
+static const unsigned int max9867_rates_48k[] = {
+ 8000, 16000, 32000, 48000,
};
-static const struct ni_div_rates {
- u32 mclk;
- u16 ni[max_pcm_rate];
-} ni_div[] = {
- {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} },
- {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} },
- {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} },
- {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} },
- {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} },
- {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} },
- {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} },
- {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} },
+static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = {
+ .list = max9867_rates_48k,
+ .count = ARRAY_SIZE(max9867_rates_48k),
};
-static inline int get_ni_value(int mclk, int rate)
+struct max9867_priv {
+ struct regmap *regmap;
+ const struct snd_pcm_hw_constraint_list *constraints;
+ unsigned int sysclk, pclk;
+ bool master, dsp_a;
+};
+
+static int max9867_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
- int i, ret = 0;
+ struct max9867_priv *max9867 =
+ snd_soc_component_get_drvdata(dai->component);
- /* find the closest rate index*/
- for (i = 0; i < ARRAY_SIZE(ni_div); i++) {
- if (ni_div[i].mclk >= mclk)
- break;
- }
- if (i == ARRAY_SIZE(ni_div))
- return -EINVAL;
+ if (max9867->constraints)
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, max9867->constraints);
- switch (rate) {
- case 8000:
- return ni_div[i].ni[pcm_rate_8];
- case 16000:
- return ni_div[i].ni[pcm_rate_16];
- case 32000:
- return ni_div[i].ni[pcm_rate_32];
- case 44100:
- return ni_div[i].ni[pcm_rate_44];
- case 48000:
- return ni_div[i].ni[pcm_rate_48];
- default:
- pr_err("%s wrong rate %d\n", __func__, rate);
- ret = -EINVAL;
- }
- return ret;
+ return 0;
}
static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
+ int value;
+ unsigned long int rate, ratio;
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
- unsigned int ni_h, ni_l;
- int value;
+ unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params),
+ max9867->pclk);
- value = get_ni_value(max9867->sysclk, params_rate(params));
- if (value < 0)
- return value;
-
- ni_h = (0xFF00 & value) >> 8;
- ni_l = 0x00FF & value;
/* set up the ni value */
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
- MAX9867_NI_HIGH_MASK, ni_h);
+ MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8);
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
- MAX9867_NI_LOW_MASK, ni_l);
- if (!max9867->master) {
- /*
- * digital pll locks on to any externally supplied LRCLK signal
- * and also enable rapid lock mode.
- */
- regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
- MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
- regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
- MAX9867_PLL, MAX9867_PLL);
- } else {
- unsigned long int bclk_rate, pclk_bclk_ratio;
- int bclk_value;
-
- bclk_rate = params_rate(params) * 2 * params_width(params);
- pclk_bclk_ratio = max9867->pclk/bclk_rate;
- switch (params_width(params)) {
- case 8:
- case 16:
- switch (pclk_bclk_ratio) {
- case 2:
- bclk_value = MAX9867_IFC1B_PCLK_2;
- break;
- case 4:
- bclk_value = MAX9867_IFC1B_PCLK_4;
- break;
+ MAX9867_NI_LOW_MASK, 0x00FF & ni);
+ if (max9867->master) {
+ if (max9867->dsp_a) {
+ value = MAX9867_IFC1B_48X;
+ } else {
+ rate = params_rate(params) * 2 * params_width(params);
+ ratio = max9867->pclk / rate;
+ switch (params_width(params)) {
case 8:
- bclk_value = MAX9867_IFC1B_PCLK_8;
- break;
case 16:
- bclk_value = MAX9867_IFC1B_PCLK_16;
+ switch (ratio) {
+ case 2:
+ value = MAX9867_IFC1B_PCLK_2;
+ break;
+ case 4:
+ value = MAX9867_IFC1B_PCLK_4;
+ break;
+ case 8:
+ value = MAX9867_IFC1B_PCLK_8;
+ break;
+ case 16:
+ value = MAX9867_IFC1B_PCLK_16;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 24:
+ value = MAX9867_IFC1B_48X;
+ break;
+ case 32:
+ value = MAX9867_IFC1B_64X;
break;
default:
- dev_err(component->dev,
- "unsupported sampling rate\n");
return -EINVAL;
}
- break;
- case 24:
- bclk_value = MAX9867_IFC1B_24BIT;
- break;
- case 32:
- bclk_value = MAX9867_IFC1B_32BIT;
- break;
- default:
- dev_err(component->dev, "unsupported sampling rate\n");
- return -EINVAL;
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
- MAX9867_IFC1B_BCLK_MASK, bclk_value);
+ MAX9867_IFC1B_BCLK_MASK, value);
+ } else {
+ /*
+ * digital pll locks on to any externally supplied LRCLK signal
+ * and also enable rapid lock mode.
+ */
+ regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
+ MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
+ regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
+ MAX9867_PLL, MAX9867_PLL);
}
return 0;
}
-static int max9867_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
-
- regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
- MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
- return 0;
-}
-
static int max9867_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
- if (mute)
- regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
- MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK);
- else
- regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
- MAX9867_DAC_MUTE_MASK, 0);
- return 0;
+ return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
+ 1 << 6, !!mute << 6);
}
static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/* Set the prescaler based on the master clock frequency*/
if (freq >= 10000000 && freq <= 20000000) {
value |= MAX9867_PSCLK_10_20;
- max9867->pclk = freq;
+ max9867->pclk = freq;
} else if (freq >= 20000000 && freq <= 40000000) {
value |= MAX9867_PSCLK_20_40;
- max9867->pclk = freq/2;
+ max9867->pclk = freq / 2;
} else if (freq >= 40000000 && freq <= 60000000) {
value |= MAX9867_PSCLK_40_60;
- max9867->pclk = freq/4;
+ max9867->pclk = freq / 4;
} else {
dev_err(component->dev,
"Invalid clock frequency %uHz (required 10-60MHz)\n",
freq);
return -EINVAL;
}
- value = value << MAX9867_PSCLK_SHIFT;
+ if (freq % 48000 == 0)
+ max9867->constraints = &max9867_constraints_48k;
+ else if (freq % 44100 == 0)
+ max9867->constraints = &max9867_constraints_44k1;
+ else
+ dev_warn(component->dev,
+ "Unable to set exact rate with %uHz clock frequency\n",
+ freq);
max9867->sysclk = freq;
+ value = value << MAX9867_PSCLK_SHIFT;
/* exact integer mode is not supported */
value &= ~MAX9867_FREQ_MASK;
regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
@@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_component *component = codec_dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
- u8 iface1A = 0, iface1B = 0;
+ u8 iface1A, iface1B;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- max9867->master = 1;
- iface1A |= MAX9867_MASTER;
+ max9867->master = true;
+ iface1A = MAX9867_MASTER;
+ iface1B = MAX9867_IFC1B_48X;
break;
case SND_SOC_DAIFMT_CBS_CFS:
- max9867->master = 0;
- iface1A &= ~MAX9867_MASTER;
+ max9867->master = false;
+ iface1A = iface1B = 0;
break;
default:
return -EINVAL;
@@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
+ max9867->dsp_a = false;
iface1A |= MAX9867_I2S_DLY;
break;
case SND_SOC_DAIFMT_DSP_A:
+ max9867->dsp_a = true;
iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ;
break;
default:
@@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
+
return 0;
}
static const struct snd_soc_dai_ops max9867_dai_ops = {
- .set_fmt = max9867_dai_set_fmt,
.set_sysclk = max9867_set_dai_sysclk,
- .prepare = max9867_prepare,
+ .set_fmt = max9867_dai_set_fmt,
.digital_mute = max9867_mute,
- .hw_params = max9867_dai_hw_params,
+ .startup = max9867_startup,
+ .hw_params = max9867_dai_hw_params,
};
-#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
-#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-
static struct snd_soc_dai_driver max9867_dai[] = {
{
.name = "max9867-aif1",
@@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = MAX9867_RATES,
- .formats = MAX9867_FORMATS,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 2,
- .rates = MAX9867_RATES,
- .formats = MAX9867_FORMATS,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &max9867_dai_ops,
.symmetric_rates = 1,
}
};
-#ifdef CONFIG_PM_SLEEP
-static int max9867_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int max9867_suspend(struct snd_soc_component *component)
{
- struct max9867_priv *max9867 = dev_get_drvdata(dev);
+ snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
- /* Drop down to power saving mode when system is suspended */
- regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
- MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK);
return 0;
}
-static int max9867_resume(struct device *dev)
+static int max9867_resume(struct snd_soc_component *component)
{
- struct max9867_priv *max9867 = dev_get_drvdata(dev);
+ snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
- regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
- MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
return 0;
}
+#else
+#define max9867_suspend NULL
+#define max9867_resume NULL
#endif
+static int max9867_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ int err;
+ struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ err = regcache_sync(max9867->regmap);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+ MAX9867_SHTDOWN, MAX9867_SHTDOWN);
+ if (err)
+ return err;
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+ MAX9867_SHTDOWN, 0);
+ if (err)
+ return err;
+
+ regcache_mark_dirty(max9867->regmap);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_component_driver max9867_component = {
.controls = max9867_snd_controls,
.num_controls = ARRAY_SIZE(max9867_snd_controls),
@@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = {
.num_dapm_routes = ARRAY_SIZE(max9867_audio_map),
.dapm_widgets = max9867_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets),
+ .suspend = max9867_suspend,
+ .resume = max9867_resume,
+ .set_bias_level = max9867_set_bias_level,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
@@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = {
{ 0x0B, 0x00 },
{ 0x0C, 0x00 },
{ 0x0D, 0x00 },
- { 0x0E, 0x00 },
- { 0x0F, 0x00 },
+ { 0x0E, 0x40 },
+ { 0x0F, 0x40 },
{ 0x10, 0x00 },
{ 0x11, 0x00 },
{ 0x12, 0x00 },
@@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max9867_priv *max9867;
- int ret = 0, reg;
+ int ret, reg;
- max9867 = devm_kzalloc(&i2c->dev,
- sizeof(*max9867), GFP_KERNEL);
+ max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL);
if (!max9867)
return -ENOMEM;
@@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
return ret;
}
- ret = regmap_read(max9867->regmap,
- MAX9867_REVISION, &reg);
+ ret = regmap_read(max9867->regmap, MAX9867_REVISION, &reg);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read: %d\n", ret);
return ret;
@@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_info(&i2c->dev, "device revision: %x\n", reg);
ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
max9867_dai, ARRAY_SIZE(max9867_dai));
- if (ret < 0) {
+ if (ret < 0)
dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
- return ret;
- }
return ret;
}
@@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max9867_of_match);
-static const struct dev_pm_ops max9867_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
-};
-
static struct i2c_driver max9867_i2c_driver = {
.driver = {
.name = "max9867",
.of_match_table = of_match_ptr(max9867_of_match),
- .pm = &max9867_pm_ops,
},
.probe = max9867_i2c_probe,
.id_table = max9867_i2c_id,
@@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = {
module_i2c_driver(max9867_i2c_driver);
-MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
-MODULE_DESCRIPTION("ALSA SoC MAX9867 driver");
+MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
+MODULE_DESCRIPTION("ASoC MAX9867 driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h
index 55cd9976ff47..2277798291a1 100644
--- a/sound/soc/codecs/max9867.h
+++ b/sound/soc/codecs/max9867.h
@@ -26,13 +26,11 @@
#define MAX9867_PSCLK_10_20 0x1
#define MAX9867_PSCLK_20_40 0x2
#define MAX9867_PSCLK_40_60 0x3
-#define MAX9867_AUDIOCLKHIGH 0x06
-#define MAX9867_NI_HIGH_WIDTH 0x7
-#define MAX9867_NI_HIGH_MASK 0x7F
-#define MAX9867_NI_LOW_MASK 0x7F
-#define MAX9867_NI_LOW_SHIFT 0x1
-#define MAX9867_PLL (1<<7)
-#define MAX9867_AUDIOCLKLOW 0x07
+#define MAX9867_AUDIOCLKHIGH 0x06
+#define MAX9867_NI_HIGH_MASK 0x7F
+#define MAX9867_NI_LOW_MASK 0xFE
+#define MAX9867_PLL (1<<7)
+#define MAX9867_AUDIOCLKLOW 0x07
#define MAX9867_RAPID_LOCK 0x01
#define MAX9867_IFC1A 0x08
#define MAX9867_MASTER (1<<7)
@@ -43,40 +41,29 @@
#define MAX9867_BCI_MODE (1<<5)
#define MAX9867_IFC1B 0x09
#define MAX9867_IFC1B_BCLK_MASK 7
-#define MAX9867_IFC1B_32BIT 0x01
-#define MAX9867_IFC1B_24BIT 0x02
-#define MAX9867_IFC1B_PCLK_2 4
-#define MAX9867_IFC1B_PCLK_4 5
-#define MAX9867_IFC1B_PCLK_8 6
-#define MAX9867_IFC1B_PCLK_16 7
+#define MAX9867_IFC1B_64X 0x01
+#define MAX9867_IFC1B_48X 0x02
+#define MAX9867_IFC1B_PCLK_2 0x04
+#define MAX9867_IFC1B_PCLK_4 0x05
+#define MAX9867_IFC1B_PCLK_8 0x06
+#define MAX9867_IFC1B_PCLK_16 0x07
#define MAX9867_CODECFLTR 0x0a
-#define MAX9867_DACGAIN 0x0b
+#define MAX9867_SIDETONE 0x0b
#define MAX9867_DACLEVEL 0x0c
-#define MAX9867_DAC_MUTE_SHIFT 0x6
-#define MAX9867_DAC_MUTE_WIDTH 0x1
-#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT)
#define MAX9867_ADCLEVEL 0x0d
#define MAX9867_LEFTLINELVL 0x0e
-#define MAX9867_RIGTHLINELVL 0x0f
+#define MAX9867_RIGHTLINELVL 0x0f
#define MAX9867_LEFTVOL 0x10
#define MAX9867_RIGHTVOL 0x11
#define MAX9867_LEFTMICGAIN 0x12
#define MAX9867_RIGHTMICGAIN 0x13
#define MAX9867_INPUTCONFIG 0x14
-#define MAX9867_INPUT_SHIFT 0x6
#define MAX9867_MICCONFIG 0x15
#define MAX9867_MODECONFIG 0x16
#define MAX9867_PWRMAN 0x17
-#define MAX9867_SHTDOWN_MASK (1<<7)
+#define MAX9867_SHTDOWN 0x80
#define MAX9867_REVISION 0xff
#define MAX9867_CACHEREGNUM 10
-/* codec private data */
-struct max9867_priv {
- struct regmap *regmap;
- unsigned int sysclk;
- unsigned int pclk;
- unsigned int master;
-};
#endif
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index e3c8cd17daf2..4dd1a609756b 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -585,7 +585,7 @@ static int nau8540_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;
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index 622ce947f134..c6152a044416 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -1,18 +1,14 @@
-/*
- * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver
- *
- * Copyright 2017 Nuvoton Technology Corp.
- *
- * Author: David Lin <ctlin0@nuvoton.com>
- * Co-author: John Hsu <kchsu0@nuvoton.com>
- * Co-author: Seven Li <wtli@nuvoton.com>
- *
- * Based on WM8974.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
+//
+// nau8822.c -- NAU8822 ALSA Soc Audio driver
+//
+// Copyright 2017 Nuvoton Technology Crop.
+//
+// Author: David Lin <ctlin0@nuvoton.com>
+// Co-author: John Hsu <kchsu0@nuvoton.com>
+// Co-author: Seven Li <wtli@nuvoton.com>
+//
+// Based on WM8974.c
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index aa79c969cd44..9c552983a293 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -1,13 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * nau8822.h -- NAU8822 Soc Audio Codec driver
+ * nau8822.h -- NAU8822 ALSA SoC Audio driver
+ *
+ * Copyright 2017 Nuvoton Technology Crop.
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.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 __NAU8822_H__
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index b9fed99d8b5e..7bbcbf5f05c8 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
{
u32 gain, sidetone;
- if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) {
- WARN_ON(1);
+ if (WARN_ON(sig_org == 0 || sig_cros == 0))
return 0;
- }
sig_org = nau8825_intlog10_dec3(sig_org);
sig_cros = nau8825_intlog10_dec3(sig_cros);
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 771b46e1974b..6714aa8d9026 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
};
static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
+ PCM3060_REG_SHIFT_DAPSV, 1),
+
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
SND_SOC_DAPM_INPUT("INL"),
SND_SOC_DAPM_INPUT("INR"),
+
+ SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
+ PCM3060_REG_SHIFT_ADPSV, 1),
};
static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
- { "OUTL", NULL, "Playback" },
- { "OUTR", NULL, "Playback" },
+ { "OUTL", NULL, "DAC" },
+ { "OUTR", NULL, "DAC" },
- { "Capture", NULL, "INL" },
- { "Capture", NULL, "INR" },
+ { "ADC", NULL, "INL" },
+ { "ADC", NULL, "INR" },
};
/* soc component */
@@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap);
/* device */
+static void pcm3060_parse_dt(const struct device_node *np,
+ struct pcm3060_priv *priv)
+{
+ priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
+}
+
int pcm3060_probe(struct device *dev)
{
int rc;
+ struct pcm3060_priv *priv = dev_get_drvdata(dev);
+
+ if (dev->of_node)
+ pcm3060_parse_dt(dev->of_node, priv);
+
+ if (priv->out_se)
+ regmap_update_bits(priv->regmap, PCM3060_REG64,
+ PCM3060_REG_SE, PCM3060_REG_SE);
rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
pcm3060_dai,
diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h
index fd89a68aa8a7..6a027b4a845d 100644
--- a/sound/soc/codecs/pcm3060.h
+++ b/sound/soc/codecs/pcm3060.h
@@ -25,6 +25,7 @@ struct pcm3060_priv_dai {
struct pcm3060_priv {
struct regmap *regmap;
struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
+ u8 out_se: 1;
};
int pcm3060_probe(struct device *dev);
@@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev);
#define PCM3060_REG_MRST 0x80
#define PCM3060_REG_SRST 0x40
#define PCM3060_REG_ADPSV 0x20
+#define PCM3060_REG_SHIFT_ADPSV 0x05
#define PCM3060_REG_DAPSV 0x10
+#define PCM3060_REG_SHIFT_DAPSV 0x04
#define PCM3060_REG_SE 0x01
#define PCM3060_REG65 0x41
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 52cc950c9fd1..08d3fe192e65 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
- SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
- SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
- SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
- SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
@@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
- SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
- SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
- SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
@@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
unsigned int fmt;
unsigned int sample_min;
unsigned int channel_max;
+ unsigned int channel_maxs[] = {
+ 6, /* rx */
+ 8 /* tx */
+ };
if (tx)
fmt = pcm3168a->dac_fmt;
@@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
channel_max = 2;
break;
case PCM3168A_FMT_LEFT_J:
- sample_min = 24;
- if (tx)
- channel_max = 8;
- else
- channel_max = 6;
- break;
case PCM3168A_FMT_I2S:
sample_min = 24;
- if (tx)
- channel_max = 8;
- else
- channel_max = 6;
+ channel_max = channel_maxs[tx];
break;
default:
sample_min = 24;
@@ -770,15 +758,22 @@ err_clk:
}
EXPORT_SYMBOL_GPL(pcm3168a_probe);
-void pcm3168a_remove(struct device *dev)
+static void pcm3168a_disable(struct device *dev)
{
struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
- pm_runtime_disable(dev);
regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
- pcm3168a->supplies);
+ pcm3168a->supplies);
clk_disable_unprepare(pcm3168a->scki);
}
+
+void pcm3168a_remove(struct device *dev)
+{
+ pm_runtime_disable(dev);
+#ifndef CONFIG_PM
+ pcm3168a_disable(dev);
+#endif
+}
EXPORT_SYMBOL_GPL(pcm3168a_remove);
#ifdef CONFIG_PM
@@ -833,10 +828,7 @@ static int pcm3168a_rt_suspend(struct device *dev)
regcache_cache_only(pcm3168a->regmap, true);
- regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
- pcm3168a->supplies);
-
- clk_disable_unprepare(pcm3168a->scki);
+ pcm3168a_disable(dev);
return 0;
}
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index f0f2d4fd3769..6cb1653be804 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -53,6 +53,8 @@ struct pcm512x_priv {
unsigned long overclock_pll;
unsigned long overclock_dac;
unsigned long overclock_dsp;
+ int mute;
+ struct mutex mutex;
};
/*
@@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds =
SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
pcm512x_ramp_step_text);
+static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
+{
+ return regmap_update_bits(
+ pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
+ (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
+ | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
+}
+
+static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&pcm512x->mutex);
+ ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
+ ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
+ mutex_unlock(&pcm512x->mutex);
+
+ return 0;
+}
+
+static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+ int ret, changed = 0;
+
+ mutex_lock(&pcm512x->mutex);
+
+ if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
+ pcm512x->mute ^= 0x4;
+ changed = 1;
+ }
+ if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
+ pcm512x->mute ^= 0x2;
+ changed = 1;
+ }
+
+ if (changed) {
+ ret = pcm512x_update_mute(pcm512x);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to update digital mute: %d\n", ret);
+ mutex_unlock(&pcm512x->mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&pcm512x->mutex);
+
+ return changed;
+}
+
static const struct snd_kcontrol_new pcm512x_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
@@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
-SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
- PCM512x_RQMR_SHIFT, 1, 1),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Digital Playback Switch",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_stereo_info,
+ .get = pcm512x_digital_playback_switch_get,
+ .put = pcm512x_digital_playback_switch_put
+},
SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
SOC_ENUM("DSP Program", pcm512x_dsp_program),
@@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_component *component = dai->component;
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+ int ret;
+ unsigned int mute_det;
+
+ mutex_lock(&pcm512x->mutex);
+
+ if (mute) {
+ pcm512x->mute |= 0x1;
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
+ PCM512x_RQML | PCM512x_RQMR,
+ PCM512x_RQML | PCM512x_RQMR);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set digital mute: %d\n", ret);
+ mutex_unlock(&pcm512x->mutex);
+ return ret;
+ }
+
+ regmap_read_poll_timeout(pcm512x->regmap,
+ PCM512x_ANALOG_MUTE_DET,
+ mute_det, (mute_det & 0x3) == 0,
+ 200, 10000);
+
+ mutex_unlock(&pcm512x->mutex);
+ } else {
+ pcm512x->mute &= ~0x1;
+ ret = pcm512x_update_mute(pcm512x);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to update digital mute: %d\n", ret);
+ mutex_unlock(&pcm512x->mutex);
+ return ret;
+ }
+
+ regmap_read_poll_timeout(pcm512x->regmap,
+ PCM512x_ANALOG_MUTE_DET,
+ mute_det,
+ (mute_det & 0x3)
+ == ((~pcm512x->mute >> 1) & 0x3),
+ 200, 10000);
+ }
+
+ mutex_unlock(&pcm512x->mutex);
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
+ .digital_mute = pcm512x_digital_mute,
};
static struct snd_soc_dai_driver pcm512x_dai = {
@@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (!pcm512x)
return -ENOMEM;
+ mutex_init(&pcm512x->mutex);
+
dev_set_drvdata(dev, pcm512x);
pcm512x->regmap = regmap;
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
index d70d9c0c2088..9dda8693498e 100644
--- a/sound/soc/codecs/pcm512x.h
+++ b/sound/soc/codecs/pcm512x.h
@@ -112,7 +112,9 @@
#define PCM512x_RQST_SHIFT 4
/* Page 0, Register 3 - mute */
+#define PCM512x_RQMR (1 << 0)
#define PCM512x_RQMR_SHIFT 0
+#define PCM512x_RQML (1 << 4)
#define PCM512x_RQML_SHIFT 4
/* Page 0, Register 4 - PLL */
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index 27f7445b2432..e74b2e8cd423 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1246,6 +1246,7 @@ MODULE_DEVICE_TABLE(of, rt5660_of_match);
static const struct acpi_device_id rt5660_acpi_match[] = {
{ "10EC5660", 0 },
+ { "10EC3277", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match);
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 7eb2cbd39d6e..da6647015708 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
+#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -33,6 +34,9 @@
#define RT5663_DEVICE_ID_2 0x6451
#define RT5663_DEVICE_ID_1 0x6406
+#define RT5663_POWER_ON_DELAY_MS 300
+#define RT5663_SUPPLY_CURRENT_UA 500000
+
enum {
CODEC_VER_1,
CODEC_VER_0,
@@ -48,6 +52,11 @@ struct impedance_mapping_table {
unsigned int dc_offset_r_manual_mic;
};
+static const char *const rt5663_supply_names[] = {
+ "avdd",
+ "cpvdd",
+};
+
struct rt5663_priv {
struct snd_soc_component *component;
struct rt5663_platform_data pdata;
@@ -56,6 +65,7 @@ struct rt5663_priv {
struct snd_soc_jack *hs_jack;
struct timer_list btn_check_timer;
struct impedance_mapping_table *imp_table;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)];
int codec_ver;
int sysclk;
@@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
{
struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5663_priv *rt5663;
- int ret;
+ int ret, i;
unsigned int val;
struct regmap *regmap;
@@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
else
rt5663_parse_dp(rt5663, &i2c->dev);
+ for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++)
+ rt5663->supplies[i].supply = rt5663_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev,
+ ARRAY_SIZE(rt5663->supplies),
+ rt5663->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Set load for regulator. */
+ for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) {
+ ret = regulator_set_load(rt5663->supplies[i].consumer,
+ RT5663_SUPPLY_CURRENT_UA);
+ if (ret < 0) {
+ dev_err(&i2c->dev,
+ "Failed to set regulator load on %s, ret: %d\n",
+ rt5663->supplies[i].supply, ret);
+ return ret;
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies),
+ rt5663->supplies);
+
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+ msleep(RT5663_POWER_ON_DELAY_MS);
+
regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
ret);
- return ret;
+ goto err_enable;
}
ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
@@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev,
"Device with ID register %#x is not rt5663\n",
val);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_enable;
}
if (IS_ERR(rt5663->regmap)) {
ret = PTR_ERR(rt5663->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
- return ret;
+ goto err_enable;
}
/* reset and calibrate */
@@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
ret = request_irq(i2c->irq, rt5663_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5663", rt5663);
- if (ret)
+ if (ret) {
dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
__func__, ret);
+ goto err_enable;
+ }
}
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5663,
rt5663_dai, ARRAY_SIZE(rt5663_dai));
- if (ret) {
- if (i2c->irq)
- free_irq(i2c->irq, rt5663);
- }
+ if (ret)
+ goto err_enable;
+ return 0;
+
+
+ /*
+ * Error after enabling regulators should goto err_enable
+ * to disable regulators.
+ */
+err_enable:
+ if (i2c->irq)
+ free_irq(i2c->irq, rt5663);
+
+ regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
return ret;
}
@@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, rt5663);
+ regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
+
return 0;
}
diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c
index 85524acf3e9c..c07e8a80b4b7 100644
--- a/sound/soc/codecs/simple-amplifier.c
+++ b/sound/soc/codecs/simple-amplifier.c
@@ -19,6 +19,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#define DRV_NAME "simple-amplifier"
@@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
(SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0),
};
static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
{ "DRV", NULL, "INL" },
{ "DRV", NULL, "INR" },
+ { "OUTL", NULL, "VCC" },
+ { "OUTR", NULL, "VCC" },
{ "OUTL", NULL, "DRV" },
{ "OUTR", NULL, "DRV" },
};
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index 36aebdb8f55c..aaba39295079 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
.non_legacy_dai_naming = 1,
};
-static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
+static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
.hw_params = tas6424_hw_params,
.set_fmt = tas6424_set_dai_fmt,
.set_tdm_slot = tas6424_set_dai_tdm_slot,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 608ad49ad978..c6048d95c6d3 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
if (freq/i > 20000000) {
dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
__func__, freq);
- return -EINVAL;
+ return -EINVAL;
}
aic31xx->p_div = i;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 6a271e6e6b8f..6aa0edf8c5ef 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
aic3x->master = 0;
iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ aic3x->master = 1;
+ iface_areg |= BIT_CLK_MASTER;
+ iface_areg &= ~WORD_CLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ aic3x->master = 1;
+ iface_areg |= WORD_CLK_MASTER;
+ iface_areg &= ~BIT_CLK_MASTER;
+ break;
default:
return -EINVAL;
}
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index a957eaeb7bc1..32907b1e20cf 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to enable supplies: %d\n", ret);
- goto exit;
+ goto exit;
}
if (dac33->power_gpio >= 0)
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 61294c787f27..409bed30a4e4 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
dev_warn(component->dev,
"Unsupported ASRC rate1 (%s)\n",
arizona_sample_rate_val_to_name(val));
- return -EINVAL;
+ return -EINVAL;
}
break;
default:
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index ccdf088461b7..54c306707c02 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
if (wm9705->mfd_pdata) {
wm9705->ac97 = wm9705->mfd_pdata->ac97;
regmap = wm9705->mfd_pdata->regmap;
- } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+ } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
WM9705_VENDOR_ID_MASK);
if (IS_ERR(wm9705->ac97)) {
@@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9705->ac97);
return PTR_ERR(regmap);
}
-#endif
+ } else {
+ return -ENXIO;
}
snd_soc_component_set_drvdata(component, wm9705->ac97);
@@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
static void wm9705_soc_remove(struct snd_soc_component *component)
{
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
- if (!wm9705->mfd_pdata) {
+ if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9705->ac97);
}
-#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9705 = {
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index e873baa9e778..01949eaba4fd 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
if (wm9712->mfd_pdata) {
wm9712->ac97 = wm9712->mfd_pdata->ac97;
regmap = wm9712->mfd_pdata->regmap;
- } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+ } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
int ret;
wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
@@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9712->ac97);
return PTR_ERR(regmap);
}
-#endif
+ } else {
+ return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
static void wm9712_soc_remove(struct snd_soc_component *component)
{
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
- if (!wm9712->mfd_pdata) {
+ if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9712->ac97);
}
-#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 643863bb32e0..5a2fdf4f69bf 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
if (wm9713->mfd_pdata) {
wm9713->ac97 = wm9713->mfd_pdata->ac97;
regmap = wm9713->mfd_pdata->regmap;
- } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+ } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
WM9713_VENDOR_ID_MASK);
if (IS_ERR(wm9713->ac97))
@@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9713->ac97);
return PTR_ERR(regmap);
}
-#endif
+ } else {
+ return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
static void wm9713_soc_remove(struct snd_soc_component *component)
{
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
- if (!wm9713->mfd_pdata) {
+ if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9713->ac97);
}
-#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9713 = {
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 66501b8dc46f..1dd291cebe67 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp)
return 0;
}
-int wm_adsp1_init(struct wm_adsp *dsp)
+static int wm_adsp_common_init(struct wm_adsp *dsp)
{
int ret;
@@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp)
return ret;
INIT_LIST_HEAD(&dsp->alg_regions);
+ INIT_LIST_HEAD(&dsp->ctl_list);
mutex_init(&dsp->pwr_lock);
return 0;
}
+
+int wm_adsp1_init(struct wm_adsp *dsp)
+{
+ return wm_adsp_common_init(dsp);
+}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
@@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
- ret = wm_adsp_create_name(dsp);
+ ret = wm_adsp_common_init(dsp);
if (ret)
return ret;
@@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp)
break;
}
- INIT_LIST_HEAD(&dsp->alg_regions);
- INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
- mutex_init(&dsp->pwr_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
deleted file mode 100644
index 778faff28e0e..000000000000
--- a/sound/soc/davinci/Kconfig
+++ /dev/null
@@ -1,106 +0,0 @@
-config SND_DAVINCI_SOC
- tristate
- depends on ARCH_DAVINCI
- select SND_EDMA_SOC
-
-config SND_EDMA_SOC
- tristate "SoC Audio for Texas Instruments chips using eDMA"
- depends on TI_EDMA
- select SND_SOC_GENERIC_DMAENGINE_PCM
- help
- Say Y or M here if you want audio support for TI SoC which uses eDMA.
- The following line of SoCs are supported by this platform driver:
- - daVinci devices
- - AM335x
- - AM437x/AM438x
- - DRA7xx family
-
-config SND_DAVINCI_SOC_I2S
- tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support"
- depends on SND_EDMA_SOC
- help
- Say Y or M here if you want to have support for McBSP IP found in
- Texas Instruments DaVinci DA850 SoCs.
-
-config SND_DAVINCI_SOC_MCASP
- tristate "Multichannel Audio Serial Port (McASP) support"
- depends on SND_SDMA_SOC || SND_EDMA_SOC
- help
- Say Y or M here if you want to have support for McASP IP found in
- various Texas Instruments SoCs like:
- - daVinci devices
- - Sitara line of SoCs (AM335x, AM438x, etc)
- - DRA7x devices
-
-config SND_DAVINCI_SOC_VCIF
- tristate
-
-config SND_DAVINCI_SOC_GENERIC_EVM
- tristate
- select SND_SOC_TLV320AIC3X
- select SND_DAVINCI_SOC_MCASP
-
-config SND_AM33XX_SOC_EVM
- tristate "SoC Audio for the AM33XX chip based boards"
- depends on SND_EDMA_SOC && SOC_AM33XX && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
- help
- Say Y or M if you want to add support for SoC audio on AM33XX
- boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
- AM335X-EVMSK, and BeagelBone with AudioCape boards have this
- setup.
-
-config SND_DAVINCI_SOC_EVM
- tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
- depends on SND_EDMA_SOC && I2C
- depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
- select SND_DAVINCI_SOC_GENERIC_EVM
- help
- Say Y if you want to add support for SoC audio on TI
- DaVinci DM6446, DM355 or DM365 EVM platforms.
-
-choice
- prompt "DM365 codec select"
- depends on SND_DAVINCI_SOC_EVM
- depends on MACH_DAVINCI_DM365_EVM
-
-config SND_DM365_AIC3X_CODEC
- tristate "Audio Codec - AIC3101"
- help
- Say Y if you want to add support for AIC3101 audio codec
-
-config SND_DM365_VOICE_CODEC
- tristate "Voice Codec - CQ93VC"
- select MFD_DAVINCI_VOICECODEC
- select SND_DAVINCI_SOC_VCIF
- select SND_SOC_CQ0093VC
- help
- Say Y if you want to add support for SoC On-chip voice codec
-endchoice
-
-config SND_DM6467_SOC_EVM
- tristate "SoC Audio support for DaVinci DM6467 EVM"
- depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
- select SND_SOC_SPDIF
-
- help
- Say Y if you want to add support for SoC audio on TI
-
-config SND_DA830_SOC_EVM
- tristate "SoC Audio support for DA830/OMAP-L137 EVM"
- depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
-
- help
- Say Y if you want to add support for SoC audio on TI
- DA830/OMAP-L137 EVM
-
-config SND_DA850_SOC_EVM
- tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
- help
- Say Y if you want to add support for SoC audio on TI
- DA850/OMAP-L138 EVM
-
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
deleted file mode 100644
index 23c6592eb31a..000000000000
--- a/sound/soc/davinci/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# DAVINCI Platform Support
-snd-soc-edma-objs := edma-pcm.o
-snd-soc-davinci-i2s-objs := davinci-i2s.o
-snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
-snd-soc-davinci-vcif-objs:= davinci-vcif.o
-
-obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
-obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
-obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
-obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
-
-# Generic DAVINCI/AM33xx Machine Support
-snd-soc-evm-objs := davinci-evm.o
-
-obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 6ec19fb4a934..2e75b5bc5f1d 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -221,7 +221,7 @@ config SND_SOC_PHYCORE_AC97
config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
- depends on ARCH_MXC && I2C
+ depends on ARCH_MXC && !ARM64 && I2C
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 44433b20435c..81f2fe2c6d23 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/* Common settings for corresponding Freescale CPU DAI driver */
- if (strstr(cpu_np->name, "ssi")) {
+ if (of_node_name_eq(cpu_np, "ssi")) {
/* Only SSI needs to configure AUDMUX */
ret = fsl_asoc_card_audmux_init(np, priv);
if (ret) {
dev_err(&pdev->dev, "failed to init audmux\n");
goto asrc_fail;
}
- } else if (strstr(cpu_np->name, "esai")) {
+ } else if (of_node_name_eq(cpu_np, "esai")) {
priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
- } else if (strstr(cpu_np->name, "sai")) {
+ } else if (of_node_name_eq(cpu_np, "sai")) {
priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
}
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c
index 1255dfe19eef..6f6294149476 100644
--- a/sound/soc/fsl/fsl_ssi_dbg.c
+++ b/sound/soc/fsl/fsl_ssi_dbg.c
@@ -124,17 +124,7 @@ static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
return 0;
}
-static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fsl_ssi_stats_show, inode->i_private);
-}
-
-static const struct file_operations fsl_ssi_stats_ops = {
- .open = fsl_ssi_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(fsl_ssi_stats);
int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
{
@@ -144,7 +134,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444,
ssi_dbg->dbg_dir, ssi_dbg,
- &fsl_ssi_stats_ops);
+ &fsl_ssi_stats_fops);
if (!ssi_dbg->dbg_stats) {
debugfs_remove(ssi_dbg->dbg_dir);
return -ENOMEM;
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index c954be0a0f96..92c2cf06f40a 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple sound card support
+ It also support DPCM of multi CPU single Codec ststem.
config SND_SIMPLE_SCU_CARD
tristate "ASoC Simple SCU sound card support"
@@ -20,8 +21,9 @@ config SND_AUDIO_GRAPH_CARD
depends on OF
select SND_SIMPLE_CARD_UTILS
help
- This option enables generic simple simple sound card support
+ This option enables generic simple sound card support
with OF-graph DT bindings.
+ It also support DPCM of multi CPU single Codec ststem.
config SND_AUDIO_GRAPH_SCU_CARD
tristate "ASoC Audio Graph SCU sound card support"
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 25c819e402e1..0d6144560a1e 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -23,19 +23,29 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct graph_dai_props {
- struct asoc_simple_dai cpu_dai;
- struct asoc_simple_dai codec_dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
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 asoc_simple_dai *dais;
+ struct snd_soc_codec_conf *codec_conf;
struct gpio_desc *pa_gpio;
};
+#define graph_priv_to_card(priv) (&(priv)->snd_card)
+#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
+#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
+#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
+
+#define PREFIX "audio-graph-card,"
+
static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -63,11 +73,6 @@ static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
};
-#define graph_priv_to_card(priv) (&(priv)->snd_card)
-#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
-#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
-#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
-
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -75,13 +80,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret;
- ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
- ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@@ -92,9 +97,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
- asoc_simple_card_clk_disable(&dai_props->codec_dai);
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
@@ -108,9 +113,7 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
- if (priv->mclk_fs)
- mclk_fs = priv->mclk_fs;
- else if (dai_props->mclk_fs)
+ if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
@@ -139,86 +142,238 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec = rtd->codec_dai;
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- struct graph_dai_props *dai_props =
- graph_priv_to_props(priv, rtd->num);
- int ret;
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+ int ret = 0;
- ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
if (ret < 0)
return ret;
- ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
-static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
- struct graph_card_data *priv,
- int idx)
+static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+
+ return 0;
+}
+
+static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct graph_card_data *priv,
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_cpu)
{
struct device *dev = graph_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
- struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
- struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
- struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
- struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
- struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
- struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
+ struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
+ struct device_node *ep = is_cpu ? cpu_ep : codec_ep;
+ struct device_node *port = of_get_parent(ep);
+ struct device_node *ports = of_get_parent(port);
+ struct device_node *node = of_graph_get_port_parent(ep);
+ struct asoc_simple_dai *dai;
+ struct snd_soc_dai_link_component *codecs = dai_link->codecs;
int ret;
- if (rcpu_ep != cpu_ep) {
- dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n",
- cpu_ep->name, codec_ep->name, rcpu_ep->name);
- ret = -EINVAL;
- goto dai_link_of_err;
+ dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec");
+
+ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs);
+
+ asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata);
+
+ of_node_put(ports);
+ of_node_put(port);
+
+ if (is_cpu) {
+
+ /* BE is dummy */
+ codecs->of_node = NULL;
+ codecs->dai_name = "snd-soc-dummy-dai";
+ codecs->name = "snd-soc-dummy";
+
+ /* FE settings */
+ dai_link->dynamic = 1;
+ dai_link->dpcm_merged_format = 1;
+
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
+ ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "fe.%s",
+ dai_link->cpu_dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* card->num_links includes Codec */
+ asoc_simple_card_canonicalize_cpu(dai_link,
+ of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
+ } else {
+ struct snd_soc_codec_conf *cconf;
+
+ /* FE is dummy */
+ dai_link->cpu_of_node = NULL;
+ dai_link->cpu_dai_name = "snd-soc-dummy-dai";
+ dai_link->cpu_name = "snd-soc-dummy";
+
+ /* BE settings */
+ dai_link->no_pcm = 1;
+ dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
+
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
+ ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "be.%s",
+ codecs->dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* check "prefix" from top node */
+ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
+ "prefix");
+ snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
+ PREFIX "prefix");
+ snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
+ "prefix");
+ snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
+ "prefix");
}
+ ret = asoc_simple_card_of_parse_tdm(ep, dai);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
+ if (ret < 0)
+ return ret;
+
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
+
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
+ dai_link->ops = &asoc_graph_card_ops;
+ dai_link->init = asoc_graph_card_dai_init;
+
+ return 0;
+}
+
+static int asoc_graph_card_dai_link_of(struct device_node *top,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct graph_card_data *priv,
+ int *dai_idx, int link_idx)
+{
+ struct device *dev = graph_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
+ struct device_node *cpu_port = of_get_parent(cpu_ep);
+ struct device_node *codec_port = of_get_parent(codec_ep);
+ struct device_node *cpu_ports = of_get_parent(cpu_port);
+ struct device_node *codec_ports = of_get_parent(codec_port);
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
+ int ret;
+
+ dev_dbg(dev, "link_of\n");
+
+ cpu_dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+ codec_dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
- of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
- of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
+ /* Factor to mclk, used in hw_params() */
+ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
+ of_node_put(cpu_port);
+ of_node_put(cpu_ports);
+ of_node_put(codec_port);
+ of_node_put(codec_ports);
+
+ ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+ NULL, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"%s-%s",
dai_link->cpu_dai_name,
dai_link->codecs->dai_name);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
dai_link->ops = &asoc_graph_card_ops;
dai_link->init = asoc_graph_card_dai_init;
@@ -226,12 +381,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
-dai_link_of_err:
- of_node_put(cpu_ep);
- of_node_put(rcpu_ep);
- of_node_put(codec_ep);
-
- return ret;
+ return 0;
}
static int asoc_graph_card_parse_of(struct graph_card_data *priv)
@@ -239,44 +389,173 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct of_phandle_iterator it;
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_card *card = graph_priv_to_card(priv);
- struct device_node *node = dev->of_node;
- int rc, idx = 0;
- int ret;
+ struct device_node *top = dev->of_node;
+ struct device_node *node = top;
+ struct device_node *cpu_port;
+ struct device_node *cpu_ep = NULL;
+ struct device_node *codec_ep = NULL;
+ struct device_node *codec_port = NULL;
+ struct device_node *codec_port_old = NULL;
+ int rc, ret;
+ int link_idx, dai_idx, conf_idx;
+ int cpu;
ret = asoc_simple_card_of_parse_widgets(card, NULL);
if (ret < 0)
return ret;
- ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
+ ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
- /* Factor to mclk, used in hw_params() */
- of_property_read_u32(node, "mclk-fs", &priv->mclk_fs);
-
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
- ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
- if (ret < 0) {
- of_node_put(it.node);
-
- return ret;
+ link_idx = 0;
+ dai_idx = 0;
+ conf_idx = 0;
+ codec_port_old = NULL;
+ for (cpu = 1; cpu >= 0; cpu--) {
+ /*
+ * Detect all CPU first, and Detect all Codec 2nd.
+ *
+ * In Normal sound case, all DAIs are detected
+ * as "CPU-Codec".
+ *
+ * In DPCM sound case,
+ * all CPUs are detected as "CPU-dummy", and
+ * all Codecs are detected as "dummy-Codec".
+ * To avoid random sub-device numbering,
+ * detect "dummy-Codec" in last;
+ */
+ of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+ cpu_port = it.node;
+ cpu_ep = NULL;
+ while (1) {
+ cpu_ep = of_get_next_child(cpu_port, cpu_ep);
+ if (!cpu_ep)
+ break;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ codec_port = of_get_parent(codec_ep);
+
+ of_node_put(codec_ep);
+ of_node_put(codec_port);
+
+ dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep);
+
+ if (of_get_child_count(codec_port) > 1) {
+ /*
+ * for DPCM sound
+ */
+ if (!cpu) {
+ if (codec_port_old == codec_port)
+ continue;
+ codec_port_old = codec_port;
+ }
+ ret = asoc_graph_card_dai_link_of_dpcm(
+ top, cpu_ep, codec_ep, priv,
+ &dai_idx, link_idx++,
+ &conf_idx, cpu);
+ } else if (cpu) {
+ /*
+ * for Normal sound
+ */
+ ret = asoc_graph_card_dai_link_of(
+ top, cpu_ep, codec_ep, priv,
+ &dai_idx, link_idx++);
+ }
+ if (ret < 0)
+ return ret;
+ }
}
}
return asoc_simple_card_parse_card_name(card, NULL);
}
-static int asoc_graph_get_dais_count(struct device *dev)
+static void asoc_graph_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
- int count = 0;
+ struct device_node *cpu_port;
+ struct device_node *cpu_ep;
+ struct device_node *codec_ep;
+ struct device_node *codec_port;
+ struct device_node *codec_port_old;
+ struct device_node *codec_port_old2;
int rc;
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
- count++;
-
- return count;
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for "dummy-Codec"
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
+ codec_port_old = NULL;
+ codec_port_old2 = NULL;
+ of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+ cpu_port = it.node;
+ cpu_ep = NULL;
+ while (1) {
+ cpu_ep = of_get_next_child(cpu_port, cpu_ep);
+ if (!cpu_ep)
+ break;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ codec_port = of_get_parent(codec_ep);
+
+ of_node_put(codec_ep);
+ of_node_put(codec_port);
+
+ (*link_num)++;
+ (*dais_num)++;
+
+ if (codec_port_old == codec_port) {
+ if (codec_port_old2 != codec_port_old) {
+ (*link_num)++;
+ (*ccnf_num)++;
+ }
+
+ codec_port_old2 = codec_port_old;
+ continue;
+ }
+
+ (*dais_num)++;
+ codec_port_old = codec_port;
+ }
+ }
}
static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
@@ -300,22 +579,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
- int num, ret, i;
+ struct snd_soc_codec_conf *cconf;
+ int lnum = 0, dnum = 0, cnum = 0;
+ int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- num = asoc_graph_get_dais_count(dev);
- if (num == 0)
+ asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
return -EINVAL;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -324,7 +608,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -339,16 +623,20 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
- card->owner = THIS_MODULE;
- card->dev = dev;
- card->dai_link = dai_link;
- 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;
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+ card->dai_link = dai_link;
+ card->num_links = lnum;
+ 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;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
@@ -379,6 +667,7 @@ static int asoc_graph_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_graph_of_match[] = {
{ .compatible = "audio-graph-card", },
+ { .compatible = "audio-graph-scu-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index b83bb31021a9..e1b192ea147b 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -24,14 +24,18 @@
struct graph_card_data {
struct snd_soc_card snd_card;
- struct snd_soc_codec_conf codec_conf;
struct graph_dai_props {
- struct asoc_simple_dai dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
@@ -39,13 +43,24 @@ struct graph_card_data {
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
+#define PREFIX "audio-graph-card,"
+
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+ int ret = 0;
+
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
+ if (ret)
+ return ret;
- return asoc_simple_card_clk_enable(&dai_props->dai);
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
+ if (ret)
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+ return ret;
}
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
@@ -54,7 +69,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_graph_card_ops = {
@@ -65,39 +82,49 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai;
- struct snd_soc_dai_link *dai_link;
- struct graph_dai_props *dai_props;
- int num = rtd->num;
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+ int ret = 0;
- dai_link = graph_priv_to_link(priv, num);
- dai_props = graph_priv_to_props(priv, num);
- dai = dai_link->dynamic ?
- rtd->cpu_dai :
- rtd->codec_dai;
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
+ if (ret < 0)
+ return ret;
- return asoc_simple_card_init_dai(dai, &dai_props->dai);
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+ /* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
-static int asoc_graph_card_dai_link_of(struct device_node *ep,
+static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep,
+ struct device_node *codec_ep,
struct graph_card_data *priv,
- unsigned int daifmt,
- int idx, int is_fe)
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_fe)
{
struct device *dev = graph_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
- struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
+ struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct snd_soc_card *card = graph_priv_to_card(priv);
+ struct device_node *ep = is_fe ? cpu_ep : codec_ep;
+ struct device_node *node = of_graph_get_port_parent(ep);
+ struct asoc_simple_dai *dai;
int ret;
if (is_fe) {
@@ -113,11 +140,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
if (ret)
return ret;
- ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@@ -131,6 +161,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else {
+ struct snd_soc_codec_conf *cconf;
+
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@@ -140,11 +172,17 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
if (ret < 0)
return ret;
- ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@@ -154,13 +192,20 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
- snd_soc_of_parse_audio_prefix(card,
- &priv->codec_conf,
+ /* check "prefix" from top node */
+ snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
"prefix");
+ /* check "prefix" from each node if top doesn't have */
+ if (!cconf->of_node)
+ snd_soc_of_parse_node_prefix(node, cconf,
+ dai_link->codecs->of_node,
+ PREFIX "prefix");
}
- ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai);
+ asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
+
+ ret = asoc_simple_card_of_parse_tdm(ep, dai);
if (ret)
return ret;
@@ -168,7 +213,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
- dai_link->dai_fmt = daifmt;
+ ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+ NULL, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_graph_card_ops;
@@ -186,11 +235,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct device_node *cpu_port;
struct device_node *cpu_ep;
struct device_node *codec_ep;
- struct device_node *rcpu_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
- unsigned int daifmt = 0;
- int dai_idx, ret;
+ int dai_idx, link_idx, conf_idx, ret;
int rc, codec;
if (!node)
@@ -201,47 +248,20 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
* see simple-card
*/
- ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
+ ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
- asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
+ asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata);
/*
* it supports multi CPU, single CODEC only here
* see asoc_graph_get_dais_count
*/
- /* find 1st codec */
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
- cpu_port = it.node;
- cpu_ep = of_get_next_child(cpu_port, NULL);
- codec_ep = of_graph_get_remote_endpoint(cpu_ep);
- rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
-
- of_node_put(cpu_ep);
- of_node_put(codec_ep);
- of_node_put(rcpu_ep);
-
- if (!codec_ep)
- continue;
-
- if (rcpu_ep != cpu_ep) {
- dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
- cpu_ep->name, codec_ep->name, rcpu_ep->name);
- ret = -EINVAL;
- goto parse_of_err;
- }
-
- ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
- NULL, &daifmt);
- if (ret < 0) {
- of_node_put(cpu_port);
- goto parse_of_err;
- }
- }
-
+ link_idx = 0;
dai_idx = 0;
+ conf_idx = 0;
codec_port_old = NULL;
for (codec = 0; codec < 2; codec++) {
/*
@@ -257,31 +277,23 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
of_node_put(cpu_ep);
of_node_put(codec_ep);
+ of_node_put(cpu_port);
of_node_put(codec_port);
+ it.node = NULL;
if (codec) {
- if (!codec_port)
- continue;
-
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
-
- /* Back-End (= Codec) */
- ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
- if (ret < 0) {
- of_node_put(cpu_port);
- goto parse_of_err;
- }
- } else {
- /* Front-End (= CPU) */
- ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
- if (ret < 0) {
- of_node_put(cpu_port);
- goto parse_of_err;
- }
}
+
+ ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep,
+ priv, &dai_idx,
+ link_idx++, &conf_idx,
+ !codec);
+ if (ret < 0)
+ goto parse_of_err;
}
}
@@ -289,13 +301,24 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
if (ret)
goto parse_of_err;
+ if ((card->num_links != link_idx) ||
+ (card->num_configs != conf_idx)) {
+ dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n",
+ card->num_links, link_idx, card->num_configs, conf_idx);
+ ret = -EINVAL;
+ goto parse_of_err;
+ }
+
ret = 0;
parse_of_err:
return ret;
}
-static int asoc_graph_get_dais_count(struct device *dev)
+static void asoc_graph_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
@@ -304,10 +327,48 @@ static int asoc_graph_get_dais_count(struct device *dev)
struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
- int count = 0;
+ struct device_node *codec_port_old2;
int rc;
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for dummy-Codec
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
codec_port_old = NULL;
+ codec_port_old2 = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL);
@@ -318,20 +379,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
of_node_put(codec_ep);
of_node_put(codec_port);
- if (cpu_ep)
- count++;
+ (*link_num)++;
+ (*dais_num)++;
- if (!codec_port)
- continue;
+ if (codec_port_old == codec_port) {
+ if (codec_port_old2 != codec_port_old) {
+ (*link_num)++;
+ (*ccnf_num)++;
+ }
- if (codec_port_old == codec_port)
+ codec_port_old2 = codec_port_old;
continue;
+ }
- count++;
+ (*dais_num)++;
codec_port_old = codec_port;
}
-
- return count;
}
static int asoc_graph_card_probe(struct platform_device *pdev)
@@ -339,22 +402,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
- int num, ret, i;
+ struct snd_soc_codec_conf *cconf;
+ int lnum = 0, dnum = 0, cnum = 0;
+ int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- num = asoc_graph_get_dais_count(dev);
- if (num == 0)
+ asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
return -EINVAL;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -363,7 +431,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -371,15 +439,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
- card->num_links = num;
- card->codec_conf = &priv->codec_conf;
- card->num_configs = 1;
+ card->num_links = lnum;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index f34cc6cddfa2..b807a47515eb 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
-void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+void asoc_simple_card_parse_convert(struct device *dev,
+ struct device_node *np,
+ char *prefix,
struct asoc_simple_card_data *data)
{
- struct device_node *np = dev->of_node;
char prop[128];
if (!prefix)
@@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
-static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
- struct clk *clk)
-{
- dai->clk = clk;
-}
-
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
{
- return clk_prepare_enable(dai->clk);
+ if (dai)
+ return clk_prepare_enable(dai->clk);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
{
- clk_disable_unprepare(dai->clk);
+ if (dai)
+ clk_disable_unprepare(dai->clk);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
@@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk);
- asoc_simple_card_clk_register(simple_dai, clk);
+ simple_dai->clk = clk;
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val;
} else {
@@ -272,13 +271,24 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
{
struct device_node *node;
struct device_node *endpoint;
+ struct of_endpoint info;
int i, id;
int ret;
+ /* use driver specified DAI ID if exist */
ret = snd_soc_get_dai_id(ep);
if (ret != -ENOTSUPP)
return ret;
+ /* use endpoint/port reg if exist */
+ ret = of_graph_parse_endpoint(ep, &info);
+ if (ret == 0) {
+ if (info.id)
+ return info.id;
+ if (info.port)
+ return info.port;
+ }
+
node = of_graph_get_port_parent(ep);
/*
@@ -348,6 +358,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
{
int ret;
+ if (!simple_dai)
+ return 0;
+
if (simple_dai->sysclk) {
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
simple_dai->clk_direction);
@@ -415,8 +428,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
- char *prefix,
- int optional)
+ char *prefix)
{
struct device_node *node = card->dev->of_node;
char prop[128];
@@ -426,11 +438,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
- if (!of_property_read_bool(node, prop)) {
- if (optional)
- return 0;
- return -EINVAL;
- }
+ if (!of_property_read_bool(node, prop))
+ return 0;
return snd_soc_of_parse_audio_routing(card, prop);
}
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 5a3f59aa4ba5..37e001cf9cd1 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -18,16 +18,19 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct simple_dai_props {
- struct asoc_simple_dai cpu_dai;
- struct asoc_simple_dai codec_dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
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 asoc_simple_dai *dais;
+ struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -47,13 +50,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
simple_priv_to_props(priv, rtd->num);
int ret;
- ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
- ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@@ -65,14 +68,17 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
- asoc_simple_card_clk_disable(&dai_props->codec_dai);
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
unsigned long rate)
{
+ if (!simple_dai)
+ return 0;
+
if (!simple_dai->clk)
return 0;
@@ -94,19 +100,17 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
- if (priv->mclk_fs)
- mclk_fs = priv->mclk_fs;
- else if (dai_props->mclk_fs)
+ if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
- ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
+ ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
if (ret < 0)
return ret;
- ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
+ ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
if (ret < 0)
return ret;
@@ -134,33 +138,169 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec = rtd->codec_dai;
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- struct simple_dai_props *dai_props =
- simple_priv_to_props(priv, rtd->num);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
- ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
if (ret < 0)
return ret;
- ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
-static int asoc_simple_card_dai_link_of(struct device_node *node,
+static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+
+ return 0;
+}
+
+static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
+ struct device_node *node,
+ struct device_node *np,
+ struct device_node *codec,
+ struct simple_card_data *priv,
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_fe,
+ bool is_top_level_node)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+ struct asoc_simple_dai *dai;
+ struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+
+ char prop[128];
+ char *prefix = "";
+ int ret;
+
+ /* For single DAI link & old style of DT node */
+ if (is_top_level_node)
+ prefix = PREFIX;
+
+ if (is_fe) {
+ int is_single_links = 0;
+
+ /* BE is dummy */
+ codecs->of_node = NULL;
+ codecs->dai_name = "snd-soc-dummy-dai";
+ codecs->name = "snd-soc-dummy";
+
+ /* FE settings */
+ dai_link->dynamic = 1;
+ dai_link->dpcm_merged_format = 1;
+
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
+ ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
+ &is_single_links);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "fe.%s",
+ dai_link->cpu_dai_name);
+ if (ret < 0)
+ return ret;
+
+ asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
+ } else {
+ struct snd_soc_codec_conf *cconf;
+
+ /* FE is dummy */
+ dai_link->cpu_of_node = NULL;
+ dai_link->cpu_dai_name = "snd-soc-dummy-dai";
+ dai_link->cpu_name = "snd-soc-dummy";
+
+ /* BE settings */
+ dai_link->no_pcm = 1;
+ dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
+
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
+ ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "be.%s",
+ codecs->dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* check "prefix" from top node */
+ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
+ PREFIX "prefix");
+ snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
+ "prefix");
+ snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
+ "prefix");
+ }
+
+ asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata);
+
+ ret = asoc_simple_card_of_parse_tdm(np, dai);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
+ if (ret < 0)
+ return ret;
+
+ snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
+ of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(node, prop, &dai_props->mclk_fs);
+ of_property_read_u32(np, prop, &dai_props->mclk_fs);
+
+ ret = asoc_simple_card_parse_daifmt(dev, node, codec,
+ prefix, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
+ dai_link->ops = &asoc_simple_card_ops;
+ dai_link->init = asoc_simple_card_dai_init;
+
+ return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *top,
+ struct device_node *node,
struct simple_card_data *priv,
- int idx,
+ int *dai_idx, int link_idx,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
- struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
- struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct device_node *cpu = NULL;
struct device_node *plat = NULL;
struct device_node *codec = NULL;
@@ -193,12 +333,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
goto dai_link_of_err;
}
+ cpu_dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+ codec_dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
- of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
+ snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
+ of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(node, prop, &dai_props->mclk_fs);
+ of_property_read_u32(cpu, prop, &dai_props->mclk_fs);
+ of_property_read_u32(codec, prop, &dai_props->mclk_fs);
ret = asoc_simple_card_parse_cpu(cpu, dai_link,
DAI, CELL, &single_cpu);
@@ -286,61 +435,148 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *top = dev->of_node;
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct device_node *dai_link;
- struct device_node *node = dev->of_node;
- int ret;
-
- if (!node)
+ struct device_node *node;
+ struct device_node *np;
+ struct device_node *codec;
+ bool is_fe;
+ int ret, loop;
+ int dai_idx, link_idx, conf_idx;
+
+ if (!top)
return -EINVAL;
- dai_link = of_get_child_by_name(node, PREFIX "dai-link");
-
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
- goto card_parse_end;
+ return ret;
- ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
+ ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
- goto card_parse_end;
-
- /* Factor to mclk, used in hw_params() */
- of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
+ return ret;
/* Single/Muti DAI link(s) & New style of DT node */
- if (dai_link) {
- struct device_node *np = NULL;
- int i = 0;
-
- for_each_child_of_node(node, np) {
- dev_dbg(dev, "\tlink %d:\n", i);
- ret = asoc_simple_card_dai_link_of(np, priv,
- i, false);
- if (ret < 0) {
- of_node_put(np);
- goto card_parse_end;
+ loop = 1;
+ link_idx = 0;
+ dai_idx = 0;
+ conf_idx = 0;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = dev->of_node;
+ loop = 0;
+ }
+
+ do {
+ /* DPCM */
+ if (of_get_child_count(node) > 2) {
+ for_each_child_of_node(node, np) {
+ codec = of_get_child_by_name(node,
+ loop ? "codec" :
+ PREFIX "codec");
+ if (!codec)
+ return -ENODEV;
+
+ is_fe = (np != codec);
+
+ ret = asoc_simple_card_dai_link_of_dpcm(
+ top, node, np, codec, priv,
+ &dai_idx, link_idx++, &conf_idx,
+ is_fe, !loop);
}
- i++;
+ } else {
+ ret = asoc_simple_card_dai_link_of(
+ top, node, priv,
+ &dai_idx, link_idx++, !loop);
}
- } else {
- /* For single DAI link & old style of DT node */
- ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
if (ret < 0)
- goto card_parse_end;
- }
+ return ret;
+
+ node = of_get_next_child(top, node);
+ } while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
- goto card_parse_end;
-
- ret = asoc_simple_card_parse_aux_devs(node, priv);
+ return ret;
-card_parse_end:
- of_node_put(dai_link);
+ ret = asoc_simple_card_parse_aux_devs(top, priv);
return ret;
}
+static void asoc_simple_card_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
+{
+ struct device_node *top = dev->of_node;
+ struct device_node *node;
+ int loop;
+ int num;
+
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for "dummy-Codec"
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
+ if (!top) {
+ (*link_num) = 1;
+ (*dais_num) = 2;
+ (*ccnf_num) = 0;
+ return;
+ }
+
+ loop = 1;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = top;
+ loop = 0;
+ }
+
+ do {
+ num = of_get_child_count(node);
+ (*dais_num) += num;
+ if (num > 2) {
+ (*link_num) += num;
+ (*ccnf_num)++;
+ } else {
+ (*link_num)++;
+ }
+ node = of_get_next_child(top, node);
+ } while (loop && node);
+}
+
static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
@@ -362,25 +598,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
- int num, ret, i;
-
- /* Get the number of DAI links */
- if (np && of_get_child_by_name(np, PREFIX "dai-link"))
- num = of_get_child_count(np);
- else
- num = 1;
+ struct snd_soc_codec_conf *cconf;
+ int lnum = 0, dnum = 0, cnum = 0;
+ int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
+ return -EINVAL;
+
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -389,7 +628,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -397,13 +636,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
- card->num_links = num;
+ card->num_links = lnum;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) {
@@ -419,6 +662,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct asoc_simple_card_info *cinfo;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platform;
+ int dai_idx = 0;
cinfo = dev->platform_data;
if (!cinfo) {
@@ -435,6 +679,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
return -EINVAL;
}
+ dai_props->cpu_dai = &priv->dais[dai_idx++];
+ dai_props->codec_dai = &priv->dais[dai_idx++];
+
codecs = dai_link->codecs;
codecs->name = cinfo->codec;
codecs->dai_name = cinfo->codec_dai.name;
@@ -448,10 +695,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
dai_link->cpu_dai_name = cinfo->cpu_dai.name;
dai_link->dai_fmt = cinfo->daifmt;
dai_link->init = asoc_simple_card_dai_init;
- memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
- sizeof(priv->dai_props->cpu_dai));
- memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
- sizeof(priv->dai_props->codec_dai));
+ memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
+ sizeof(*priv->dai_props->cpu_dai));
+ memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
+ sizeof(*priv->dai_props->codec_dai));
}
snd_soc_card_set_drvdata(card, priv);
@@ -476,6 +723,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", },
+ { .compatible = "simple-scu-audio-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index 85b46f0eae0f..9d7299d536a8 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -21,14 +21,18 @@
struct simple_card_data {
struct snd_soc_card snd_card;
- struct snd_soc_codec_conf codec_conf;
struct simple_dai_props {
- struct asoc_simple_dai dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -46,8 +50,17 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
+ int ret;
+
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
+ if (ret)
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
- return asoc_simple_card_clk_enable(&dai_props->dai);
+ return ret;
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
@@ -57,7 +70,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_simple_card_ops = {
@@ -67,42 +82,57 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai;
- struct snd_soc_dai_link *dai_link;
- struct simple_dai_props *dai_props;
- int num = rtd->num;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+ int ret;
+
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
+ if (ret < 0)
+ return ret;
- dai_link = simple_priv_to_link(priv, num);
- dai_props = simple_priv_to_props(priv, num);
- dai = dai_link->dynamic ?
- rtd->cpu_dai :
- rtd->codec_dai;
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
+ if (ret < 0)
+ return ret;
- return asoc_simple_card_init_dai(dai, &dai_props->dai);
+ return 0;
}
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+ /* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
-static int asoc_simple_card_dai_link_of(struct device_node *np,
+static int asoc_simple_card_dai_link_of(struct device_node *link,
+ struct device_node *np,
+ struct device_node *codec,
struct simple_card_data *priv,
- unsigned int daifmt,
- int idx, bool is_fe)
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_fe,
+ bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct asoc_simple_dai *dai;
+ char *prefix = "";
int ret;
+ /* For single DAI link & old style of DT node */
+ if (is_top_level_node)
+ prefix = PREFIX;
+
if (is_fe) {
int is_single_links = 0;
struct snd_soc_dai_link_component *codecs;
@@ -117,12 +147,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
- ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@@ -134,6 +167,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
+ struct snd_soc_codec_conf *cconf;
+
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@@ -143,11 +178,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
- ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@@ -157,13 +198,20 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
- snd_soc_of_parse_audio_prefix(card,
- &priv->codec_conf,
+ /* check "prefix" from top node */
+ snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
+ /* check "prefix" from each node if top doesn't have */
+ if (!cconf->of_node)
+ snd_soc_of_parse_node_prefix(np, cconf,
+ dai_link->codecs->of_node,
+ "prefix");
}
- ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
+ asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
+
+ ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
@@ -171,7 +219,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
- dai_link->dai_fmt = daifmt;
+ ret = asoc_simple_card_parse_daifmt(dev, link, codec,
+ prefix, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
@@ -184,52 +236,136 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *top = dev->of_node;
+ struct device_node *node;
struct device_node *np;
+ struct device_node *codec;
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct device_node *node = dev->of_node;
- unsigned int daifmt = 0;
bool is_fe;
- int ret, i;
+ int ret, loop;
+ int dai_idx, link_idx, conf_idx;
- if (!node)
+ if (!top)
return -EINVAL;
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
return ret;
- ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
+ ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
return ret;
- asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
+ asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
- /* find 1st codec */
- np = of_get_child_by_name(node, PREFIX "codec");
- if (!np)
- return -ENODEV;
+ loop = 1;
+ link_idx = 0;
+ dai_idx = 0;
+ conf_idx = 0;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = dev->of_node;
+ loop = 0;
+ }
+
+ do {
+ codec = of_get_child_by_name(node,
+ loop ? "codec" : PREFIX "codec");
+ if (!codec)
+ return -ENODEV;
+
+ for_each_child_of_node(node, np) {
+ is_fe = (np != codec);
+
+ ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
+ &dai_idx, link_idx++,
+ &conf_idx,
+ is_fe, !loop);
+ if (ret < 0)
+ return ret;
+ }
+ node = of_get_next_child(top, node);
+ } while (loop && node);
- ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
+ ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
return ret;
- i = 0;
- for_each_child_of_node(node, np) {
- is_fe = false;
- if (strcmp(np->name, PREFIX "cpu") == 0)
- is_fe = true;
+ return 0;
+}
- ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
- if (ret < 0)
- return ret;
- i++;
+static void asoc_simple_card_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
+{
+ struct device_node *top = dev->of_node;
+ struct device_node *node;
+ int loop;
+ int num;
+
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for "dummy-Codec"
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
+ if (!top) {
+ (*link_num) = 1;
+ (*dais_num) = 2;
+ (*ccnf_num) = 0;
+ return;
}
- ret = asoc_simple_card_parse_card_name(card, PREFIX);
- if (ret < 0)
- return ret;
+ loop = 1;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = top;
+ loop = 0;
+ }
- return 0;
+ do {
+ num = of_get_child_count(node);
+ (*dais_num) += num;
+ if (num > 2) {
+ (*link_num) += num;
+ (*ccnf_num)++;
+ } else {
+ (*link_num)++;
+ }
+ node = of_get_next_child(top, node);
+ } while (loop && node);
}
static int asoc_simple_card_probe(struct platform_device *pdev)
@@ -237,21 +373,27 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct snd_soc_card *card;
+ struct snd_soc_codec_conf *cconf;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- int num, ret, i;
+ int ret, i;
+ int lnum = 0, dnum = 0, cnum = 0;
/* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- num = of_get_child_count(np);
+ asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
+ return -EINVAL;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -260,7 +402,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -268,15 +410,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
- card->num_links = num;
- card->codec_conf = &priv->codec_conf;
- card->num_configs = 1;
+ card->num_links = lnum;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
ret = asoc_simple_card_parse_of(priv);
if (ret < 0) {
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 18e717703685..2fd1b61e8331 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
recommended option
config SND_SOC_INTEL_SKYLAKE
- tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
+ tristate "All Skylake/SST Platforms"
depends on PCI && ACPI
- select SND_SOC_INTEL_SKYLAKE_COMMON
+ select SND_SOC_INTEL_SKL
+ select SND_SOC_INTEL_APL
+ select SND_SOC_INTEL_KBL
+ select SND_SOC_INTEL_GLK
+ select SND_SOC_INTEL_CNL
+ select SND_SOC_INTEL_CFL
help
- If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
- GeminiLake or CannonLake platform with the DSP enabled in the BIOS
- then enable this option by saying Y or m.
+ This is a backwards-compatible option to select all devices
+ supported by the Intel SST/Skylake driver. This option is no
+ longer recommended and will be deprecated when the SOF
+ driver is introduced. Distributions should explicitly
+ select which platform uses this driver.
+
+config SND_SOC_INTEL_SKL
+ tristate "Skylake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel Skylake platform with the DSP enabled
+ in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_APL
+ tristate "Broxton/ApolloLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel Broxton/ApolloLake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_KBL
+ tristate "Kabylake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel Kabylake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_GLK
+ tristate "GeminiLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel GeminiLake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CNL
+ tristate "CannonLake/WhiskyLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel CNL/WHL platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CFL
+ tristate "CoffeeLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel CoffeeLake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_SKYLAKE_FAMILY
+ tristate
+ select SND_SOC_INTEL_SKYLAKE_COMMON
-if SND_SOC_INTEL_SKYLAKE
+if SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_INTEL_SKYLAKE_SSP_CLK
tristate
@@ -129,13 +188,19 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST
select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
+ select SND_HDA_INTEL_DSP_DETECTION_SKL if SND_SOC_INTEL_SKL
+ select SND_HDA_INTEL_DSP_DETECTION_APL if SND_SOC_INTEL_APL
+ select SND_HDA_INTEL_DSP_DETECTION_KBL if SND_SOC_INTEL_KBL
+ select SND_HDA_INTEL_DSP_DETECTION_GLK if SND_SOC_INTEL_GLK
+ select SND_HDA_INTEL_DSP_DETECTION_CNL if SND_SOC_INTEL_CNL
+ select SND_HDA_INTEL_DSP_DETECTION_CFL if SND_SOC_INTEL_CFL
select SND_SOC_ACPI_INTEL_MATCH
help
If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
-endif ## SND_SOC_INTEL_SKYLAKE
+endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_ACPI_INTEL_MATCH
tristate
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index c90b04cc071d..ac542535b9d5 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev)
byt_rvp_platform_data.res_info = &bytcr_res_info;
}
+ /* update machine parameters */
+ mach->mach_params.acpi_ipc_irq_index =
+ pdata->res_info->acpi_ipc_irq_index;
+
plat_dev = platform_device_register_data(dev, pdata->platform, -1,
NULL, 0);
if (IS_ERR(plat_dev)) {
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
index 27413ebae956..b8c456753f01 100644
--- a/sound/soc/intel/atom/sst/sst_loader.c
+++ b/sound/soc/intel/atom/sst/sst_loader.c
@@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst)
const struct firmware *fw;
retval = request_firmware(&fw, sst->firmware_name, sst->dev);
- if (fw == NULL) {
- dev_err(sst->dev, "fw is returning as null\n");
- return -EINVAL;
- }
if (retval) {
dev_err(sst->dev, "request fw failed %d\n", retval);
return retval;
}
+ if (fw == NULL) {
+ dev_err(sst->dev, "fw is returning as null\n");
+ return -EINVAL;
+ }
mutex_lock(&sst->sst_lock);
retval = sst_cache_and_parse_fw(sst, fw);
mutex_unlock(&sst->sst_lock);
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index af93244b4868..00a37a09dc9b 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
{
struct ipc_post *msg;
- msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (large) {
- msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
if (!msg->mailbox_data) {
kfree(msg);
return -ENOMEM;
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index b177db2a0dbb..0a7e40d06395 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
endif ## SND_SST_ATOM_HIFI2_PLATFORM
-if SND_SOC_INTEL_SKYLAKE
+if SND_SOC_INTEL_SKL
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "SKL with RT286 I2S mode"
@@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+endif ## SND_SOC_INTEL_SKL
+
+if SND_SOC_INTEL_APL
+
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+endif ## SND_SOC_INTEL_APL
+
+if SND_SOC_INTEL_KBL
+
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
tristate "KBL with RT5663 and MAX98927 in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -293,6 +301,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_INTEL_KBL_RT5660_MACH
+ tristate "KBL with RT5660 in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_RT5660
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for RT5660 I2S audio codec.
+ Say Y if you have such a device.
+
+endif ## SND_SOC_INTEL_KBL
+
+if SND_SOC_INTEL_GLK
+
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
tristate "GLK with RT5682 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -307,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
Say Y if you have such a device.
If unsure select "N".
-endif ## SND_SOC_INTEL_SKYLAKE
+endif ## SND_SOC_INTEL_GLK
if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 5381e27df9cc..bf072ea299b7 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
+snd-soc-kbl_rt5660-objs := kbl_rt5660.o
snd-soc-skl_rt286-objs := skl_rt286.o
snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9
obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
+obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 8587bd3d1cc1..a22366ce33c4 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -29,7 +29,6 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
-#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -674,6 +673,33 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
+ { /* Point of View Mobii TAB-P1005W-232 (V2.0) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"),
+ },
+ .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),
+ },
+ {
+ /* Prowise PT301 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Prowise"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PT301"),
+ },
+ .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_BOARD_VENDOR, "TECLAST"),
@@ -1152,10 +1178,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
- struct sst_platform_info *p_info = mach->pdata;
- const struct sst_res_info *res_info = p_info->res_info;
-
- if (res_info->acpi_ipc_irq_index == 0)
+ if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index c44298130720..e528995668b7 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -32,7 +32,6 @@
#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>
#include <sound/soc.h>
@@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
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;
-
- if (res_info->acpi_ipc_irq_index == 0)
+ if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 9d9f6e41d81c..08a5152e635a 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -390,6 +390,20 @@ static struct snd_soc_card snd_soc_card_cht = {
static const struct dmi_system_id cht_max98090_quirk_table[] = {
{
+ /* Clapper model Chromebook */
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"),
+ },
+ .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
+ },
+ {
+ /* Gnawty model Chromebook (Acer Chromebook CB3-111) */
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"),
+ },
+ .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
+ },
+ {
/* Swanky model Chromebook (Toshiba Chromebook 2) */
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Swanky"),
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index f5a5ea6a093c..250a356a0cbf 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -27,7 +27,6 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
-#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
- struct sst_platform_info *p_info = mach->pdata;
- const struct sst_res_info *res_info = p_info->res_info;
-
- if (res_info->acpi_ipc_irq_index == 0)
+ if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 51f0d45d6f8f..9de64f447e7b 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
const char *i2c_name;
int i;
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
index c4b94e2617c5..c74c4f17316f 100644
--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c
+++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c
@@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev)
{
struct glk_card_private *ctx;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 3fa1c3ca6d37..723a4935ed76 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
jack = &ctx->kabylake_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ 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);
da7219_aad_jack_det(component, &ctx->kabylake_headset);
@@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
}
-static struct snd_soc_ops skylaye_refcap_ops = {
+static struct snd_soc_ops skylake_refcap_ops = {
.startup = kabylake_refcap_startup,
};
@@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
new file mode 100644
index 000000000000..3255e0029276
--- /dev/null
+++ b/sound/soc/intel/boards/kbl_rt5660.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018-19 Canonical Corporation.
+
+/*
+ * Intel Kabylake I2S Machine Driver with RT5660 Codec
+ *
+ * Modified from:
+ * Intel Kabylake I2S Machine driver supporting MAXIM98357a and
+ * DA7219 codecs
+ * Also referred to:
+ * Intel Broadwell I2S Machine driver supporting RT5677 codec
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../../codecs/hdac_hdmi.h"
+#include "../../codecs/rt5660.h"
+
+#define KBL_RT5660_CODEC_DAI "rt5660-aif1"
+#define DUAL_CHANNEL 2
+
+static struct snd_soc_card *kabylake_audio_card;
+static struct snd_soc_jack skylake_hdmi[3];
+static struct snd_soc_jack lineout_jack;
+static struct snd_soc_jack mic_jack;
+
+struct kbl_hdmi_pcm {
+ struct list_head head;
+ struct snd_soc_dai *codec_dai;
+ int device;
+};
+
+struct kbl_codec_private {
+ struct gpio_desc *gpio_lo_mute;
+ struct list_head hdmi_pcm_list;
+};
+
+enum {
+ KBL_DPCM_AUDIO_PB = 0,
+ KBL_DPCM_AUDIO_CP,
+ KBL_DPCM_AUDIO_HDMI1_PB,
+ KBL_DPCM_AUDIO_HDMI2_PB,
+ KBL_DPCM_AUDIO_HDMI3_PB,
+};
+
+#define GPIO_LINEOUT_MUTE_INDEX 0
+#define GPIO_LINEOUT_DET_INDEX 3
+#define GPIO_LINEIN_DET_INDEX 4
+
+static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true };
+static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false };
+static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false };
+
+
+static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = {
+ { "lineout-mute-gpios", &lineout_mute_gpio, 1 },
+ { "lineout-det-gpios", &lineout_det_gpio, 1 },
+ { "mic-det-gpios", &mic_det_gpio, 1 },
+ { NULL },
+};
+
+static struct snd_soc_jack_pin lineout_jack_pin = {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+};
+
+static struct snd_soc_jack_pin mic_jack_pin = {
+ .pin = "Line In",
+ .mask = SND_JACK_MICROPHONE,
+};
+
+static struct snd_soc_jack_gpio lineout_jack_gpio = {
+ .name = "lineout-det",
+ .report = SND_JACK_LINEOUT,
+ .debounce_time = 200,
+};
+
+static struct snd_soc_jack_gpio mic_jack_gpio = {
+ .name = "mic-det",
+ .report = SND_JACK_MICROPHONE,
+ .debounce_time = 200,
+};
+
+static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card);
+
+ gpiod_set_value_cansleep(priv->gpio_lo_mute,
+ !(SND_SOC_DAPM_EVENT_ON(event)));
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new kabylake_rt5660_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Line In"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = {
+ SND_SOC_DAPM_MIC("Line In", NULL),
+ SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout),
+};
+
+static const struct snd_soc_dapm_route kabylake_rt5660_map[] = {
+ /* other jacks */
+ {"IN1P", NULL, "Line In"},
+ {"IN2P", NULL, "Line In"},
+ {"Line Out", NULL, "LOUTR"},
+ {"Line Out", NULL, "LOUTL"},
+
+ /* CODEC BE connections */
+ { "AIF1 Playback", NULL, "ssp0 Tx"},
+ { "ssp0 Tx", NULL, "codec0_out"},
+
+ { "codec0_in", NULL, "ssp0 Rx" },
+ { "ssp0 Rx", NULL, "AIF1 Capture" },
+
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+};
+
+static int kabylake_ssp0_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 SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+ ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios);
+ if (ret)
+ dev_warn(component->dev, "Failed to add driver gpios\n");
+
+ /* Request rt5660 GPIO for lineout mute control, return if fails */
+ ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->gpio_lo_mute)) {
+ dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n");
+ return PTR_ERR(ctx->gpio_lo_mute);
+ }
+
+ /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */
+ ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack",
+ SND_JACK_LINEOUT, &lineout_jack,
+ &lineout_jack_pin, 1);
+ if (ret)
+ dev_warn(component->dev, "Can't create Lineout jack\n");
+ else {
+ lineout_jack_gpio.gpiod_dev = component->dev;
+ ret = snd_soc_jack_add_gpios(&lineout_jack, 1,
+ &lineout_jack_gpio);
+ if (ret)
+ dev_warn(component->dev, "Can't add Lineout jack gpio\n");
+ }
+
+ /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */
+ ret = snd_soc_card_jack_new(rtd->card, "Mic Jack",
+ SND_JACK_MICROPHONE, &mic_jack,
+ &mic_jack_pin, 1);
+ if (ret)
+ dev_warn(component->dev, "Can't create mic jack\n");
+ else {
+ mic_jack_gpio.gpiod_dev = component->dev;
+ ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio);
+ if (ret)
+ dev_warn(component->dev, "Can't add mic jack gpio\n");
+ }
+
+ /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+ snd_soc_dapm_force_enable_pin(dapm, "BST1");
+ snd_soc_dapm_force_enable_pin(dapm, "BST2");
+
+ return 0;
+}
+
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
+{
+ struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai = rtd->codec_dai;
+ struct kbl_hdmi_pcm *pcm;
+
+ pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ pcm->device = device;
+ pcm->codec_dai = dai;
+
+ list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+ return 0;
+}
+
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
+}
+
+static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
+
+static int kabylake_rt5660_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;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ RT5660_SCLK_S_PLL1, params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT5660_PLL1_S_BCLK,
+ params_rate(params) * 50,
+ params_rate(params) * 512);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+
+ return ret;
+}
+
+static struct snd_soc_ops kabylake_rt5660_ops = {
+ .hw_params = kabylake_rt5660_hw_params,
+};
+
+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 int kbl_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /*
+ * On this platform for PCM device we support,
+ * 48Khz
+ * stereo
+ * 16 bit audio
+ */
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+ return 0;
+}
+
+static const struct snd_soc_ops kabylake_rt5660_fe_ops = {
+ .startup = kbl_fe_startup,
+};
+
+/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */
+static struct snd_soc_dai_link kabylake_rt5660_dais[] = {
+ /* Front End DAI links */
+ [KBL_DPCM_AUDIO_PB] = {
+ .name = "Kbl Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .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_playback = 1,
+ .ops = &kabylake_rt5660_fe_ops,
+ },
+ [KBL_DPCM_AUDIO_CP] = {
+ .name = "Kbl Audio Capture Port",
+ .stream_name = "Audio Record",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .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,
+ .ops = &kabylake_rt5660_fe_ops,
+ },
+ [KBL_DPCM_AUDIO_HDMI1_PB] = {
+ .name = "Kbl 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:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_HDMI2_PB] = {
+ .name = "Kbl 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:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_HDMI3_PB] = {
+ .name = "Kbl 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:1f.3",
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "SSP0-Codec",
+ .id = 0,
+ .cpu_dai_name = "SSP0 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "i2c-10EC3277:00",
+ .codec_dai_name = KBL_RT5660_CODEC_DAI,
+ .init = kabylake_rt5660_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 = kabylake_ssp0_fixup,
+ .ops = &kabylake_rt5660_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "iDisp1",
+ .id = 1,
+ .cpu_dai_name = "iDisp1 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = kabylake_hdmi1_init,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .id = 2,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:1f.3",
+ .init = kabylake_hdmi2_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .id = 3,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .platform_name = "0000:00:1f.3",
+ .init = kabylake_hdmi3_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+};
+
+
+#define NAME_SIZE 32
+static int kabylake_card_late_probe(struct snd_soc_card *card)
+{
+ struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
+ struct kbl_hdmi_pcm *pcm;
+ struct snd_soc_component *component = NULL;
+ int err, i = 0;
+ char jack_name[NAME_SIZE];
+
+ 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, &skylake_hdmi[i],
+ NULL, 0);
+
+ if (err)
+ return err;
+
+ err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+ &skylake_hdmi[i]);
+ if (err < 0)
+ return err;
+
+ i++;
+
+ }
+
+ if (!component)
+ return -EINVAL;
+
+ return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+/* kabylake audio machine driver for rt5660 */
+static struct snd_soc_card kabylake_audio_card_rt5660 = {
+ .name = "kblrt5660",
+ .owner = THIS_MODULE,
+ .dai_link = kabylake_rt5660_dais,
+ .num_links = ARRAY_SIZE(kabylake_rt5660_dais),
+ .controls = kabylake_rt5660_controls,
+ .num_controls = ARRAY_SIZE(kabylake_rt5660_controls),
+ .dapm_widgets = kabylake_rt5660_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets),
+ .dapm_routes = kabylake_rt5660_map,
+ .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map),
+ .fully_routed = true,
+ .late_probe = kabylake_card_late_probe,
+};
+
+static int kabylake_audio_probe(struct platform_device *pdev)
+{
+ struct kbl_codec_private *ctx;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+ kabylake_audio_card =
+ (struct snd_soc_card *)pdev->id_entry->driver_data;
+
+ kabylake_audio_card->dev = &pdev->dev;
+ snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
+ return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
+}
+
+static const struct platform_device_id kbl_board_ids[] = {
+ {
+ .name = "kbl_rt5660",
+ .driver_data =
+ (kernel_ulong_t)&kabylake_audio_card_rt5660,
+ },
+ { }
+};
+
+static struct platform_driver kabylake_audio = {
+ .probe = kabylake_audio_probe,
+ .driver = {
+ .name = "kbl_rt5660",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = kbl_board_ids,
+};
+
+module_platform_driver(kabylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode");
+MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5660");
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 99e1320c485f..d71475200b08 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -25,9 +25,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
@@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
-static struct snd_soc_ops skylaye_refcap_ops = {
+static struct snd_soc_ops skylake_refcap_ops = {
.startup = kabylake_refcap_startup,
};
@@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = {
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_rt5663_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
@@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
kabylake_audio_card->dev = &pdev->dev;
snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index a737c915d46a..7044d8c2b187 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -26,10 +26,10 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5514.h"
#include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
@@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = {
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
kabylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index b415dd4c85f5..b9a21e64ead2 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -12,8 +12,8 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#include "skl_hda_dsp_common.h"
static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
@@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = {
#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
#define IDISP_CODEC_MASK 0x4
-static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
+static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
{
struct snd_soc_card *card = &hda_soc_card;
struct snd_soc_dai_link *dai_link;
u32 codec_count, codec_mask;
int i, num_links, num_route;
- codec_mask = pdata->codec_mask;
+ codec_mask = mach_params->codec_mask;
codec_count = hweight_long(codec_mask);
- if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
+ if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) {
num_links = IDISP_DAI_COUNT;
num_route = IDISP_ROUTE_COUNT;
} else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
@@ -127,30 +127,30 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
card->num_dapm_routes = num_route;
for_each_card_prelinks(card, i, dai_link)
- dai_link->platform_name = pdata->platform;
+ dai_link->platform_name = mach_params->platform;
return 0;
}
static int skl_hda_audio_probe(struct platform_device *pdev)
{
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
struct skl_hda_private *ctx;
int ret;
dev_dbg(&pdev->dev, "%s: entry\n", __func__);
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- pdata = dev_get_drvdata(&pdev->dev);
- if (!pdata)
+ mach = (&pdev->dev)->platform_data;
+ if (!mach)
return -EINVAL;
- ret = skl_hda_fill_card_info(pdata);
+ ret = skl_hda_fill_card_info(&mach->mach_params);
if (ret < 0) {
dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
return ret;
@@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
ctx->pcm_count = hda_soc_card.num_links;
ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
- ctx->platform_name = pdata->platform;
+ ctx->platform_name = mach->mach_params.platform;
hda_soc_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&hda_soc_card, ctx);
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index d31482b8c9bb..0922106bd323 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -21,9 +21,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi"
@@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
-static const struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
.startup = skylake_refcap_startup,
};
@@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
@@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_nau8825_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index e877bb60beb1..8433c521d39f 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -23,11 +23,11 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
@@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
-static const struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
.startup = skylake_refcap_startup,
};
@@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
@@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_nau88125_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index c1f50a079d34..56c81e20b5bf 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
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 \
+ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \
soc-acpi-intel-hda-match.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.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
index f39386e540d3..61dedc103b19 100644
--- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
@@ -6,9 +6,41 @@
*
*/
+#include <linux/dmi.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+enum {
+ APL_RVP,
+};
+
+static const struct dmi_system_id apl_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+ DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"),
+ },
+ .driver_data = (void *)(APL_RVP),
+ },
+ {}
+};
+
+static struct snd_soc_acpi_mach *apl_quirk(void *arg)
+{
+ struct snd_soc_acpi_mach *mach = arg;
+ const struct dmi_system_id *dmi_id;
+ unsigned long apl_machine_id;
+
+ dmi_id = dmi_first_match(apl_table);
+ if (dmi_id) {
+ apl_machine_id = (unsigned long)dmi_id->driver_data;
+ if (apl_machine_id == APL_RVP)
+ return NULL;
+ }
+
+ return mach;
+}
+
static struct snd_soc_acpi_codecs bxt_codecs = {
.num_codecs = 1,
.codecs = {"MX98357A"}
@@ -19,6 +51,9 @@ 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",
+ .sof_fw_filename = "intel/sof-apl.ri",
+ .sof_tplg_filename = "intel/sof-apl-rt298.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
},
{
.id = "DLGS7219",
@@ -47,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
{
.id = "INT34C3",
.drv_name = "bxt_tdf8532",
+ .machine_quirk = apl_quirk,
.sof_fw_filename = "intel/sof-apl.ri",
.sof_tplg_filename = "intel/sof-apl-tdf8532.tplg",
.asoc_plat_name = "0000:00:0e.0",
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
new file mode 100644
index 000000000000..33b441dca4d3
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-icl-match.c - tables and support for ICL 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 icl_pdata = {
+ .use_tplg_pcm = true,
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
+ {
+ .id = "INT34C2",
+ .drv_name = "icl_rt274",
+ .fw_filename = "intel/dsp_fw_icl.bin",
+ .pdata = &icl_pdata,
+ .sof_fw_filename = "intel/sof-icl.ri",
+ .sof_tplg_filename = "intel/sof-icl-rt274.tplg",
+ .asoc_plat_name = "0000:00:1f.3",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
index a317b7790fce..e6fa6f470526 100644
--- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
@@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.quirk_data = &kbl_7219_98927_codecs,
.pdata = &skl_dmic_data
},
+ {
+ .id = "10EC5660",
+ .drv_name = "kbl_rt5660",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
+ {
+ .id = "10EC3277",
+ .drv_name = "kbl_rt5660",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 8bfb8b0fa3d5..b0e6fb93eaf8 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = {
.init_fw = cnl_sst_init_fw,
.cleanup = cnl_sst_dsp_cleanup
},
+ {
+ .id = 0xa348,
+ .num_cores = 4,
+ .loader_ops = bxt_get_loader_ops,
+ .init = cnl_sst_dsp_init,
+ .init_fw = cnl_sst_init_fw,
+ .cleanup = cnl_sst_dsp_cleanup
+ },
};
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index 01a050cf8775..5d125a3df527 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl)
unsigned int dmic_geo = 0;
u8 j;
+ if (!nhlt)
+ return 0;
+
epnt = (struct nhlt_endpoint *)nhlt->desc;
for (j = 0; j < nhlt->endpoint_count; j++) {
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 5234fafb758a..9f3ce73593ae 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -249,6 +249,8 @@ enum skl_ipc_glb_reply {
IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
+ IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150,
+ IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151,
IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
@@ -392,18 +394,47 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
return 0;
}
-static int skl_ipc_set_reply_error_code(u32 reply)
+struct skl_ipc_err_map {
+ const char *msg;
+ enum skl_ipc_glb_reply reply;
+ int err;
+};
+
+static struct skl_ipc_err_map skl_err_map[] = {
+ {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM},
+ {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY},
+ {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING,
+ IPC_GLB_REPLY_SCLK_ALREADY_RUNNING},
+ {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING,
+ IPC_GLB_REPLY_MCLK_ALREADY_RUNNING},
+};
+
+static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply)
{
- switch (reply) {
- case IPC_GLB_REPLY_OUT_OF_MEMORY:
- return -ENOMEM;
+ int i;
- case IPC_GLB_REPLY_BUSY:
- return -EBUSY;
+ for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) {
+ if (skl_err_map[i].reply == reply)
+ break;
+ }
- default:
+ if (i == ARRAY_SIZE(skl_err_map)) {
+ dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n",
+ reply,
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
return -EINVAL;
}
+
+ if (skl_err_map[i].err < 0)
+ dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
+ skl_err_map[i].msg,
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+ else
+ dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
+ skl_err_map[i].msg,
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+
+ return skl_err_map[i].err;
}
void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
@@ -441,10 +472,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
}
} else {
- msg->errno = skl_ipc_set_reply_error_code(reply);
- dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
- dev_err(ipc->dev, "FW Error Code: %u\n",
- ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+ msg->errno = skl_ipc_set_reply_error_code(ipc, reply);
switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
case IPC_GLB_LOAD_MULTIPLE_MODS:
case IPC_GLB_LOAD_LIBRARY:
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 7487f388e65d..60c94836bf5b 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -40,6 +40,9 @@
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
#include "../../../soc/codecs/hdac_hda.h"
#endif
+static int skl_pci_binding;
+module_param_named(pci_binding, skl_pci_binding, int, 0444);
+MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
/*
* initialize the PCI registers
@@ -311,7 +314,7 @@ static int skl_suspend(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_bus *bus = pci_get_drvdata(pci);
struct skl *skl = bus_to_skl(bus);
- int ret = 0;
+ int ret;
/*
* Do not suspend if streams which are marked ignore suspend are
@@ -333,14 +336,10 @@ static int skl_suspend(struct device *dev)
skl->skl_sst->fw_loaded = false;
}
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
- ret = snd_hdac_display_power(bus, false);
- if (ret < 0)
- dev_err(bus->dev,
- "Cannot turn OFF display power on i915\n");
- }
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+ snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
- return ret;
+ return 0;
}
static int skl_resume(struct device *dev)
@@ -352,14 +351,8 @@ static int skl_resume(struct device *dev)
int ret;
/* Turned OFF in HDMI codec driver after codec reconfiguration */
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
- ret = snd_hdac_display_power(bus, true);
- if (ret < 0) {
- dev_err(bus->dev,
- "Cannot turn on display power on i915\n");
- return ret;
- }
- }
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+ snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
/*
* resume only when we are not in suspend active, otherwise need to
@@ -517,7 +510,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
if (pdata) {
skl->use_tplg_pcm = pdata->use_tplg_pcm;
- pdata->dmic_num = skl_get_dmic_geo(skl);
+ mach->mach_params.dmic_num = skl_get_dmic_geo(skl);
}
return 0;
@@ -527,7 +520,6 @@ static int skl_machine_device_register(struct skl *skl)
{
struct snd_soc_acpi_mach *mach = skl->mach;
struct hdac_bus *bus = skl_to_bus(skl);
- struct skl_machine_pdata *pdata;
struct platform_device *pdev;
int ret;
@@ -537,6 +529,16 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
+ mach->mach_params.platform = dev_name(bus->dev);
+ mach->mach_params.codec_mask = bus->codec_mask;
+
+ ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
+ if (ret) {
+ dev_err(bus->dev, "failed to add machine device platform data\n");
+ platform_device_put(pdev);
+ return ret;
+ }
+
ret = platform_device_add(pdev);
if (ret) {
dev_err(bus->dev, "failed to add machine device\n");
@@ -544,12 +546,6 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
- if (mach->pdata) {
- pdata = (struct skl_machine_pdata *)mach->pdata;
- pdata->platform = dev_name(bus->dev);
- pdata->codec_mask = bus->codec_mask;
- dev_set_drvdata(&pdev->dev, mach->pdata);
- }
skl->i2s_dev = pdev;
@@ -783,11 +779,9 @@ static int skl_i915_init(struct hdac_bus *bus)
if (err < 0)
return err;
- err = snd_hdac_display_power(bus, true);
- if (err < 0)
- dev_err(bus->dev, "Cannot turn on display power on i915\n");
+ snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
- return err;
+ return 0;
}
static void skl_probe_work(struct work_struct *work)
@@ -823,12 +817,10 @@ static void skl_probe_work(struct work_struct *work)
return;
}
- if (bus->ppcap) {
- err = skl_machine_device_register(skl);
- if (err < 0) {
- dev_err(bus->dev, "machine register failed: %d\n", err);
- goto out_err;
- }
+ err = skl_machine_device_register(skl);
+ if (err < 0) {
+ dev_err(bus->dev, "machine register failed: %d\n", err);
+ goto out_err;
}
/*
@@ -837,14 +829,8 @@ static void skl_probe_work(struct work_struct *work)
list_for_each_entry(hlink, &bus->hlink_list, list)
snd_hdac_ext_bus_link_put(bus, hlink);
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
- err = snd_hdac_display_power(bus, false);
- if (err < 0) {
- dev_err(bus->dev, "Cannot turn off display power on i915\n");
- skl_machine_device_unregister(skl);
- return;
- }
- }
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+ snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
/* configure PM */
pm_runtime_put_noidle(bus->dev);
@@ -855,7 +841,7 @@ static void skl_probe_work(struct work_struct *work)
out_err:
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
- err = snd_hdac_display_power(bus, false);
+ snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
}
/*
@@ -928,6 +914,12 @@ static int skl_first_init(struct hdac_bus *bus)
snd_hdac_bus_parse_capabilities(bus);
+ /* check if PPCAP exists */
+ if (!bus->ppcap) {
+ dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n");
+ return -ENODEV;
+ }
+
if (skl_acquire_irq(bus, 0) < 0)
return -EBUSY;
@@ -937,23 +929,25 @@ static int skl_first_init(struct hdac_bus *bus)
gcap = snd_hdac_chip_readw(bus, GCAP);
dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
- /* allow 64bit DMA address if supported by H/W */
- if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
- dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(bus->dev, DMA_BIT_MASK(32));
- dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
- }
-
/* read number of streams from GCAP register */
cp_streams = (gcap >> 8) & 0x0f;
pb_streams = (gcap >> 12) & 0x0f;
- if (!pb_streams && !cp_streams)
+ if (!pb_streams && !cp_streams) {
+ dev_err(bus->dev, "no streams found in GCAP definitions?\n");
return -EIO;
+ }
bus->num_streams = cp_streams + pb_streams;
+ /* allow 64bit DMA address if supported by H/W */
+ if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
+ dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
+ } else {
+ dma_set_mask(bus->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
+ }
+
/* initialize streams */
snd_hdac_ext_stream_init_all
(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
@@ -978,6 +972,36 @@ static int skl_probe(struct pci_dev *pci,
struct hdac_bus *bus = NULL;
int err;
+ switch (skl_pci_binding) {
+ case SND_SKL_PCI_BIND_AUTO:
+ /*
+ * detect DSP by checking class/subclass/prog-id information
+ * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
+ * class=04 subclass 01 prog-if 00: DSP is present
+ * (and may be required e.g. for DMIC or SSP support)
+ * class=04 subclass 03 prog-if 80: use DSP or legacy mode
+ */
+ if (pci->class == 0x040300) {
+ dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n");
+ return -ENODEV;
+ }
+ if (pci->class != 0x040100 && pci->class != 0x040380) {
+ dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
+ return -ENODEV;
+ }
+ dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+ break;
+ case SND_SKL_PCI_BIND_LEGACY:
+ dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n");
+ return -ENODEV;
+ case SND_SKL_PCI_BIND_ASOC:
+ dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n");
+ break;
+ default:
+ dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
+ break;
+ }
+
/* we use ext core ops, so provide NULL for ops here */
err = skl_create(pci, NULL, &skl);
if (err < 0)
@@ -986,8 +1010,10 @@ static int skl_probe(struct pci_dev *pci,
bus = skl_to_bus(skl);
err = skl_first_init(bus);
- if (err < 0)
+ if (err < 0) {
+ dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
goto out_free;
+ }
skl->pci_id = pci->device;
@@ -996,37 +1022,48 @@ static int skl_probe(struct pci_dev *pci,
skl->nhlt = skl_nhlt_init(bus->dev);
if (skl->nhlt == NULL) {
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
+ dev_err(bus->dev, "no nhlt info found\n");
err = -ENODEV;
goto out_free;
- }
-
- err = skl_nhlt_create_sysfs(skl);
- if (err < 0)
- goto out_nhlt_free;
+#else
+ dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n");
+#endif
+ } else {
- skl_nhlt_update_topology_bin(skl);
+ err = skl_nhlt_create_sysfs(skl);
+ if (err < 0) {
+ dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
+ goto out_nhlt_free;
+ }
- pci_set_drvdata(skl->pci, bus);
+ skl_nhlt_update_topology_bin(skl);
- /* check if dsp is there */
- if (bus->ppcap) {
/* create device for dsp clk */
err = skl_clock_device_register(skl);
- if (err < 0)
+ if (err < 0) {
+ dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
goto out_clk_free;
+ }
+ }
- err = skl_find_machine(skl, (void *)pci_id->driver_data);
- if (err < 0)
- goto out_nhlt_free;
+ pci_set_drvdata(skl->pci, bus);
- err = skl_init_dsp(skl);
- if (err < 0) {
- dev_dbg(bus->dev, "error failed to register dsp\n");
- goto out_nhlt_free;
- }
- skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
- skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
+ err = skl_find_machine(skl, (void *)pci_id->driver_data);
+ if (err < 0) {
+ dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
+ goto out_nhlt_free;
}
+
+ err = skl_init_dsp(skl);
+ if (err < 0) {
+ dev_dbg(bus->dev, "error failed to register dsp\n");
+ goto out_nhlt_free;
+ }
+ skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+ skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
@@ -1034,8 +1071,10 @@ static int skl_probe(struct pci_dev *pci,
/* create device for soc dmic */
err = skl_dmic_device_register(skl);
- if (err < 0)
+ if (err < 0) {
+ dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
goto out_dsp_free;
+ }
schedule_work(&skl->probe_work);
@@ -1103,21 +1142,36 @@ static void skl_remove(struct pci_dev *pci)
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
.driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
/* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
/* KBL */
{ PCI_DEVICE(0x8086, 0x9D71),
.driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
+ /* CFL */
+ { PCI_DEVICE(0x8086, 0xa348),
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 8d48cd7c56c8..85f8bb6687dc 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -119,10 +119,7 @@ struct skl_dma_params {
};
struct skl_machine_pdata {
- u32 dmic_num;
bool use_tplg_pcm; /* use dais and dai links from topology */
- const char *platform;
- u32 codec_mask;
};
struct skl_dsp_ops {
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 192f4d7b37b6..bff7d71d0742 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -828,7 +828,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
/* request irq */
irq_id = platform_get_irq(pdev, 0);
if (!irq_id) {
- dev_err(dev, "%s no irq found\n", dev->of_node->name);
+ dev_err(dev, "%pOFn no irq found\n", dev->of_node);
return -ENXIO;
}
ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index c0b6697503fd..166aed28330d 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1092,7 +1092,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
irq_id = platform_get_irq(pdev, 0);
if (irq_id <= 0) {
- dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
+ dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node);
return irq_id < 0 ? irq_id : -ENXIO;
}
ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index 8b8426ed2363..8779fe23671d 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD
imply SND_MESON_AXG_TDMIN
imply SND_MESON_AXG_TDMOUT
imply SND_MESON_AXG_SPDIFOUT
+ imply SND_MESON_AXG_SPDIFIN
imply SND_MESON_AXG_PDM
help
Select Y or M to add support for the AXG SoC sound card
@@ -67,6 +68,13 @@ config SND_MESON_AXG_SPDIFOUT
Select Y or M to add support for SPDIF output serializer embedded
in the Amlogic AXG SoC family
+config SND_MESON_AXG_SPDIFIN
+ tristate "Amlogic AXG SPDIF Input Support"
+ imply SND_SOC_SPDIF
+ help
+ Select Y or M to add support for SPDIF input embedded
+ in the Amlogic AXG SoC family
+
config SND_MESON_AXG_PDM
tristate "Amlogic AXG PDM Input Support"
imply SND_SOC_DMIC
@@ -74,5 +82,4 @@ config SND_MESON_AXG_PDM
help
Select Y or M to add support for PDM input embedded
in the Amlogic AXG SoC family
-
endmenu
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index 4cd25104029d..b45dfb9e2f88 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -8,6 +8,7 @@ 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-spdifin-objs := axg-spdifin.o
snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
snd-soc-meson-axg-pdm-objs := axg-pdm.o
@@ -19,5 +20,6 @@ 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_SPDIFIN) += snd-soc-meson-axg-spdifin.o
obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
index cb6c4013ca33..d9f516cfbeda 100644
--- a/sound/soc/meson/axg-fifo.h
+++ b/sound/soc/meson/axg-fifo.h
@@ -25,7 +25,8 @@ struct snd_soc_pcm_runtime;
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE)
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
#define AXG_FIFO_BURST 8
#define AXG_FIFO_MIN_CNT 64
diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c
new file mode 100644
index 000000000000..01b2035fa841
--- /dev/null
+++ b/sound/soc/meson/axg-spdifin.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/bitfield.h>
+#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>
+
+#define SPDIFIN_CTRL0 0x00
+#define SPDIFIN_CTRL0_EN BIT(31)
+#define SPDIFIN_CTRL0_RST_OUT BIT(29)
+#define SPDIFIN_CTRL0_RST_IN BIT(28)
+#define SPDIFIN_CTRL0_WIDTH_SEL BIT(24)
+#define SPDIFIN_CTRL0_STATUS_CH_SHIFT 11
+#define SPDIFIN_CTRL0_STATUS_SEL GENMASK(10, 8)
+#define SPDIFIN_CTRL0_SRC_SEL GENMASK(5, 4)
+#define SPDIFIN_CTRL0_CHK_VALID BIT(3)
+#define SPDIFIN_CTRL1 0x04
+#define SPDIFIN_CTRL1_BASE_TIMER GENMASK(19, 0)
+#define SPDIFIN_CTRL1_IRQ_MASK GENMASK(27, 20)
+#define SPDIFIN_CTRL2 0x08
+#define SPDIFIN_THRES_PER_REG 3
+#define SPDIFIN_THRES_WIDTH 10
+#define SPDIFIN_CTRL3 0x0c
+#define SPDIFIN_CTRL4 0x10
+#define SPDIFIN_TIMER_PER_REG 4
+#define SPDIFIN_TIMER_WIDTH 8
+#define SPDIFIN_CTRL5 0x14
+#define SPDIFIN_CTRL6 0x18
+#define SPDIFIN_STAT0 0x1c
+#define SPDIFIN_STAT0_MODE GENMASK(30, 28)
+#define SPDIFIN_STAT0_MAXW GENMASK(17, 8)
+#define SPDIFIN_STAT0_IRQ GENMASK(7, 0)
+#define SPDIFIN_IRQ_MODE_CHANGED BIT(2)
+#define SPDIFIN_STAT1 0x20
+#define SPDIFIN_STAT2 0x24
+#define SPDIFIN_MUTE_VAL 0x28
+
+#define SPDIFIN_MODE_NUM 7
+
+struct axg_spdifin_cfg {
+ const unsigned int *mode_rates;
+ unsigned int ref_rate;
+};
+
+struct axg_spdifin {
+ const struct axg_spdifin_cfg *conf;
+ struct regmap *map;
+ struct clk *refclk;
+ struct clk *pclk;
+};
+
+/*
+ * TODO:
+ * It would have been nice to check the actual rate against the sample rate
+ * requested in hw_params(). Unfortunately, I was not able to make the mode
+ * detection and IRQ work reliably:
+ *
+ * 1. IRQs are generated on mode change only, so there is no notification
+ * on transition between no signal and mode 0 (32kHz).
+ * 2. Mode detection very often has glitches, and may detects the
+ * lowest or the highest mode before zeroing in on the actual mode.
+ *
+ * This makes calling snd_pcm_stop() difficult to get right. Even notifying
+ * the kcontrol would be very unreliable at this point.
+ * Let's keep things simple until the magic spell that makes this work is
+ * found.
+ */
+
+static unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv)
+{
+ unsigned int stat, mode, rate = 0;
+
+ regmap_read(priv->map, SPDIFIN_STAT0, &stat);
+ mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat);
+
+ /*
+ * If max width is zero, we are not capturing anything.
+ * Also Sometimes, when the capture is on but there is no data,
+ * mode is SPDIFIN_MODE_NUM, but not always ...
+ */
+ if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) &&
+ mode < SPDIFIN_MODE_NUM)
+ rate = priv->conf->mode_rates[mode];
+
+ return rate;
+}
+
+static int axg_spdifin_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+ /* Apply both reset */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_RST_OUT |
+ SPDIFIN_CTRL0_RST_IN,
+ 0);
+
+ /* Clear out reset before in reset */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT);
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_RST_IN, SPDIFIN_CTRL0_RST_IN);
+
+ return 0;
+}
+
+static int axg_spdifin_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(priv->refclk);
+ if (ret) {
+ dev_err(dai->dev,
+ "failed to enable spdifin reference clock\n");
+ return ret;
+ }
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
+ SPDIFIN_CTRL0_EN);
+
+ return 0;
+}
+
+static void axg_spdifin_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
+ clk_disable_unprepare(priv->refclk);
+}
+
+static void axg_spdifin_write_mode_param(struct regmap *map, int mode,
+ unsigned int val,
+ unsigned int num_per_reg,
+ unsigned int base_reg,
+ unsigned int width)
+{
+ uint64_t offset = mode;
+ unsigned int reg, shift, rem;
+
+ rem = do_div(offset, num_per_reg);
+
+ reg = offset * regmap_get_reg_stride(map) + base_reg;
+ shift = width * (num_per_reg - 1 - rem);
+
+ regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift,
+ val << shift);
+}
+
+static void axg_spdifin_write_timer(struct regmap *map, int mode,
+ unsigned int val)
+{
+ axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG,
+ SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH);
+}
+
+static void axg_spdifin_write_threshold(struct regmap *map, int mode,
+ unsigned int val)
+{
+ axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG,
+ SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH);
+}
+
+static unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv,
+ int mode,
+ unsigned int rate)
+{
+ /*
+ * Number of period of the reference clock during a period of the
+ * input signal reference clock
+ */
+ return rate / (128 * priv->conf->mode_rates[mode]);
+}
+
+static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,
+ struct axg_spdifin *priv)
+{
+ unsigned int rate, t_next;
+ int ret, i = SPDIFIN_MODE_NUM - 1;
+
+ /* Set spdif input reference clock */
+ ret = clk_set_rate(priv->refclk, priv->conf->ref_rate);
+ if (ret) {
+ dev_err(dai->dev, "reference clock rate set failed\n");
+ return ret;
+ }
+
+ /*
+ * The rate actually set might be slightly different, get
+ * the actual rate for the following mode calculation
+ */
+ rate = clk_get_rate(priv->refclk);
+
+ /* HW will update mode every 1ms */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL1,
+ SPDIFIN_CTRL1_BASE_TIMER,
+ FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));
+
+ /* Threshold based on the minimum width between two edges */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL);
+
+ /* Calculate the last timer which has no threshold */
+ t_next = axg_spdifin_mode_timer(priv, i, rate);
+ axg_spdifin_write_timer(priv->map, i, t_next);
+
+ do {
+ unsigned int t;
+
+ i -= 1;
+
+ /* Calculate the timer */
+ t = axg_spdifin_mode_timer(priv, i, rate);
+
+ /* Set the timer value */
+ axg_spdifin_write_timer(priv->map, i, t);
+
+ /* Set the threshold value */
+ axg_spdifin_write_threshold(priv->map, i, t + t_next);
+
+ /* Save the current timer for the next threshold calculation */
+ t_next = t;
+
+ } while (i > 0);
+
+ return 0;
+}
+
+static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(priv->pclk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable pclk\n");
+ return ret;
+ }
+
+ ret = axg_spdifin_sample_mode_config(dai, priv);
+ if (ret) {
+ dev_err(dai->dev, "mode configuration failed\n");
+ clk_disable_unprepare(priv->pclk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(priv->pclk);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops axg_spdifin_ops = {
+ .prepare = axg_spdifin_prepare,
+ .startup = axg_spdifin_startup,
+ .shutdown = axg_spdifin_shutdown,
+};
+
+static int axg_spdifin_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 axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+
+ for (i = 0; i < 24; i++)
+ ucontrol->value.iec958.status[i] = 0xff;
+
+ return 0;
+}
+
+static int axg_spdifin_get_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
+ int i, j;
+
+ for (i = 0; i < 6; i++) {
+ unsigned int val;
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_STATUS_SEL,
+ FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i));
+
+ regmap_read(priv->map, SPDIFIN_STAT1, &val);
+
+ for (j = 0; j < 4; j++) {
+ unsigned int offset = i * 4 + j;
+
+ ucontrol->value.iec958.status[offset] =
+ (val >> (j * 8)) & 0xff;
+ }
+ }
+
+ return 0;
+}
+
+#define AXG_SPDIFIN_IEC958_MASK \
+ { \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), \
+ .info = axg_spdifin_iec958_info, \
+ .get = axg_spdifin_get_status_mask, \
+ }
+
+#define AXG_SPDIFIN_IEC958_STATUS \
+ { \
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE), \
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE), \
+ .info = axg_spdifin_iec958_info, \
+ .get = axg_spdifin_get_status, \
+ }
+
+static const char * const spdifin_chsts_src_texts[] = {
+ "A", "B",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_STATUS_CH_SHIFT,
+ spdifin_chsts_src_texts);
+
+static int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 192000;
+
+ return 0;
+}
+
+static int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
+
+ ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv);
+
+ return 0;
+}
+
+#define AXG_SPDIFIN_LOCK_RATE(xname) \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE), \
+ .get = axg_spdifin_rate_lock_get, \
+ .info = axg_spdifin_rate_lock_info, \
+ .name = xname, \
+ }
+
+static const struct snd_kcontrol_new axg_spdifin_controls[] = {
+ AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"),
+ SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1),
+ SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src",
+ axg_spdifin_chsts_src_enum),
+ AXG_SPDIFIN_IEC958_MASK,
+ AXG_SPDIFIN_IEC958_STATUS,
+};
+
+static const struct snd_soc_component_driver axg_spdifin_component_drv = {
+ .controls = axg_spdifin_controls,
+ .num_controls = ARRAY_SIZE(axg_spdifin_controls),
+};
+
+static const struct regmap_config axg_spdifin_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPDIFIN_MUTE_VAL,
+};
+
+static const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = {
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+
+static const struct axg_spdifin_cfg axg_cfg = {
+ .mode_rates = axg_spdifin_mode_rates,
+ .ref_rate = 333333333,
+};
+
+static const struct of_device_id axg_spdifin_of_match[] = {
+ {
+ .compatible = "amlogic,axg-spdifin",
+ .data = &axg_cfg,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_spdifin_of_match);
+
+static struct snd_soc_dai_driver *
+axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
+{
+ struct snd_soc_dai_driver *drv;
+ int i;
+
+ drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return ERR_PTR(-ENOMEM);
+
+ drv->name = "SPDIF Input";
+ drv->ops = &axg_spdifin_ops;
+ drv->probe = axg_spdifin_dai_probe;
+ drv->remove = axg_spdifin_dai_remove;
+ drv->capture.stream_name = "Capture";
+ drv->capture.channels_min = 1;
+ drv->capture.channels_max = 2;
+ drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+
+ for (i = 0; i < SPDIFIN_MODE_NUM; i++) {
+ unsigned int rb =
+ snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]);
+
+ if (rb == SNDRV_PCM_RATE_KNOT)
+ return ERR_PTR(-EINVAL);
+
+ drv->capture.rates |= rb;
+ }
+
+ return drv;
+}
+
+static int axg_spdifin_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct axg_spdifin *priv;
+ struct snd_soc_dai_driver *dai_drv;
+ 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);
+
+ priv->conf = of_device_get_match_data(dev);
+ if (!priv->conf) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ 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_spdifin_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->refclk = devm_clk_get(dev, "refclk");
+ if (IS_ERR(priv->refclk)) {
+ ret = PTR_ERR(priv->refclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get mclk: %d\n", ret);
+ return ret;
+ }
+
+ dai_drv = axg_spdifin_get_dai_drv(dev, priv);
+ if (IS_ERR(dai_drv)) {
+ dev_err(dev, "failed to get dai driver: %ld\n",
+ PTR_ERR(dai_drv));
+ return PTR_ERR(dai_drv);
+ }
+
+ return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv,
+ dai_drv, 1);
+}
+
+static struct platform_driver axg_spdifin_pdrv = {
+ .probe = axg_spdifin_probe,
+ .driver = {
+ .name = "axg-spdifin",
+ .of_match_table = axg_spdifin_of_match,
+ },
+};
+module_platform_driver(axg_spdifin_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG SPDIF Input 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
index c2c9bb312586..0e9ca3882ae5 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -25,6 +25,8 @@
#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
#define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
+#define TODDR_MSB_POS 31
+
static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai)
{
@@ -36,14 +38,7 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
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.
- */
+ unsigned int type, width;
switch (params_physical_width(params)) {
case 8:
@@ -66,8 +61,8 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
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)));
+ CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) |
+ CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1)));
return 0;
}
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
deleted file mode 100644
index 6dccea6fdaeb..000000000000
--- a/sound/soc/omap/Kconfig
+++ /dev/null
@@ -1,129 +0,0 @@
-config SND_OMAP_SOC
- tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)"
- depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
- select SND_SDMA_SOC
-
-config SND_SDMA_SOC
- tristate "SoC Audio for Texas Instruments chips using sDMA"
- depends on DMA_OMAP || COMPILE_TEST
- select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_OMAP_SOC_DMIC
- tristate
-
-config SND_OMAP_SOC_MCBSP
- tristate
-
-config SND_OMAP_SOC_MCPDM
- tristate
-
-config SND_OMAP_SOC_HDMI_AUDIO
- tristate "HDMI audio support for OMAP4+ based SoCs"
- depends on SND_SDMA_SOC
- help
- For HDMI audio to work OMAPDSS HDMI support should be
- enabled.
- The hdmi audio driver implements cpu-dai component using the
- callbacks provided by OMAPDSS and registers the component
- under DSS HDMI device. Omap-pcm is registered for platform
- component also under DSS HDMI device. Dummy codec is used as
- as codec component. The hdmi audio driver implements also
- the card and registers it under its own platform device.
- The device for the driver is registered by OMAPDSS hdmi
- driver.
-
-config SND_OMAP_SOC_N810
- tristate "SoC Audio support for Nokia N810"
- depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC3X
- help
- Say Y if you want to add support for SoC audio on Nokia N810.
-
-config SND_OMAP_SOC_RX51
- tristate "SoC Audio support for Nokia N900 (RX-51)"
- depends on SND_SDMA_SOC && ARM && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC3X
- select SND_SOC_TPA6130A2
- depends on GPIOLIB
- help
- Say Y if you want to add support for SoC audio on Nokia N900
- cellphone.
-
-config SND_OMAP_SOC_AMS_DELTA
- tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
- depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_CX20442
- help
- Say Y if you want to add support for SoC audio device connected to
- a handset and a speakerphone found on Amstrad E3 (Delta) videophone.
-
- Note that in order to get those devices fully supported, you have to
- build the kernel with standard serial port driver included and
- configured for at least 4 ports. Then, from userspace, you must load
- a line discipline #19 on the modem (ttyS3) serial line. The simplest
- way to achieve this is to install util-linux-ng and use the included
- ldattach utility. This can be started automatically from udev,
- a simple rule like this one should do the trick (it does for me):
- ACTION=="add", KERNEL=="controlC0", \
- RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
-
-config SND_OMAP_SOC_OSK5912
- tristate "SoC Audio support for omap osk5912"
- depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23_I2C
- help
- Say Y if you want to add support for SoC audio on osk5912.
-
-config SND_OMAP_SOC_AM3517EVM
- tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
- depends on SND_SDMA_SOC && MACH_OMAP3517EVM && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23_I2C
- help
- Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
- EVM.
-
-config SND_OMAP_SOC_OMAP_TWL4030
- tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
- depends on TWL4030_CORE && SND_SDMA_SOC
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on TI SoC based boards
- using twl4030 as c codec. This driver currently supports:
- - Beagleboard or Devkit8000
- - Gumstix Overo or CompuLab CM-T35/CM-T3730
- - IGEP v2
- - OMAP3EVM
- - SDP3430
- - Zoom2
-
-config SND_OMAP_SOC_OMAP_ABE_TWL6040
- tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
- depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK
- depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
- select SND_OMAP_SOC_DMIC
- select SND_OMAP_SOC_MCPDM
- select SND_SOC_TWL6040
- select SND_SOC_DMIC
- select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)
- select CLK_TWL6040
- help
- Say Y if you want to add support for SoC audio on OMAP boards using
- ABE and twl6040 codec. This driver currently supports:
- - SDP4430/Blaze boards
- - PandaBoard (4430)
- - PandaBoardES (4460)
- - omap5-uevm (5432)
-
-config SND_OMAP_SOC_OMAP3_PANDORA
- tristate "SoC Audio support for OMAP3 Pandora"
- depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
deleted file mode 100644
index 53eba3413485..000000000000
--- a/sound/soc/omap/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# OMAP Platform Support
-snd-soc-sdma-objs := sdma-pcm.o
-snd-soc-omap-dmic-objs := omap-dmic.o
-snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o
-snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
-
-obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o
-obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
-obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
-obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
-obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
-
-# OMAP Machine Support
-snd-soc-n810-objs := n810.o
-snd-soc-rx51-objs := rx51.o
-snd-soc-ams-delta-objs := ams-delta.o
-snd-soc-osk5912-objs := osk5912.o
-snd-soc-am3517evm-objs := am3517evm.o
-snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
-snd-soc-omap-twl4030-objs := omap-twl4030.o
-snd-soc-omap3pandora-objs := omap3pandora.o
-
-obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
-obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
-obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
-obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
-obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
deleted file mode 100644
index d5651026ec10..000000000000
--- a/sound/soc/omap/am3517evm.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM
- *
- * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
- *
- * Based on sound/soc/omap/beagle.c by Steve Sakoman
- *
- * Copyright (C) 2009 Texas Instruments Incorporated
- *
- * 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.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-
-#include "../codecs/tlv320aic23.h"
-
-#define CODEC_CLOCK 12000000
-
-static int am3517evm_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 the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- CODEC_CLOCK, SND_SOC_CLOCK_IN);
- if (ret < 0)
- printk(KERN_ERR "can't set codec system clock\n");
-
- return ret;
-}
-
-static const struct snd_soc_ops am3517evm_ops = {
- .hw_params = am3517evm_hw_params,
-};
-
-/* am3517evm machine dapm widgets */
-static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
- SND_SOC_DAPM_HP("Line Out", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
- SND_SOC_DAPM_MIC("Mic In", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* Line Out connected to LLOUT, RLOUT */
- {"Line Out", NULL, "LOUT"},
- {"Line Out", NULL, "ROUT"},
-
- {"LLINEIN", NULL, "Line In"},
- {"RLINEIN", NULL, "Line In"},
-
- {"MICIN", NULL, "Mic In"},
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link am3517evm_dai = {
- .name = "TLV320AIC23",
- .stream_name = "AIC23",
- .cpu_dai_name = "omap-mcbsp.1",
- .codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "omap-mcbsp.1",
- .codec_name = "tlv320aic23-codec.2-001a",
- .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &am3517evm_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_am3517evm = {
- .name = "am3517evm",
- .owner = THIS_MODULE,
- .dai_link = &am3517evm_dai,
- .num_links = 1,
-
- .dapm_widgets = tlv320aic23_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *am3517evm_snd_device;
-
-static int __init am3517evm_soc_init(void)
-{
- int ret;
-
- if (!machine_is_omap3517evm())
- return -ENODEV;
- pr_info("OMAP3517 / AM3517 EVM SoC init\n");
-
- am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
- if (!am3517evm_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
-
- ret = platform_device_add(am3517evm_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(am3517evm_snd_device);
-
- return ret;
-}
-
-static void __exit am3517evm_soc_exit(void)
-{
- platform_device_unregister(am3517evm_snd_device);
-}
-
-module_init(am3517evm_soc_init);
-module_exit(am3517evm_soc_exit);
-
-MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
deleted file mode 100644
index 79d4dc785e5c..000000000000
--- a/sound/soc/omap/mcbsp.c
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*
- * sound/soc/omap/mcbsp.c
- *
- * Copyright (C) 2004 Nokia Corporation
- * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- * Peter Ujfalusi <peter.ujfalusi@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.
- *
- * Multichannel mode not supported.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "mcbsp.h"
-
-static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
- void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
- if (mcbsp->pdata->reg_size == 2) {
- ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
- writew_relaxed((u16)val, addr);
- } else {
- ((u32 *)mcbsp->reg_cache)[reg] = val;
- writel_relaxed(val, addr);
- }
-}
-
-static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
-{
- void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
- if (mcbsp->pdata->reg_size == 2) {
- return !from_cache ? readw_relaxed(addr) :
- ((u16 *)mcbsp->reg_cache)[reg];
- } else {
- return !from_cache ? readl_relaxed(addr) :
- ((u32 *)mcbsp->reg_cache)[reg];
- }
-}
-
-static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
- writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
-}
-
-static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
-{
- return readl_relaxed(mcbsp->st_data->io_base_st + reg);
-}
-
-#define MCBSP_READ(mcbsp, reg) \
- omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
-#define MCBSP_WRITE(mcbsp, reg, val) \
- omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
-#define MCBSP_READ_CACHE(mcbsp, reg) \
- omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
-
-#define MCBSP_ST_READ(mcbsp, reg) \
- omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
-#define MCBSP_ST_WRITE(mcbsp, reg, val) \
- omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
-
-static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
-{
- dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
- dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n",
- MCBSP_READ(mcbsp, DRR2));
- dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n",
- MCBSP_READ(mcbsp, DRR1));
- dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n",
- MCBSP_READ(mcbsp, DXR2));
- dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n",
- MCBSP_READ(mcbsp, DXR1));
- dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, SPCR2));
- dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, SPCR1));
- dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, RCR2));
- dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, RCR1));
- dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, XCR2));
- dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, XCR1));
- dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
- MCBSP_READ(mcbsp, SRGR2));
- dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
- MCBSP_READ(mcbsp, SRGR1));
- dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n",
- MCBSP_READ(mcbsp, PCR0));
- dev_dbg(mcbsp->dev, "***********************\n");
-}
-
-static irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcbsp *mcbsp = dev_id;
- u16 irqst;
-
- irqst = MCBSP_READ(mcbsp, IRQST);
- dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
-
- if (irqst & RSYNCERREN)
- dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
- if (irqst & RFSREN)
- dev_dbg(mcbsp->dev, "RX Frame Sync\n");
- if (irqst & REOFEN)
- dev_dbg(mcbsp->dev, "RX End Of Frame\n");
- if (irqst & RRDYEN)
- dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
- if (irqst & RUNDFLEN)
- dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
- if (irqst & ROVFLEN)
- dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
-
- if (irqst & XSYNCERREN)
- dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
- if (irqst & XFSXEN)
- dev_dbg(mcbsp->dev, "TX Frame Sync\n");
- if (irqst & XEOFEN)
- dev_dbg(mcbsp->dev, "TX End Of Frame\n");
- if (irqst & XRDYEN)
- dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
- if (irqst & XUNDFLEN)
- dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
- if (irqst & XOVFLEN)
- dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
- if (irqst & XEMPTYEOFEN)
- dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
-
- MCBSP_WRITE(mcbsp, IRQST, irqst);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcbsp *mcbsp_tx = dev_id;
- u16 irqst_spcr2;
-
- irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
- dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
-
- if (irqst_spcr2 & XSYNC_ERR) {
- dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
- irqst_spcr2);
- /* Writing zero to XSYNC_ERR clears the IRQ */
- MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
- }
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcbsp *mcbsp_rx = dev_id;
- u16 irqst_spcr1;
-
- irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
- dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
-
- if (irqst_spcr1 & RSYNC_ERR) {
- dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
- irqst_spcr1);
- /* Writing zero to RSYNC_ERR clears the IRQ */
- MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * omap_mcbsp_config simply write a config to the
- * appropriate McBSP.
- * You either call this function or set the McBSP registers
- * by yourself before calling omap_mcbsp_start().
- */
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
- const struct omap_mcbsp_reg_cfg *config)
-{
- dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
- mcbsp->id, mcbsp->phys_base);
-
- /* We write the given config */
- MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
- MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
- MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
- MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
- MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
- MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
- MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
- MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
- MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
- MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
- MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
- if (mcbsp->pdata->has_ccr) {
- MCBSP_WRITE(mcbsp, XCCR, config->xccr);
- MCBSP_WRITE(mcbsp, RCCR, config->rccr);
- }
- /* Enable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
-
- /* Enable TX/RX sync error interrupts by default */
- if (mcbsp->irq)
- MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
- RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
-}
-
-/**
- * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
- * @id - mcbsp id
- * @stream - indicates the direction of data flow (rx or tx)
- *
- * Returns the address of mcbsp data transmit register or data receive register
- * to be used by DMA for transferring/receiving data based on the value of
- * @stream for the requested mcbsp given by @id
- */
-static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
- unsigned int stream)
-{
- int data_reg;
-
- if (mcbsp->pdata->reg_size == 2) {
- if (stream)
- data_reg = OMAP_MCBSP_REG_DRR1;
- else
- data_reg = OMAP_MCBSP_REG_DXR1;
- } else {
- if (stream)
- data_reg = OMAP_MCBSP_REG_DRR;
- else
- data_reg = OMAP_MCBSP_REG_DXR;
- }
-
- return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
-}
-
-static void omap_st_on(struct omap_mcbsp *mcbsp)
-{
- unsigned int w;
-
- if (mcbsp->pdata->force_ick_on)
- mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
-
- /* Disable Sidetone clock auto-gating for normal operation */
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
-
- /* Enable McBSP Sidetone */
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
-
- /* Enable Sidetone from Sidetone Core */
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
-}
-
-static void omap_st_off(struct omap_mcbsp *mcbsp)
-{
- unsigned int w;
-
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
-
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
-
- /* Enable Sidetone clock auto-gating to reduce power consumption */
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
-
- if (mcbsp->pdata->force_ick_on)
- mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
-}
-
-static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
-{
- u16 val, i;
-
- val = MCBSP_ST_READ(mcbsp, SSELCR);
-
- if (val & ST_COEFFWREN)
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
- MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
-
- for (i = 0; i < 128; i++)
- MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
-
- i = 0;
-
- val = MCBSP_ST_READ(mcbsp, SSELCR);
- while (!(val & ST_COEFFWRDONE) && (++i < 1000))
- val = MCBSP_ST_READ(mcbsp, SSELCR);
-
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
- if (i == 1000)
- dev_err(mcbsp->dev, "McBSP FIR load error!\n");
-}
-
-static void omap_st_chgain(struct omap_mcbsp *mcbsp)
-{
- u16 w;
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- w = MCBSP_ST_READ(mcbsp, SSELCR);
-
- MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
- ST_CH1GAIN(st_data->ch1gain));
-}
-
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENOENT;
-
- spin_lock_irq(&mcbsp->lock);
- if (channel == 0)
- st_data->ch0gain = chgain;
- else if (channel == 1)
- st_data->ch1gain = chgain;
- else
- ret = -EINVAL;
-
- if (st_data->enabled)
- omap_st_chgain(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENOENT;
-
- spin_lock_irq(&mcbsp->lock);
- if (channel == 0)
- *chgain = st_data->ch0gain;
- else if (channel == 1)
- *chgain = st_data->ch1gain;
- else
- ret = -EINVAL;
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-static int omap_st_start(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (st_data->enabled && !st_data->running) {
- omap_st_fir_write(mcbsp, st_data->taps);
- omap_st_chgain(mcbsp);
-
- if (!mcbsp->free) {
- omap_st_on(mcbsp);
- st_data->running = 1;
- }
- }
-
- return 0;
-}
-
-int omap_st_enable(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (!st_data)
- return -ENODEV;
-
- spin_lock_irq(&mcbsp->lock);
- st_data->enabled = 1;
- omap_st_start(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
-
- return 0;
-}
-
-static int omap_st_stop(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (st_data->running) {
- if (!mcbsp->free) {
- omap_st_off(mcbsp);
- st_data->running = 0;
- }
- }
-
- return 0;
-}
-
-int omap_st_disable(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENODEV;
-
- spin_lock_irq(&mcbsp->lock);
- omap_st_stop(mcbsp);
- st_data->enabled = 0;
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (!st_data)
- return -ENODEV;
-
- return st_data->enabled;
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH2 register.
- */
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
- if (mcbsp->pdata->buffer_size == 0)
- return;
-
- if (threshold && threshold <= mcbsp->max_tx_thres)
- MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH1 register.
- */
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
- if (mcbsp->pdata->buffer_size == 0)
- return;
-
- if (threshold && threshold <= mcbsp->max_rx_thres)
- MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
-}
-
-/*
- * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
- */
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
-{
- u16 buffstat;
-
- if (mcbsp->pdata->buffer_size == 0)
- return 0;
-
- /* Returns the number of free locations in the buffer */
- buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
-
- /* Number of slots are different in McBSP ports */
- return mcbsp->pdata->buffer_size - buffstat;
-}
-
-/*
- * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
- * to reach the threshold value (when the DMA will be triggered to read it)
- */
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
-{
- u16 buffstat, threshold;
-
- if (mcbsp->pdata->buffer_size == 0)
- return 0;
-
- /* Returns the number of used locations in the buffer */
- buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
- /* RX threshold */
- threshold = MCBSP_READ(mcbsp, THRSH1);
-
- /* Return the number of location till we reach the threshold limit */
- if (threshold <= buffstat)
- return 0;
- else
- return threshold - buffstat;
-}
-
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
-{
- void *reg_cache;
- int err;
-
- reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
- if (!reg_cache) {
- return -ENOMEM;
- }
-
- spin_lock(&mcbsp->lock);
- if (!mcbsp->free) {
- dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
- mcbsp->id);
- err = -EBUSY;
- goto err_kfree;
- }
-
- mcbsp->free = false;
- mcbsp->reg_cache = reg_cache;
- spin_unlock(&mcbsp->lock);
-
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
- mcbsp->pdata->ops->request(mcbsp->id - 1);
-
- /*
- * Make sure that transmitter, receiver and sample-rate generator are
- * not running before activating IRQs.
- */
- MCBSP_WRITE(mcbsp, SPCR1, 0);
- MCBSP_WRITE(mcbsp, SPCR2, 0);
-
- if (mcbsp->irq) {
- err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
- "McBSP", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request IRQ\n");
- goto err_clk_disable;
- }
- } else {
- err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
- "McBSP TX", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
- goto err_clk_disable;
- }
-
- err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
- "McBSP RX", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
- goto err_free_irq;
- }
- }
-
- return 0;
-err_free_irq:
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
-err_clk_disable:
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
- mcbsp->pdata->ops->free(mcbsp->id - 1);
-
- /* Disable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
- spin_lock(&mcbsp->lock);
- mcbsp->free = true;
- mcbsp->reg_cache = NULL;
-err_kfree:
- spin_unlock(&mcbsp->lock);
- kfree(reg_cache);
-
- return err;
-}
-
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
-{
- void *reg_cache;
-
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
- mcbsp->pdata->ops->free(mcbsp->id - 1);
-
- /* Disable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
- /* Disable interrupt requests */
- if (mcbsp->irq)
- MCBSP_WRITE(mcbsp, IRQEN, 0);
-
- if (mcbsp->irq) {
- free_irq(mcbsp->irq, (void *)mcbsp);
- } else {
- free_irq(mcbsp->rx_irq, (void *)mcbsp);
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
- }
-
- reg_cache = mcbsp->reg_cache;
-
- /*
- * Select CLKS source from internal source unconditionally before
- * marking the McBSP port as free.
- * If the external clock source via MCBSP_CLKS pin has been selected the
- * system will refuse to enter idle if the CLKS pin source is not reset
- * back to internal source.
- */
- if (!mcbsp_omap1())
- omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
-
- spin_lock(&mcbsp->lock);
- if (mcbsp->free)
- dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
- else
- mcbsp->free = true;
- mcbsp->reg_cache = NULL;
- spin_unlock(&mcbsp->lock);
-
- kfree(reg_cache);
-}
-
-/*
- * Here we start the McBSP, by enabling transmitter, receiver or both.
- * If no transmitter or receiver is active prior calling, then sample-rate
- * generator and frame sync are started.
- */
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx)
-{
- int enable_srg = 0;
- u16 w;
-
- if (mcbsp->st_data)
- omap_st_start(mcbsp);
-
- /* Only enable SRG, if McBSP is master */
- w = MCBSP_READ_CACHE(mcbsp, PCR0);
- if (w & (FSXM | FSRM | CLKXM | CLKRM))
- enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
- if (enable_srg) {
- /* Start the sample generator */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
- }
-
- /* Enable transmitter and receiver */
- tx &= 1;
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | tx);
-
- rx &= 1;
- w = MCBSP_READ_CACHE(mcbsp, SPCR1);
- MCBSP_WRITE(mcbsp, SPCR1, w | rx);
-
- /*
- * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
- * REVISIT: 100us may give enough time for two CLKSRG, however
- * due to some unknown PM related, clock gating etc. reason it
- * is now at 500us.
- */
- udelay(500);
-
- if (enable_srg) {
- /* Start frame sync */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
- }
-
- if (mcbsp->pdata->has_ccr) {
- /* Release the transmitter and receiver */
- w = MCBSP_READ_CACHE(mcbsp, XCCR);
- w &= ~(tx ? XDISABLE : 0);
- MCBSP_WRITE(mcbsp, XCCR, w);
- w = MCBSP_READ_CACHE(mcbsp, RCCR);
- w &= ~(rx ? RDISABLE : 0);
- MCBSP_WRITE(mcbsp, RCCR, w);
- }
-
- /* Dump McBSP Regs */
- omap_mcbsp_dump_reg(mcbsp);
-}
-
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
-{
- int idle;
- u16 w;
-
- /* Reset transmitter */
- tx &= 1;
- if (mcbsp->pdata->has_ccr) {
- w = MCBSP_READ_CACHE(mcbsp, XCCR);
- w |= (tx ? XDISABLE : 0);
- MCBSP_WRITE(mcbsp, XCCR, w);
- }
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
-
- /* Reset receiver */
- rx &= 1;
- if (mcbsp->pdata->has_ccr) {
- w = MCBSP_READ_CACHE(mcbsp, RCCR);
- w |= (rx ? RDISABLE : 0);
- MCBSP_WRITE(mcbsp, RCCR, w);
- }
- w = MCBSP_READ_CACHE(mcbsp, SPCR1);
- MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
-
- idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
- if (idle) {
- /* Reset the sample rate generator */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
- }
-
- if (mcbsp->st_data)
- omap_st_stop(mcbsp);
-}
-
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
-{
- struct clk *fck_src;
- const char *src;
- int r;
-
- if (fck_src_id == MCBSP_CLKS_PAD_SRC)
- src = "pad_fck";
- else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
- src = "prcm_fck";
- else
- return -EINVAL;
-
- fck_src = clk_get(mcbsp->dev, src);
- if (IS_ERR(fck_src)) {
- dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
- return -EINVAL;
- }
-
- pm_runtime_put_sync(mcbsp->dev);
-
- r = clk_set_parent(mcbsp->fclk, fck_src);
- if (r) {
- dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
- src);
- clk_put(fck_src);
- return r;
- }
-
- pm_runtime_get_sync(mcbsp->dev);
-
- clk_put(fck_src);
-
- return 0;
-
-}
-
-#define max_thres(m) (mcbsp->pdata->buffer_size)
-#define valid_threshold(m, val) ((val) <= max_thres(m))
-#define THRESHOLD_PROP_BUILDER(prop) \
-static ssize_t prop##_show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
- \
- return sprintf(buf, "%u\n", mcbsp->prop); \
-} \
- \
-static ssize_t prop##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t size) \
-{ \
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
- unsigned long val; \
- int status; \
- \
- status = kstrtoul(buf, 0, &val); \
- if (status) \
- return status; \
- \
- if (!valid_threshold(mcbsp, val)) \
- return -EDOM; \
- \
- mcbsp->prop = val; \
- return size; \
-} \
- \
-static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
-
-THRESHOLD_PROP_BUILDER(max_tx_thres);
-THRESHOLD_PROP_BUILDER(max_rx_thres);
-
-static const char *dma_op_modes[] = {
- "element", "threshold",
-};
-
-static ssize_t dma_op_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- int dma_op_mode, i = 0;
- ssize_t len = 0;
- const char * const *s;
-
- dma_op_mode = mcbsp->dma_op_mode;
-
- for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
- if (dma_op_mode == i)
- len += sprintf(buf + len, "[%s] ", *s);
- else
- len += sprintf(buf + len, "%s ", *s);
- }
- len += sprintf(buf + len, "\n");
-
- return len;
-}
-
-static ssize_t dma_op_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- int i;
-
- i = sysfs_match_string(dma_op_modes, buf);
- if (i < 0)
- return i;
-
- spin_lock_irq(&mcbsp->lock);
- if (!mcbsp->free) {
- size = -EBUSY;
- goto unlock;
- }
- mcbsp->dma_op_mode = i;
-
-unlock:
- spin_unlock_irq(&mcbsp->lock);
-
- return size;
-}
-
-static DEVICE_ATTR_RW(dma_op_mode);
-
-static const struct attribute *additional_attrs[] = {
- &dev_attr_max_tx_thres.attr,
- &dev_attr_max_rx_thres.attr,
- &dev_attr_dma_op_mode.attr,
- NULL,
-};
-
-static const struct attribute_group additional_attr_group = {
- .attrs = (struct attribute **)additional_attrs,
-};
-
-static ssize_t st_taps_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- ssize_t status = 0;
- int i;
-
- spin_lock_irq(&mcbsp->lock);
- for (i = 0; i < st_data->nr_taps; i++)
- status += sprintf(&buf[status], (i ? ", %d" : "%d"),
- st_data->taps[i]);
- if (i)
- status += sprintf(&buf[status], "\n");
- spin_unlock_irq(&mcbsp->lock);
-
- return status;
-}
-
-static ssize_t st_taps_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int val, tmp, status, i = 0;
-
- spin_lock_irq(&mcbsp->lock);
- memset(st_data->taps, 0, sizeof(st_data->taps));
- st_data->nr_taps = 0;
-
- do {
- status = sscanf(buf, "%d%n", &val, &tmp);
- if (status < 0 || status == 0) {
- size = -EINVAL;
- goto out;
- }
- if (val < -32768 || val > 32767) {
- size = -EINVAL;
- goto out;
- }
- st_data->taps[i++] = val;
- buf += tmp;
- if (*buf != ',')
- break;
- buf++;
- } while (1);
-
- st_data->nr_taps = i;
-
-out:
- spin_unlock_irq(&mcbsp->lock);
-
- return size;
-}
-
-static DEVICE_ATTR_RW(st_taps);
-
-static const struct attribute *sidetone_attrs[] = {
- &dev_attr_st_taps.attr,
- NULL,
-};
-
-static const struct attribute_group sidetone_attr_group = {
- .attrs = (struct attribute **)sidetone_attrs,
-};
-
-static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res)
-{
- struct omap_mcbsp_st_data *st_data;
- int err;
-
- st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
- if (!st_data)
- return -ENOMEM;
-
- st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
- if (IS_ERR(st_data->mcbsp_iclk)) {
- dev_warn(mcbsp->dev,
- "Failed to get ick, sidetone might be broken\n");
- st_data->mcbsp_iclk = NULL;
- }
-
- st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
- resource_size(res));
- if (!st_data->io_base_st)
- return -ENOMEM;
-
- err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- if (err)
- return err;
-
- mcbsp->st_data = st_data;
- return 0;
-}
-
-/*
- * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
- * 730 has only 2 McBSP, and both of them are MPU peripherals.
- */
-int omap_mcbsp_init(struct platform_device *pdev)
-{
- struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
- struct resource *res;
- int ret = 0;
-
- spin_lock_init(&mcbsp->lock);
- mcbsp->free = true;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
- if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mcbsp->io_base))
- return PTR_ERR(mcbsp->io_base);
-
- mcbsp->phys_base = res->start;
- mcbsp->reg_cache_size = resource_size(res);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
- if (!res)
- mcbsp->phys_dma_base = mcbsp->phys_base;
- else
- mcbsp->phys_dma_base = res->start;
-
- /*
- * OMAP1, 2 uses two interrupt lines: TX, RX
- * OMAP2430, OMAP3 SoC have combined IRQ line as well.
- * OMAP4 and newer SoC only have the combined IRQ line.
- * Use the combined IRQ if available since it gives better debugging
- * possibilities.
- */
- mcbsp->irq = platform_get_irq_byname(pdev, "common");
- if (mcbsp->irq == -ENXIO) {
- mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
-
- if (mcbsp->tx_irq == -ENXIO) {
- mcbsp->irq = platform_get_irq(pdev, 0);
- mcbsp->tx_irq = 0;
- } else {
- mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
- mcbsp->irq = 0;
- }
- }
-
- if (!pdev->dev.of_node) {
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!res) {
- dev_err(&pdev->dev, "invalid tx DMA channel\n");
- return -ENODEV;
- }
- mcbsp->dma_req[0] = res->start;
- mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!res) {
- dev_err(&pdev->dev, "invalid rx DMA channel\n");
- return -ENODEV;
- }
- mcbsp->dma_req[1] = res->start;
- mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
- } else {
- mcbsp->dma_data[0].filter_data = "tx";
- mcbsp->dma_data[1].filter_data = "rx";
- }
-
- mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
- mcbsp->dma_data[0].maxburst = 4;
-
- mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
- mcbsp->dma_data[1].maxburst = 4;
-
- mcbsp->fclk = clk_get(&pdev->dev, "fck");
- if (IS_ERR(mcbsp->fclk)) {
- ret = PTR_ERR(mcbsp->fclk);
- dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
- return ret;
- }
-
- mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
- if (mcbsp->pdata->buffer_size) {
- /*
- * Initially configure the maximum thresholds to a safe value.
- * The McBSP FIFO usage with these values should not go under
- * 16 locations.
- * If the whole FIFO without safety buffer is used, than there
- * is a possibility that the DMA will be not able to push the
- * new data on time, causing channel shifts in runtime.
- */
- mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
- mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
-
- ret = sysfs_create_group(&mcbsp->dev->kobj,
- &additional_attr_group);
- if (ret) {
- dev_err(mcbsp->dev,
- "Unable to create additional controls\n");
- goto err_thres;
- }
- } else {
- mcbsp->max_tx_thres = -EINVAL;
- mcbsp->max_rx_thres = -EINVAL;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
- if (res) {
- ret = omap_st_add(mcbsp, res);
- if (ret) {
- dev_err(mcbsp->dev,
- "Unable to create sidetone controls\n");
- goto err_st;
- }
- }
-
- return 0;
-
-err_st:
- if (mcbsp->pdata->buffer_size)
- sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-err_thres:
- clk_put(mcbsp->fclk);
- return ret;
-}
-
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp)
-{
- if (mcbsp->pdata->buffer_size)
- sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
- if (mcbsp->st_data) {
- sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- clk_put(mcbsp->st_data->mcbsp_iclk);
- }
-}
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 943b44de1464..67159a6b90a8 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -79,7 +79,7 @@ config SND_PXA2XX_SOC_TOSA
tristate "SoC AC97 Audio support for Tosa"
depends on SND_PXA2XX_SOC && MACH_TOSA
depends on MFD_TC6393XB
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -89,7 +89,7 @@ config SND_PXA2XX_SOC_TOSA
config SND_PXA2XX_SOC_E740
tristate "SoC AC97 Audio support for e740"
depends on SND_PXA2XX_SOC && MACH_E740
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_SOC_WM9705
select SND_PXA2XX_SOC_AC97
help
@@ -99,7 +99,7 @@ config SND_PXA2XX_SOC_E740
config SND_PXA2XX_SOC_E750
tristate "SoC AC97 Audio support for e750"
depends on SND_PXA2XX_SOC && MACH_E750
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_SOC_WM9705
select SND_PXA2XX_SOC_AC97
help
@@ -109,7 +109,7 @@ config SND_PXA2XX_SOC_E750
config SND_PXA2XX_SOC_E800
tristate "SoC AC97 Audio support for e800"
depends on SND_PXA2XX_SOC && MACH_E800
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_SOC_WM9712
select SND_PXA2XX_SOC_AC97
help
@@ -120,7 +120,7 @@ config SND_PXA2XX_SOC_EM_X270
tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
MACH_CM_X300)
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -131,7 +131,7 @@ config SND_PXA2XX_SOC_PALM27X
bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
MACH_PALMT5 || MACH_PALMTE2)
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -161,7 +161,7 @@ config SND_SOC_TTC_DKB
config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_PXA_SOC_SSP
select SND_SOC_WM9713
@@ -169,16 +169,6 @@ config SND_SOC_ZYLONITE
Say Y if you want to add support for SoC audio on the
Marvell Zylonite reference platform.
-config SND_SOC_RAUMFELD
- tristate "SoC Audio support Raumfeld audio adapter"
- depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR)
- depends on I2C && SPI_MASTER
- select SND_PXA_SOC_SSP
- select SND_SOC_CS4270
- select SND_SOC_AK4104
- help
- Say Y if you want to add support for SoC audio on Raumfeld devices
-
config SND_PXA2XX_SOC_HX4700
tristate "SoC Audio support for HP iPAQ hx4700"
depends on SND_PXA2XX_SOC && MACH_H4700 && I2C
@@ -201,7 +191,7 @@ config SND_PXA2XX_SOC_MAGICIAN
config SND_PXA2XX_SOC_MIOA701
tristate "SoC Audio support for MIO A701"
depends on SND_PXA2XX_SOC && MACH_MIOA701
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9713
help
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 5b265662f04f..0ab2a9dcb720 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -49,6 +49,5 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
-obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
deleted file mode 100644
index 111a907c4eb9..000000000000
--- a/sound/soc/pxa/raumfeld.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * raumfeld_audio.c -- SoC audio for Raumfeld audio devices
- *
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- *
- * based on code from:
- *
- * Wolfson Microelectronics PLC.
- * Openedhand Ltd.
- * Liam Girdwood <lrg@slimlogic.co.uk>
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-
-#include "pxa-ssp.h"
-
-#define GPIO_SPDIF_RESET (38)
-#define GPIO_MCLK_RESET (111)
-#define GPIO_CODEC_RESET (120)
-
-static struct i2c_client *max9486_client;
-static struct i2c_board_info max9486_hwmon_info = {
- I2C_BOARD_INFO("max9485", 0x63),
-};
-
-#define MAX9485_MCLK_FREQ_112896 0x22
-#define MAX9485_MCLK_FREQ_122880 0x23
-#define MAX9485_MCLK_FREQ_225792 0x32
-#define MAX9485_MCLK_FREQ_245760 0x33
-
-static void set_max9485_clk(char clk)
-{
- i2c_master_send(max9486_client, &clk, 1);
-}
-
-static void raumfeld_enable_audio(bool en)
-{
- if (en) {
- gpio_set_value(GPIO_MCLK_RESET, 1);
-
- /* wait some time to let the clocks become stable */
- msleep(100);
-
- gpio_set_value(GPIO_SPDIF_RESET, 1);
- gpio_set_value(GPIO_CODEC_RESET, 1);
- } else {
- gpio_set_value(GPIO_MCLK_RESET, 0);
- gpio_set_value(GPIO_SPDIF_RESET, 0);
- gpio_set_value(GPIO_CODEC_RESET, 0);
- }
-}
-
-/* CS4270 */
-static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* set freq to 0 to enable all possible codec sample rates */
- return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
-}
-
-static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* set freq to 0 to enable all possible codec sample rates */
- snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
-}
-
-static int raumfeld_cs4270_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;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int clk = 0;
- int ret = 0;
-
- switch (params_rate(params)) {
- case 44100:
- set_max9485_clk(MAX9485_MCLK_FREQ_112896);
- clk = 11289600;
- break;
- case 48000:
- set_max9485_clk(MAX9485_MCLK_FREQ_122880);
- clk = 12288000;
- break;
- case 88200:
- set_max9485_clk(MAX9485_MCLK_FREQ_225792);
- clk = 22579200;
- break;
- case 96000:
- set_max9485_clk(MAX9485_MCLK_FREQ_245760);
- clk = 24576000;
- break;
- default:
- return -EINVAL;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
- if (ret < 0)
- return ret;
-
- /* setup the CPU DAI */
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static const struct snd_soc_ops raumfeld_cs4270_ops = {
- .startup = raumfeld_cs4270_startup,
- .shutdown = raumfeld_cs4270_shutdown,
- .hw_params = raumfeld_cs4270_hw_params,
-};
-
-static int raumfeld_analog_suspend(struct snd_soc_card *card)
-{
- raumfeld_enable_audio(false);
- return 0;
-}
-
-static int raumfeld_analog_resume(struct snd_soc_card *card)
-{
- raumfeld_enable_audio(true);
- return 0;
-}
-
-/* AK4104 */
-
-static int raumfeld_ak4104_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, clk = 0;
-
- switch (params_rate(params)) {
- case 44100:
- set_max9485_clk(MAX9485_MCLK_FREQ_112896);
- clk = 11289600;
- break;
- case 48000:
- set_max9485_clk(MAX9485_MCLK_FREQ_122880);
- clk = 12288000;
- break;
- case 88200:
- set_max9485_clk(MAX9485_MCLK_FREQ_225792);
- clk = 22579200;
- break;
- case 96000:
- set_max9485_clk(MAX9485_MCLK_FREQ_245760);
- clk = 24576000;
- break;
- default:
- return -EINVAL;
- }
-
- /* setup the CPU DAI */
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops raumfeld_ak4104_ops = {
- .hw_params = raumfeld_ak4104_hw_params,
-};
-
-#define DAI_LINK_CS4270 \
-{ \
- .name = "CS4270", \
- .stream_name = "CS4270", \
- .cpu_dai_name = "pxa-ssp-dai.0", \
- .platform_name = "pxa-pcm-audio", \
- .codec_dai_name = "cs4270-hifi", \
- .codec_name = "cs4270.0-0048", \
- .dai_fmt = SND_SOC_DAIFMT_I2S | \
- SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBS_CFS, \
- .ops = &raumfeld_cs4270_ops, \
-}
-
-#define DAI_LINK_AK4104 \
-{ \
- .name = "ak4104", \
- .stream_name = "Playback", \
- .cpu_dai_name = "pxa-ssp-dai.1", \
- .codec_dai_name = "ak4104-hifi", \
- .platform_name = "pxa-pcm-audio", \
- .dai_fmt = SND_SOC_DAIFMT_I2S | \
- SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBS_CFS, \
- .ops = &raumfeld_ak4104_ops, \
- .codec_name = "spi0.0", \
-}
-
-static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = {
- DAI_LINK_CS4270,
- DAI_LINK_AK4104,
-};
-
-static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = {
- DAI_LINK_CS4270,
-};
-
-static struct snd_soc_card snd_soc_raumfeld_connector = {
- .name = "Raumfeld Connector",
- .owner = THIS_MODULE,
- .dai_link = snd_soc_raumfeld_connector_dai,
- .num_links = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
- .suspend_post = raumfeld_analog_suspend,
- .resume_pre = raumfeld_analog_resume,
-};
-
-static struct snd_soc_card snd_soc_raumfeld_speaker = {
- .name = "Raumfeld Speaker",
- .owner = THIS_MODULE,
- .dai_link = snd_soc_raumfeld_speaker_dai,
- .num_links = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
- .suspend_post = raumfeld_analog_suspend,
- .resume_pre = raumfeld_analog_resume,
-};
-
-static struct platform_device *raumfeld_audio_device;
-
-static int __init raumfeld_audio_init(void)
-{
- int ret;
-
- if (!machine_is_raumfeld_speaker() &&
- !machine_is_raumfeld_connector())
- return 0;
-
- max9486_client = i2c_new_device(i2c_get_adapter(0),
- &max9486_hwmon_info);
-
- if (!max9486_client)
- return -ENOMEM;
-
- set_max9485_clk(MAX9485_MCLK_FREQ_122880);
-
- /* Register analog device */
- raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
- if (!raumfeld_audio_device)
- return -ENOMEM;
-
- if (machine_is_raumfeld_speaker())
- platform_set_drvdata(raumfeld_audio_device,
- &snd_soc_raumfeld_speaker);
-
- if (machine_is_raumfeld_connector())
- platform_set_drvdata(raumfeld_audio_device,
- &snd_soc_raumfeld_connector);
-
- ret = platform_device_add(raumfeld_audio_device);
- if (ret < 0) {
- platform_device_put(raumfeld_audio_device);
- return ret;
- }
-
- raumfeld_enable_audio(true);
- return 0;
-}
-
-static void __exit raumfeld_audio_exit(void)
-{
- raumfeld_enable_audio(false);
-
- platform_device_unregister(raumfeld_audio_device);
-
- i2c_unregister_device(max9486_client);
-
- gpio_free(GPIO_MCLK_RESET);
- gpio_free(GPIO_CODEC_RESET);
- gpio_free(GPIO_SPDIF_RESET);
-}
-
-module_init(raumfeld_audio_init);
-module_exit(raumfeld_audio_exit);
-
-/* Module information */
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("Raumfeld audio SoC");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 2a4c912d1e48..804ae0d93058 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -66,6 +66,7 @@ config SND_SOC_QDSP6_ASM
tristate
config SND_SOC_QDSP6_ASM_DAI
+ select SND_SOC_COMPRESS
tristate
config SND_SOC_QDSP6
@@ -100,6 +101,7 @@ config SND_SOC_SDM845
depends on QCOM_APR
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
+ select SND_SOC_RT5663
help
To add support for audio on Qualcomm Technologies Inc.
SDM845 SoC-based systems.
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index d07271ea4c45..028bce671cbc 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
if (ret) {
dev_err(soc_runtime->dev,
"error writing to rdmactl reg: %d\n", ret);
- return ret;
+ return ret;
}
data->dma_ch = dma_ch;
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 8f6c8fc073a9..dc645ba4d8d0 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -341,6 +341,7 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
switch (dai->id) {
case HDMI_RX:
+ case DISPLAY_PORT_RX:
q6afe_hdmi_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].hdmi);
break;
@@ -445,6 +446,7 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"HDMI Playback", NULL, "HDMI_RX"},
+ {"Display Port Playback", NULL, "DISPLAY_PORT_RX"},
{"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
{"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
{"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
@@ -561,13 +563,13 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
};
-static struct snd_soc_dai_ops q6hdmi_ops = {
+static const struct snd_soc_dai_ops q6hdmi_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6hdmi_hw_params,
.shutdown = q6afe_dai_shutdown,
};
-static struct snd_soc_dai_ops q6i2s_ops = {
+static const struct snd_soc_dai_ops q6i2s_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6i2s_hw_params,
.set_fmt = q6i2s_set_fmt,
@@ -575,14 +577,14 @@ static struct snd_soc_dai_ops q6i2s_ops = {
.set_sysclk = q6afe_mi2s_set_sysclk,
};
-static struct snd_soc_dai_ops q6slim_ops = {
+static const struct snd_soc_dai_ops q6slim_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6slim_hw_params,
.shutdown = q6afe_dai_shutdown,
.set_channel_map = q6slim_set_channel_map,
};
-static struct snd_soc_dai_ops q6tdm_ops = {
+static const struct snd_soc_dai_ops q6tdm_ops = {
.prepare = q6afe_dai_prepare,
.shutdown = q6afe_dai_shutdown,
.set_sysclk = q6afe_mi2s_set_sysclk,
@@ -1090,6 +1092,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5),
Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6),
Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7),
+ {
+ .playback = {
+ .stream_name = "Display Port Playback",
+ .rates = SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_max = 192000,
+ .rate_min = 48000,
+ },
+ .ops = &q6hdmi_ops,
+ .id = DISPLAY_PORT_RX,
+ .name = "DISPLAY_PORT",
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
};
static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
@@ -1311,6 +1332,7 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 829b5e987b2a..e0945f7a58c8 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -71,6 +71,7 @@
/* Port IDs */
#define AFE_API_VERSION_HDMI_CONFIG 0x1
#define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E
+#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020
#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
/* Clock set API version */
@@ -704,6 +705,8 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
QUINARY_TDM_RX_7, 1, 1},
[QUINARY_TDM_TX_7] = { AFE_PORT_ID_QUINARY_TDM_TX_7,
QUINARY_TDM_TX_7, 0, 1},
+ [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX,
+ DISPLAY_PORT_RX, 1, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -1384,6 +1387,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
switch (port_id) {
case AFE_PORT_ID_MULTICHAN_HDMI_RX:
+ case AFE_PORT_ID_HDMI_OVER_DP_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
break;
case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX:
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 86115de5c1b2..5b986b74dd36 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -10,6 +10,8 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <linux/spinlock.h>
+#include <sound/compress_driver.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
@@ -30,6 +32,15 @@
#define CAPTURE_MIN_PERIOD_SIZE 320
#define SID_MASK_DEFAULT 0xF
+/* Default values used if user space does not set */
+#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
+#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
+#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
+#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
+#define Q6ASM_DAI_TX_RX 0
+#define Q6ASM_DAI_TX 1
+#define Q6ASM_DAI_RX 2
+
enum stream_state {
Q6ASM_STREAM_IDLE = 0,
Q6ASM_STREAM_STOPPED,
@@ -38,11 +49,18 @@ enum stream_state {
struct q6asm_dai_rtd {
struct snd_pcm_substream *substream;
+ struct snd_compr_stream *cstream;
+ struct snd_compr_params codec_param;
+ struct snd_dma_buffer dma_buffer;
+ spinlock_t lock;
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
unsigned int pcm_irq_pos; /* IRQ position */
unsigned int periods;
+ unsigned int bytes_sent;
+ unsigned int bytes_received;
+ unsigned int copied_total;
uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
@@ -137,6 +155,21 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.mask = 0,
};
+static const struct snd_compr_codec_caps q6asm_compr_caps = {
+ .num_descriptors = 1,
+ .descriptor[0].max_ch = 2,
+ .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
+ 24000, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000 },
+ .descriptor[0].num_sample_rates = 13,
+ .descriptor[0].bit_rate[0] = 320,
+ .descriptor[0].bit_rate[1] = 128,
+ .descriptor[0].num_bitrates = 2,
+ .descriptor[0].profiles = 0,
+ .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+ .descriptor[0].formats = 0,
+};
+
static void event_handler(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -460,6 +493,306 @@ static struct snd_pcm_ops q6asm_dai_ops = {
.mmap = q6asm_dai_mmap,
};
+static void compress_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6asm_dai_rtd *prtd = priv;
+ struct snd_compr_stream *substream = prtd->cstream;
+ unsigned long flags;
+ uint64_t avail;
+
+ switch (opcode) {
+ case ASM_CLIENT_EVENT_CMD_RUN_DONE:
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (!prtd->bytes_sent) {
+ q6asm_write_async(prtd->audio_client, prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ prtd->bytes_sent += prtd->pcm_count;
+ }
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
+ case ASM_CLIENT_EVENT_CMD_EOS_DONE:
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ break;
+
+ case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ prtd->copied_total += prtd->pcm_count;
+ snd_compr_fragment_elapsed(substream);
+
+ if (prtd->state != Q6ASM_STREAM_RUNNING) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail >= prtd->pcm_count) {
+ q6asm_write_async(prtd->audio_client,
+ prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ prtd->bytes_sent += prtd->pcm_count;
+ }
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ struct q6asm_dai_rtd *prtd;
+ int stream_id, size, ret;
+
+ stream_id = cpu_dai->driver->id;
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata) {
+ dev_err(dev, "Drv data not found ..\n");
+ return -EINVAL;
+ }
+
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+ if (!prtd)
+ return -ENOMEM;
+
+ prtd->cstream = stream;
+ prtd->audio_client = q6asm_audio_client_alloc(dev,
+ (q6asm_cb)compress_event_handler,
+ prtd, stream_id, LEGACY_PCM_MODE);
+ if (!prtd->audio_client) {
+ dev_err(dev, "Could not allocate memory\n");
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
+ COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
+ &prtd->dma_buffer);
+ if (ret) {
+ dev_err(dev, "Cannot allocate buffer(s)\n");
+ return ret;
+ }
+
+ if (pdata->sid < 0)
+ prtd->phys = prtd->dma_buffer.addr;
+ else
+ prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
+
+ snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
+ spin_lock_init(&prtd->lock);
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+
+ if (prtd->audio_client) {
+ if (prtd->state)
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+
+ snd_dma_free_pages(&prtd->dma_buffer);
+ q6asm_unmap_memory_regions(stream->direction,
+ prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ }
+ q6routing_stream_close(rtd->dai_link->id, stream->direction);
+ kfree(prtd);
+
+ return 0;
+}
+
+static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ int dir = stream->direction;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ int ret;
+
+ memcpy(&prtd->codec_param, params, sizeof(*params));
+
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata)
+ return -EINVAL;
+
+ if (!prtd || !prtd->audio_client) {
+ dev_err(dev, "private data null or audio client freed\n");
+ return -EINVAL;
+ }
+
+ prtd->periods = runtime->fragments;
+ prtd->pcm_count = runtime->fragment_size;
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+ prtd->bits_per_sample = 16;
+ if (dir == SND_COMPRESS_PLAYBACK) {
+ ret = q6asm_open_write(prtd->audio_client, params->codec.id,
+ prtd->bits_per_sample);
+
+ if (ret < 0) {
+ dev_err(dev, "q6asm_open_write failed\n");
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
+ }
+ }
+
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+ ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+ prtd->session_id, dir);
+ if (ret) {
+ dev_err(dev, "Stream reg failed ret:%d\n", ret);
+ return ret;
+ }
+
+ ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
+ (prtd->pcm_size / prtd->periods),
+ prtd->periods);
+
+ if (ret < 0) {
+ dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
+ return -ENOMEM;
+ }
+
+ prtd->state = Q6ASM_STREAM_RUNNING;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ tstamp->copied_total = prtd->copied_total;
+ tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ return 0;
+}
+
+static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
+ size_t count)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->bytes_received += count;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ return count;
+}
+
+static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream,
+ struct vm_area_struct *vma)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct device *dev = c->dev;
+
+ return dma_mmap_coherent(dev, vma,
+ prtd->dma_buffer.area, prtd->dma_buffer.addr,
+ prtd->dma_buffer.bytes);
+}
+
+static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps)
+{
+ caps->direction = SND_COMPRESS_PLAYBACK;
+ caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
+ caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
+ caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
+ caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ caps->num_codecs = 1;
+ caps->codecs[0] = SND_AUDIOCODEC_MP3;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec)
+{
+ switch (codec->codec) {
+ case SND_AUDIOCODEC_MP3:
+ *codec = q6asm_compr_caps;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_compr_ops q6asm_dai_compr_ops = {
+ .open = q6asm_dai_compr_open,
+ .free = q6asm_dai_compr_free,
+ .set_params = q6asm_dai_compr_set_params,
+ .pointer = q6asm_dai_compr_pointer,
+ .trigger = q6asm_dai_compr_trigger,
+ .get_caps = q6asm_dai_compr_get_caps,
+ .get_codec_caps = q6asm_dai_compr_get_codec_caps,
+ .mmap = q6asm_dai_compr_mmap,
+ .ack = q6asm_dai_compr_ack,
+};
+
static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm_substream *psubstream, *csubstream;
@@ -515,7 +848,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.ops = &q6asm_dai_ops,
.pcm_new = q6asm_dai_pcm_new,
.pcm_free = q6asm_dai_pcm_free,
-
+ .compr_ops = &q6asm_dai_compr_ops,
};
static struct snd_soc_dai_driver q6asm_fe_dais[] = {
@@ -529,6 +862,41 @@ static struct snd_soc_dai_driver q6asm_fe_dais[] = {
Q6ASM_FEDAI_DRIVER(8),
};
+static int of_q6asm_parse_dai_data(struct device *dev,
+ struct q6asm_dai_data *pdata)
+{
+ static struct snd_soc_dai_driver *dai_drv;
+ struct snd_soc_pcm_stream empty_stream;
+ struct device_node *node;
+ int ret, id, dir;
+
+ memset(&empty_stream, 0, sizeof(empty_stream));
+
+ for_each_child_of_node(dev->of_node, node) {
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id > MAX_SESSIONS || id < 0) {
+ dev_err(dev, "valid dai id not found:%d\n", ret);
+ continue;
+ }
+
+ dai_drv = &q6asm_fe_dais[id];
+
+ ret = of_property_read_u32(node, "direction", &dir);
+ if (ret)
+ continue;
+
+ if (dir == Q6ASM_DAI_RX)
+ dai_drv->capture = empty_stream;
+ else if (dir == Q6ASM_DAI_TX)
+ dai_drv->playback = empty_stream;
+
+ if (of_property_read_bool(node, "is-compress-dai"))
+ dai_drv->compress_new = snd_soc_new_compress;
+ }
+
+ return 0;
+}
+
static int q6asm_dai_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -549,6 +917,8 @@ static int q6asm_dai_probe(struct platform_device *pdev)
dev_set_drvdata(dev, pdata);
+ of_q6asm_parse_dai_data(dev, pdata);
+
return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
q6asm_fe_dais,
ARRAY_SIZE(q6asm_fe_dais));
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index e1cfa846a1dc..4f85cb19a309 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -12,6 +12,7 @@
#include <linux/kref.h>
#include <linux/of.h>
#include <uapi/sound/asound.h>
+#include <uapi/sound/compress_params.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -36,6 +37,7 @@
#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
#define ASM_SESSION_CMD_RUN_V2 0x00010DAA
#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
+#define ASM_MEDIA_FMT_MP3 0x00010BE9
#define ASM_DATA_CMD_WRITE_V2 0x00010DAB
#define ASM_DATA_CMD_READ_V2 0x00010DAC
#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
@@ -868,6 +870,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
switch (format) {
+ case SND_AUDIOCODEC_MP3:
+ open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
+ break;
case FORMAT_LINEAR_PCM:
open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
break;
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index d61b8404f7da..ddcd9978cf57 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -453,6 +453,9 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(HDMI_RX) };
+static const struct snd_kcontrol_new display_port_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(DISPLAY_PORT_RX) };
+
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) };
@@ -655,6 +658,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
hdmi_mixer_controls,
ARRAY_SIZE(hdmi_mixer_controls)),
+ SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ display_port_mixer_controls,
+ ARRAY_SIZE(display_port_mixer_controls)),
+
SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
slimbus_rx_mixer_controls,
ARRAY_SIZE(slimbus_rx_mixer_controls)),
@@ -833,6 +840,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("DISPLAY_PORT_RX Audio Mixer",
+ "DISPLAY_PORT_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"),
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 9effbecc571f..1db8ef668223 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -6,18 +6,31 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
+#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
#include "common.h"
#include "qdsp6/q6afe.h"
+#include "../codecs/rt5663.h"
#define DEFAULT_SAMPLE_RATE_48K 48000
#define DEFAULT_MCLK_RATE 24576000
-#define DEFAULT_BCLK_RATE 12288000
+#define TDM_BCLK_RATE 6144000
+#define MI2S_BCLK_RATE 1536000
+#define LEFT_SPK_TDM_TX_MASK 0x30
+#define RIGHT_SPK_TDM_TX_MASK 0xC0
+#define SPK_TDM_RX_MASK 0x03
+#define NUM_TDM_SLOTS 8
struct sdm845_snd_data {
+ struct snd_soc_jack jack;
+ bool jack_setup;
struct snd_soc_card *card;
uint32_t pri_mi2s_clk_count;
+ uint32_t sec_mi2s_clk_count;
uint32_t quat_tdm_clk_count;
};
@@ -28,12 +41,12 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, j;
int channels, slot_width;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- slot_width = 32;
+ slot_width = 16;
break;
default:
dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
@@ -75,6 +88,35 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
goto end;
}
}
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name_prefix, "Left")) {
+ ret = snd_soc_dai_set_tdm_slot(
+ codec_dai, LEFT_SPK_TDM_TX_MASK,
+ SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+ slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "DEV0 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!strcmp(codec_dai->component->name_prefix, "Right")) {
+ ret = snd_soc_dai_set_tdm_slot(
+ codec_dai, RIGHT_SPK_TDM_TX_MASK,
+ SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+ slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "DEV1 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+
end:
return ret;
}
@@ -84,9 +126,27 @@ static int sdm845_snd_hw_params(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 *codec_dai = rtd->codec_dai;
int ret = 0;
switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ /*
+ * Use ASRC for internal clocks, as PLL rate isn't multiple
+ * of BCLK.
+ */
+ rt5663_sel_asrc_clk_src(
+ codec_dai->component,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
+ ret = snd_soc_dai_set_sysclk(
+ codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev,
+ "snd_soc_dai_set_sysclk err = %d\n", ret);
+ break;
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
ret = sdm845_tdm_snd_hw_params(substream, params);
@@ -98,24 +158,87 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_card *card = rtd->card;
+ struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
+ int i, rval;
+
+ if (!pdata->jack_setup) {
+ struct snd_jack *jack;
+
+ rval = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pdata->jack, NULL, 0);
+
+ if (rval < 0) {
+ dev_err(card->dev, "Unable to add Headphone Jack\n");
+ return rval;
+ }
+
+ jack = pdata->jack.jack;
+
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ pdata->jack_setup = true;
+ }
+
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ struct snd_soc_dai *dai = rtd->codec_dais[i];
+
+ component = dai->component;
+ rval = snd_soc_component_set_jack(
+ component, &pdata->jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
+ }
+
+ return 0;
+}
+
+
static int sdm845_snd_startup(struct snd_pcm_substream *substream)
{
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ unsigned int codec_dai_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;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int j;
+ int ret;
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX:
case PRIMARY_MI2S_TX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
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);
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
+
+ case SECONDARY_MI2S_TX:
+ if (++(data->sec_mi2s_clk_count) == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
}
snd_soc_dai_set_fmt(cpu_dai, fmt);
break;
@@ -125,7 +248,35 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
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);
+ TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+
+ codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name_prefix,
+ "Left")) {
+ ret = snd_soc_dai_set_fmt(
+ codec_dai, codec_dai_fmt);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "Left TDM fmt err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!strcmp(codec_dai->component->name_prefix,
+ "Right")) {
+ ret = snd_soc_dai_set_fmt(
+ codec_dai, codec_dai_fmt);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "Right TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
}
break;
@@ -156,6 +307,14 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
};
break;
+ case SECONDARY_MI2S_TX:
+ if (--(data->sec_mi2s_clk_count) == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ 0, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ break;
+
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
if (--(data->quat_tdm_clk_count) == 0) {
@@ -171,7 +330,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
}
}
-static struct snd_soc_ops sdm845_be_ops = {
+static const struct snd_soc_ops sdm845_be_ops = {
.hw_params = sdm845_snd_hw_params,
.startup = sdm845_snd_startup,
.shutdown = sdm845_snd_shutdown,
@@ -193,7 +352,15 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static void sdm845_add_be_ops(struct snd_soc_card *card)
+static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static void sdm845_add_ops(struct snd_soc_card *card)
{
struct snd_soc_dai_link *link;
int i;
@@ -203,6 +370,7 @@ static void sdm845_add_be_ops(struct snd_soc_card *card)
link->ops = &sdm845_be_ops;
link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
}
+ link->init = sdm845_dai_init;
}
}
@@ -224,6 +392,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
goto data_alloc_fail;
}
+ card->dapm_widgets = sdm845_snd_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
card->dev = dev;
dev_set_drvdata(dev, card);
ret = qcom_snd_parse_of(card);
@@ -235,7 +405,7 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
data->card = card;
snd_soc_card_set_drvdata(card, data);
- sdm845_add_be_ops(card);
+ sdm845_add_ops(card);
ret = snd_soc_register_card(card);
if (ret) {
dev_err(dev, "Sound card registration failed\n");
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 28327dd2c6cb..e821ccc70f47 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -249,28 +249,8 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
out = out << shift;
mask = 0x0f1f << shift;
- switch (id / 2) {
- case 0:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
- break;
- case 1:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
- break;
- case 2:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
- break;
- case 3:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
- break;
- case 4:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
- break;
- }
+ rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in);
+ rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
if (en)
rsnd_mod_bset(adg_mod, DIV_EN, en, en);
@@ -299,17 +279,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
if (id == 8)
return;
- switch (id / 4) {
- case 0:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
- break;
- case 1:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
- break;
- case 2:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
- break;
- }
+ rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
}
@@ -613,7 +583,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
return -ENOMEM;
ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
- NULL, NULL, 0, 0);
+ NULL, 0, 0);
if (ret)
return ret;
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index cc191cd5fb82..e6bb6a9a0684 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -116,10 +116,11 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_cmd_ops = {
- .name = CMD_NAME,
- .init = rsnd_cmd_init,
- .start = rsnd_cmd_start,
- .stop = rsnd_cmd_stop,
+ .name = CMD_NAME,
+ .init = rsnd_cmd_init,
+ .start = rsnd_cmd_start,
+ .stop = rsnd_cmd_stop,
+ .get_status = rsnd_mod_get_status,
};
static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
@@ -162,7 +163,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
for_each_rsnd_cmd(cmd, priv, i) {
ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
&rsnd_cmd_ops, NULL,
- rsnd_mod_get_status, RSND_MOD_CMD, i);
+ RSND_MOD_CMD, i);
if (ret)
return ret;
}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index f930f51b686f..59e250cc2e9d 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -123,8 +123,8 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_warn(dev, "%s[%d] is not your expected module\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_warn(dev, "%s is not your expected module\n",
+ rsnd_mod_name(mod));
}
}
@@ -137,20 +137,69 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
return mod->ops->dma_req(io, mod);
}
-u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
+#define MOD_NAME_NUM 5
+#define MOD_NAME_SIZE 16
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+ static char names[MOD_NAME_NUM][MOD_NAME_SIZE];
+ static int num;
+ char *name = names[num];
+
+ num++;
+ if (num >= MOD_NAME_NUM)
+ num = 0;
+
+ /*
+ * Let's use same char to avoid pointlessness memory
+ * Thus, rsnd_mod_name() should be used immediately
+ * Don't keep pointer
+ */
+ if ((mod)->ops->id_sub) {
+ snprintf(name, MOD_NAME_SIZE, "%s[%d%d]",
+ mod->ops->name,
+ rsnd_mod_id(mod),
+ rsnd_mod_id_sub(mod));
+ } else {
+ snprintf(name, MOD_NAME_SIZE, "%s[%d]",
+ mod->ops->name,
+ rsnd_mod_id(mod));
+ }
+
+ return name;
+}
+
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
enum rsnd_mod_type type)
{
return &mod->status;
}
+int rsnd_mod_id_raw(struct rsnd_mod *mod)
+{
+ return mod->id;
+}
+
+int rsnd_mod_id(struct rsnd_mod *mod)
+{
+ if ((mod)->ops->id)
+ return (mod)->ops->id(mod);
+
+ return rsnd_mod_id_raw(mod);
+}
+
+int rsnd_mod_id_sub(struct rsnd_mod *mod)
+{
+ if ((mod)->ops->id_sub)
+ return (mod)->ops->id_sub(mod);
+
+ return 0;
+}
+
int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
struct clk *clk,
- u32* (*get_status)(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type),
enum rsnd_mod_type type,
int id)
{
@@ -164,7 +213,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
mod->type = type;
mod->clk = clk;
mod->priv = priv;
- mod->get_status = get_status;
return ret;
}
@@ -228,7 +276,20 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
if (ctu_mod) {
- u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod);
+ u32 converted_chan = rsnd_io_converted_chan(io);
+
+ /*
+ * !! Note !!
+ *
+ * converted_chan will be used for CTU,
+ * or TDM Split mode.
+ * User shouldn't use CTU with TDM Split mode.
+ */
+ if (rsnd_runtime_is_tdm_split(io)) {
+ struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
+
+ dev_err(dev, "CTU and TDM Split should be used\n");
+ }
if (converted_chan)
return converted_chan;
@@ -246,7 +307,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
rsnd_runtime_channel_original_with_params(io, params);
/* Use Multi SSI */
- if (rsnd_runtime_is_ssi_multi(io))
+ if (rsnd_runtime_is_multi_ssi(io))
chan /= rsnd_rdai_ssi_lane_get(rdai);
/* TDM Extend Mode needs 8ch */
@@ -256,7 +317,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
return chan;
}
-int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
int lane = rsnd_rdai_ssi_lane_get(rdai);
@@ -267,11 +328,16 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
return (chan > 2) && (lane > 1);
}
-int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io)
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io)
{
return rsnd_runtime_channel_for_ssi(io) >= 6;
}
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io)
+{
+ return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT);
+}
+
/*
* ADINR function
*/
@@ -472,20 +538,19 @@ static int rsnd_status_update(u32 *status,
enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \
for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \
int tmp = 0; \
- u32 *status = mod->get_status(io, mod, types[i]); \
+ u32 *status = mod->ops->get_status(mod, io, types[i]); \
int func_call = rsnd_status_update(status, \
__rsnd_mod_shift_##fn, \
__rsnd_mod_add_##fn, \
__rsnd_mod_call_##fn); \
- rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n", \
- rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \
+ rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \
+ rsnd_mod_name(mod), *status, \
(func_call && (mod)->ops->fn) ? #fn : ""); \
if (func_call && (mod)->ops->fn) \
tmp = (mod)->ops->fn(mod, io, param); \
if (tmp && (tmp != -EPROBE_DEFER)) \
- dev_err(dev, "%s[%d] : %s error %d\n", \
- rsnd_mod_name(mod), rsnd_mod_id(mod), \
- #fn, tmp); \
+ dev_err(dev, "%s : %s error %d\n", \
+ rsnd_mod_name(mod), #fn, tmp); \
ret |= tmp; \
} \
ret; \
@@ -512,8 +577,8 @@ int rsnd_dai_connect(struct rsnd_mod *mod,
io->mod[type] = mod;
- dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "%s is connected to io (%s)\n",
+ rsnd_mod_name(mod),
rsnd_io_is_play(io) ? "Playback" : "Capture");
return 0;
@@ -750,6 +815,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
switch (slots) {
case 2:
+ /* TDM Split Mode */
case 6:
case 8:
/* TDM Extend Mode */
@@ -965,6 +1031,82 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.prepare = rsnd_soc_dai_prepare,
};
+static void rsnd_parse_connect_simple(struct rsnd_priv *priv,
+ struct device_node *dai_np,
+ int dai_i, int is_play)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+ struct rsnd_dai_stream *io = is_play ?
+ &rdai->playback :
+ &rdai->capture;
+ struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
+ struct device_node *np;
+ int i, j;
+
+ if (!ssiu_np)
+ return;
+
+ if (!rsnd_io_to_mod_ssi(io))
+ return;
+
+ /*
+ * This driver assumes that it is TDM Split mode
+ * if it includes ssiu node
+ */
+ for (i = 0;; i++) {
+ struct device_node *node = is_play ?
+ of_parse_phandle(dai_np, "playback", i) :
+ of_parse_phandle(dai_np, "capture", i);
+
+ if (!node)
+ break;
+
+ j = 0;
+ for_each_child_of_node(ssiu_np, np) {
+ if (np == node) {
+ rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+ dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+ }
+ j++;
+ }
+
+ }
+}
+
+static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io,
+ struct device_node *endpoint)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *remote_port = of_graph_get_remote_port(endpoint);
+ struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint);
+
+ if (!rsnd_io_to_mod_ssi(io))
+ return;
+
+ /* HDMI0 */
+ if (strstr(remote_node->full_name, "hdmi@fead0000")) {
+ rsnd_flags_set(io, RSND_STREAM_HDMI0);
+ dev_dbg(dev, "%s connected to HDMI0\n", io->name);
+ }
+
+ /* HDMI1 */
+ if (strstr(remote_node->full_name, "hdmi@feae0000")) {
+ rsnd_flags_set(io, RSND_STREAM_HDMI1);
+ dev_dbg(dev, "%s connected to HDMI1\n", io->name);
+ }
+
+ /*
+ * This driver assumes that it is TDM Split mode
+ * if remote node has multi endpoint
+ */
+ if (of_get_child_count(remote_port) > 1) {
+ rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+ dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+ }
+}
+
void rsnd_parse_connect_common(struct rsnd_dai *rdai,
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
struct device_node *node,
@@ -1051,24 +1193,24 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
drv->name = rdai->name;
drv->ops = &rsnd_soc_dai_ops;
- snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
+ snprintf(io_playback->name, RSND_DAI_NAME_SIZE,
"DAI%d Playback", dai_i);
drv->playback.rates = RSND_RATES;
drv->playback.formats = RSND_FMTS;
drv->playback.channels_min = 2;
drv->playback.channels_max = 8;
- drv->playback.stream_name = rdai->playback.name;
+ drv->playback.stream_name = io_playback->name;
- snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+ snprintf(io_capture->name, RSND_DAI_NAME_SIZE,
"DAI%d Capture", dai_i);
drv->capture.rates = RSND_RATES;
drv->capture.formats = RSND_FMTS;
drv->capture.channels_min = 2;
drv->capture.channels_max = 8;
- drv->capture.stream_name = rdai->capture.name;
+ drv->capture.stream_name = io_capture->name;
- rdai->playback.rdai = rdai;
- rdai->capture.rdai = rdai;
+ io_playback->rdai = rdai;
+ io_capture->rdai = rdai;
rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
rsnd_rdai_width_set(rdai, 32); /* default 32bit width */
@@ -1081,6 +1223,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
break;
rsnd_parse_connect_ssi(rdai, playback, capture);
+ rsnd_parse_connect_ssiu(rdai, playback, capture);
rsnd_parse_connect_src(rdai, playback, capture);
rsnd_parse_connect_ctu(rdai, playback, capture);
rsnd_parse_connect_mix(rdai, playback, capture);
@@ -1137,12 +1280,23 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
if (is_graph) {
for_each_endpoint_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i);
- rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
+ if (rsnd_is_gen3(priv)) {
+ struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+
+ rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+ rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
+ }
dai_i++;
}
} else {
- for_each_child_of_node(dai_node, dai_np)
- __rsnd_dai_probe(priv, dai_np, dai_i++);
+ for_each_child_of_node(dai_node, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, dai_i);
+ if (rsnd_is_gen3(priv)) {
+ rsnd_parse_connect_simple(priv, dai_np, dai_i, 1);
+ rsnd_parse_connect_simple(priv, dai_np, dai_i, 0);
+ }
+ dai_i++;
+ }
}
return 0;
@@ -1157,8 +1311,40 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
int ret;
+ /*
+ * rsnd assumes that it might be used under DPCM if user want to use
+ * channel / rate convert. Then, rsnd should be FE.
+ * And then, this function will be called *after* BE settings.
+ * this means, each BE already has fixuped hw_params.
+ * see
+ * dpcm_fe_dai_hw_params()
+ * dpcm_be_dai_hw_params()
+ */
+ io->converted_rate = 0;
+ io->converted_chan = 0;
+ if (fe->dai_link->dynamic) {
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct snd_soc_dpcm *dpcm;
+ struct snd_pcm_hw_params *be_params;
+ int stream = substream->stream;
+
+ for_each_dpcm_be(fe, stream, dpcm) {
+ be_params = &dpcm->hw_params;
+ if (params_channels(hw_params) != params_channels(be_params))
+ io->converted_chan = params_channels(be_params);
+ if (params_rate(hw_params) != params_rate(be_params))
+ io->converted_rate = params_rate(be_params);
+ }
+ if (io->converted_chan)
+ dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
+ if (io->converted_rate)
+ dev_dbg(dev, "convert rate = %d\n", io->converted_rate);
+ }
+
ret = rsnd_dai_call(hw_params, io, substream, hw_params);
if (ret)
return ret;
@@ -1339,6 +1525,18 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
};
int ret;
+ /*
+ * 1) Avoid duplicate register (ex. MIXer case)
+ * 2) re-register if card was rebinded
+ */
+ list_for_each_entry(kctrl, &card->controls, list) {
+ struct rsnd_kctrl_cfg *c = kctrl->private_data;
+
+ if (strcmp(kctrl->id.name, name) == 0 &&
+ c->mod == mod)
+ return 0;
+ }
+
if (size > RSND_MAX_CHANNELS)
return -EINVAL;
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index ad702377a6c3..8cb06dab234e 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -72,10 +72,7 @@
struct rsnd_ctu {
struct rsnd_mod mod;
struct rsnd_kctrl_cfg_m pass;
- struct rsnd_kctrl_cfg_m sv0;
- struct rsnd_kctrl_cfg_m sv1;
- struct rsnd_kctrl_cfg_m sv2;
- struct rsnd_kctrl_cfg_m sv3;
+ struct rsnd_kctrl_cfg_m sv[4];
struct rsnd_kctrl_cfg_s reset;
int channels;
u32 flags;
@@ -107,13 +104,6 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod)
rsnd_mod_write(mod, CTU_SWRSR, 0);
}
-int rsnd_ctu_converted_channel(struct rsnd_mod *mod)
-{
- struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-
- return ctu->channels;
-}
-
static int rsnd_ctu_probe_(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -127,7 +117,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
u32 cpmdr = 0;
u32 scmdr = 0;
- int i;
+ int i, j;
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
u32 val = rsnd_kctrl_valm(ctu->pass, i);
@@ -146,45 +136,13 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, CTU_SCMDR, scmdr);
- if (scmdr > 0) {
- rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0));
- rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1));
- rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2));
- rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3));
- rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4));
- rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5));
- rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6));
- rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7));
- }
- if (scmdr > 1) {
- rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0));
- rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1));
- rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2));
- rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3));
- rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4));
- rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5));
- rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6));
- rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7));
- }
- if (scmdr > 2) {
- rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0));
- rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1));
- rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2));
- rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3));
- rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4));
- rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5));
- rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6));
- rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7));
- }
- if (scmdr > 3) {
- rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0));
- rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1));
- rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2));
- rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3));
- rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4));
- rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5));
- rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6));
- rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7));
+ for (i = 0; i < 4; i++) {
+
+ if (i >= scmdr)
+ break;
+
+ for (j = 0; j < RSND_MAX_CHANNELS; j++)
+ rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
}
rsnd_mod_write(mod, CTU_CTUIR, 0);
@@ -201,10 +159,10 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
rsnd_kctrl_valm(ctu->pass, i) = 0;
- rsnd_kctrl_valm(ctu->sv0, i) = 0;
- rsnd_kctrl_valm(ctu->sv1, i) = 0;
- rsnd_kctrl_valm(ctu->sv2, i) = 0;
- rsnd_kctrl_valm(ctu->sv3, i) = 0;
+ rsnd_kctrl_valm(ctu->sv[0], i) = 0;
+ rsnd_kctrl_valm(ctu->sv[1], i) = 0;
+ rsnd_kctrl_valm(ctu->sv[2], i) = 0;
+ rsnd_kctrl_valm(ctu->sv[3], i) = 0;
}
rsnd_kctrl_vals(ctu->reset) = 0;
}
@@ -233,43 +191,6 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *fe_params)
-{
- struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
- struct snd_soc_pcm_runtime *fe = substream->private_data;
-
- /*
- * CTU assumes that it is used under DPCM if user want to use
- * channel transfer. Then, CTU should be FE.
- * And then, this function will be called *after* BE settings.
- * this means, each BE already has fixuped hw_params.
- * see
- * dpcm_fe_dai_hw_params()
- * dpcm_be_dai_hw_params()
- */
- ctu->channels = 0;
- if (fe->dai_link->dynamic) {
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct snd_soc_dpcm *dpcm;
- struct snd_pcm_hw_params *be_params;
- int stream = substream->stream;
-
- for_each_dpcm_be(fe, stream, dpcm) {
- be_params = &dpcm->hw_params;
- if (params_channels(fe_params) != params_channels(be_params))
- ctu->channels = params_channels(be_params);
- }
-
- dev_dbg(dev, "CTU convert channels %d\n", ctu->channels);
- }
-
- return 0;
-}
-
static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd)
@@ -291,7 +212,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv0, RSND_MAX_CHANNELS,
+ &ctu->sv[0], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -300,7 +221,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv1, RSND_MAX_CHANNELS,
+ &ctu->sv[1], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -309,7 +230,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv2, RSND_MAX_CHANNELS,
+ &ctu->sv[2], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -318,7 +239,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv3, RSND_MAX_CHANNELS,
+ &ctu->sv[3], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -334,13 +255,34 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
return ret;
}
+static int rsnd_ctu_id(struct rsnd_mod *mod)
+{
+ /*
+ * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
+ * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
+ */
+ return mod->id / 4;
+}
+
+static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
+{
+ /*
+ * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
+ * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
+ */
+ return mod->id % 4;
+}
+
static struct rsnd_mod_ops rsnd_ctu_ops = {
.name = CTU_NAME,
.probe = rsnd_ctu_probe_,
.init = rsnd_ctu_init,
.quit = rsnd_ctu_quit,
- .hw_params = rsnd_ctu_hw_params,
.pcm_new = rsnd_ctu_pcm_new,
+ .get_status = rsnd_mod_get_status,
+ .id = rsnd_ctu_id,
+ .id_sub = rsnd_ctu_id_sub,
+ .id_cmd = rsnd_mod_id_raw,
};
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
@@ -404,7 +346,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
- clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
+ clk, RSND_MOD_CTU, i);
if (ret) {
of_node_put(np);
goto rsnd_ctu_probe_done;
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 6d1947515dc8..0324a5c39619 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -174,8 +174,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev_dbg(dev, "%s[%d] %pad -> %pad\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "%s %pad -> %pad\n",
+ rsnd_mod_name(mod),
&cfg.src_addr, &cfg.dst_addr);
ret = dmaengine_slave_config(dmaen->chan, &cfg);
@@ -218,7 +218,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
int i = 0;
for_each_child_of_node(of_node, np) {
- if (i == rsnd_mod_id(mod) && (!chan))
+ if (i == rsnd_mod_id_raw(mod) && (!chan))
chan = of_dma_request_slave_channel(np, name);
i++;
}
@@ -289,12 +289,13 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_dmaen_ops = {
- .name = "audmac",
- .prepare = rsnd_dmaen_prepare,
- .cleanup = rsnd_dmaen_cleanup,
- .start = rsnd_dmaen_start,
- .stop = rsnd_dmaen_stop,
- .pointer= rsnd_dmaen_pointer,
+ .name = "audmac",
+ .prepare = rsnd_dmaen_prepare,
+ .cleanup = rsnd_dmaen_cleanup,
+ .start = rsnd_dmaen_start,
+ .stop = rsnd_dmaen_stop,
+ .pointer = rsnd_dmaen_pointer,
+ .get_status = rsnd_mod_get_status,
};
/*
@@ -343,14 +344,16 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
const u8 *entry = NULL;
int id = 255;
int size = 0;
- if (mod == ssi) {
- int busif = rsnd_ssi_get_busif(io);
+ if ((mod == ssi) ||
+ (mod == ssiu)) {
+ int busif = rsnd_mod_id_sub(ssiu);
entry = gen2_id_table_ssiu;
size = ARRAY_SIZE(gen2_id_table_ssiu);
@@ -368,8 +371,7 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
if ((!entry) || (size <= id)) {
struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
- dev_err(dev, "unknown connection (%s[%d])\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod));
/* use non-prohibited SRS number as error */
return 0x00; /* SSI00 */
@@ -477,10 +479,11 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
}
static struct rsnd_mod_ops rsnd_dmapp_ops = {
- .name = "audmac-pp",
- .start = rsnd_dmapp_start,
- .stop = rsnd_dmapp_stop,
- .quit = rsnd_dmapp_stop,
+ .name = "audmac-pp",
+ .start = rsnd_dmapp_start,
+ .stop = rsnd_dmapp_stop,
+ .quit = rsnd_dmapp_stop,
+ .get_status = rsnd_mod_get_status,
};
/*
@@ -529,13 +532,14 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
struct device *dev = rsnd_priv_to_dev(priv);
phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
- int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
+ int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
+ !!(rsnd_io_to_mod_ssiu(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
!!rsnd_io_to_mod_mix(io) ||
!!rsnd_io_to_mod_ctu(io);
int id = rsnd_mod_id(mod);
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
struct dma_addr {
dma_addr_t out_addr;
dma_addr_t in_addr;
@@ -619,7 +623,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
struct rsnd_mod **mod_from,
struct rsnd_mod **mod_to)
{
- struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *ssi;
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
@@ -630,6 +634,28 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
struct device *dev = rsnd_priv_to_dev(priv);
int nr, i, idx;
+ /*
+ * It should use "rcar_sound,ssiu" on DT.
+ * But, we need to keep compatibility for old version.
+ *
+ * If it has "rcar_sound.ssiu", it will be used.
+ * If not, "rcar_sound.ssi" will be used.
+ * see
+ * rsnd_ssiu_dma_req()
+ * rsnd_ssi_dma_req()
+ */
+ if (rsnd_ssiu_of_node(priv)) {
+ struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
+
+ /* use SSIU */
+ ssi = ssiu;
+ if (this == rsnd_io_to_mod_ssi(io))
+ this = ssiu;
+ } else {
+ /* keep compatible, use SSI */
+ ssi = rsnd_io_to_mod_ssi(io);
+ }
+
if (!ssi)
return;
@@ -690,12 +716,10 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
*mod_to = mod[1];
}
- dev_dbg(dev, "module connection (this is %s[%d])\n",
- rsnd_mod_name(this), rsnd_mod_id(this));
+ dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this));
for (i = 0; i <= idx; i++) {
- dev_dbg(dev, " %s[%d]%s\n",
+ dev_dbg(dev, " %s%s\n",
rsnd_mod_name(mod[i] ? mod[i] : &mem),
- rsnd_mod_id (mod[i] ? mod[i] : &mem),
(mod[i] == *mod_from) ? " from" :
(mod[i] == *mod_to) ? " to" : "");
}
@@ -756,16 +780,14 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
*dma_mod = rsnd_mod_get(dma);
ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
- rsnd_mod_get_status, type, dma_id);
+ type, dma_id);
if (ret < 0)
return ret;
- dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
- rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
+ dev_dbg(dev, "%s %s -> %s\n",
+ rsnd_mod_name(*dma_mod),
rsnd_mod_name(mod_from ? mod_from : &mem),
- rsnd_mod_id (mod_from ? mod_from : &mem),
- rsnd_mod_name(mod_to ? mod_to : &mem),
- rsnd_mod_id (mod_to ? mod_to : &mem));
+ rsnd_mod_name(mod_to ? mod_to : &mem));
ret = attach(io, dma, mod_from, mod_to);
if (ret < 0)
@@ -823,5 +845,5 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
priv->dma = dmac;
/* dummy mem mod for debug */
- return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
+ return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 2b16e0ce6bc5..8d91c0eb0880 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -40,11 +40,8 @@ struct rsnd_dvc {
struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
- u32 flags;
};
-#define KCTRL_INITIALIZED (1 << 0)
-
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
@@ -89,14 +86,8 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
val[i] = rsnd_kctrl_valm(dvc->volume, i);
/* Enable Digital Volume */
- rsnd_mod_write(mod, DVC_VOL0R, val[0]);
- rsnd_mod_write(mod, DVC_VOL1R, val[1]);
- rsnd_mod_write(mod, DVC_VOL2R, val[2]);
- rsnd_mod_write(mod, DVC_VOL3R, val[3]);
- rsnd_mod_write(mod, DVC_VOL4R, val[4]);
- rsnd_mod_write(mod, DVC_VOL5R, val[5]);
- rsnd_mod_write(mod, DVC_VOL6R, val[6]);
- rsnd_mod_write(mod, DVC_VOL7R, val[7]);
+ for (i = 0; i < RSND_MAX_CHANNELS; i++)
+ rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);
}
static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
@@ -227,9 +218,6 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
int channels = rsnd_rdai_channels_get(rdai);
int ret;
- if (rsnd_flags_has(dvc, KCTRL_INITIALIZED))
- return 0;
-
/* Volume */
ret = rsnd_kctrl_new_m(mod, io, rtd,
is_play ?
@@ -285,8 +273,6 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
if (ret < 0)
return ret;
- rsnd_flags_set(dvc, KCTRL_INITIALIZED);
-
return 0;
}
@@ -306,6 +292,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = {
.init = rsnd_dvc_init,
.quit = rsnd_dvc_quit,
.pcm_new = rsnd_dvc_pcm_new,
+ .get_status = rsnd_mod_get_status,
};
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
@@ -365,7 +352,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
- clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
+ clk, RSND_MOD_DVC, i);
if (ret) {
of_node_put(np);
goto rsnd_dvc_probe_done;
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 1f7881cc16b2..7cda60188f41 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -26,8 +26,8 @@ struct rsnd_gen {
struct regmap *regmap[RSND_BASE_MAX];
/* RSND_REG_MAX base */
- struct regmap_field *regs[RSND_REG_MAX];
- const char *reg_name[RSND_REG_MAX];
+ struct regmap_field *regs[REG_MAX];
+ const char *reg_name[REG_MAX];
};
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
@@ -49,11 +49,11 @@ struct rsnd_regmap_field_conf {
}
/* single address mapping */
#define RSND_GEN_S_REG(id, offset) \
- RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
+ RSND_REG_SET(id, offset, 0, #id)
/* multi address mapping */
#define RSND_GEN_M_REG(id, offset, _id_offset) \
- RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
+ RSND_REG_SET(id, offset, _id_offset, #id)
/*
* basic function
@@ -71,9 +71,17 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
return 1;
}
-u32 rsnd_read(struct rsnd_priv *priv,
- struct rsnd_mod *mod, enum rsnd_reg reg)
+static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
{
+ if (mod->ops->id_cmd)
+ return mod->ops->id_cmd(mod);
+
+ return rsnd_mod_id(mod);
+}
+
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
u32 val;
@@ -81,35 +89,36 @@ u32 rsnd_read(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return 0;
- regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
+ regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
- dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod),
rsnd_reg_name(gen, reg), reg, val);
return val;
}
-void rsnd_write(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data)
+void rsnd_mod_write(struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 data)
{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
- regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+ regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
- dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod),
rsnd_reg_name(gen, reg), reg, data);
}
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 mask, u32 data)
+void rsnd_mod_bset(struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 mask, u32 data)
{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
@@ -117,10 +126,10 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
return;
regmap_fields_force_update_bits(gen->regs[reg],
- rsnd_mod_id(mod), mask, data);
+ rsnd_mod_id_cmd(mod), mask, data);
- dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
+ rsnd_mod_name(mod),
rsnd_reg_name(gen, reg), reg, data, mask);
}
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 8e3b57eaa708..a3e0370f5704 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -256,6 +256,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = {
.init = rsnd_mix_init,
.quit = rsnd_mix_quit,
.pcm_new = rsnd_mix_pcm_new,
+ .get_status = rsnd_mod_get_status,
};
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
@@ -315,7 +316,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
- clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
+ clk, RSND_MOD_MIX, i);
if (ret) {
of_node_put(np);
goto rsnd_mix_probe_done;
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 4464d1d0a042..605e4b934982 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -42,165 +42,175 @@
*/
enum rsnd_reg {
/* SCU (MIX/CTU/DVC) */
- RSND_REG_SRC_I_BUSIF_MODE,
- RSND_REG_SRC_O_BUSIF_MODE,
- RSND_REG_SRC_ROUTE_MODE0,
- RSND_REG_SRC_SWRSR,
- RSND_REG_SRC_SRCIR,
- RSND_REG_SRC_ADINR,
- RSND_REG_SRC_IFSCR,
- RSND_REG_SRC_IFSVR,
- RSND_REG_SRC_SRCCR,
- RSND_REG_SRC_CTRL,
- RSND_REG_SRC_BSDSR,
- RSND_REG_SRC_BSISR,
- RSND_REG_SRC_INT_ENABLE0,
- RSND_REG_SRC_BUSIF_DALIGN,
- RSND_REG_SRCIN_TIMSEL0,
- RSND_REG_SRCIN_TIMSEL1,
- RSND_REG_SRCIN_TIMSEL2,
- RSND_REG_SRCIN_TIMSEL3,
- RSND_REG_SRCIN_TIMSEL4,
- RSND_REG_SRCOUT_TIMSEL0,
- RSND_REG_SRCOUT_TIMSEL1,
- RSND_REG_SRCOUT_TIMSEL2,
- RSND_REG_SRCOUT_TIMSEL3,
- RSND_REG_SRCOUT_TIMSEL4,
- RSND_REG_SCU_SYS_STATUS0,
- RSND_REG_SCU_SYS_STATUS1,
- RSND_REG_SCU_SYS_INT_EN0,
- RSND_REG_SCU_SYS_INT_EN1,
- RSND_REG_CMD_CTRL,
- RSND_REG_CMD_BUSIF_MODE,
- RSND_REG_CMD_BUSIF_DALIGN,
- RSND_REG_CMD_ROUTE_SLCT,
- RSND_REG_CMDOUT_TIMSEL,
- RSND_REG_CTU_SWRSR,
- RSND_REG_CTU_CTUIR,
- RSND_REG_CTU_ADINR,
- RSND_REG_CTU_CPMDR,
- RSND_REG_CTU_SCMDR,
- RSND_REG_CTU_SV00R,
- RSND_REG_CTU_SV01R,
- RSND_REG_CTU_SV02R,
- RSND_REG_CTU_SV03R,
- RSND_REG_CTU_SV04R,
- RSND_REG_CTU_SV05R,
- RSND_REG_CTU_SV06R,
- RSND_REG_CTU_SV07R,
- RSND_REG_CTU_SV10R,
- RSND_REG_CTU_SV11R,
- RSND_REG_CTU_SV12R,
- RSND_REG_CTU_SV13R,
- RSND_REG_CTU_SV14R,
- RSND_REG_CTU_SV15R,
- RSND_REG_CTU_SV16R,
- RSND_REG_CTU_SV17R,
- RSND_REG_CTU_SV20R,
- RSND_REG_CTU_SV21R,
- RSND_REG_CTU_SV22R,
- RSND_REG_CTU_SV23R,
- RSND_REG_CTU_SV24R,
- RSND_REG_CTU_SV25R,
- RSND_REG_CTU_SV26R,
- RSND_REG_CTU_SV27R,
- RSND_REG_CTU_SV30R,
- RSND_REG_CTU_SV31R,
- RSND_REG_CTU_SV32R,
- RSND_REG_CTU_SV33R,
- RSND_REG_CTU_SV34R,
- RSND_REG_CTU_SV35R,
- RSND_REG_CTU_SV36R,
- RSND_REG_CTU_SV37R,
- RSND_REG_MIX_SWRSR,
- RSND_REG_MIX_MIXIR,
- RSND_REG_MIX_ADINR,
- RSND_REG_MIX_MIXMR,
- RSND_REG_MIX_MVPDR,
- RSND_REG_MIX_MDBAR,
- RSND_REG_MIX_MDBBR,
- RSND_REG_MIX_MDBCR,
- RSND_REG_MIX_MDBDR,
- RSND_REG_MIX_MDBER,
- RSND_REG_DVC_SWRSR,
- RSND_REG_DVC_DVUIR,
- RSND_REG_DVC_ADINR,
- RSND_REG_DVC_DVUCR,
- RSND_REG_DVC_ZCMCR,
- RSND_REG_DVC_VOL0R,
- RSND_REG_DVC_VOL1R,
- RSND_REG_DVC_VOL2R,
- RSND_REG_DVC_VOL3R,
- RSND_REG_DVC_VOL4R,
- RSND_REG_DVC_VOL5R,
- RSND_REG_DVC_VOL6R,
- RSND_REG_DVC_VOL7R,
- RSND_REG_DVC_DVUER,
- RSND_REG_DVC_VRCTR,
- RSND_REG_DVC_VRPDR,
- RSND_REG_DVC_VRDBR,
+ SRC_I_BUSIF_MODE,
+ SRC_O_BUSIF_MODE,
+ SRC_ROUTE_MODE0,
+ SRC_SWRSR,
+ SRC_SRCIR,
+ SRC_ADINR,
+ SRC_IFSCR,
+ SRC_IFSVR,
+ SRC_SRCCR,
+ SRC_CTRL,
+ SRC_BSDSR,
+ SRC_BSISR,
+ SRC_INT_ENABLE0,
+ SRC_BUSIF_DALIGN,
+ SRCIN_TIMSEL0,
+ SRCIN_TIMSEL1,
+ SRCIN_TIMSEL2,
+ SRCIN_TIMSEL3,
+ SRCIN_TIMSEL4,
+ SRCOUT_TIMSEL0,
+ SRCOUT_TIMSEL1,
+ SRCOUT_TIMSEL2,
+ SRCOUT_TIMSEL3,
+ SRCOUT_TIMSEL4,
+ SCU_SYS_STATUS0,
+ SCU_SYS_STATUS1,
+ SCU_SYS_INT_EN0,
+ SCU_SYS_INT_EN1,
+ CMD_CTRL,
+ CMD_BUSIF_MODE,
+ CMD_BUSIF_DALIGN,
+ CMD_ROUTE_SLCT,
+ CMDOUT_TIMSEL,
+ CTU_SWRSR,
+ CTU_CTUIR,
+ CTU_ADINR,
+ CTU_CPMDR,
+ CTU_SCMDR,
+ CTU_SV00R,
+ CTU_SV01R,
+ CTU_SV02R,
+ CTU_SV03R,
+ CTU_SV04R,
+ CTU_SV05R,
+ CTU_SV06R,
+ CTU_SV07R,
+ CTU_SV10R,
+ CTU_SV11R,
+ CTU_SV12R,
+ CTU_SV13R,
+ CTU_SV14R,
+ CTU_SV15R,
+ CTU_SV16R,
+ CTU_SV17R,
+ CTU_SV20R,
+ CTU_SV21R,
+ CTU_SV22R,
+ CTU_SV23R,
+ CTU_SV24R,
+ CTU_SV25R,
+ CTU_SV26R,
+ CTU_SV27R,
+ CTU_SV30R,
+ CTU_SV31R,
+ CTU_SV32R,
+ CTU_SV33R,
+ CTU_SV34R,
+ CTU_SV35R,
+ CTU_SV36R,
+ CTU_SV37R,
+ MIX_SWRSR,
+ MIX_MIXIR,
+ MIX_ADINR,
+ MIX_MIXMR,
+ MIX_MVPDR,
+ MIX_MDBAR,
+ MIX_MDBBR,
+ MIX_MDBCR,
+ MIX_MDBDR,
+ MIX_MDBER,
+ DVC_SWRSR,
+ DVC_DVUIR,
+ DVC_ADINR,
+ DVC_DVUCR,
+ DVC_ZCMCR,
+ DVC_VOL0R,
+ DVC_VOL1R,
+ DVC_VOL2R,
+ DVC_VOL3R,
+ DVC_VOL4R,
+ DVC_VOL5R,
+ DVC_VOL6R,
+ DVC_VOL7R,
+ DVC_DVUER,
+ DVC_VRCTR,
+ DVC_VRPDR,
+ DVC_VRDBR,
/* ADG */
- RSND_REG_BRRA,
- RSND_REG_BRRB,
- RSND_REG_BRGCKR,
- RSND_REG_DIV_EN,
- RSND_REG_AUDIO_CLK_SEL0,
- RSND_REG_AUDIO_CLK_SEL1,
- RSND_REG_AUDIO_CLK_SEL2,
+ BRRA,
+ BRRB,
+ BRGCKR,
+ DIV_EN,
+ AUDIO_CLK_SEL0,
+ AUDIO_CLK_SEL1,
+ AUDIO_CLK_SEL2,
/* SSIU */
- RSND_REG_SSI_MODE,
- RSND_REG_SSI_MODE0,
- RSND_REG_SSI_MODE1,
- RSND_REG_SSI_MODE2,
- RSND_REG_SSI_CONTROL,
- RSND_REG_SSI_CTRL,
- RSND_REG_SSI_BUSIF0_MODE,
- RSND_REG_SSI_BUSIF0_ADINR,
- RSND_REG_SSI_BUSIF0_DALIGN,
- RSND_REG_SSI_BUSIF1_MODE,
- RSND_REG_SSI_BUSIF1_ADINR,
- RSND_REG_SSI_BUSIF1_DALIGN,
- RSND_REG_SSI_BUSIF2_MODE,
- RSND_REG_SSI_BUSIF2_ADINR,
- RSND_REG_SSI_BUSIF2_DALIGN,
- RSND_REG_SSI_BUSIF3_MODE,
- RSND_REG_SSI_BUSIF3_ADINR,
- RSND_REG_SSI_BUSIF3_DALIGN,
- RSND_REG_SSI_BUSIF4_MODE,
- RSND_REG_SSI_BUSIF4_ADINR,
- RSND_REG_SSI_BUSIF4_DALIGN,
- RSND_REG_SSI_BUSIF5_MODE,
- RSND_REG_SSI_BUSIF5_ADINR,
- RSND_REG_SSI_BUSIF5_DALIGN,
- RSND_REG_SSI_BUSIF6_MODE,
- RSND_REG_SSI_BUSIF6_ADINR,
- RSND_REG_SSI_BUSIF6_DALIGN,
- RSND_REG_SSI_BUSIF7_MODE,
- RSND_REG_SSI_BUSIF7_ADINR,
- RSND_REG_SSI_BUSIF7_DALIGN,
- RSND_REG_SSI_INT_ENABLE,
- RSND_REG_SSI_SYS_STATUS0,
- RSND_REG_SSI_SYS_STATUS1,
- RSND_REG_SSI_SYS_STATUS2,
- RSND_REG_SSI_SYS_STATUS3,
- RSND_REG_SSI_SYS_STATUS4,
- RSND_REG_SSI_SYS_STATUS5,
- RSND_REG_SSI_SYS_STATUS6,
- RSND_REG_SSI_SYS_STATUS7,
- RSND_REG_HDMI0_SEL,
- RSND_REG_HDMI1_SEL,
+ SSI_MODE,
+ SSI_MODE0,
+ SSI_MODE1,
+ SSI_MODE2,
+ SSI_CONTROL,
+ SSI_CTRL,
+ SSI_BUSIF0_MODE,
+ SSI_BUSIF1_MODE,
+ SSI_BUSIF2_MODE,
+ SSI_BUSIF3_MODE,
+ SSI_BUSIF4_MODE,
+ SSI_BUSIF5_MODE,
+ SSI_BUSIF6_MODE,
+ SSI_BUSIF7_MODE,
+ SSI_BUSIF0_ADINR,
+ SSI_BUSIF1_ADINR,
+ SSI_BUSIF2_ADINR,
+ SSI_BUSIF3_ADINR,
+ SSI_BUSIF4_ADINR,
+ SSI_BUSIF5_ADINR,
+ SSI_BUSIF6_ADINR,
+ SSI_BUSIF7_ADINR,
+ SSI_BUSIF0_DALIGN,
+ SSI_BUSIF1_DALIGN,
+ SSI_BUSIF2_DALIGN,
+ SSI_BUSIF3_DALIGN,
+ SSI_BUSIF4_DALIGN,
+ SSI_BUSIF5_DALIGN,
+ SSI_BUSIF6_DALIGN,
+ SSI_BUSIF7_DALIGN,
+ SSI_INT_ENABLE,
+ SSI_SYS_STATUS0,
+ SSI_SYS_STATUS1,
+ SSI_SYS_STATUS2,
+ SSI_SYS_STATUS3,
+ SSI_SYS_STATUS4,
+ SSI_SYS_STATUS5,
+ SSI_SYS_STATUS6,
+ SSI_SYS_STATUS7,
+ HDMI0_SEL,
+ HDMI1_SEL,
/* SSI */
- RSND_REG_SSICR,
- RSND_REG_SSISR,
- RSND_REG_SSITDR,
- RSND_REG_SSIRDR,
- RSND_REG_SSIWSR,
+ SSICR,
+ SSISR,
+ SSITDR,
+ SSIRDR,
+ SSIWSR,
- RSND_REG_MAX,
+ REG_MAX,
};
+#define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i))
+#define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i))
+#define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j))
+#define DVC_VOLxR(i) (DVC_VOL0R + (i))
+#define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i))
+#define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i))
+#define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i))
+#define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i))
+#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i))
+
struct rsnd_priv;
struct rsnd_mod;
@@ -210,20 +220,9 @@ struct rsnd_dai_stream;
/*
* R-Car basic functions
*/
-#define rsnd_mod_read(m, r) \
- rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
-#define rsnd_mod_write(m, r, d) \
- rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
-#define rsnd_mod_bset(m, r, s, d) \
- rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
-
-u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
-void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data);
-void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data);
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
- u32 mask, u32 data);
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data);
+void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data);
u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
@@ -301,6 +300,12 @@ struct rsnd_mod_ops {
int (*cleanup)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
+ u32 *(*get_status)(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type);
+ int (*id)(struct rsnd_mod *mod);
+ int (*id_sub)(struct rsnd_mod *mod);
+ int (*id_cmd)(struct rsnd_mod *mod);
};
struct rsnd_dai_stream;
@@ -310,9 +315,6 @@ struct rsnd_mod {
struct rsnd_mod_ops *ops;
struct rsnd_priv *priv;
struct clk *clk;
- u32 *(*get_status)(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type);
u32 status;
};
/*
@@ -375,8 +377,6 @@ struct rsnd_mod {
#define __rsnd_mod_call_pointer 0
#define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_name(mod) ((mod)->ops->name)
-#define rsnd_mod_id(mod) ((mod)->id)
#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
#define rsnd_mod_power_off(mod) clk_disable((mod)->clk)
#define rsnd_mod_get(ip) (&(ip)->mod)
@@ -385,9 +385,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
struct clk *clk,
- u32* (*get_status)(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type),
enum rsnd_mod_type type,
int id);
void rsnd_mod_quit(struct rsnd_mod *mod);
@@ -396,9 +393,13 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
void rsnd_mod_interrupt(struct rsnd_mod *mod,
void (*callback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io));
-u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
enum rsnd_mod_type type);
+int rsnd_mod_id(struct rsnd_mod *mod);
+int rsnd_mod_id_raw(struct rsnd_mod *mod);
+int rsnd_mod_id_sub(struct rsnd_mod *mod);
+char *rsnd_mod_name(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_mod_next(int *iterator,
struct rsnd_dai_stream *io,
enum rsnd_mod_type *array,
@@ -430,8 +431,9 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
rsnd_runtime_channel_for_ssi_with_params(io, NULL)
int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
struct snd_pcm_hw_params *params);
-int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
-int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
/*
* DT
@@ -440,6 +442,7 @@ int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
#define RSND_NODE_DAI "rcar_sound,dai"
#define RSND_NODE_SSI "rcar_sound,ssi"
+#define RSND_NODE_SSIU "rcar_sound,ssiu"
#define RSND_NODE_SRC "rcar_sound,src"
#define RSND_NODE_CTU "rcar_sound,ctu"
#define RSND_NODE_MIX "rcar_sound,mix"
@@ -456,8 +459,17 @@ struct rsnd_dai_stream {
struct rsnd_mod *dma;
struct rsnd_dai *rdai;
struct device *dmac_dev; /* for IPMMU */
+ u32 converted_rate; /* converted sampling rate */
+ int converted_chan; /* converted channels */
u32 parent_ssi_status;
+ u32 flags;
};
+
+/* flags */
+#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */
+#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */
+#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */
+
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU)
@@ -472,6 +484,8 @@ struct rsnd_dai_stream {
#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io)
#define rsnd_io_to_runtime(io) ((io)->substream ? \
(io)->substream->runtime : NULL)
+#define rsnd_io_converted_rate(io) ((io)->converted_rate)
+#define rsnd_io_converted_chan(io) ((io)->converted_chan)
int rsnd_io_is_working(struct rsnd_dai_stream *io);
struct rsnd_dai {
@@ -712,18 +726,9 @@ extern const char * const volume_ramp_rate[];
int rsnd_ssi_probe(struct rsnd_priv *priv);
void rsnd_ssi_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
-int rsnd_ssi_get_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
-#define RSND_SSI_HDMI_PORT0 0xf0
-#define RSND_SSI_HDMI_PORT1 0xf1
-int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io);
-void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
- struct device_node *endpoint,
- int dai_i);
-
#define rsnd_ssi_is_pin_sharing(io) \
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
@@ -742,6 +747,10 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod);
int rsnd_ssiu_probe(struct rsnd_priv *priv);
void rsnd_ssiu_remove(struct rsnd_priv *priv);
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+ struct device_node *playback,
+ struct device_node *capture);
+#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU)
/*
* R-Car SRC
@@ -767,7 +776,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
*/
int rsnd_ctu_probe(struct rsnd_priv *priv);
void rsnd_ctu_remove(struct rsnd_priv *priv);
-int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index cd38a43b976f..50348a2c9203 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -25,7 +25,6 @@ struct rsnd_src {
struct rsnd_mod *dma;
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
- u32 convert_rate; /* sampling rate convert */
int irq;
};
@@ -89,12 +88,12 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
return 0;
if (!rsnd_src_sync_is_enabled(mod))
- return src->convert_rate;
+ return rsnd_io_converted_rate(io);
convert_rate = src->sync.val;
if (!convert_rate)
- convert_rate = src->convert_rate;
+ convert_rate = rsnd_io_converted_rate(io);
if (!convert_rate)
convert_rate = runtime->rate;
@@ -135,40 +134,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
return rate;
}
-static int rsnd_src_hw_params(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *fe_params)
-{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct snd_soc_pcm_runtime *fe = substream->private_data;
-
- /*
- * SRC assumes that it is used under DPCM if user want to use
- * sampling rate convert. Then, SRC should be FE.
- * And then, this function will be called *after* BE settings.
- * this means, each BE already has fixuped hw_params.
- * see
- * dpcm_fe_dai_hw_params()
- * dpcm_be_dai_hw_params()
- */
- src->convert_rate = 0;
- if (fe->dai_link->dynamic) {
- int stream = substream->stream;
- struct snd_soc_dpcm *dpcm;
- struct snd_pcm_hw_params *be_params;
-
- for_each_dpcm_be(fe, stream, dpcm) {
- be_params = &dpcm->hw_params;
-
- if (params_rate(fe_params) != params_rate(be_params))
- src->convert_rate = params_rate(be_params);
- }
- }
-
- return 0;
-}
-
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
@@ -349,9 +314,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
if ((status0 & val0) || (status1 & val1)) {
- rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x, 0x%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
- status0, status1);
+ rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
+ rsnd_mod_name(mod), status0, status1);
ret = true;
}
@@ -527,16 +491,16 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_src_ops = {
- .name = SRC_NAME,
- .dma_req = rsnd_src_dma_req,
- .probe = rsnd_src_probe_,
- .init = rsnd_src_init,
- .quit = rsnd_src_quit,
- .start = rsnd_src_start,
- .stop = rsnd_src_stop,
- .irq = rsnd_src_irq,
- .hw_params = rsnd_src_hw_params,
- .pcm_new = rsnd_src_pcm_new,
+ .name = SRC_NAME,
+ .dma_req = rsnd_src_dma_req,
+ .probe = rsnd_src_probe_,
+ .init = rsnd_src_init,
+ .quit = rsnd_src_quit,
+ .start = rsnd_src_start,
+ .stop = rsnd_src_stop,
+ .irq = rsnd_src_irq,
+ .pcm_new = rsnd_src_pcm_new,
+ .get_status = rsnd_mod_get_status,
};
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -605,8 +569,7 @@ int rsnd_src_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(src),
- &rsnd_src_ops, clk, rsnd_mod_get_status,
- RSND_MOD_SRC, i);
+ &rsnd_src_ops, clk, RSND_MOD_SRC, i);
if (ret) {
of_node_put(np);
goto rsnd_src_probe_done;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 6ec78f3096dd..45ef295743ec 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -99,9 +99,7 @@ struct rsnd_ssi {
/* flags */
#define RSND_SSI_CLK_PIN_SHARE (1 << 0)
#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
-#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */
-#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */
-#define RSND_SSI_PROBED (1 << 4)
+#define RSND_SSI_PROBED (1 << 2)
#define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \
@@ -119,19 +117,7 @@ struct rsnd_ssi {
(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
-int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
-{
- struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
- if (rsnd_flags_has(ssi, RSND_SSI_HDMI0))
- return RSND_SSI_HDMI_PORT0;
-
- if (rsnd_flags_has(ssi, RSND_SSI_HDMI1))
- return RSND_SSI_HDMI_PORT1;
-
- return 0;
-}
+static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
{
@@ -150,11 +136,6 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
return use_busif;
}
-int rsnd_ssi_get_busif(struct rsnd_dai_stream *io)
-{
- return 0; /* BUSIF0 only for now */
-}
-
static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, SSISR, 0);
@@ -181,8 +162,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
udelay(5);
}
- dev_warn(dev, "%s[%d] status check failed\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
}
static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
@@ -224,7 +204,7 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
{
- if (rsnd_runtime_is_ssi_multi(io))
+ if (rsnd_runtime_is_multi_ssi(io))
return rsnd_ssi_multi_slaves(io);
return 0;
@@ -320,6 +300,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0;
}
+ if (rsnd_runtime_is_tdm_split(io))
+ chan = rsnd_io_converted_chan(io);
+
main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
if (!main_rate) {
dev_err(dev, "unsupported clock rate\n");
@@ -346,9 +329,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
ssi->rate = rate;
ssi->chan = chan;
- dev_dbg(dev, "%s[%d] outputs %u Hz\n",
- rsnd_mod_name(mod),
- rsnd_mod_id(mod), rate);
+ dev_dbg(dev, "%s outputs %d chan %u Hz\n",
+ rsnd_mod_name(mod), chan, rate);
return 0;
}
@@ -379,14 +361,23 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
u32 cr_own = ssi->cr_own;
u32 cr_mode = ssi->cr_mode;
u32 wsr = ssi->wsr;
- int is_tdm;
+ int width;
+ int is_tdm, is_tdm_split;
+
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
- is_tdm = rsnd_runtime_is_ssi_tdm(io);
+ if (is_tdm)
+ dev_dbg(dev, "TDM mode\n");
+ if (is_tdm_split)
+ dev_dbg(dev, "TDM Split mode\n");
cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
@@ -405,7 +396,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
* rsnd_ssiu_init_gen2()
*/
wsr = ssi->wsr;
- if (is_tdm) {
+ if (is_tdm || is_tdm_split) {
wsr |= WS_MODE;
cr_own |= CHNL_8;
}
@@ -421,7 +412,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own |= TRMD;
cr_own &= ~DWL_MASK;
- switch (snd_pcm_format_width(runtime->format)) {
+ width = snd_pcm_format_width(runtime->format);
+ if (is_tdm_split) {
+ /*
+ * The SWL and DWL bits in SSICR should be fixed at 32-bit
+ * setting when TDM split mode.
+ * see datasheet
+ * Operation :: TDM Format Split Function (TDM Split Mode)
+ */
+ width = 32;
+ }
+
+ switch (width) {
case 8:
cr_own |= DWL_8;
break;
@@ -431,6 +433,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
case 24:
cr_own |= DWL_24;
break;
+ case 32:
+ cr_own |= DWL_32;
+ break;
}
if (rsnd_ssi_is_dma_mode(mod)) {
@@ -494,8 +499,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
return 0;
if (!ssi->usrcnt) {
- dev_err(dev, "%s[%d] usrcnt error\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod));
return -EIO;
}
@@ -654,8 +658,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
/* DMA only */
if (is_dma && (status & (UIRQ | OIRQ))) {
- rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), status);
+ rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
stop = true;
}
@@ -681,6 +685,41 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
+static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
+{
+ /*
+ * SSIP (= SSI parent) needs to be special, otherwise,
+ * 2nd SSI might doesn't start. see also rsnd_mod_call()
+ *
+ * We can't include parent SSI status on SSI, because we don't know
+ * how many SSI requests parent SSI. Thus, it is localed on "io" now.
+ * ex) trouble case
+ * Playback: SSI0
+ * Capture : SSI1 (needs SSI0)
+ *
+ * 1) start Capture -> SSI0/SSI1 are started.
+ * 2) start Playback -> SSI0 doesn't work, because it is already
+ * marked as "started" on 1)
+ *
+ * OTOH, using each mod's status is good for MUX case.
+ * It doesn't need to start in 2nd start
+ * ex)
+ * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
+ * |
+ * IO-1: SRC1 -> CTU2 -+
+ *
+ * 1) start IO-0 -> start SSI0
+ * 2) start IO-1 -> SSI0 doesn't need to start, because it is
+ * already started on 1)
+ */
+ if (type == RSND_MOD_SSIP)
+ return &io->parent_ssi_status;
+
+ return rsnd_mod_get_status(mod, io, type);
+}
+
/*
* SSI PIO
*/
@@ -730,7 +769,7 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- int ret;
+ int ret = 0;
/*
* SSIP/SSIU/IRQ are not needed on
@@ -744,10 +783,6 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
* see rsnd_ssi_pcm_new()
*/
- ret = rsnd_ssiu_attach(io, mod);
- if (ret < 0)
- return ret;
-
/*
* SSI might be called again as PIO fallback
* It is easy to manual handling for IRQ request/free
@@ -876,18 +911,19 @@ static int rsnd_ssi_prepare(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
- .name = SSI_NAME,
- .probe = rsnd_ssi_common_probe,
- .remove = rsnd_ssi_common_remove,
- .init = rsnd_ssi_pio_init,
- .quit = rsnd_ssi_quit,
- .start = rsnd_ssi_start,
- .stop = rsnd_ssi_stop,
- .irq = rsnd_ssi_irq,
- .pointer = rsnd_ssi_pio_pointer,
- .pcm_new = rsnd_ssi_pcm_new,
- .hw_params = rsnd_ssi_hw_params,
- .prepare = rsnd_ssi_prepare,
+ .name = SSI_NAME,
+ .probe = rsnd_ssi_common_probe,
+ .remove = rsnd_ssi_common_remove,
+ .init = rsnd_ssi_pio_init,
+ .quit = rsnd_ssi_quit,
+ .start = rsnd_ssi_start,
+ .stop = rsnd_ssi_stop,
+ .irq = rsnd_ssi_irq,
+ .pointer = rsnd_ssi_pio_pointer,
+ .pcm_new = rsnd_ssi_pcm_new,
+ .hw_params = rsnd_ssi_hw_params,
+ .prepare = rsnd_ssi_prepare,
+ .get_status = rsnd_ssi_get_status,
};
static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
@@ -928,8 +964,7 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
*/
mod->ops = &rsnd_ssi_pio_ops;
- dev_info(dev, "%s[%d] fallback to PIO mode\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod));
return 0;
}
@@ -941,6 +976,17 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
int is_play = rsnd_io_is_play(io);
char *name;
+ /*
+ * It should use "rcar_sound,ssiu" on DT.
+ * But, we need to keep compatibility for old version.
+ *
+ * If it has "rcar_sound.ssiu", it will be used.
+ * If not, "rcar_sound.ssi" will be used.
+ * see
+ * rsnd_ssiu_dma_req()
+ * rsnd_dma_of_path()
+ */
+
if (rsnd_ssi_use_busif(io))
name = is_play ? "rxu" : "txu";
else
@@ -951,27 +997,27 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
}
static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
- .name = SSI_NAME,
- .dma_req = rsnd_ssi_dma_req,
- .probe = rsnd_ssi_dma_probe,
- .remove = rsnd_ssi_common_remove,
- .init = rsnd_ssi_init,
- .quit = rsnd_ssi_quit,
- .start = rsnd_ssi_start,
- .stop = rsnd_ssi_stop,
- .irq = rsnd_ssi_irq,
- .pcm_new = rsnd_ssi_pcm_new,
- .fallback = rsnd_ssi_fallback,
- .hw_params = rsnd_ssi_hw_params,
- .prepare = rsnd_ssi_prepare,
+ .name = SSI_NAME,
+ .dma_req = rsnd_ssi_dma_req,
+ .probe = rsnd_ssi_dma_probe,
+ .remove = rsnd_ssi_common_remove,
+ .init = rsnd_ssi_init,
+ .quit = rsnd_ssi_quit,
+ .start = rsnd_ssi_start,
+ .stop = rsnd_ssi_stop,
+ .irq = rsnd_ssi_irq,
+ .pcm_new = rsnd_ssi_pcm_new,
+ .fallback = rsnd_ssi_fallback,
+ .hw_params = rsnd_ssi_hw_params,
+ .prepare = rsnd_ssi_prepare,
+ .get_status = rsnd_ssi_get_status,
};
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
+static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
{
return mod->ops == &rsnd_ssi_dma_ops;
}
-
/*
* ssi mod function
*/
@@ -1027,54 +1073,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
of_node_put(node);
}
-static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io,
- struct device_node *remote_ep)
-{
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
- struct rsnd_ssi *ssi;
- struct device_node *remote_node = of_graph_get_port_parent(remote_ep);
-
- /* support Gen3 only */
- if (!rsnd_is_gen3(priv))
- return;
-
- if (!mod)
- return;
-
- ssi = rsnd_mod_to_ssi(mod);
-
- /* HDMI0 */
- if (strstr(remote_node->full_name, "hdmi@fead0000")) {
- rsnd_flags_set(ssi, RSND_SSI_HDMI0);
- dev_dbg(dev, "%s[%d] connected to HDMI0\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
- }
-
- /* HDMI1 */
- if (strstr(remote_node->full_name, "hdmi@feae0000")) {
- rsnd_flags_set(ssi, RSND_SSI_HDMI1);
- dev_dbg(dev, "%s[%d] connected to HDMI1\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
- }
-}
-
-void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
- struct device_node *endpoint,
- int dai_i)
-{
- struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
- struct device_node *remote_ep;
-
- remote_ep = of_graph_get_remote_endpoint(endpoint);
- if (!remote_ep)
- return;
-
- __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep);
- __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep);
-}
-
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
{
if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
@@ -1091,41 +1089,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
}
-static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type)
-{
- /*
- * SSIP (= SSI parent) needs to be special, otherwise,
- * 2nd SSI might doesn't start. see also rsnd_mod_call()
- *
- * We can't include parent SSI status on SSI, because we don't know
- * how many SSI requests parent SSI. Thus, it is localed on "io" now.
- * ex) trouble case
- * Playback: SSI0
- * Capture : SSI1 (needs SSI0)
- *
- * 1) start Capture -> SSI0/SSI1 are started.
- * 2) start Playback -> SSI0 doesn't work, because it is already
- * marked as "started" on 1)
- *
- * OTOH, using each mod's status is good for MUX case.
- * It doesn't need to start in 2nd start
- * ex)
- * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
- * |
- * IO-1: SRC1 -> CTU2 -+
- *
- * 1) start IO-0 -> start SSI0
- * 2) start IO-1 -> SSI0 doesn't need to start, because it is
- * already started on 1)
- */
- if (type == RSND_MOD_SSIP)
- return &io->parent_ssi_status;
-
- return rsnd_mod_get_status(io, mod, type);
-}
-
int rsnd_ssi_probe(struct rsnd_priv *priv)
{
struct device_node *node;
@@ -1192,7 +1155,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
ops = &rsnd_ssi_dma_ops;
ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
- rsnd_ssi_get_status, RSND_MOD_SSI, i);
+ RSND_MOD_SSI, i);
if (ret) {
of_node_put(np);
goto rsnd_ssi_probe_done;
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 39b67643b5dc..c5934adcfd01 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -12,8 +12,14 @@ struct rsnd_ssiu {
struct rsnd_mod mod;
u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
unsigned int usrcnt;
+ int id;
+ int id_sub;
};
+/* SSI_MODE */
+#define TDM_EXT (1 << 0)
+#define TDM_SPLIT (1 << 8)
+
#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
#define for_each_rsnd_ssiu(pos, priv, i) \
@@ -22,6 +28,33 @@ struct rsnd_ssiu {
((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
i++)
+/*
+ * SSI Gen2 Gen3
+ * 0 BUSIF0-3 BUSIF0-7
+ * 1 BUSIF0-3 BUSIF0-7
+ * 2 BUSIF0-3 BUSIF0-7
+ * 3 BUSIF0 BUSIF0-7
+ * 4 BUSIF0 BUSIF0-7
+ * 5 BUSIF0 BUSIF0
+ * 6 BUSIF0 BUSIF0
+ * 7 BUSIF0 BUSIF0
+ * 8 BUSIF0 BUSIF0
+ * 9 BUSIF0-3 BUSIF0-7
+ * total 22 52
+ */
+static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
+static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
+
+static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+ int busif = rsnd_mod_id_sub(mod);
+
+ return &ssiu->busif_status[busif];
+}
+
static int rsnd_ssiu_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -32,6 +65,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
int id = rsnd_mod_id(mod);
u32 mask1, val1;
u32 mask2, val2;
+ int i;
/* clear status */
switch (id) {
@@ -40,16 +74,12 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
case 2:
case 3:
case 4:
- rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
- rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
- rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
- rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
+ for (i = 0; i < 4; i++)
+ rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
break;
case 9:
- rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
- rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
- rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
- rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
+ for (i = 0; i < 4; i++)
+ rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << (id * 4));
break;
}
@@ -115,8 +145,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
- .name = SSIU_NAME,
- .init = rsnd_ssiu_init,
+ .name = SSIU_NAME,
+ .init = rsnd_ssiu_init,
+ .get_status = rsnd_ssiu_get_status,
};
static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
@@ -124,7 +155,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
- int hdmi = rsnd_ssi_hdmi_port(io);
+ u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
+ u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
int ret;
u32 mode = 0;
@@ -134,20 +166,21 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
ssiu->usrcnt++;
- if (rsnd_runtime_is_ssi_tdm(io)) {
- /*
- * TDM Extend Mode
- * see
- * rsnd_ssi_config_init()
- */
- mode = 0x1;
- }
+ /*
+ * TDM Extend/Split Mode
+ * see
+ * rsnd_ssi_config_init()
+ */
+ if (rsnd_runtime_is_tdm(io))
+ mode = TDM_EXT;
+ else if (rsnd_runtime_is_tdm_split(io))
+ mode = TDM_SPLIT;
rsnd_mod_write(mod, SSI_MODE, mode);
if (rsnd_ssi_use_busif(io)) {
int id = rsnd_mod_id(mod);
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(mod);
/*
* FIXME
@@ -162,46 +195,18 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
id, busif);
}
-#define RSND_WRITE_BUSIF(i) \
- rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \
- rsnd_get_adinr_bit(mod, io) | \
- (rsnd_io_is_play(io) ? \
- rsnd_runtime_channel_after_ctu(io) : \
- rsnd_runtime_channel_original(io))); \
- rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \
- rsnd_get_busif_shift(io, mod) | 1); \
- rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \
- rsnd_get_dalign(mod, io))
-
- switch (busif) {
- case 0:
- RSND_WRITE_BUSIF(0);
- break;
- case 1:
- RSND_WRITE_BUSIF(1);
- break;
- case 2:
- RSND_WRITE_BUSIF(2);
- break;
- case 3:
- RSND_WRITE_BUSIF(3);
- break;
- case 4:
- RSND_WRITE_BUSIF(4);
- break;
- case 5:
- RSND_WRITE_BUSIF(5);
- break;
- case 6:
- RSND_WRITE_BUSIF(6);
- break;
- case 7:
- RSND_WRITE_BUSIF(7);
- break;
- }
+ rsnd_mod_write(mod, SSI_BUSIF_ADINR(busif),
+ rsnd_get_adinr_bit(mod, io) |
+ (rsnd_io_is_play(io) ?
+ rsnd_runtime_channel_after_ctu(io) :
+ rsnd_runtime_channel_original(io)));
+ rsnd_mod_write(mod, SSI_BUSIF_MODE(busif),
+ rsnd_get_busif_shift(io, mod) | 1);
+ rsnd_mod_write(mod, SSI_BUSIF_DALIGN(busif),
+ rsnd_get_dalign(mod, io));
}
- if (hdmi) {
+ if (has_hdmi0 || has_hdmi1) {
enum rsnd_mod_type rsnd_ssi_array[] = {
RSND_MOD_SSIM1,
RSND_MOD_SSIM2,
@@ -227,14 +232,10 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
rsnd_mod_id(pos) << shift;
}
- switch (hdmi) {
- case RSND_SSI_HDMI_PORT0:
+ if (has_hdmi0)
rsnd_mod_write(mod, HDMI0_SEL, val);
- break;
- case RSND_SSI_HDMI_PORT1:
+ if (has_hdmi1)
rsnd_mod_write(mod, HDMI1_SEL, val);
- break;
- }
}
return 0;
@@ -244,7 +245,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(mod);
if (!rsnd_ssi_use_busif(io))
return 0;
@@ -262,7 +263,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(mod);
if (!rsnd_ssi_use_busif(io))
return 0;
@@ -278,11 +279,53 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
return 0;
}
+static int rsnd_ssiu_id(struct rsnd_mod *mod)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+ /* see rsnd_ssiu_probe() */
+ return ssiu->id;
+}
+
+static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+ /* see rsnd_ssiu_probe() */
+ return ssiu->id_sub;
+}
+
+static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ int is_play = rsnd_io_is_play(io);
+ char *name;
+
+ /*
+ * It should use "rcar_sound,ssiu" on DT.
+ * But, we need to keep compatibility for old version.
+ *
+ * If it has "rcar_sound.ssiu", it will be used.
+ * If not, "rcar_sound.ssi" will be used.
+ * see
+ * rsnd_ssi_dma_req()
+ * rsnd_dma_of_path()
+ */
+
+ name = is_play ? "rx" : "tx";
+
+ return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
+ mod, name);
+}
+
static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
- .name = SSIU_NAME,
- .init = rsnd_ssiu_init_gen2,
- .start = rsnd_ssiu_start_gen2,
- .stop = rsnd_ssiu_stop_gen2,
+ .name = SSIU_NAME,
+ .dma_req = rsnd_ssiu_dma_req,
+ .init = rsnd_ssiu_init_gen2,
+ .start = rsnd_ssiu_start_gen2,
+ .stop = rsnd_ssiu_stop_gen2,
+ .get_status = rsnd_ssiu_get_status,
};
static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
@@ -293,36 +336,85 @@ static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
}
-int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
- struct rsnd_mod *ssi_mod)
+static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_io_to_priv(io);
- struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
+ struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *mod;
+ struct rsnd_ssiu *ssiu;
+ int i;
- rsnd_mod_confirm_ssi(ssi_mod);
+ if (!ssi_mod)
+ return;
- return rsnd_dai_connect(mod, io, mod->type);
+ /* select BUSIF0 */
+ for_each_rsnd_ssiu(ssiu, priv, i) {
+ mod = rsnd_mod_get(ssiu);
+
+ if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
+ (rsnd_mod_id_sub(mod) == 0)) {
+ rsnd_dai_connect(mod, io, mod->type);
+ return;
+ }
+ }
}
-static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type)
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+ struct device_node *playback,
+ struct device_node *capture)
{
- struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
- int busif = rsnd_ssi_get_busif(io);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device_node *node = rsnd_ssiu_of_node(priv);
+ struct device_node *np;
+ struct rsnd_mod *mod;
+ struct rsnd_dai_stream *io_p = &rdai->playback;
+ struct rsnd_dai_stream *io_c = &rdai->capture;
+ int i;
- return &ssiu->busif_status[busif];
+ /* use rcar_sound,ssiu if exist */
+ if (node) {
+ i = 0;
+ for_each_child_of_node(node, np) {
+ mod = rsnd_ssiu_mod_get(priv, i);
+ if (np == playback)
+ rsnd_dai_connect(mod, io_p, mod->type);
+ if (np == capture)
+ rsnd_dai_connect(mod, io_c, mod->type);
+ i++;
+ }
+
+ of_node_put(node);
+ }
+
+ /* Keep DT compatibility */
+ if (!rsnd_io_to_mod_ssiu(io_p))
+ rsnd_parse_connect_ssiu_compatible(priv, io_p);
+ if (!rsnd_io_to_mod_ssiu(io_c))
+ rsnd_parse_connect_ssiu_compatible(priv, io_c);
}
int rsnd_ssiu_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *node;
struct rsnd_ssiu *ssiu;
struct rsnd_mod_ops *ops;
+ const int *list = NULL;
int i, nr, ret;
- /* same number to SSI */
- nr = priv->ssi_nr;
+ /*
+ * Keep DT compatibility.
+ * if it has "rcar_sound,ssiu", use it.
+ * if not, use "rcar_sound,ssi"
+ * see
+ * rsnd_ssiu_bufsif_to_id()
+ */
+ node = rsnd_ssiu_of_node(priv);
+ if (node)
+ nr = of_get_child_count(node);
+ else
+ nr = priv->ssi_nr;
+
ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
if (!ssiu)
return -ENOMEM;
@@ -335,10 +427,46 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
else
ops = &rsnd_ssiu_ops_gen2;
+ /* Keep compatibility */
+ nr = 0;
+ if ((node) &&
+ (ops == &rsnd_ssiu_ops_gen2)) {
+ ops->id = rsnd_ssiu_id;
+ ops->id_sub = rsnd_ssiu_id_sub;
+
+ if (rsnd_is_gen2(priv)) {
+ list = gen2_id;
+ nr = ARRAY_SIZE(gen2_id);
+ } else if (rsnd_is_gen3(priv)) {
+ list = gen3_id;
+ nr = ARRAY_SIZE(gen3_id);
+ } else {
+ dev_err(dev, "unknown SSIU\n");
+ return -ENODEV;
+ }
+ }
+
for_each_rsnd_ssiu(ssiu, priv, i) {
+ if (node) {
+ int j;
+
+ /*
+ * see
+ * rsnd_ssiu_get_id()
+ * rsnd_ssiu_get_id_sub()
+ */
+ for (j = 0; j < nr; j++) {
+ if (list[j] > i)
+ break;
+ ssiu->id = j;
+ ssiu->id_sub = i - list[ssiu->id];
+ }
+ } else {
+ ssiu->id = i;
+ }
+
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
- ops, NULL, rsnd_ssiu_get_status,
- RSND_MOD_SSIU, i);
+ ops, NULL, RSND_MOD_SSIU, i);
if (ret)
return ret;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b29d0f65611e..0462b3ec977a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1467,7 +1467,7 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
for (i = 0; i < num_dais; ++i) {
struct snd_soc_dai_driver *drv = dais[i]->driver;
- if (!rtd->dai_link->no_pcm && drv->pcm_new)
+ if (drv->pcm_new)
ret = drv->pcm_new(rtd, dais[i]);
if (ret < 0) {
dev_err(dais[i]->dev,
@@ -3485,12 +3485,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
- struct snd_soc_codec_conf *codec_conf,
- struct device_node *of_node,
- const char *propname)
+void snd_soc_of_parse_node_prefix(struct device_node *np,
+ struct snd_soc_codec_conf *codec_conf,
+ struct device_node *of_node,
+ const char *propname)
{
- struct device_node *np = card->dev->of_node;
const char *str;
int ret;
@@ -3503,7 +3502,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
codec_conf->of_node = of_node;
codec_conf->name_prefix = str;
}
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname)
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d597eba61992..bcb35cae2a2c 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -74,14 +74,14 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
return ret;
}
- dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
- sai->pdev->dev.of_node->name,
+ dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n",
+ sai->pdev->dev.of_node,
synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
- dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
- sai->pdev->dev.of_node->name,
+ dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n",
+ sai->pdev->dev.of_node,
prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
clk_disable_unprepare(sai->pclk);
return -EINVAL;
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 211589b0b2ef..d4825700b63f 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -336,8 +336,7 @@ static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
struct stm32_sai_sub_data *sai = mclk->sai_data;
- unsigned int div;
- int ret;
+ int div, ret;
div = stm32_sai_get_clk_div(sai, parent_rate, rate);
if (div < 0)
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
index 8f5f999df631..df1fed0aa001 100644
--- a/sound/soc/sunxi/sun50i-codec-analog.c
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -274,6 +274,7 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
* stream widgets at the card level.
*/
+ SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0),
SND_SOC_DAPM_MUX("Headphone Source Playback Route",
SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL,
@@ -361,6 +362,7 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
{ "Headphone Source Playback Route", "Mixer", "Left Mixer" },
{ "Headphone Source Playback Route", "Mixer", "Right Mixer" },
{ "Headphone Amp", NULL, "Headphone Source Playback Route" },
+ { "Headphone Amp", NULL, "hpvcc" },
{ "HP", NULL, "Headphone Amp" },
/* Microphone Routes */
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig
new file mode 100644
index 000000000000..4bf3c15d4e51
--- /dev/null
+++ b/sound/soc/ti/Kconfig
@@ -0,0 +1,209 @@
+menu "Audio support for Texas Instruments SoCs"
+depends on DMA_OMAP || TI_EDMA || COMPILE_TEST
+
+config SND_SOC_TI_EDMA_PCM
+ tristate
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_TI_SDMA_PCM
+ tristate
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
+comment "Texas Instruments DAI support for:"
+config SND_SOC_DAVINCI_ASP
+ tristate "daVinci Audio Serial Port (ASP) or McBSP suport"
+ depends on ARCH_DAVINCI || COMPILE_TEST
+ select SND_SOC_TI_EDMA_PCM
+ help
+ Say Y or M here if you want audio support via daVinci ASP or McBSP.
+ The driver only implements the ASP support which is a subset of
+ daVinci McBSP (w/o the multichannel support).
+
+config SND_SOC_DAVINCI_MCASP
+ tristate "Multichannel Audio Serial Port (McASP) support"
+ select SND_SOC_TI_EDMA_PCM if TI_EDMA
+ select SND_SOC_TI_SDMA_PCM if DMA_OMAP
+ help
+ Say Y or M here if you want to have support for McASP IP found in
+ various Texas Instruments SoCs like:
+ - daVinci devices
+ - Sitara line of SoCs (AM335x, AM438x, etc)
+ - DRA7x devices
+ - Keystone devices
+
+config SND_SOC_DAVINCI_VCIF
+ tristate "daVinci Voice Interface (VCIF) suport"
+ depends on ARCH_DAVINCI || COMPILE_TEST
+ select SND_SOC_TI_EDMA_PCM
+ help
+ Say Y or M here if you want audio support via daVinci VCIF.
+
+config SND_SOC_OMAP_DMIC
+ tristate "Digital Microphone Module (DMIC) support"
+ depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ Say Y or M here if you want to have support for DMIC IP found in
+ OMAP4 and OMAP5.
+
+config SND_SOC_OMAP_MCBSP
+ tristate "Multichannel Buffered Serial Port (McBSP) support"
+ depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ Say Y or M here if you want to have support for McBSP IP found in
+ Texas Instruments OMAP1/2/3/4/5 SoCs.
+
+config SND_SOC_OMAP_MCPDM
+ tristate "Multichannel PDM Controller (McPDM) support"
+ depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ Say Y or M here if you want to have support for McPDM IP found in
+ OMAP4 and OMAP5.
+
+comment "Audio support for boards with Texas Instruments SoCs"
+config SND_SOC_NOKIA_N810
+ tristate "SoC Audio support for Nokia N810"
+ depends on MACH_NOKIA_N810 && I2C
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TLV320AIC3X
+ help
+ Say Y or M if you want to add support for SoC audio on Nokia N810.
+
+config SND_SOC_NOKIA_RX51
+ tristate "SoC Audio support for Nokia RX-51"
+ depends on ARCH_OMAP3 && I2C && GPIOLIB
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TLV320AIC3X
+ select SND_SOC_TPA6130A2
+ help
+ Say Y or M if you want to add support for SoC audio on Nokia RX-51
+ hardware. This is also known as Nokia N900 product.
+
+config SND_SOC_OMAP3_PANDORA
+ tristate "SoC Audio support for OMAP3 Pandora"
+ depends on ARCH_OMAP3
+ depends on TWL4030_CORE
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y or M if you want to add support for SoC audio on the OMAP3 Pandora.
+
+config SND_SOC_OMAP3_TWL4030
+ tristate "SoC Audio support for OMAP3 based boards with twl4030 codec"
+ depends on ARCH_OMAP3 || COMPILE_TEST
+ depends on TWL4030_CORE
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y or M if you want to add support for SoC audio on OMAP3 based
+ boards using twl4030 as codec. This driver currently supports:
+ - Beagleboard or Devkit8000
+ - Gumstix Overo or CompuLab CM-T35/CM-T3730
+ - IGEP v2
+ - OMAP3EVM
+ - SDP3430
+ - Zoom2
+
+config SND_SOC_OMAP_ABE_TWL6040
+ tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
+ depends on TWL6040_CORE && COMMON_CLK
+ depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
+ select SND_SOC_OMAP_DMIC
+ select SND_SOC_OMAP_MCPDM
+ select SND_SOC_TWL6040
+ help
+ Say Y or M if you want to add support for SoC audio on OMAP boards
+ using ABE and twl6040 codec. This driver currently supports:
+ - SDP4430/Blaze boards
+ - PandaBoard (4430)
+ - PandaBoardES (4460)
+ - OMAP5 uEVM
+
+config SND_SOC_OMAP_AMS_DELTA
+ tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
+ depends on MACH_AMS_DELTA && TTY
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_CX20442
+ help
+ Say Y or M if you want to add support for SoC audio device
+ connected to a handset and a speakerphone found on Amstrad E3 (Delta)
+ videophone.
+
+ Note that in order to get those devices fully supported, you have to
+ build the kernel with standard serial port driver included and
+ configured for at least 4 ports. Then, from userspace, you must load
+ a line discipline #19 on the modem (ttyS3) serial line. The simplest
+ way to achieve this is to install util-linux-ng and use the included
+ ldattach utility. This can be started automatically from udev,
+ a simple rule like this one should do the trick (it does for me):
+ ACTION=="add", KERNEL=="controlC0", \
+ RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
+
+config SND_SOC_OMAP_HDMI
+ tristate "OMAP4/5 HDMI audio support"
+ depends on OMAP4_DSS_HDMI || OMAP5_DSS_HDMI || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ For HDMI audio to work OMAPDSS HDMI support should be
+ enabled.
+ The hdmi audio driver implements cpu-dai component using the
+ callbacks provided by OMAPDSS and registers the component
+ under DSS HDMI device. Omap-pcm is registered for platform
+ component also under DSS HDMI device. Dummy codec is used as
+ as codec component. The hdmi audio driver implements also
+ the card and registers it under its own platform device.
+ The device for the driver is registered by OMAPDSS hdmi
+ driver.
+
+config SND_SOC_OMAP_OSK5912
+ tristate "SoC Audio support for omap osk5912"
+ depends on MACH_OMAP_OSK && I2C
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TLV320AIC23_I2C
+ help
+ Say Y or M if you want to add support for SoC audio on osk5912.
+
+config SND_SOC_DAVINCI_EVM
+ tristate "SoC Audio support for DaVinci EVMs"
+ depends on ARCH_DAVINCI && I2C
+ select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_DM355_EVM
+ select SND_SOC_DAVINCI_ASP if SND_SOC_DM365_AIC3X_CODEC
+ select SND_SOC_DAVINCI_VCIF if SND_SOC_DM365_VOICE_CODEC
+ select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_EVM # DM6446
+ select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DM6467_EVM
+ select SND_SOC_SPDIF if MACH_DAVINCI_DM6467_EVM
+ select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA830_EVM
+ select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA850_EVM
+ select SND_SOC_TLV320AIC3X
+ help
+ Say Y if you want to add support for SoC audio on the following TI
+ DaVinci EVM platforms:
+ - DM355
+ - DM365
+ - DM6446
+ - DM6447
+ - DM830
+ - DM850
+
+choice
+ prompt "DM365 codec select"
+ depends on SND_SOC_DAVINCI_EVM
+ depends on MACH_DAVINCI_DM365_EVM
+
+config SND_SOC_DM365_AIC3X_CODEC
+ bool "Audio Codec - AIC3101"
+ help
+ Say Y if you want to add support for AIC3101 audio codec
+
+config SND_SOC_DM365_VOICE_CODEC
+ bool "Voice Codec - CQ93VC"
+ select MFD_DAVINCI_VOICECODEC
+ select SND_SOC_CQ0093VC
+ help
+ Say Y if you want to add support for SoC On-chip voice codec
+endchoice
+
+endmenu
+
diff --git a/sound/soc/ti/Makefile b/sound/soc/ti/Makefile
new file mode 100644
index 000000000000..08c44d56ef3e
--- /dev/null
+++ b/sound/soc/ti/Makefile
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Platform drivers
+snd-soc-ti-edma-objs := edma-pcm.o
+snd-soc-ti-sdma-objs := sdma-pcm.o
+
+obj-$(CONFIG_SND_SOC_TI_EDMA_PCM) += snd-soc-ti-edma.o
+obj-$(CONFIG_SND_SOC_TI_SDMA_PCM) += snd-soc-ti-sdma.o
+
+# CPU DAI drivers
+snd-soc-davinci-asp-objs := davinci-i2s.o
+snd-soc-davinci-mcasp-objs := davinci-mcasp.o
+snd-soc-davinci-vcif-objs := davinci-vcif.o
+snd-soc-omap-dmic-objs := omap-dmic.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
+
+obj-$(CONFIG_SND_SOC_DAVINCI_ASP) += snd-soc-davinci-asp.o
+obj-$(CONFIG_SND_SOC_DAVINCI_MCASP) += snd-soc-davinci-mcasp.o
+obj-$(CONFIG_SND_SOC_DAVINCI_VCIF) += snd-soc-davinci-vcif.o
+obj-$(CONFIG_SND_SOC_OMAP_DMIC) += snd-soc-omap-dmic.o
+obj-$(CONFIG_SND_SOC_OMAP_MCBSP) += snd-soc-omap-mcbsp.o
+obj-$(CONFIG_SND_SOC_OMAP_MCPDM) += snd-soc-omap-mcpdm.o
+
+# Machine drivers
+snd-soc-davinci-evm-objs := davinci-evm.o
+snd-soc-n810-objs := n810.o
+snd-soc-rx51-objs := rx51.o
+snd-soc-omap3pandora-objs := omap3pandora.o
+snd-soc-omap-twl4030-objs := omap-twl4030.o
+snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
+snd-soc-ams-delta-objs := ams-delta.o
+snd-soc-omap-hdmi-objs := omap-hdmi.o
+snd-soc-osk5912-objs := osk5912.o
+
+obj-$(CONFIG_SND_SOC_DAVINCI_EVM) += snd-soc-davinci-evm.o
+obj-$(CONFIG_SND_SOC_NOKIA_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_SOC_NOKIA_RX51) += snd-soc-rx51.o
+obj-$(CONFIG_SND_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
+obj-$(CONFIG_SND_SOC_OMAP3_TWL4030) += snd-soc-omap-twl4030.o
+obj-$(CONFIG_SND_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
+obj-$(CONFIG_SND_SOC_OMAP_AMS_DELTA) += snd-soc-ams-delta.o
+obj-$(CONFIG_SND_SOC_OMAP_HDMI) += snd-soc-omap-hdmi.o
+obj-$(CONFIG_SND_SOC_OMAP_OSK5912) += snd-soc-osk5912.o
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/ti/ams-delta.c
index 4dce494dfbd3..4dce494dfbd3 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index 7a369e0f2093..4869d6311510 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -170,7 +170,7 @@ static struct snd_soc_dai_link dm355_evm_dai = {
};
static struct snd_soc_dai_link dm365_evm_dai = {
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
+#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcbsp",
@@ -181,7 +181,7 @@ static struct snd_soc_dai_link dm365_evm_dai = {
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
+#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.stream_name = "CQ93",
.cpu_dai_name = "davinci-vcif",
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index a3206e65e5e5..a3206e65e5e5 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/ti/davinci-i2s.h
index 48dac3e2521a..48dac3e2521a 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/ti/davinci-i2s.h
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 267aee776b2d..eeda6d5565bc 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -28,6 +28,7 @@
#include <linux/of_device.h>
#include <linux/platform_data/davinci_asp.h>
#include <linux/math64.h>
+#include <linux/bitmap.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -38,7 +39,7 @@
#include <sound/dmaengine_pcm.h>
#include "edma-pcm.h"
-#include "../omap/sdma-pcm.h"
+#include "sdma-pcm.h"
#include "davinci-mcasp.h"
#define MCASP_MAX_AFIFO_DEPTH 64
@@ -84,6 +85,7 @@ struct davinci_mcasp {
u32 tdm_mask[2];
int slot_width;
u8 op_mode;
+ u8 dismod;
u8 num_serializer;
u8 *serial_dir;
u8 version;
@@ -95,6 +97,8 @@ struct davinci_mcasp {
int sysclk_freq;
bool bclk_master;
+ unsigned long pdir; /* Pin direction bitfield */
+
/* McASP FIFO related */
u8 txnumevt;
u8 rxnumevt;
@@ -169,6 +173,30 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
}
+static inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
+{
+ u32 bit = PIN_BIT_AMUTE;
+
+ for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
+ if (enable)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ }
+}
+
+static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
+{
+ u32 bit;
+
+ for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) {
+ if (enable)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ }
+}
+
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
{
if (mcasp->rxnumevt) { /* enable FIFO */
@@ -192,6 +220,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
}
/* Activate serializer(s) */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
/* Release RX state machine */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
@@ -219,7 +248,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
/* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ mcasp_set_clk_pdir(mcasp, true);
+
/* Activate serializer(s) */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
/* wait for XDATA to be cleared */
@@ -228,6 +260,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
(cnt < 100000))
cnt++;
+ mcasp_set_axr_pdir(mcasp, true);
+
/* Release TX state machine */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
/* Release Frame Sync generator */
@@ -258,8 +292,10 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
* In synchronous mode stop the TX clocks if no other stream is
* running
*/
- if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
+ if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
+ mcasp_set_clk_pdir(mcasp, false);
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
+ }
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
@@ -285,6 +321,9 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
*/
if (mcasp_is_synchronous(mcasp) && mcasp->streams)
val = TXHCLKRST | TXCLKRST | TXFSRST;
+ else
+ mcasp_set_clk_pdir(mcasp, false);
+
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
@@ -294,6 +333,8 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
}
+
+ mcasp_set_axr_pdir(mcasp, false);
}
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
@@ -444,8 +485,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ /* BCLK */
+ set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ set_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ set_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBS_CFM:
@@ -456,8 +502,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ /* BCLK */
+ set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBM_CFS:
@@ -468,8 +519,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ /* BCLK */
+ clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ set_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ set_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 0;
break;
case SND_SOC_DAIFMT_CBM_CFM:
@@ -480,8 +536,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
- ACLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ /* BCLK */
+ clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 0;
break;
default:
@@ -596,11 +657,11 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
if (dir == SND_SOC_CLOCK_OUT) {
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
+ set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
} else {
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
+ clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
}
mcasp->sysclk_freq = freq;
@@ -773,17 +834,23 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
mcasp->serial_dir[i]);
if (mcasp->serial_dir[i] == TX_MODE &&
tx_ser < max_active_serializers) {
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
- DISMOD_LOW, DISMOD_MASK);
+ mcasp->dismod, DISMOD_MASK);
+ set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
tx_ser++;
} else if (mcasp->serial_dir[i] == RX_MODE &&
rx_ser < max_active_serializers) {
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
rx_ser++;
} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
SRMOD_INACTIVE, SRMOD_MASK);
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
+ } else if (mcasp->serial_dir[i] == TX_MODE) {
+ /* Unused TX pins, clear PDIR */
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ mcasp->dismod, DISMOD_MASK);
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
}
}
@@ -1645,6 +1712,7 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
if (pdev->dev.platform_data) {
pdata = pdev->dev.platform_data;
+ pdata->dismod = DISMOD_LOW;
return pdata;
} else if (match) {
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
@@ -1734,6 +1802,18 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
if (ret >= 0)
pdata->sram_size_capture = val;
+ ret = of_property_read_u32(np, "dismod", &val);
+ if (ret >= 0) {
+ if (val == 0 || val == 2 || val == 3) {
+ pdata->dismod = DISMOD_VAL(val);
+ } else {
+ dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
+ pdata->dismod = DISMOD_LOW;
+ }
+ } else {
+ pdata->dismod = DISMOD_LOW;
+ }
+
return pdata;
nodata:
@@ -1909,6 +1989,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->version = pdata->version;
mcasp->txnumevt = pdata->txnumevt;
mcasp->rxnumevt = pdata->rxnumevt;
+ mcasp->dismod = pdata->dismod;
mcasp->dev = &pdev->dev;
@@ -2068,9 +2149,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = davinci_mcasp_get_dma_type(mcasp);
switch (ret) {
case PCM_EDMA:
-#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
- (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
- IS_MODULE(CONFIG_SND_EDMA_SOC))
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
+ IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM))
ret = edma_pcm_platform_register(&pdev->dev);
#else
dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
@@ -2079,9 +2160,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
#endif
break;
case PCM_SDMA:
-#if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \
- (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
- IS_MODULE(CONFIG_SND_SDMA_SOC))
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
+ IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM))
ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
#else
dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/ti/davinci-mcasp.h
index afddc8010c54..5e4060d8fe56 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/ti/davinci-mcasp.h
@@ -108,27 +108,18 @@
/*
* DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
- */
-#define AXR(n) (1<<n)
-#define PFUNC_AMUTE BIT(25)
-#define ACLKX BIT(26)
-#define AHCLKX BIT(27)
-#define AFSX BIT(28)
-#define ACLKR BIT(29)
-#define AHCLKR BIT(30)
-#define AFSR BIT(31)
-
-/*
* DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ * DAVINCI_MCASP_PDOUT_REG - Pin output in GPIO mode
+ * DAVINCI_MCASP_PDSET_REG - Pin input in GPIO mode
*/
-#define AXR(n) (1<<n)
-#define PDIR_AMUTE BIT(25)
-#define ACLKX BIT(26)
-#define AHCLKX BIT(27)
-#define AFSX BIT(28)
-#define ACLKR BIT(29)
-#define AHCLKR BIT(30)
-#define AFSR BIT(31)
+#define PIN_BIT_AXR(n) (n)
+#define PIN_BIT_AMUTE 25
+#define PIN_BIT_ACLKX 26
+#define PIN_BIT_AHCLKX 27
+#define PIN_BIT_AFSX 28
+#define PIN_BIT_ACLKR 29
+#define PIN_BIT_AHCLKR 30
+#define PIN_BIT_AFSR 31
/*
* DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
@@ -218,6 +209,7 @@
#define DISMOD_3STATE (0x0)
#define DISMOD_LOW (0x2 << 2)
#define DISMOD_HIGH (0x3 << 2)
+#define DISMOD_VAL(x) ((x) << 2)
#define DISMOD_MASK DISMOD_HIGH
#define TXSTATE BIT(4)
#define RXSTATE BIT(5)
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/ti/davinci-vcif.c
index 5415b72393fa..5415b72393fa 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/ti/davinci-vcif.c
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/ti/edma-pcm.c
index 59e588abe54b..59e588abe54b 100644
--- a/sound/soc/davinci/edma-pcm.c
+++ b/sound/soc/ti/edma-pcm.c
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/ti/edma-pcm.h
index b0957744851c..8058bdb0f032 100644
--- a/sound/soc/davinci/edma-pcm.h
+++ b/sound/soc/ti/edma-pcm.h
@@ -20,13 +20,13 @@
#ifndef __EDMA_PCM_H__
#define __EDMA_PCM_H__
-#if IS_ENABLED(CONFIG_SND_EDMA_SOC)
+#if IS_ENABLED(CONFIG_SND_SOC_TI_EDMA_PCM)
int edma_pcm_platform_register(struct device *dev);
#else
static inline int edma_pcm_platform_register(struct device *dev)
{
return 0;
}
-#endif /* CONFIG_SND_EDMA_SOC */
+#endif /* CONFIG_SND_SOC_TI_EDMA_PCM */
#endif /* __EDMA_PCM_H__ */
diff --git a/sound/soc/omap/n810.c b/sound/soc/ti/n810.c
index 9cfefe44a75f..9cfefe44a75f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/ti/n810.c
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c
index fed45b41f9d3..fed45b41f9d3 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/ti/omap-abe-twl6040.c
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/ti/omap-dmic.c
index cba9645b6487..cba9645b6487 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/ti/omap-dmic.c
diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/ti/omap-dmic.h
index 231e728bff0e..231e728bff0e 100644
--- a/sound/soc/omap/omap-dmic.h
+++ b/sound/soc/ti/omap-dmic.h
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/ti/omap-hdmi.c
index 673a9eb153b2..673a9eb153b2 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/ti/omap-hdmi.c
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/ti/omap-mcbsp-priv.h
index 46ae1269a698..7865cda4bf0a 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/ti/omap-mcbsp-priv.h
@@ -1,28 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * sound/soc/omap/mcbsp.h
- *
* OMAP Multi-Channel Buffered Serial Port
*
* Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.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 __ASOC_MCBSP_H
-#define __ASOC_MCBSP_H
+
+#ifndef __OMAP_MCBSP_PRIV_H__
+#define __OMAP_MCBSP_PRIV_H__
+
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#ifdef CONFIG_ARCH_OMAP1
#define mcbsp_omap1() 1
@@ -30,8 +17,6 @@
#define mcbsp_omap1() 0
#endif
-#include <sound/dmaengine_pcm.h>
-
/* McBSP register numbers. Register address offset = num * reg_step */
enum {
/* Common registers */
@@ -85,15 +70,6 @@ enum {
OMAP_MCBSP_REG_SSELCR,
};
-/* OMAP3 sidetone control registers */
-#define OMAP_ST_REG_REV 0x00
-#define OMAP_ST_REG_SYSCONFIG 0x10
-#define OMAP_ST_REG_IRQSTATUS 0x18
-#define OMAP_ST_REG_IRQENABLE 0x1C
-#define OMAP_ST_REG_SGAINCR 0x24
-#define OMAP_ST_REG_SFIRCR 0x28
-#define OMAP_ST_REG_SSELCR 0x2C
-
/************************** McBSP SPCR1 bit definitions ***********************/
#define RRST BIT(0)
#define RRDY BIT(1)
@@ -202,24 +178,6 @@ enum {
#define SIDLEMODE(value) (((value) & 0x3) << 3)
#define CLOCKACTIVITY(value) (((value) & 0x3) << 8)
-/********************** McBSP SSELCR bit definitions ***********************/
-#define SIDETONEEN BIT(10)
-
-/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
-#define ST_AUTOIDLE BIT(0)
-
-/********************** McBSP Sidetone SGAINCR bit definitions *************/
-#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
-#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
-
-/********************** McBSP Sidetone SFIRCR bit definitions **************/
-#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
-
-/********************** McBSP Sidetone SSELCR bit definitions **************/
-#define ST_SIDETONEEN BIT(0)
-#define ST_COEFFWREN BIT(1)
-#define ST_COEFFWRDONE BIT(2)
-
/********************** McBSP DMA operating modes **************************/
#define MCBSP_DMA_MODE_ELEMENT 0
#define MCBSP_DMA_MODE_THRESHOLD 1
@@ -278,16 +236,7 @@ struct omap_mcbsp_reg_cfg {
u16 rccr;
};
-struct omap_mcbsp_st_data {
- void __iomem *io_base_st;
- struct clk *mcbsp_iclk;
- bool running;
- bool enabled;
- s16 taps[128]; /* Sidetone filter coefficients */
- int nr_taps; /* Number of filter coefficients in use */
- s16 ch0gain;
- s16 ch1gain;
-};
+struct omap_mcbsp_st_data;
struct omap_mcbsp {
struct device *dev;
@@ -330,29 +279,46 @@ struct omap_mcbsp {
struct pm_qos_request pm_qos_req;
};
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
- const struct omap_mcbsp_reg_cfg *config);
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx);
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
-
-/* McBSP functional clock source changing function */
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
+static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+ void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
+ writew_relaxed((u16)val, addr);
+ } else {
+ ((u32 *)mcbsp->reg_cache)[reg] = val;
+ writel_relaxed(val, addr);
+ }
+}
+
+static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
+ bool from_cache)
+{
+ void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ return !from_cache ? readw_relaxed(addr) :
+ ((u16 *)mcbsp->reg_cache)[reg];
+ } else {
+ return !from_cache ? readl_relaxed(addr) :
+ ((u32 *)mcbsp->reg_cache)[reg];
+ }
+}
+
+#define MCBSP_READ(mcbsp, reg) \
+ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
+#define MCBSP_WRITE(mcbsp, reg, val) \
+ omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
+#define MCBSP_READ_CACHE(mcbsp, reg) \
+ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
+
/* Sidetone specific API */
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
-int omap_st_enable(struct omap_mcbsp *mcbsp);
-int omap_st_disable(struct omap_mcbsp *mcbsp);
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_init(struct platform_device *pdev);
+void omap_mcbsp_st_cleanup(struct platform_device *pdev);
-int omap_mcbsp_init(struct platform_device *pdev);
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
-#endif /* __ASOC_MCBSP_H */
+#endif /* __OMAP_MCBSP_PRIV_H__ */
diff --git a/sound/soc/ti/omap-mcbsp-st.c b/sound/soc/ti/omap-mcbsp-st.c
new file mode 100644
index 000000000000..1a3fe854e856
--- /dev/null
+++ b/sound/soc/ti/omap-mcbsp-st.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * McBSP Sidetone support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ * Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include "omap-mcbsp.h"
+#include "omap-mcbsp-priv.h"
+
+/* OMAP3 sidetone control registers */
+#define OMAP_ST_REG_REV 0x00
+#define OMAP_ST_REG_SYSCONFIG 0x10
+#define OMAP_ST_REG_IRQSTATUS 0x18
+#define OMAP_ST_REG_IRQENABLE 0x1C
+#define OMAP_ST_REG_SGAINCR 0x24
+#define OMAP_ST_REG_SFIRCR 0x28
+#define OMAP_ST_REG_SSELCR 0x2C
+
+/********************** McBSP SSELCR bit definitions ***********************/
+#define SIDETONEEN BIT(10)
+
+/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
+#define ST_AUTOIDLE BIT(0)
+
+/********************** McBSP Sidetone SGAINCR bit definitions *************/
+#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
+#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
+
+/********************** McBSP Sidetone SFIRCR bit definitions **************/
+#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
+
+/********************** McBSP Sidetone SSELCR bit definitions **************/
+#define ST_SIDETONEEN BIT(0)
+#define ST_COEFFWREN BIT(1)
+#define ST_COEFFWRDONE BIT(2)
+
+struct omap_mcbsp_st_data {
+ void __iomem *io_base_st;
+ struct clk *mcbsp_iclk;
+ bool running;
+ bool enabled;
+ s16 taps[128]; /* Sidetone filter coefficients */
+ int nr_taps; /* Number of filter coefficients in use */
+ s16 ch0gain;
+ s16 ch1gain;
+};
+
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+ writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
+}
+
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+{
+ return readl_relaxed(mcbsp->st_data->io_base_st + reg);
+}
+
+#define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
+#define MCBSP_ST_WRITE(mcbsp, reg, val) \
+ omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
+
+static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ if (mcbsp->pdata->force_ick_on)
+ mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
+
+ /* Disable Sidetone clock auto-gating for normal operation */
+ w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+ MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
+
+ /* Enable McBSP Sidetone */
+ w = MCBSP_READ(mcbsp, SSELCR);
+ MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
+
+ /* Enable Sidetone from Sidetone Core */
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+ MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
+}
+
+static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+ MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
+
+ w = MCBSP_READ(mcbsp, SSELCR);
+ MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
+
+ /* Enable Sidetone clock auto-gating to reduce power consumption */
+ w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+ MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
+
+ if (mcbsp->pdata->force_ick_on)
+ mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
+}
+
+static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
+{
+ u16 val, i;
+
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ if (val & ST_COEFFWREN)
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
+
+ for (i = 0; i < 128; i++)
+ MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
+
+ i = 0;
+
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+ while (!(val & ST_COEFFWRDONE) && (++i < 1000))
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+ if (i == 1000)
+ dev_err(mcbsp->dev, "McBSP FIR load error!\n");
+}
+
+static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp)
+{
+ u16 w;
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) |
+ ST_CH1GAIN(st_data->ch1gain));
+}
+
+static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel,
+ s16 chgain)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENOENT;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (channel == 0)
+ st_data->ch0gain = chgain;
+ else if (channel == 1)
+ st_data->ch1gain = chgain;
+ else
+ ret = -EINVAL;
+
+ if (st_data->enabled)
+ omap_mcbsp_st_chgain(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel,
+ s16 *chgain)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENOENT;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (channel == 0)
+ *chgain = st_data->ch0gain;
+ else if (channel == 1)
+ *chgain = st_data->ch1gain;
+ else
+ ret = -EINVAL;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (!st_data)
+ return -ENODEV;
+
+ spin_lock_irq(&mcbsp->lock);
+ st_data->enabled = 1;
+ omap_mcbsp_st_start(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return 0;
+}
+
+static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENODEV;
+
+ spin_lock_irq(&mcbsp->lock);
+ omap_mcbsp_st_stop(mcbsp);
+ st_data->enabled = 0;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (!st_data)
+ return -ENODEV;
+
+ return st_data->enabled;
+}
+
+static ssize_t st_taps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ ssize_t status = 0;
+ int i;
+
+ spin_lock_irq(&mcbsp->lock);
+ for (i = 0; i < st_data->nr_taps; i++)
+ status += sprintf(&buf[status], (i ? ", %d" : "%d"),
+ st_data->taps[i]);
+ if (i)
+ status += sprintf(&buf[status], "\n");
+ spin_unlock_irq(&mcbsp->lock);
+
+ return status;
+}
+
+static ssize_t st_taps_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int val, tmp, status, i = 0;
+
+ spin_lock_irq(&mcbsp->lock);
+ memset(st_data->taps, 0, sizeof(st_data->taps));
+ st_data->nr_taps = 0;
+
+ do {
+ status = sscanf(buf, "%d%n", &val, &tmp);
+ if (status < 0 || status == 0) {
+ size = -EINVAL;
+ goto out;
+ }
+ if (val < -32768 || val > 32767) {
+ size = -EINVAL;
+ goto out;
+ }
+ st_data->taps[i++] = val;
+ buf += tmp;
+ if (*buf != ',')
+ break;
+ buf++;
+ } while (1);
+
+ st_data->nr_taps = i;
+
+out:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(st_taps);
+
+static const struct attribute *sidetone_attrs[] = {
+ &dev_attr_st_taps.attr,
+ NULL,
+};
+
+static const struct attribute_group sidetone_attr_group = {
+ .attrs = (struct attribute **)sidetone_attrs,
+};
+
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->enabled && !st_data->running) {
+ omap_mcbsp_st_fir_write(mcbsp, st_data->taps);
+ omap_mcbsp_st_chgain(mcbsp);
+
+ if (!mcbsp->free) {
+ omap_mcbsp_st_on(mcbsp);
+ st_data->running = 1;
+ }
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->running) {
+ if (!mcbsp->free) {
+ omap_mcbsp_st_off(mcbsp);
+ st_data->running = 0;
+ }
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_st_init(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+ struct omap_mcbsp_st_data *st_data;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+ if (!res)
+ return 0;
+
+ st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
+ if (!st_data)
+ return -ENOMEM;
+
+ st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+ if (IS_ERR(st_data->mcbsp_iclk)) {
+ dev_warn(mcbsp->dev,
+ "Failed to get ick, sidetone might be broken\n");
+ st_data->mcbsp_iclk = NULL;
+ }
+
+ st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
+ resource_size(res));
+ if (!st_data->io_base_st)
+ return -ENOMEM;
+
+ ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ if (ret)
+ return ret;
+
+ mcbsp->st_data = st_data;
+
+ return 0;
+}
+
+void omap_mcbsp_st_cleanup(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
+ if (mcbsp->st_data) {
+ sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ clk_put(mcbsp->st_data->mcbsp_iclk);
+ }
+}
+
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int max = mc->max;
+ int min = mc->min;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = min;
+ uinfo->value.integer.max = max;
+ return 0;
+}
+
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
+static int \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+ struct snd_ctl_elem_value *uc) \
+{ \
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
+ struct soc_mixer_control *mc = \
+ (struct soc_mixer_control *)kc->private_value; \
+ int max = mc->max; \
+ int min = mc->min; \
+ int val = uc->value.integer.value[0]; \
+ \
+ if (val < min || val > max) \
+ return -EINVAL; \
+ \
+ /* OMAP McBSP implementation uses index values 0..4 */ \
+ return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \
+} \
+ \
+static int \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+ struct snd_ctl_elem_value *uc) \
+{ \
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
+ s16 chgain; \
+ \
+ if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \
+ return -EAGAIN; \
+ \
+ uc->value.integer.value[0] = chgain; \
+ return 0; \
+}
+
+OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
+
+static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+ u8 value = ucontrol->value.integer.value[0];
+
+ if (value == omap_mcbsp_st_is_enabled(mcbsp))
+ return 0;
+
+ if (value)
+ omap_mcbsp_st_enable(mcbsp);
+ else
+ omap_mcbsp_st_disable(mcbsp);
+
+ return 1;
+}
+
+static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp);
+ return 0;
+}
+
+#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
+ xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = omap_mcbsp_st_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.min = xmin, .max = xmax} }
+
+#define OMAP_MCBSP_ST_CONTROLS(port) \
+static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
+SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
+ omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
+ -32768, 32767, \
+ omap_mcbsp_get_st_ch0_volume, \
+ omap_mcbsp_set_st_ch0_volume), \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
+ -32768, 32767, \
+ omap_mcbsp_get_st_ch1_volume, \
+ omap_mcbsp_set_st_ch1_volume), \
+}
+
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
+
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (!mcbsp->st_data) {
+ dev_warn(mcbsp->dev, "No sidetone data for port\n");
+ return 0;
+ }
+
+ switch (port_id) {
+ case 2: /* McBSP 2 */
+ return snd_soc_add_dai_controls(cpu_dai,
+ omap_mcbsp2_st_controls,
+ ARRAY_SIZE(omap_mcbsp2_st_controls));
+ case 3: /* McBSP 3 */
+ return snd_soc_add_dai_controls(cpu_dai,
+ omap_mcbsp3_st_controls,
+ ARRAY_SIZE(omap_mcbsp3_st_controls));
+ default:
+ dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index 2d6decbfc99e..a395598f1f20 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -35,21 +35,12 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include "mcbsp.h"
+#include "omap-mcbsp-priv.h"
#include "omap-mcbsp.h"
#include "sdma-pcm.h"
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
-#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
- xhandler_get, xhandler_put) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = omap_mcbsp_st_info_volsw, \
- .get = xhandler_get, .put = xhandler_put, \
- .private_value = (unsigned long) &(struct soc_mixer_control) \
- {.min = xmin, .max = xmax} }
-
enum {
OMAP_MCBSP_WORD_8 = 0,
OMAP_MCBSP_WORD_12,
@@ -59,6 +50,699 @@ enum {
OMAP_MCBSP_WORD_32,
};
+static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
+{
+ dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+ dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2));
+ dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1));
+ dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2));
+ dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1));
+ dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2));
+ dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1));
+ dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2));
+ dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1));
+ dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2));
+ dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1));
+ dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2));
+ dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1));
+ dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0));
+ dev_dbg(mcbsp->dev, "***********************\n");
+}
+
+static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
+{
+ struct clk *fck_src;
+ const char *src;
+ int r;
+
+ if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+ src = "pad_fck";
+ else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+ src = "prcm_fck";
+ else
+ return -EINVAL;
+
+ fck_src = clk_get(mcbsp->dev, src);
+ if (IS_ERR(fck_src)) {
+ dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
+ return -EINVAL;
+ }
+
+ pm_runtime_put_sync(mcbsp->dev);
+
+ r = clk_set_parent(mcbsp->fclk, fck_src);
+ if (r) {
+ dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
+ src);
+ clk_put(fck_src);
+ return r;
+ }
+
+ pm_runtime_get_sync(mcbsp->dev);
+
+ clk_put(fck_src);
+
+ return 0;
+}
+
+static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst;
+
+ irqst = MCBSP_READ(mcbsp, IRQST);
+ dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
+
+ if (irqst & RSYNCERREN)
+ dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
+ if (irqst & RFSREN)
+ dev_dbg(mcbsp->dev, "RX Frame Sync\n");
+ if (irqst & REOFEN)
+ dev_dbg(mcbsp->dev, "RX End Of Frame\n");
+ if (irqst & RRDYEN)
+ dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
+ if (irqst & RUNDFLEN)
+ dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
+ if (irqst & ROVFLEN)
+ dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
+
+ if (irqst & XSYNCERREN)
+ dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
+ if (irqst & XFSXEN)
+ dev_dbg(mcbsp->dev, "TX Frame Sync\n");
+ if (irqst & XEOFEN)
+ dev_dbg(mcbsp->dev, "TX End Of Frame\n");
+ if (irqst & XRDYEN)
+ dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
+ if (irqst & XUNDFLEN)
+ dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
+ if (irqst & XOVFLEN)
+ dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
+ if (irqst & XEMPTYEOFEN)
+ dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
+
+ MCBSP_WRITE(mcbsp, IRQST, irqst);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst_spcr2;
+
+ irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
+ dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
+
+ if (irqst_spcr2 & XSYNC_ERR) {
+ dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
+ irqst_spcr2);
+ /* Writing zero to XSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst_spcr1;
+
+ irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
+ dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
+
+ if (irqst_spcr1 & RSYNC_ERR) {
+ dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
+ irqst_spcr1);
+ /* Writing zero to RSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+static void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+ const struct omap_mcbsp_reg_cfg *config)
+{
+ dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
+ mcbsp->id, mcbsp->phys_base);
+
+ /* We write the given config */
+ MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
+ MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
+ MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
+ MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
+ MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
+ MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
+ MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
+ MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
+ MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
+ MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
+ MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
+ if (mcbsp->pdata->has_ccr) {
+ MCBSP_WRITE(mcbsp, XCCR, config->xccr);
+ MCBSP_WRITE(mcbsp, RCCR, config->rccr);
+ }
+ /* Enable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
+
+ /* Enable TX/RX sync error interrupts by default */
+ if (mcbsp->irq)
+ MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
+ RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
+}
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @mcbsp: omap_mcbsp struct for the McBSP instance
+ * @stream: Stream direction (playback/capture)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data
+ */
+static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
+ unsigned int stream)
+{
+ int data_reg;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (mcbsp->pdata->reg_size == 2)
+ data_reg = OMAP_MCBSP_REG_DXR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DXR;
+ } else {
+ if (mcbsp->pdata->reg_size == 2)
+ data_reg = OMAP_MCBSP_REG_DRR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DRR;
+ }
+
+ return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
+ */
+static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (threshold && threshold <= mcbsp->max_tx_thres)
+ MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
+ */
+static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (threshold && threshold <= mcbsp->max_rx_thres)
+ MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
+ */
+static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat;
+
+ /* Returns the number of free locations in the buffer */
+ buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
+
+ /* Number of slots are different in McBSP ports */
+ return mcbsp->pdata->buffer_size - buffstat;
+}
+
+/*
+ * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
+ * to reach the threshold value (when the DMA will be triggered to read it)
+ */
+static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat, threshold;
+
+ /* Returns the number of used locations in the buffer */
+ buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
+ /* RX threshold */
+ threshold = MCBSP_READ(mcbsp, THRSH1);
+
+ /* Return the number of location till we reach the threshold limit */
+ if (threshold <= buffstat)
+ return 0;
+ else
+ return threshold - buffstat;
+}
+
+static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+ int err;
+
+ reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
+ if (!reg_cache)
+ return -ENOMEM;
+
+ spin_lock(&mcbsp->lock);
+ if (!mcbsp->free) {
+ dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id);
+ err = -EBUSY;
+ goto err_kfree;
+ }
+
+ mcbsp->free = false;
+ mcbsp->reg_cache = reg_cache;
+ spin_unlock(&mcbsp->lock);
+
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+ mcbsp->pdata->ops->request(mcbsp->id - 1);
+
+ /*
+ * Make sure that transmitter, receiver and sample-rate generator are
+ * not running before activating IRQs.
+ */
+ MCBSP_WRITE(mcbsp, SPCR1, 0);
+ MCBSP_WRITE(mcbsp, SPCR2, 0);
+
+ if (mcbsp->irq) {
+ err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
+ "McBSP", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request IRQ\n");
+ goto err_clk_disable;
+ }
+ } else {
+ err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
+ "McBSP TX", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
+ goto err_clk_disable;
+ }
+
+ err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
+ "McBSP RX", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
+ goto err_free_irq;
+ }
+ }
+
+ return 0;
+err_free_irq:
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+err_clk_disable:
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+ /* Disable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+ spin_lock(&mcbsp->lock);
+ mcbsp->free = true;
+ mcbsp->reg_cache = NULL;
+err_kfree:
+ spin_unlock(&mcbsp->lock);
+ kfree(reg_cache);
+
+ return err;
+}
+
+static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+ /* Disable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+ /* Disable interrupt requests */
+ if (mcbsp->irq)
+ MCBSP_WRITE(mcbsp, IRQEN, 0);
+
+ if (mcbsp->irq) {
+ free_irq(mcbsp->irq, (void *)mcbsp);
+ } else {
+ free_irq(mcbsp->rx_irq, (void *)mcbsp);
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+ }
+
+ reg_cache = mcbsp->reg_cache;
+
+ /*
+ * Select CLKS source from internal source unconditionally before
+ * marking the McBSP port as free.
+ * If the external clock source via MCBSP_CLKS pin has been selected the
+ * system will refuse to enter idle if the CLKS pin source is not reset
+ * back to internal source.
+ */
+ if (!mcbsp_omap1())
+ omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
+
+ spin_lock(&mcbsp->lock);
+ if (mcbsp->free)
+ dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
+ else
+ mcbsp->free = true;
+ mcbsp->reg_cache = NULL;
+ spin_unlock(&mcbsp->lock);
+
+ kfree(reg_cache);
+}
+
+/*
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
+ */
+static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
+{
+ int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int rx = !tx;
+ int enable_srg = 0;
+ u16 w;
+
+ if (mcbsp->st_data)
+ omap_mcbsp_st_start(mcbsp);
+
+ /* Only enable SRG, if McBSP is master */
+ w = MCBSP_READ_CACHE(mcbsp, PCR0);
+ if (w & (FSXM | FSRM | CLKXM | CLKRM))
+ enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+ if (enable_srg) {
+ /* Start the sample generator */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
+ }
+
+ /* Enable transmitter and receiver */
+ tx &= 1;
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | tx);
+
+ rx &= 1;
+ w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+ MCBSP_WRITE(mcbsp, SPCR1, w | rx);
+
+ /*
+ * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
+ * REVISIT: 100us may give enough time for two CLKSRG, however
+ * due to some unknown PM related, clock gating etc. reason it
+ * is now at 500us.
+ */
+ udelay(500);
+
+ if (enable_srg) {
+ /* Start frame sync */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
+ }
+
+ if (mcbsp->pdata->has_ccr) {
+ /* Release the transmitter and receiver */
+ w = MCBSP_READ_CACHE(mcbsp, XCCR);
+ w &= ~(tx ? XDISABLE : 0);
+ MCBSP_WRITE(mcbsp, XCCR, w);
+ w = MCBSP_READ_CACHE(mcbsp, RCCR);
+ w &= ~(rx ? RDISABLE : 0);
+ MCBSP_WRITE(mcbsp, RCCR, w);
+ }
+
+ /* Dump McBSP Regs */
+ omap_mcbsp_dump_reg(mcbsp);
+}
+
+static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
+{
+ int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int rx = !tx;
+ int idle;
+ u16 w;
+
+ /* Reset transmitter */
+ tx &= 1;
+ if (mcbsp->pdata->has_ccr) {
+ w = MCBSP_READ_CACHE(mcbsp, XCCR);
+ w |= (tx ? XDISABLE : 0);
+ MCBSP_WRITE(mcbsp, XCCR, w);
+ }
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
+
+ /* Reset receiver */
+ rx &= 1;
+ if (mcbsp->pdata->has_ccr) {
+ w = MCBSP_READ_CACHE(mcbsp, RCCR);
+ w |= (rx ? RDISABLE : 0);
+ MCBSP_WRITE(mcbsp, RCCR, w);
+ }
+ w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+ MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
+
+ idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+ if (idle) {
+ /* Reset the sample rate generator */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
+ }
+
+ if (mcbsp->st_data)
+ omap_mcbsp_st_stop(mcbsp);
+}
+
+#define max_thres(m) (mcbsp->pdata->buffer_size)
+#define valid_threshold(m, val) ((val) <= max_thres(m))
+#define THRESHOLD_PROP_BUILDER(prop) \
+static ssize_t prop##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%u\n", mcbsp->prop); \
+} \
+ \
+static ssize_t prop##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t size) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ unsigned long val; \
+ int status; \
+ \
+ status = kstrtoul(buf, 0, &val); \
+ if (status) \
+ return status; \
+ \
+ if (!valid_threshold(mcbsp, val)) \
+ return -EDOM; \
+ \
+ mcbsp->prop = val; \
+ return size; \
+} \
+ \
+static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store)
+
+THRESHOLD_PROP_BUILDER(max_tx_thres);
+THRESHOLD_PROP_BUILDER(max_rx_thres);
+
+static const char * const dma_op_modes[] = {
+ "element", "threshold",
+};
+
+static ssize_t dma_op_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int dma_op_mode, i = 0;
+ ssize_t len = 0;
+ const char * const *s;
+
+ dma_op_mode = mcbsp->dma_op_mode;
+
+ for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
+ if (dma_op_mode == i)
+ len += sprintf(buf + len, "[%s] ", *s);
+ else
+ len += sprintf(buf + len, "%s ", *s);
+ }
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t dma_op_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int i;
+
+ i = sysfs_match_string(dma_op_modes, buf);
+ if (i < 0)
+ return i;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (!mcbsp->free) {
+ size = -EBUSY;
+ goto unlock;
+ }
+ mcbsp->dma_op_mode = i;
+
+unlock:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(dma_op_mode);
+
+static const struct attribute *additional_attrs[] = {
+ &dev_attr_max_tx_thres.attr,
+ &dev_attr_max_rx_thres.attr,
+ &dev_attr_dma_op_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group additional_attr_group = {
+ .attrs = (struct attribute **)additional_attrs,
+};
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+static int omap_mcbsp_init(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+ struct resource *res;
+ int ret = 0;
+
+ spin_lock_init(&mcbsp->lock);
+ mcbsp->free = true;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcbsp->io_base))
+ return PTR_ERR(mcbsp->io_base);
+
+ mcbsp->phys_base = res->start;
+ mcbsp->reg_cache_size = resource_size(res);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+ if (!res)
+ mcbsp->phys_dma_base = mcbsp->phys_base;
+ else
+ mcbsp->phys_dma_base = res->start;
+
+ /*
+ * OMAP1, 2 uses two interrupt lines: TX, RX
+ * OMAP2430, OMAP3 SoC have combined IRQ line as well.
+ * OMAP4 and newer SoC only have the combined IRQ line.
+ * Use the combined IRQ if available since it gives better debugging
+ * possibilities.
+ */
+ mcbsp->irq = platform_get_irq_byname(pdev, "common");
+ if (mcbsp->irq == -ENXIO) {
+ mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
+
+ if (mcbsp->tx_irq == -ENXIO) {
+ mcbsp->irq = platform_get_irq(pdev, 0);
+ mcbsp->tx_irq = 0;
+ } else {
+ mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
+ mcbsp->irq = 0;
+ }
+ }
+
+ if (!pdev->dev.of_node) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid tx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[0] = res->start;
+ mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid rx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[1] = res->start;
+ mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+ } else {
+ mcbsp->dma_data[0].filter_data = "tx";
+ mcbsp->dma_data[1].filter_data = "rx";
+ }
+
+ mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ mcbsp->fclk = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(mcbsp->fclk)) {
+ ret = PTR_ERR(mcbsp->fclk);
+ dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
+ return ret;
+ }
+
+ mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
+ if (mcbsp->pdata->buffer_size) {
+ /*
+ * Initially configure the maximum thresholds to a safe value.
+ * The McBSP FIFO usage with these values should not go under
+ * 16 locations.
+ * If the whole FIFO without safety buffer is used, than there
+ * is a possibility that the DMA will be not able to push the
+ * new data on time, causing channel shifts in runtime.
+ */
+ mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+ mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
+
+ ret = sysfs_create_group(&mcbsp->dev->kobj,
+ &additional_attr_group);
+ if (ret) {
+ dev_err(mcbsp->dev,
+ "Unable to create additional controls\n");
+ goto err_thres;
+ }
+ }
+
+ ret = omap_mcbsp_st_init(pdev);
+ if (ret)
+ goto err_st;
+
+ return 0;
+
+err_st:
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+err_thres:
+ clk_put(mcbsp->fclk);
+ return ret;
+}
+
/*
* Stream DMA parameters. DMA request line and port address are set runtime
* since they are different between OMAP1 and later OMAPs
@@ -71,6 +755,10 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
int words;
+ /* No need to proceed further if McBSP does not have FIFO */
+ if (mcbsp->pdata->buffer_size == 0)
+ return;
+
/*
* Configure McBSP threshold based on either:
* packet_size, when the sDMA is in packet mode, or based on the
@@ -201,27 +889,26 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
- int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
mcbsp->active++;
- omap_mcbsp_start(mcbsp, play, !play);
+ omap_mcbsp_start(mcbsp, substream->stream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- omap_mcbsp_stop(mcbsp, play, !play);
+ omap_mcbsp_stop(mcbsp, substream->stream);
mcbsp->active--;
break;
default:
- err = -EINVAL;
+ return -EINVAL;
}
- return err;
+ return 0;
}
static snd_pcm_sframes_t omap_mcbsp_dai_delay(
@@ -234,6 +921,10 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
u16 fifo_use;
snd_pcm_sframes_t delay;
+ /* No need to proceed further if McBSP does not have FIFO */
+ if (mcbsp->pdata->buffer_size == 0)
+ return 0;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
else
@@ -649,132 +1340,6 @@ static const struct snd_soc_component_driver omap_mcbsp_component = {
.name = "omap-mcbsp",
};
-static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max;
- int min = mc->min;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = min;
- uinfo->value.integer.max = max;
- return 0;
-}
-
-#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
-static int \
-omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
- struct snd_ctl_elem_value *uc) \
-{ \
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
- struct soc_mixer_control *mc = \
- (struct soc_mixer_control *)kc->private_value; \
- int max = mc->max; \
- int min = mc->min; \
- int val = uc->value.integer.value[0]; \
- \
- if (val < min || val > max) \
- return -EINVAL; \
- \
- /* OMAP McBSP implementation uses index values 0..4 */ \
- return omap_st_set_chgain(mcbsp, channel, val); \
-} \
- \
-static int \
-omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
- struct snd_ctl_elem_value *uc) \
-{ \
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
- s16 chgain; \
- \
- if (omap_st_get_chgain(mcbsp, channel, &chgain)) \
- return -EAGAIN; \
- \
- uc->value.integer.value[0] = chgain; \
- return 0; \
-}
-
-OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
-
-static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
- u8 value = ucontrol->value.integer.value[0];
-
- if (value == omap_st_is_enabled(mcbsp))
- return 0;
-
- if (value)
- omap_st_enable(mcbsp);
- else
- omap_st_disable(mcbsp);
-
- return 1;
-}
-
-static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
- ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
- return 0;
-}
-
-#define OMAP_MCBSP_ST_CONTROLS(port) \
-static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
-SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
- omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
- -32768, 32767, \
- omap_mcbsp_get_st_ch0_volume, \
- omap_mcbsp_set_st_ch0_volume), \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
- -32768, 32767, \
- omap_mcbsp_get_st_ch1_volume, \
- omap_mcbsp_set_st_ch1_volume), \
-}
-
-OMAP_MCBSP_ST_CONTROLS(2);
-OMAP_MCBSP_ST_CONTROLS(3);
-
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
-{
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
- if (!mcbsp->st_data) {
- dev_warn(mcbsp->dev, "No sidetone data for port\n");
- return 0;
- }
-
- switch (port_id) {
- case 2: /* McBSP 2 */
- return snd_soc_add_dai_controls(cpu_dai,
- omap_mcbsp2_st_controls,
- ARRAY_SIZE(omap_mcbsp2_st_controls));
- case 3: /* McBSP 3 */
- return snd_soc_add_dai_controls(cpu_dai,
- omap_mcbsp3_st_controls,
- ARRAY_SIZE(omap_mcbsp3_st_controls));
- default:
- dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
- break;
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
-
static struct omap_mcbsp_platform_data omap2420_pdata = {
.reg_step = 4,
.reg_size = 2,
@@ -862,6 +1427,11 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
if (ret)
return ret;
+ if (mcbsp->pdata->reg_size == 2) {
+ omap_mcbsp_dai.playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ omap_mcbsp_dai.capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ }
+
ret = devm_snd_soc_register_component(&pdev->dev,
&omap_mcbsp_component,
&omap_mcbsp_dai, 1);
@@ -881,7 +1451,10 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
if (pm_qos_request_active(&mcbsp->pm_qos_req))
pm_qos_remove_request(&mcbsp->pm_qos_req);
- omap_mcbsp_cleanup(mcbsp);
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+
+ omap_mcbsp_st_cleanup(pdev);
clk_put(mcbsp->fclk);
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/ti/omap-mcbsp.h
index 2e3369c27be3..7911d24898c9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/ti/omap-mcbsp.h
@@ -22,8 +22,10 @@
*
*/
-#ifndef __OMAP_I2S_H__
-#define __OMAP_I2S_H__
+#ifndef __OMAP_MCBSP_H__
+#define __OMAP_MCBSP_H__
+
+#include <sound/dmaengine_pcm.h>
/* Source clocks for McBSP sample rate generator */
enum omap_mcbsp_clksrg_clk {
@@ -41,4 +43,4 @@ enum omap_mcbsp_div {
int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
-#endif
+#endif /* __OMAP_MCBSP_H__ */
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c
index 7d5bdc5a2890..7d5bdc5a2890 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/ti/omap-mcpdm.c
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/ti/omap-mcpdm.h
index de8cf26595b1..de8cf26595b1 100644
--- a/sound/soc/omap/omap-mcpdm.h
+++ b/sound/soc/ti/omap-mcpdm.h
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c
index cccc316743fa..cccc316743fa 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/ti/omap-twl4030.c
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/ti/omap3pandora.c
index 4e3de712159c..4e3de712159c 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/ti/omap3pandora.c
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/ti/osk5912.c
index e4096779ca05..e4096779ca05 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/ti/osk5912.c
diff --git a/sound/soc/omap/rx51.c b/sound/soc/ti/rx51.c
index 57448bd5ad77..57448bd5ad77 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/ti/rx51.c
diff --git a/sound/soc/omap/sdma-pcm.c b/sound/soc/ti/sdma-pcm.c
index 21a9c2499d48..21a9c2499d48 100644
--- a/sound/soc/omap/sdma-pcm.c
+++ b/sound/soc/ti/sdma-pcm.c
diff --git a/sound/soc/omap/sdma-pcm.h b/sound/soc/ti/sdma-pcm.h
index 34a7f90b2587..cb0627c8dd34 100644
--- a/sound/soc/omap/sdma-pcm.h
+++ b/sound/soc/ti/sdma-pcm.h
@@ -7,7 +7,7 @@
#ifndef __SDMA_PCM_H__
#define __SDMA_PCM_H__
-#if IS_ENABLED(CONFIG_SND_SDMA_SOC)
+#if IS_ENABLED(CONFIG_SND_SOC_TI_SDMA_PCM)
int sdma_pcm_platform_register(struct device *dev,
char *txdmachan, char *rxdmachan);
#else
@@ -16,6 +16,6 @@ static inline int sdma_pcm_platform_register(struct device *dev,
{
return -ENODEV;
}
-#endif /* CONFIG_SND_SDMA_SOC */
+#endif /* CONFIG_SND_SOC_TI_SDMA_PCM */
#endif /* __SDMA_PCM_H__ */
diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig
new file mode 100644
index 000000000000..25e287feb58c
--- /dev/null
+++ b/sound/soc/xilinx/Kconfig
@@ -0,0 +1,8 @@
+config SND_SOC_XILINX_I2S
+ tristate "Audio support for the the Xilinx I2S"
+ help
+ Select this option to enable Xilinx I2S Audio. This enables
+ I2S playback and capture using xilinx soft IP. In transmitter
+ mode, IP receives audio in AES format, extracts PCM and sends
+ PCM data. In receiver mode, IP receives PCM audio and
+ encapsulates PCM in AES format and sends AES data.
diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile
new file mode 100644
index 000000000000..6c1209b9ee75
--- /dev/null
+++ b/sound/soc/xilinx/Makefile
@@ -0,0 +1,2 @@
+snd-soc-xlnx-i2s-objs := xlnx_i2s.o
+obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o
diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c
new file mode 100644
index 000000000000..d4ae9eff41ce
--- /dev/null
+++ b/sound/soc/xilinx/xlnx_i2s.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx ASoC I2S audio support
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Author: Praveen Vuppala <praveenv@xilinx.com>
+ * Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "xlnx_i2s"
+
+#define I2S_CORE_CTRL_OFFSET 0x08
+#define I2S_I2STIM_OFFSET 0x20
+#define I2S_CH0_OFFSET 0x30
+#define I2S_I2STIM_VALID_MASK GENMASK(7, 0)
+
+static int xlnx_i2s_set_sclkout_div(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ void __iomem *base = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (!div || (div & ~I2S_I2STIM_VALID_MASK))
+ return -EINVAL;
+
+ writel(div, base + I2S_I2STIM_OFFSET);
+
+ return 0;
+}
+
+static int xlnx_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *i2s_dai)
+{
+ u32 reg_off, chan_id;
+ void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai);
+
+ chan_id = params_channels(params) / 2;
+
+ while (chan_id > 0) {
+ reg_off = I2S_CH0_OFFSET + ((chan_id - 1) * 4);
+ writel(chan_id, base + reg_off);
+ chan_id--;
+ }
+
+ return 0;
+}
+
+static int xlnx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *i2s_dai)
+{
+ void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ writel(1, base + I2S_CORE_CTRL_OFFSET);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ writel(0, base + I2S_CORE_CTRL_OFFSET);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = {
+ .trigger = xlnx_i2s_trigger,
+ .set_clkdiv = xlnx_i2s_set_sclkout_div,
+ .hw_params = xlnx_i2s_hw_params
+};
+
+static const struct snd_soc_component_driver xlnx_i2s_component = {
+ .name = DRV_NAME,
+};
+
+static const struct of_device_id xlnx_i2s_of_match[] = {
+ { .compatible = "xlnx,i2s-transmitter-1.0", },
+ { .compatible = "xlnx,i2s-receiver-1.0", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match);
+
+static int xlnx_i2s_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *base;
+ struct snd_soc_dai_driver *dai_drv;
+ int ret;
+ u32 ch, format, data_width;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+
+ dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ret = of_property_read_u32(node, "xlnx,num-channels", &ch);
+ if (ret < 0) {
+ dev_err(dev, "cannot get supported channels\n");
+ return ret;
+ }
+ ch = ch * 2;
+
+ ret = of_property_read_u32(node, "xlnx,dwidth", &data_width);
+ if (ret < 0) {
+ dev_err(dev, "cannot get data width\n");
+ return ret;
+ }
+ switch (data_width) {
+ case 16:
+ format = SNDRV_PCM_FMTBIT_S16_LE;
+ break;
+ case 24:
+ format = SNDRV_PCM_FMTBIT_S24_LE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) {
+ dai_drv->name = "xlnx_i2s_playback";
+ dai_drv->playback.stream_name = "Playback";
+ dai_drv->playback.formats = format;
+ dai_drv->playback.channels_min = ch;
+ dai_drv->playback.channels_max = ch;
+ dai_drv->playback.rates = SNDRV_PCM_RATE_8000_192000;
+ dai_drv->ops = &xlnx_i2s_dai_ops;
+ } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) {
+ dai_drv->name = "xlnx_i2s_capture";
+ dai_drv->capture.stream_name = "Capture";
+ dai_drv->capture.formats = format;
+ dai_drv->capture.channels_min = ch;
+ dai_drv->capture.channels_max = ch;
+ dai_drv->capture.rates = SNDRV_PCM_RATE_8000_192000;
+ dai_drv->ops = &xlnx_i2s_dai_ops;
+ } else {
+ return -ENODEV;
+ }
+
+ dev_set_drvdata(&pdev->dev, base);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component,
+ dai_drv, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "i2s component registration failed\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "%s DAI registered\n", dai_drv->name);
+
+ return ret;
+}
+
+static struct platform_driver xlnx_i2s_aud_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = xlnx_i2s_of_match,
+ },
+ .probe = xlnx_i2s_probe,
+};
+
+module_platform_driver(xlnx_i2s_aud_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Praveen Vuppala <praveenv@xilinx.com>");
+MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index e557946718a9..d9fcae071b47 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -22,9 +22,9 @@
#include <sound/core.h>
#include <sound/hwdep.h>
#include <linux/uaccess.h>
+#include <linux/nospec.h>
#include "emux_voice.h"
-
#define TMP_CLIENT_ID 0x1001
/*
@@ -66,13 +66,16 @@ snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg)
return -EFAULT;
if (info.mode < 0 || info.mode >= EMUX_MD_END)
return -EINVAL;
+ info.mode = array_index_nospec(info.mode, EMUX_MD_END);
if (info.port < 0) {
for (i = 0; i < emu->num_ports; i++)
emu->portptrs[i]->ctrls[info.mode] = info.value;
} else {
- if (info.port < emu->num_ports)
+ if (info.port < emu->num_ports) {
+ info.port = array_index_nospec(info.port, emu->num_ports);
emu->portptrs[info.port]->ctrls[info.mode] = info.value;
+ }
}
return 0;
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 6623cafc94f2..96340f23f86d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -19,6 +19,7 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
+#include <linux/bits.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -668,15 +669,133 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
}
/*
- * C-Media CM6206 is based on CM106 with two additional
- * registers that are not documented in the data sheet.
- * Values here are chosen based on sniffing USB traffic
- * under Windows.
+ * CM6206 registers from the CM6206 datasheet rev 2.1
*/
+#define CM6206_REG0_DMA_MASTER BIT(15)
+#define CM6206_REG0_SPDIFO_RATE_48K (2 << 12)
+#define CM6206_REG0_SPDIFO_RATE_96K (7 << 12)
+/* Bit 4 thru 11 is the S/PDIF category code */
+#define CM6206_REG0_SPDIFO_CAT_CODE_GENERAL (0 << 4)
+#define CM6206_REG0_SPDIFO_EMPHASIS_CD BIT(3)
+#define CM6206_REG0_SPDIFO_COPYRIGHT_NA BIT(2)
+#define CM6206_REG0_SPDIFO_NON_AUDIO BIT(1)
+#define CM6206_REG0_SPDIFO_PRO_FORMAT BIT(0)
+
+#define CM6206_REG1_TEST_SEL_CLK BIT(14)
+#define CM6206_REG1_PLLBIN_EN BIT(13)
+#define CM6206_REG1_SOFT_MUTE_EN BIT(12)
+#define CM6206_REG1_GPIO4_OUT BIT(11)
+#define CM6206_REG1_GPIO4_OE BIT(10)
+#define CM6206_REG1_GPIO3_OUT BIT(9)
+#define CM6206_REG1_GPIO3_OE BIT(8)
+#define CM6206_REG1_GPIO2_OUT BIT(7)
+#define CM6206_REG1_GPIO2_OE BIT(6)
+#define CM6206_REG1_GPIO1_OUT BIT(5)
+#define CM6206_REG1_GPIO1_OE BIT(4)
+#define CM6206_REG1_SPDIFO_INVALID BIT(3)
+#define CM6206_REG1_SPDIF_LOOP_EN BIT(2)
+#define CM6206_REG1_SPDIFO_DIS BIT(1)
+#define CM6206_REG1_SPDIFI_MIX BIT(0)
+
+#define CM6206_REG2_DRIVER_ON BIT(15)
+#define CM6206_REG2_HEADP_SEL_SIDE_CHANNELS (0 << 13)
+#define CM6206_REG2_HEADP_SEL_SURROUND_CHANNELS (1 << 13)
+#define CM6206_REG2_HEADP_SEL_CENTER_SUBW (2 << 13)
+#define CM6206_REG2_HEADP_SEL_FRONT_CHANNELS (3 << 13)
+#define CM6206_REG2_MUTE_HEADPHONE_RIGHT BIT(12)
+#define CM6206_REG2_MUTE_HEADPHONE_LEFT BIT(11)
+#define CM6206_REG2_MUTE_REAR_SURROUND_RIGHT BIT(10)
+#define CM6206_REG2_MUTE_REAR_SURROUND_LEFT BIT(9)
+#define CM6206_REG2_MUTE_SIDE_SURROUND_RIGHT BIT(8)
+#define CM6206_REG2_MUTE_SIDE_SURROUND_LEFT BIT(7)
+#define CM6206_REG2_MUTE_SUBWOOFER BIT(6)
+#define CM6206_REG2_MUTE_CENTER BIT(5)
+#define CM6206_REG2_MUTE_RIGHT_FRONT BIT(3)
+#define CM6206_REG2_MUTE_LEFT_FRONT BIT(3)
+#define CM6206_REG2_EN_BTL BIT(2)
+#define CM6206_REG2_MCUCLKSEL_1_5_MHZ (0)
+#define CM6206_REG2_MCUCLKSEL_3_MHZ (1)
+#define CM6206_REG2_MCUCLKSEL_6_MHZ (2)
+#define CM6206_REG2_MCUCLKSEL_12_MHZ (3)
+
+/* Bit 11..13 sets the sensitivity to FLY tuner volume control VP/VD signal */
+#define CM6206_REG3_FLYSPEED_DEFAULT (2 << 11)
+#define CM6206_REG3_VRAP25EN BIT(10)
+#define CM6206_REG3_MSEL1 BIT(9)
+#define CM6206_REG3_SPDIFI_RATE_44_1K BIT(0 << 7)
+#define CM6206_REG3_SPDIFI_RATE_48K BIT(2 << 7)
+#define CM6206_REG3_SPDIFI_RATE_32K BIT(3 << 7)
+#define CM6206_REG3_PINSEL BIT(6)
+#define CM6206_REG3_FOE BIT(5)
+#define CM6206_REG3_ROE BIT(4)
+#define CM6206_REG3_CBOE BIT(3)
+#define CM6206_REG3_LOSE BIT(2)
+#define CM6206_REG3_HPOE BIT(1)
+#define CM6206_REG3_SPDIFI_CANREC BIT(0)
+
+#define CM6206_REG5_DA_RSTN BIT(13)
+#define CM6206_REG5_AD_RSTN BIT(12)
+#define CM6206_REG5_SPDIFO_AD2SPDO BIT(12)
+#define CM6206_REG5_SPDIFO_SEL_FRONT (0 << 9)
+#define CM6206_REG5_SPDIFO_SEL_SIDE_SUR (1 << 9)
+#define CM6206_REG5_SPDIFO_SEL_CEN_LFE (2 << 9)
+#define CM6206_REG5_SPDIFO_SEL_REAR_SUR (3 << 9)
+#define CM6206_REG5_CODECM BIT(8)
+#define CM6206_REG5_EN_HPF BIT(7)
+#define CM6206_REG5_T_SEL_DSDA4 BIT(6)
+#define CM6206_REG5_T_SEL_DSDA3 BIT(5)
+#define CM6206_REG5_T_SEL_DSDA2 BIT(4)
+#define CM6206_REG5_T_SEL_DSDA1 BIT(3)
+#define CM6206_REG5_T_SEL_DSDAD_NORMAL 0
+#define CM6206_REG5_T_SEL_DSDAD_FRONT 4
+#define CM6206_REG5_T_SEL_DSDAD_S_SURROUND 5
+#define CM6206_REG5_T_SEL_DSDAD_CEN_LFE 6
+#define CM6206_REG5_T_SEL_DSDAD_R_SURROUND 7
+
static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
{
int err = 0, reg;
- int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
+ int val[] = {
+ /*
+ * Values here are chosen based on sniffing USB traffic
+ * under Windows.
+ *
+ * REG0: DAC is master, sample rate 48kHz, no copyright
+ */
+ CM6206_REG0_SPDIFO_RATE_48K |
+ CM6206_REG0_SPDIFO_COPYRIGHT_NA,
+ /*
+ * REG1: PLL binary search enable, soft mute enable.
+ */
+ CM6206_REG1_PLLBIN_EN |
+ CM6206_REG1_SOFT_MUTE_EN |
+ /*
+ * REG2: enable output drivers,
+ * select front channels to the headphone output,
+ * then mute the headphone channels, run the MCU
+ * at 1.5 MHz.
+ */
+ CM6206_REG2_DRIVER_ON |
+ CM6206_REG2_HEADP_SEL_FRONT_CHANNELS |
+ CM6206_REG2_MUTE_HEADPHONE_RIGHT |
+ CM6206_REG2_MUTE_HEADPHONE_LEFT,
+ /*
+ * REG3: default flyspeed, set 2.5V mic bias
+ * enable all line out ports and enable SPDIF
+ */
+ CM6206_REG3_FLYSPEED_DEFAULT |
+ CM6206_REG3_VRAP25EN |
+ CM6206_REG3_FOE |
+ CM6206_REG3_ROE |
+ CM6206_REG3_CBOE |
+ CM6206_REG3_LOSE |
+ CM6206_REG3_HPOE |
+ CM6206_REG3_SPDIFI_CANREC,
+ /* REG4 is just a bunch of GPIO lines */
+ 0x0000,
+ /* REG5: de-assert AD/DA reset signals */
+ CM6206_REG5_DA_RSTN |
+ CM6206_REG5_AD_RSTN };
for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);