aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/gtm601.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,sdm845.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml175
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml68
-rw-r--r--include/sound/soc.h34
-rw-r--r--include/sound/sof.h9
-rw-r--r--include/sound/sof/channel_map.h61
-rw-r--r--include/sound/sof/dai-imx.h20
-rw-r--r--include/sound/sof/dai.h1
-rw-r--r--include/sound/sof/info.h15
-rw-r--r--include/sound/sof/topology.h27
-rw-r--r--include/uapi/sound/sof/abi.h2
-rw-r--r--include/uapi/sound/sof/tokens.h9
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c46
-rw-r--r--sound/soc/amd/acp-pcm-dma.c59
-rw-r--r--sound/soc/amd/raven/Makefile2
-rw-r--r--sound/soc/amd/raven/acp3x-i2s.c358
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c679
-rw-r--r--sound/soc/amd/raven/acp3x.h115
-rw-r--r--sound/soc/amd/raven/pci-acp3x.c258
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c1
-rw-r--r--sound/soc/au1x/dbdma2.c15
-rw-r--r--sound/soc/au1x/dma.c22
-rw-r--r--sound/soc/bcm/cygnus-pcm.c1
-rw-r--r--sound/soc/codecs/Kconfig18
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/cros_ec_codec.c8
-rw-r--r--sound/soc/codecs/cs42l51.c16
-rw-r--r--sound/soc/codecs/cs47l15.c8
-rw-r--r--sound/soc/codecs/cs47l35.c6
-rw-r--r--sound/soc/codecs/cs47l85.c11
-rw-r--r--sound/soc/codecs/cs47l90.c11
-rw-r--r--sound/soc/codecs/cs47l92.c62
-rw-r--r--sound/soc/codecs/gtm601.c32
-rw-r--r--sound/soc/codecs/hdac_hda.c16
-rw-r--r--sound/soc/codecs/hdac_hda.h3
-rw-r--r--sound/soc/codecs/hdac_hdmi.c63
-rw-r--r--sound/soc/codecs/hdmi-codec.c32
-rw-r--r--sound/soc/codecs/madera.c162
-rw-r--r--sound/soc/codecs/madera.h2
-rw-r--r--sound/soc/codecs/max98090.c472
-rw-r--r--sound/soc/codecs/max98090.h5
-rw-r--r--sound/soc/codecs/rt5514-spi.c10
-rw-r--r--sound/soc/codecs/rt5677-spi.c10
-rw-r--r--sound/soc/codecs/rt5677-spi.h16
-rw-r--r--sound/soc/codecs/rt5682.c2
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c40
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h3
-rw-r--r--sound/soc/codecs/wcd934x.c5084
-rw-r--r--sound/soc/codecs/wm8904.c6
-rw-r--r--sound/soc/codecs/wm8962.c4
-rw-r--r--sound/soc/codecs/wsa881x.c1185
-rw-r--r--sound/soc/dwc/dwc-pcm.c25
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c2
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c1
-rw-r--r--sound/soc/fsl/fsl_audmix.c9
-rw-r--r--sound/soc/fsl/fsl_dma.c1
-rw-r--r--sound/soc/fsl/fsl_sai.c3
-rw-r--r--sound/soc/fsl/imx-audmix.c2
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c1
-rw-r--r--sound/soc/fsl/mpc5200_dma.c1
-rw-r--r--sound/soc/generic/simple-card.c6
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c26
-rw-r--r--sound/soc/intel/atom/sst/sst.c1
-rw-r--r--sound/soc/intel/baytrail/sst-baytrail-pcm.c20
-rw-r--r--sound/soc/intel/boards/Kconfig48
-rw-r--r--sound/soc/intel/boards/Makefile5
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c319
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c13
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c18
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c22
-rw-r--r--sound/soc/intel/boards/cml_rt1011_rt5682.c8
-rw-r--r--sound/soc/intel/boards/hda_dsp_common.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c13
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c8
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c4
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c4
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c8
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c4
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c371
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c43
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cml-match.c41
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c7
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-jsl-match.c7
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c13
-rw-r--r--sound/soc/intel/haswell/sst-haswell-pcm.c18
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c27
-rw-r--r--sound/soc/intel/skylake/skl.c7
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c1
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c365
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.h16
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.c13
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.h2
-rw-r--r--sound/soc/mediatek/common/mtk-base-afe.h28
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c1
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c2
-rw-r--r--sound/soc/meson/axg-fifo.c61
-rw-r--r--sound/soc/meson/axg-fifo.h9
-rw-r--r--sound/soc/meson/axg-frddr.c36
-rw-r--r--sound/soc/meson/axg-toddr.c24
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c2
-rw-r--r--sound/soc/pxa/mmp-pcm.c1
-rw-r--r--sound/soc/pxa/pxa-ssp.c1
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c1
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c1
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c1
-rw-r--r--sound/soc/qcom/lpass-platform.c1
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c3
-rw-r--r--sound/soc/qcom/sdm845.c86
-rw-r--r--sound/soc/samsung/bells.c14
-rw-r--r--sound/soc/samsung/idma.c1
-rw-r--r--sound/soc/samsung/littlemill.c10
-rw-r--r--sound/soc/samsung/lowland.c2
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c2
-rw-r--r--sound/soc/samsung/snow.c2
-rw-r--r--sound/soc/samsung/speyside.c6
-rw-r--r--sound/soc/samsung/tm2_wm5110.c6
-rw-r--r--sound/soc/samsung/tobermory.c6
-rw-r--r--sound/soc/sh/dma-sh7760.c15
-rw-r--r--sound/soc/sh/fsi.c19
-rw-r--r--sound/soc/sh/rcar/core.c57
-rw-r--r--sound/soc/sh/siu_pcm.c40
-rw-r--r--sound/soc/soc-compress.c35
-rw-r--r--sound/soc/soc-core.c444
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c14
-rw-r--r--sound/soc/soc-pcm.c11
-rw-r--r--sound/soc/soc-topology.c117
-rw-r--r--sound/soc/soc-utils.c1
-rw-r--r--sound/soc/sof/Kconfig2
-rw-r--r--sound/soc/sof/Makefile2
-rw-r--r--sound/soc/sof/control.c55
-rw-r--r--sound/soc/sof/core.c288
-rw-r--r--sound/soc/sof/imx/imx8.c8
-rw-r--r--sound/soc/sof/intel/Kconfig1
-rw-r--r--sound/soc/sof/intel/apl.c14
-rw-r--r--sound/soc/sof/intel/bdw.c41
-rw-r--r--sound/soc/sof/intel/byt.c135
-rw-r--r--sound/soc/sof/intel/cnl.c26
-rw-r--r--sound/soc/sof/intel/hda-codec.c38
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c13
-rw-r--r--sound/soc/sof/intel/hda-dai.c16
-rw-r--r--sound/soc/sof/intel/hda-ipc.c23
-rw-r--r--sound/soc/sof/intel/hda-loader.c1
-rw-r--r--sound/soc/sof/intel/hda-pcm.c4
-rw-r--r--sound/soc/sof/intel/hda-stream.c21
-rw-r--r--sound/soc/sof/intel/hda.c304
-rw-r--r--sound/soc/sof/intel/hda.h19
-rw-r--r--sound/soc/sof/intel/intel-ipc.c8
-rw-r--r--sound/soc/sof/intel/shim.h6
-rw-r--r--sound/soc/sof/ipc.c36
-rw-r--r--sound/soc/sof/loader.c68
-rw-r--r--sound/soc/sof/nocodec.c12
-rw-r--r--sound/soc/sof/ops.h34
-rw-r--r--sound/soc/sof/pcm.c172
-rw-r--r--sound/soc/sof/pm.c240
-rw-r--r--sound/soc/sof/sof-acpi-dev.c63
-rw-r--r--sound/soc/sof/sof-audio.c445
-rw-r--r--sound/soc/sof/sof-audio.h211
-rw-r--r--sound/soc/sof/sof-of-dev.c24
-rw-r--r--sound/soc/sof/sof-pci-dev.c103
-rw-r--r--sound/soc/sof/sof-priv.h214
-rw-r--r--sound/soc/sof/topology.c525
-rw-r--r--sound/soc/sof/trace.c4
-rw-r--r--sound/soc/sof/utils.c60
-rw-r--r--sound/soc/sof/xtensa/core.c2
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c1
-rw-r--r--sound/soc/stm/stm32_adfsdm.c29
-rw-r--r--sound/soc/stm/stm32_spdifrx.c40
-rw-r--r--sound/soc/tegra/tegra_wm8903.c2
-rw-r--r--sound/soc/ti/davinci-mcasp.c35
-rw-r--r--sound/soc/ti/davinci-mcasp.h4
-rw-r--r--sound/soc/ti/rx51.c12
-rw-r--r--sound/soc/txx9/txx9aclc.c15
-rw-r--r--sound/soc/uniphier/aio-dma.c31
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c14
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c10
181 files changed, 12115 insertions, 3176 deletions
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
index 3080979350a0..fa4545ed81ca 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
@@ -17,6 +17,9 @@ Required properties:
* "arb" : memory ARB line (required)
* "rst" : dedicated device reset line (optional)
- #sound-dai-cells: must be 0.
+- amlogic,fifo-depth: The size of the controller's fifo in bytes. This
+ is useful for determining certain configuration such
+ as the flush threshold of the fifo
Example of FRDDR A on the A113 SoC:
@@ -27,4 +30,5 @@ frddr_a: audio-controller@1c0 {
interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
resets = <&arb AXG_ARB_FRDDR_A>;
+ fifo-depth = <512>;
};
diff --git a/Documentation/devicetree/bindings/sound/gtm601.txt b/Documentation/devicetree/bindings/sound/gtm601.txt
index 5efc8c068de0..efa32a486c4a 100644
--- a/Documentation/devicetree/bindings/sound/gtm601.txt
+++ b/Documentation/devicetree/bindings/sound/gtm601.txt
@@ -1,10 +1,16 @@
GTM601 UMTS modem audio interface CODEC
-This device has no configuration interface. Sample rate is fixed - 8kHz.
+This device has no configuration interface. The sample rate and channels are
+based on the compatible string
+ "option,gtm601" = 8kHz mono
+ "broadmobi,bm818" = 48KHz stereo
Required properties:
- - compatible : "option,gtm601"
+ - compatible : one of
+ "option,gtm601"
+ "broadmobi,bm818"
+
Example:
diff --git a/Documentation/devicetree/bindings/sound/qcom,sdm845.txt b/Documentation/devicetree/bindings/sound/qcom,sdm845.txt
index 408c4837e6d5..ca8c89e88bfa 100644
--- a/Documentation/devicetree/bindings/sound/qcom,sdm845.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,sdm845.txt
@@ -5,7 +5,10 @@ This binding describes the SDM845 sound card, which uses qdsp for audio.
- compatible:
Usage: required
Value type: <stringlist>
- Definition: must be "qcom,sdm845-sndcard"
+ Definition: must be one of this
+ "qcom,sdm845-sndcard"
+ "qcom,db845c-sndcard"
+ "lenovo,yoga-c630-sndcard"
- audio-routing:
Usage: Optional
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml
new file mode 100644
index 000000000000..38eaf0c028f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd934x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm WCD9340/WCD9341 Audio Codec
+
+maintainers:
+ - Srinivas Kandagatla <[email protected]>
+
+description: |
+ Qualcomm WCD9340/WCD9341 Codec is a standalone Hi-Fi audio codec IC.
+ It has in-built Soundwire controller, pin controller, interrupt mux and
+ supports both I2S/I2C and SLIMbus audio interfaces.
+
+properties:
+ compatible:
+ const: slim217,250
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ description: GPIO spec for reset line to use
+ maxItems: 1
+
+ slim-ifc-dev: true
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: extclk
+
+ vdd-buck-supply:
+ description: A reference to the 1.8V buck supply
+
+ vdd-buck-sido-supply:
+ description: A reference to the 1.8V SIDO buck supply
+
+ vdd-rx-supply:
+ description: A reference to the 1.8V rx supply
+
+ vdd-tx-supply:
+ description: A reference to the 1.8V tx supply
+
+ vdd-vbat-supply:
+ description: A reference to the vbat supply
+
+ vdd-io-supply:
+ description: A reference to the 1.8V I/O supply
+
+ vdd-micbias-supply:
+ description: A reference to the micbias supply
+
+ qcom,micbias1-microvolt:
+ description: micbias1 voltage
+ minimum: 1800000
+ maximum: 2850000
+
+ qcom,micbias2-microvolt:
+ description: micbias2 voltage
+ minimum: 1800000
+ maximum: 2850000
+
+ qcom,micbias3-microvolt:
+ description: micbias3 voltage
+ minimum: 1800000
+ maximum: 2850000
+
+ qcom,micbias4-microvolt:
+ description: micbias4 voltage
+ minimum: 1800000
+ maximum: 2850000
+
+ clock-output-names:
+ const: mclk
+
+ clock-frequency:
+ description: Clock frequency of output clk in Hz
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 1
+
+ '#clock-cells':
+ const: 0
+
+ '#sound-dai-cells':
+ const: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 1
+
+ gpio@42:
+ type: object
+ allOf:
+ - $ref: ../gpio/qcom,wcd934x-gpio.yaml#
+
+patternProperties:
+ "^.*@[0-9a-f]+$":
+ type: object
+ description: |
+ WCD934x subnode for each slave devices. Bindings of each subnodes
+ depends on the specific driver providing the functionality and
+ documented in their respective bindings.
+
+ properties:
+ reg:
+ maxItems: 1
+
+ required:
+ - reg
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+ - slim-ifc-dev
+ - interrupts
+ - interrupt-controller
+ - clock-frequency
+ - clock-output-names
+ - qcom,micbias1-microvolt
+ - qcom,micbias2-microvolt
+ - qcom,micbias3-microvolt
+ - qcom,micbias4-microvolt
+ - "#interrupt-cells"
+ - "#clock-cells"
+ - "#sound-dai-cells"
+ - "#address-cells"
+ - "#size-cells"
+
+examples:
+ - |
+ codec@1,0{
+ compatible = "slim217,250";
+ reg = <1 0>;
+ reset-gpios = <&tlmm 64 0>;
+ slim-ifc-dev = <&wcd9340_ifd>;
+ #sound-dai-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <54 4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #clock-cells = <0>;
+ clock-frequency = <9600000>;
+ clock-output-names = "mclk";
+ qcom,micbias1-microvolt = <1800000>;
+ qcom,micbias2-microvolt = <1800000>;
+ qcom,micbias3-microvolt = <1800000>;
+ qcom,micbias4-microvolt = <1800000>;
+ clock-names = "extclk";
+ clocks = <&rpmhcc 2>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ gpio@42 {
+ compatible = "qcom,wcd9340-gpio";
+ reg = <0x42 0x2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
new file mode 100644
index 000000000000..ea44d03e58ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wsa881x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm WSA8810/WSA8815 Class-D Smart Speaker Amplifier
+
+maintainers:
+ - Srinivas Kandagatla <[email protected]>
+
+description: |
+ WSA8810 is a class-D smart speaker amplifier and WSA8815
+ is a high-output power class-D smart speaker amplifier.
+ Their primary operating mode uses a SoundWire digital audio
+ interface. This binding is for SoundWire interface.
+
+properties:
+ compatible:
+ const: sdw10217201000
+
+ reg:
+ maxItems: 1
+
+ powerdown-gpios:
+ description: GPIO spec for Powerdown/Shutdown line to use
+ maxItems: 1
+
+ '#thermal-sensor-cells':
+ const: 0
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - powerdown-gpios
+ - "#thermal-sensor-cells"
+ - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ soundwire@c2d0000 {
+ #address-cells = <2>;
+ #size-cells = <0>;
+ reg = <0x0c2d0000 0x2000>;
+
+ speaker@0,1 {
+ compatible = "sdw10217201000";
+ reg = <0 1>;
+ powerdown-gpios = <&wcdpinctrl 2 0>;
+ #thermal-sensor-cells = <0>;
+ #sound-dai-cells = <0>;
+ };
+
+ speaker@0,2 {
+ compatible = "sdw10217201000";
+ reg = <0 2>;
+ powerdown-gpios = <&wcdpinctrl 2 0>;
+ #thermal-sensor-cells = <0>;
+ #sound-dai-cells = <0>;
+ };
+ };
+
+...
diff --git a/include/sound/soc.h b/include/sound/soc.h
index c28a1ed5e8df..9787c80e548b 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -464,10 +464,8 @@ static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
void snd_soc_disconnect_sync(struct device *dev);
-struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
- const char *dai_link, int stream);
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
- const char *dai_link);
+ struct snd_soc_dai_link *dai_link);
bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
@@ -852,7 +850,6 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1;
- struct list_head list; /* DAI link list of the soc card */
#ifdef CONFIG_SND_SOC_TOPOLOGY
struct snd_soc_dobj dobj; /* For topology */
#endif
@@ -952,6 +949,7 @@ struct snd_soc_dai_link {
#define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, }
#define COMP_PLATFORM(_name) { .name = _name }
#define COMP_AUX(_name) { .name = _name }
+#define COMP_CODEC_CONF(_name) { .name = _name }
#define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", }
extern struct snd_soc_dai_link_component null_dailink_component[0];
@@ -962,8 +960,7 @@ struct snd_soc_codec_conf {
* specify device either by device name, or by
* DT/OF node, but not both.
*/
- const char *dev_name;
- struct device_node *of_node;
+ struct snd_soc_dai_link_component dlc;
/*
* optional map of kcontrol, widget and path name prefixes that are
@@ -989,7 +986,9 @@ struct snd_soc_card {
const char *long_name;
const char *driver_name;
const char *components;
+#ifdef CONFIG_DMI
char dmi_longname[80];
+#endif /* CONFIG_DMI */
char topology_shortname[32];
struct device *dev;
@@ -1037,7 +1036,6 @@ struct snd_soc_card {
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link; /* predefined links only */
int num_links; /* predefined links only */
- struct list_head dai_link_list; /* all links */
struct list_head rtd_list;
int num_rtd;
@@ -1107,11 +1105,6 @@ struct snd_soc_card {
((i) < (card)->num_aux_devs) && ((aux) = &(card)->aux_dev[i]); \
(i)++)
-#define for_each_card_links(card, link) \
- list_for_each_entry(link, &(card)->dai_link_list, list)
-#define for_each_card_links_safe(card, link, _link) \
- list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list)
-
#define for_each_card_rtds(card, rtd) \
list_for_each_entry(rtd, &(card)->rtd_list, list)
#define for_each_card_rtds_safe(card, rtd, _rtd) \
@@ -1150,6 +1143,7 @@ struct snd_soc_pcm_runtime {
unsigned int num_codecs;
struct delayed_work delayed_work;
+ void (*close_delayed_work_func)(struct snd_soc_pcm_runtime *rtd);
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dpcm_root;
#endif
@@ -1332,13 +1326,10 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
struct snd_soc_dai_link *dai_link);
void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link);
-int snd_soc_add_dai_link(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link);
-void snd_soc_remove_dai_link(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link);
-struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card,
- int id, const char *name,
- const char *stream_name);
+int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link);
+void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd);
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
@@ -1408,11 +1399,6 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
mutex_unlock(&dapm->card->dapm_mutex);
}
-/* bypass */
-int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg);
-
#include <sound/soc-component.h>
#endif
diff --git a/include/sound/sof.h b/include/sound/sof.h
index 479101736ee0..a0cbca021230 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -22,7 +22,6 @@ struct snd_sof_dsp_ops;
*/
struct snd_sof_pdata {
const struct firmware *fw;
- const char *drv_name;
const char *name;
const char *platform;
@@ -84,20 +83,18 @@ struct sof_dev_desc {
const void *chip_info;
/* defaults for no codec mode */
- const char *nocodec_fw_filename;
const char *nocodec_tplg_filename;
/* defaults paths for firmware and topology files */
const char *default_fw_path;
const char *default_tplg_path;
+ /* default firmware name */
+ const char *default_fw_filename;
+
const struct snd_sof_dsp_ops *ops;
- const struct sof_arch_ops *arch_ops;
};
int sof_nocodec_setup(struct device *dev,
- struct snd_sof_pdata *sof_pdata,
- struct snd_soc_acpi_mach *mach,
- const struct sof_dev_desc *desc,
const struct snd_sof_dsp_ops *ops);
#endif
diff --git a/include/sound/sof/channel_map.h b/include/sound/sof/channel_map.h
new file mode 100644
index 000000000000..21044eb5f377
--- /dev/null
+++ b/include/sound/sof/channel_map.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2019 Intel Corporation. All rights reserved.
+ */
+
+#ifndef __IPC_CHANNEL_MAP_H__
+#define __IPC_CHANNEL_MAP_H__
+
+#include <uapi/sound/sof/header.h>
+#include <sound/sof/header.h>
+
+/**
+ * \brief Channel map, specifies transformation of one-to-many or many-to-one.
+ *
+ * In case of one-to-many specifies how the output channels are computed out of
+ * a single source channel,
+ * in case of many-to-one specifies how a single target channel is computed
+ * from a multichannel input stream.
+ *
+ * Channel index specifies position of the channel in the stream on the 'one'
+ * side.
+ *
+ * Ext ID is the identifier of external part of the transformation. Depending
+ * on the context, it may be pipeline ID, dai ID, ...
+ *
+ * Channel mask describes which channels are taken into account on the "many"
+ * side. Bit[i] set to 1 means that i-th channel is used for computation
+ * (either as source or as a target).
+ *
+ * Channel mask is followed by array of coefficients in Q2.30 format,
+ * one per each channel set in the mask (left to right, LS bit set in the
+ * mask corresponds to ch_coeffs[0]).
+ */
+struct sof_ipc_channel_map {
+ uint32_t ch_index;
+ uint32_t ext_id;
+ uint32_t ch_mask;
+ uint32_t reserved;
+ int32_t ch_coeffs[0];
+} __packed;
+
+/**
+ * \brief Complete map for each channel of a multichannel stream.
+ *
+ * num_ch_map Specifies number of items in the ch_map.
+ * More than one transformation per a single channel is allowed (in case
+ * multiple external entities are transformed).
+ * A channel may be skipped in the transformation list, then it is filled
+ * with 0's by the transformation function.
+ */
+struct sof_ipc_stream_map {
+ struct sof_ipc_cmd_hdr hdr;
+ uint32_t num_ch_map;
+ uint32_t reserved[3];
+ struct sof_ipc_channel_map ch_map[0];
+} __packed;
+
+#endif /* __IPC_CHANNEL_MAP_H__ */
diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h
index e02fb0b0fae1..ff9088dcc6f2 100644
--- a/include/sound/sof/dai-imx.h
+++ b/include/sound/sof/dai-imx.h
@@ -31,4 +31,24 @@ struct sof_ipc_dai_esai_params {
uint16_t reserved2; /* alignment */
} __packed;
+/* SAI Configuration Request - SOF_IPC_DAI_SAI_CONFIG */
+struct sof_ipc_dai_sai_params {
+ struct sof_ipc_hdr hdr;
+
+ /* MCLK */
+ uint16_t reserved1;
+ uint16_t mclk_id;
+ uint32_t mclk_direction;
+
+ uint32_t mclk_rate; /* MCLK frequency in Hz */
+ uint32_t fsync_rate; /* FSYNC frequency in Hz */
+ uint32_t bclk_rate; /* BCLK frequency in Hz */
+
+ /* TDM */
+ uint32_t tdm_slots;
+ uint32_t rx_slots;
+ uint32_t tx_slots;
+ uint16_t tdm_slot_width;
+ uint16_t reserved2; /* alignment */
+} __packed;
#endif
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index c229565767e5..2565edd336f1 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -75,6 +75,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_hda_params hda;
struct sof_ipc_dai_alh_params alh;
struct sof_ipc_dai_esai_params esai;
+ struct sof_ipc_dai_sai_params sai;
};
} __packed;
diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h
index a9156b4a062c..1c560144996c 100644
--- a/include/sound/sof/info.h
+++ b/include/sound/sof/info.h
@@ -30,6 +30,7 @@
enum sof_ipc_ext_data {
SOF_IPC_EXT_DMA_BUFFER = 0,
SOF_IPC_EXT_WINDOW,
+ SOF_IPC_EXT_CC_INFO,
};
/* FW version - SOF_IPC_GLB_VERSION */
@@ -115,4 +116,18 @@ struct sof_ipc_window {
struct sof_ipc_window_elem window[];
} __packed;
+struct sof_ipc_cc_version {
+ struct sof_ipc_ext_data_hdr ext_hdr;
+ uint32_t major;
+ uint32_t minor;
+ uint32_t micro;
+
+ /* reserved for future use */
+ uint32_t reserved[4];
+
+ char name[16]; /* null terminated compiler name */
+ char optim[4]; /* null terminated compiler -O flag value */
+ char desc[]; /* null terminated compiler description */
+} __packed;
+
#endif
diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h
index c47b36240920..8e76178fedf0 100644
--- a/include/sound/sof/topology.h
+++ b/include/sound/sof/topology.h
@@ -36,6 +36,7 @@ enum sof_comp_type {
SOF_COMP_KPB, /* A key phrase buffer component */
SOF_COMP_SELECTOR, /**< channel selector component */
SOF_COMP_DEMUX,
+ SOF_COMP_ASRC, /**< Asynchronous sample rate converter */
/* keep FILEREAD/FILEWRITE as the last ones */
SOF_COMP_FILEREAD = 10000, /**< host test based file IO */
SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */
@@ -147,6 +148,32 @@ struct sof_ipc_comp_src {
uint32_t rate_mask; /**< SOF_RATE_ supported rates */
} __packed;
+/* generic ASRC component */
+struct sof_ipc_comp_asrc {
+ struct sof_ipc_comp comp;
+ struct sof_ipc_comp_config config;
+ /* either source or sink rate must be non zero */
+ uint32_t source_rate; /**< Define fixed source rate or */
+ /**< use 0 to indicate need to get */
+ /**< the rate from stream */
+ uint32_t sink_rate; /**< Define fixed sink rate or */
+ /**< use 0 to indicate need to get */
+ /**< the rate from stream */
+ uint32_t asynchronous_mode; /**< synchronous 0, asynchronous 1 */
+ /**< When 1 the ASRC tracks and */
+ /**< compensates for drift. */
+ uint32_t operation_mode; /**< push 0, pull 1, In push mode the */
+ /**< ASRC consumes a defined number */
+ /**< of frames at input, with varying */
+ /**< number of frames at output. */
+ /**< In pull mode the ASRC outputs */
+ /**< a defined number of frames while */
+ /**< number of input frames varies. */
+
+ /* reserved for future use */
+ uint32_t reserved[4];
+} __attribute__((packed));
+
/* generic MUX component */
struct sof_ipc_comp_mux {
struct sof_ipc_comp comp;
diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h
index ebfdc20ca081..c0ef1643c753 100644
--- a/include/uapi/sound/sof/abi.h
+++ b/include/uapi/sound/sof/abi.h
@@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
-#define SOF_ABI_MINOR 11
+#define SOF_ABI_MINOR 12
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index 76883e6fb750..2a25cd8da503 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -57,6 +57,12 @@
#define SOF_TKN_SRC_RATE_IN 300
#define SOF_TKN_SRC_RATE_OUT 301
+/* ASRC */
+#define SOF_TKN_ASRC_RATE_IN 320
+#define SOF_TKN_ASRC_RATE_OUT 321
+#define SOF_TKN_ASRC_ASYNCHRONOUS_MODE 322
+#define SOF_TKN_ASRC_OPERATION_MODE 323
+
/* PCM */
#define SOF_TKN_PCM_DMAC_CONFIG 353
@@ -107,8 +113,7 @@
#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE
/* SAI */
-#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000
-/* TODO: Add SAI tokens */
+#define SOF_TKN_IMX_SAI_MCLK_ID 1000
/* ESAI */
#define SOF_TKN_IMX_ESAI_MCLK_ID 1100
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index f4ee6798154a..7a5621e5e233 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -96,14 +96,19 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int da7219_clk_enable(struct snd_pcm_substream *substream,
- int wclk_rate, int bclk_rate)
+static int da7219_clk_enable(struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- clk_set_rate(da7219_dai_wclk, wclk_rate);
- clk_set_rate(da7219_dai_bclk, bclk_rate);
+ /*
+ * Set wclk to 48000 because the rate constraint of this driver is
+ * 48000. ADAU7002 spec: "The ADAU7002 requires a BCLK rate that is
+ * minimum of 64x the LRCLK sample rate." DA7219 is the only clk
+ * source so for all codecs we have to limit bclk to 64X lrclk.
+ */
+ clk_set_rate(da7219_dai_wclk, 48000);
+ clk_set_rate(da7219_dai_bclk, 48000 * 64);
ret = clk_prepare_enable(da7219_dai_bclk);
if (ret < 0) {
dev_err(rtd->dev, "can't enable master clock %d\n", ret);
@@ -156,7 +161,7 @@ static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
&constraints_rates);
machine->play_i2s_instance = I2S_SP_INSTANCE;
- return 0;
+ return da7219_clk_enable(substream);
}
static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
@@ -178,7 +183,7 @@ static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL1;
- return 0;
+ return da7219_clk_enable(substream);
}
static int cz_max_startup(struct snd_pcm_substream *substream)
@@ -199,7 +204,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream)
&constraints_rates);
machine->play_i2s_instance = I2S_BT_INSTANCE;
- return 0;
+ return da7219_clk_enable(substream);
}
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
@@ -220,7 +225,7 @@ static int cz_dmic0_startup(struct snd_pcm_substream *substream)
&constraints_rates);
machine->cap_i2s_instance = I2S_BT_INSTANCE;
- return 0;
+ return da7219_clk_enable(substream);
}
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
@@ -242,25 +247,7 @@ static int cz_dmic1_startup(struct snd_pcm_substream *substream)
machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL0;
- return 0;
-}
-
-static int cz_da7219_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- int wclk, bclk;
-
- wclk = params_rate(params);
- bclk = wclk * params_channels(params) *
- snd_pcm_format_width(params_format(params));
- /* ADAU7002 spec: "The ADAU7002 requires a BCLK rate
- * that is minimum of 64x the LRCLK sample rate."
- * DA7219 is the only clk source so for all codecs
- * we have to limit bclk to 64X lrclk.
- */
- if (bclk < (wclk * 64))
- bclk = wclk * 64;
- return da7219_clk_enable(substream, wclk, bclk);
+ return da7219_clk_enable(substream);
}
static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
@@ -271,31 +258,26 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
static const struct snd_soc_ops cz_da7219_play_ops = {
.startup = cz_da7219_play_startup,
.shutdown = cz_da7219_shutdown,
- .hw_params = cz_da7219_params,
};
static const struct snd_soc_ops cz_da7219_cap_ops = {
.startup = cz_da7219_cap_startup,
.shutdown = cz_da7219_shutdown,
- .hw_params = cz_da7219_params,
};
static const struct snd_soc_ops cz_max_play_ops = {
.startup = cz_max_startup,
.shutdown = cz_da7219_shutdown,
- .hw_params = cz_da7219_params,
};
static const struct snd_soc_ops cz_dmic0_cap_ops = {
.startup = cz_dmic0_startup,
.shutdown = cz_da7219_shutdown,
- .hw_params = cz_da7219_params,
};
static const struct snd_soc_ops cz_dmic1_cap_ops = {
.startup = cz_dmic1_startup,
.shutdown = cz_da7219_shutdown,
- .hw_params = cz_da7219_params,
};
SND_SOC_DAILINK_DEF(designware1,
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 4b9a27e25206..f54beb7f39a8 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -836,7 +836,6 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- int status;
uint64_t size;
u32 val = 0;
struct snd_pcm_runtime *runtime;
@@ -967,35 +966,19 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
}
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));
- if (substream->dma_buffer.area) {
- acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
- /* Save for runtime private data */
- rtd->dma_addr = substream->dma_buffer.addr;
- rtd->order = get_order(size);
+ acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
+ /* Save for runtime private data */
+ rtd->dma_addr = substream->dma_buffer.addr;
+ rtd->order = get_order(size);
- /* Fill the page table entries in ACP SRAM */
- rtd->size = size;
- rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
- rtd->direction = substream->stream;
+ /* Fill the page table entries in ACP SRAM */
+ rtd->size = size;
+ rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ rtd->direction = substream->stream;
- config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type);
- status = 0;
- } else {
- status = -ENOMEM;
- }
- return status;
-}
-
-static int acp_dma_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
+ config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type);
+ return 0;
}
static u64 acp_get_byte_count(struct audio_substream_data *rtd)
@@ -1142,18 +1125,18 @@ static int acp_dma_new(struct snd_soc_component *component,
switch (adata->asic_type) {
case CHIP_STONEY:
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
- SNDRV_DMA_TYPE_DEV,
- parent,
- ST_MIN_BUFFER,
- ST_MAX_BUFFER);
+ snd_pcm_set_managed_buffer_all(rtd->pcm,
+ SNDRV_DMA_TYPE_DEV,
+ parent,
+ ST_MIN_BUFFER,
+ ST_MAX_BUFFER);
break;
default:
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
- SNDRV_DMA_TYPE_DEV,
- parent,
- MIN_BUFFER,
- MAX_BUFFER);
+ snd_pcm_set_managed_buffer_all(rtd->pcm,
+ SNDRV_DMA_TYPE_DEV,
+ parent,
+ MIN_BUFFER,
+ MAX_BUFFER);
break;
}
return 0;
@@ -1219,9 +1202,7 @@ static const struct snd_soc_component_driver acp_asoc_platform = {
.name = DRV_NAME,
.open = acp_dma_open,
.close = acp_dma_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = acp_dma_hw_params,
- .hw_free = acp_dma_hw_free,
.trigger = acp_dma_trigger,
.pointer = acp_dma_pointer,
.mmap = acp_dma_mmap,
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile
index 108d1acf189b..62c22b6ed95a 100644
--- a/sound/soc/amd/raven/Makefile
+++ b/sound/soc/amd/raven/Makefile
@@ -2,5 +2,7 @@
# Raven Ridge platform Support
snd-pci-acp3x-objs := pci-acp3x.o
snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o
+snd-acp3x-i2s-objs := acp3x-i2s.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-i2s.o
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
new file mode 100644
index 000000000000..bf51cadf8682
--- /dev/null
+++ b/sound/soc/amd/raven/acp3x-i2s.c
@@ -0,0 +1,358 @@
+// 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 <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <linux/dma-mapping.h>
+
+#include "acp3x.h"
+
+#define DRV_NAME "acp3x-i2s"
+
+static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct i2s_dev_data *adata;
+ int mode;
+
+ adata = snd_soc_dai_get_drvdata(cpu_dai);
+ mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ switch (mode) {
+ case SND_SOC_DAIFMT_I2S:
+ adata->tdm_mode = TDM_DISABLE;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ adata->tdm_mode = TDM_ENABLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int acp3x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,
+ u32 tx_mask, u32 rx_mask, int slots, int slot_width)
+{
+ struct i2s_dev_data *adata;
+ u32 val, reg_val, frmt_reg, frm_len;
+ u16 slot_len;
+
+ adata = snd_soc_dai_get_drvdata(cpu_dai);
+
+ /* These values are as per Hardware Spec */
+ 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;
+ }
+
+ /* Enable I2S/BT channels TDM, respective TX/RX frame lengths.*/
+
+ frm_len = FRM_LEN | (slots << 15) | (slot_len << 18);
+ if (adata->substream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (adata->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_ITER;
+ frmt_reg = mmACP_BTTDM_TXFRMT;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_ITER;
+ frmt_reg = mmACP_I2STDM_TXFRMT;
+ }
+ } else {
+ switch (adata->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_IRER;
+ frmt_reg = mmACP_BTTDM_RXFRMT;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_IRER;
+ frmt_reg = mmACP_I2STDM_RXFRMT;
+ }
+ }
+ val = rv_readl(adata->acp3x_base + reg_val);
+ rv_writel(val | 0x2, adata->acp3x_base + reg_val);
+ rv_writel(frm_len, adata->acp3x_base + frmt_reg);
+ adata->tdm_fmt = frm_len;
+ return 0;
+}
+
+static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct i2s_stream_instance *rtd;
+ struct snd_soc_pcm_runtime *prtd;
+ struct snd_soc_card *card;
+ struct acp3x_platform_info *pinfo;
+ u32 val;
+ u32 reg_val;
+
+ prtd = substream->private_data;
+ rtd = substream->runtime->private_data;
+ card = prtd->card;
+ pinfo = snd_soc_card_get_drvdata(card);
+ if (pinfo) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rtd->i2s_instance = pinfo->play_i2s_instance;
+ else
+ rtd->i2s_instance = pinfo->cap_i2s_instance;
+ }
+
+ /* These values are as per Hardware Spec */
+ 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;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_ITER;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_ITER;
+ }
+ } else {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_IRER;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_IRER;
+ }
+ }
+ val = rv_readl(rtd->acp3x_base + reg_val);
+ val = val | (rtd->xfer_resolution << 3);
+ rv_writel(val, rtd->acp3x_base + reg_val);
+ return 0;
+}
+
+static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct i2s_stream_instance *rtd;
+ struct snd_soc_pcm_runtime *prtd;
+ struct snd_soc_card *card;
+ struct acp3x_platform_info *pinfo;
+ u32 ret, val, period_bytes, reg_val, ier_val, water_val;
+
+ prtd = substream->private_data;
+ rtd = substream->runtime->private_data;
+ card = prtd->card;
+ pinfo = snd_soc_card_get_drvdata(card);
+ if (pinfo) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rtd->i2s_instance = pinfo->play_i2s_instance;
+ else
+ rtd->i2s_instance = pinfo->cap_i2s_instance;
+ }
+ 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:
+ rtd->bytescount = acp_get_byte_count(rtd,
+ substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ water_val =
+ mmACP_BT_TX_INTR_WATERMARK_SIZE;
+ reg_val = mmACP_BTTDM_ITER;
+ ier_val = mmACP_BTTDM_IER;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ water_val =
+ mmACP_I2S_TX_INTR_WATERMARK_SIZE;
+ reg_val = mmACP_I2STDM_ITER;
+ ier_val = mmACP_I2STDM_IER;
+ }
+ } else {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ water_val =
+ mmACP_BT_RX_INTR_WATERMARK_SIZE;
+ reg_val = mmACP_BTTDM_IRER;
+ ier_val = mmACP_BTTDM_IER;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ water_val =
+ mmACP_I2S_RX_INTR_WATERMARK_SIZE;
+ reg_val = mmACP_I2STDM_IRER;
+ ier_val = mmACP_I2STDM_IER;
+ }
+ }
+ rv_writel(period_bytes, rtd->acp3x_base + water_val);
+ val = rv_readl(rtd->acp3x_base + reg_val);
+ val = val | BIT(0);
+ rv_writel(val, rtd->acp3x_base + reg_val);
+ rv_writel(1, rtd->acp3x_base + ier_val);
+ ret = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_ITER;
+ ier_val = mmACP_BTTDM_IER;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_ITER;
+ ier_val = mmACP_I2STDM_IER;
+ }
+
+ } else {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_IRER;
+ ier_val = mmACP_BTTDM_IER;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_IRER;
+ ier_val = mmACP_I2STDM_IER;
+ }
+ }
+ val = rv_readl(rtd->acp3x_base + reg_val);
+ val = val & ~BIT(0);
+ rv_writel(val, rtd->acp3x_base + reg_val);
+ rv_writel(0, rtd->acp3x_base + ier_val);
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
+ .hw_params = acp3x_i2s_hwparams,
+ .trigger = acp3x_i2s_trigger,
+ .set_fmt = acp3x_i2s_set_fmt,
+ .set_tdm_slot = acp3x_i2s_set_tdm_slot,
+};
+
+static const struct snd_soc_component_driver acp3x_dai_component = {
+ .name = "acp3x-i2s",
+};
+
+static struct snd_soc_dai_driver acp3x_i2s_dai = {
+ .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_i2s_dai_ops,
+};
+
+static int acp3x_dai_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct i2s_dev_data *adata;
+ int ret;
+
+ adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
+ GFP_KERNEL);
+ if (!adata)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
+ return -ENOMEM;
+ }
+ adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!adata->acp3x_base)
+ return -ENOMEM;
+
+ adata->i2s_irq = res->start;
+ dev_set_drvdata(&pdev->dev, adata);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &acp3x_dai_component, &acp3x_i2s_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int acp3x_dai_remove(struct platform_device *pdev)
+{
+ /* As we use devm_ memory alloc there is nothing TBD here */
+
+ return 0;
+}
+
+static struct platform_driver acp3x_dai_driver = {
+ .probe = acp3x_dai_probe,
+ .remove = acp3x_dai_remove,
+ .driver = {
+ .name = "acp3x_i2s_playcap",
+ },
+};
+
+module_platform_driver(acp3x_dai_driver);
+
+MODULE_AUTHOR("[email protected]");
+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-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
index 60709e3ba99d..5c3ec3c58e3b 100644
--- a/sound/soc/amd/raven/acp3x-pcm-dma.c
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -9,7 +9,6 @@
#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>
@@ -18,28 +17,11 @@
#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;
- u64 bytescount;
- dma_addr_t dma_addr;
- 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_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
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 |
@@ -60,7 +42,8 @@ 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,
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ 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,
@@ -76,112 +59,13 @@ static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
.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)
{
+ struct i2s_dev_data *rv_i2s_data;
u16 play_flag, cap_flag;
u32 val;
- struct i2s_dev_data *rv_i2s_data = dev_id;
+ rv_i2s_data = dev_id;
if (!rv_i2s_data)
return IRQ_NONE;
@@ -194,6 +78,13 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
snd_pcm_period_elapsed(rv_i2s_data->play_stream);
play_flag = 1;
}
+ if ((val & BIT(I2S_TX_THRESHOLD)) &&
+ rv_i2s_data->i2ssp_play_stream) {
+ rv_writel(BIT(I2S_TX_THRESHOLD),
+ rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
+ snd_pcm_period_elapsed(rv_i2s_data->i2ssp_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 +
@@ -201,6 +92,13 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
cap_flag = 1;
}
+ if ((val & BIT(I2S_RX_THRESHOLD)) &&
+ rv_i2s_data->i2ssp_capture_stream) {
+ rv_writel(BIT(I2S_RX_THRESHOLD),
+ rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
+ snd_pcm_period_elapsed(rv_i2s_data->i2ssp_capture_stream);
+ cap_flag = 1;
+ }
if (play_flag | cap_flag)
return IRQ_HANDLED;
@@ -211,15 +109,31 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
{
u16 page_idx;
- u32 low, high, val, acp_fifo_addr;
- dma_addr_t addr = rtd->dma_addr;
+ u32 low, high, val, acp_fifo_addr, reg_fifo_addr;
+ u32 reg_ringbuf_size, reg_dma_size, reg_fifo_size;
+ dma_addr_t addr;
- /* 8 scratch registers used to map one 64 bit address */
- if (direction == SNDRV_PCM_STREAM_PLAYBACK)
- val = 0;
- else
- val = rtd->num_pages * 8;
+ addr = rtd->dma_addr;
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ val = ACP_SRAM_BT_PB_PTE_OFFSET;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ val = ACP_SRAM_SP_PB_PTE_OFFSET;
+ }
+ } else {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ val = ACP_SRAM_BT_CP_PTE_OFFSET;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ val = ACP_SRAM_SP_CP_PTE_OFFSET;
+ }
+ }
/* Group Enable */
rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
@@ -241,48 +155,77 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
}
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);
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_ringbuf_size = mmACP_BT_TX_RINGBUFSIZE;
+ reg_dma_size = mmACP_BT_TX_DMA_SIZE;
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+ BT_PB_FIFO_ADDR_OFFSET;
+ reg_fifo_addr = mmACP_BT_TX_FIFOADDR;
+ reg_fifo_size = mmACP_BT_TX_FIFOSIZE;
+ rv_writel(I2S_BT_TX_MEM_WINDOW_START,
+ rtd->acp3x_base + mmACP_BT_TX_RINGBUFADDR);
+ break;
+
+ case I2S_SP_INSTANCE:
+ default:
+ reg_ringbuf_size = mmACP_I2S_TX_RINGBUFSIZE;
+ reg_dma_size = mmACP_I2S_TX_DMA_SIZE;
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+ SP_PB_FIFO_ADDR_OFFSET;
+ reg_fifo_addr = mmACP_I2S_TX_FIFOADDR;
+ reg_fifo_size = mmACP_I2S_TX_FIFOSIZE;
+ rv_writel(I2S_SP_TX_MEM_WINDOW_START,
+ rtd->acp3x_base + mmACP_I2S_TX_RINGBUFADDR);
+ }
} 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);
- }
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_ringbuf_size = mmACP_BT_RX_RINGBUFSIZE;
+ reg_dma_size = mmACP_BT_RX_DMA_SIZE;
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+ BT_CAPT_FIFO_ADDR_OFFSET;
+ reg_fifo_addr = mmACP_BT_RX_FIFOADDR;
+ reg_fifo_size = mmACP_BT_RX_FIFOSIZE;
+ rv_writel(I2S_BT_RX_MEM_WINDOW_START,
+ rtd->acp3x_base + mmACP_BT_RX_RINGBUFADDR);
+ break;
- /* Enable watermark/period interrupt to host */
- rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
- rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
+ case I2S_SP_INSTANCE:
+ default:
+ reg_ringbuf_size = mmACP_I2S_RX_RINGBUFSIZE;
+ reg_dma_size = mmACP_I2S_RX_DMA_SIZE;
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+ SP_CAPT_FIFO_ADDR_OFFSET;
+ reg_fifo_addr = mmACP_I2S_RX_FIFOADDR;
+ reg_fifo_size = mmACP_I2S_RX_FIFOSIZE;
+ rv_writel(I2S_SP_RX_MEM_WINDOW_START,
+ rtd->acp3x_base + mmACP_I2S_RX_RINGBUFADDR);
+ }
+ }
+ rv_writel(MAX_BUFFER, rtd->acp3x_base + reg_ringbuf_size);
+ rv_writel(DMA_SIZE, rtd->acp3x_base + reg_dma_size);
+ rv_writel(acp_fifo_addr, rtd->acp3x_base + reg_fifo_addr);
+ rv_writel(FIFO_SIZE, rtd->acp3x_base + reg_fifo_size);
+ rv_writel(BIT(I2S_RX_THRESHOLD) | BIT(BT_RX_THRESHOLD)
+ | BIT(I2S_TX_THRESHOLD) | BIT(BT_TX_THRESHOLD),
+ rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
}
static int acp3x_dma_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- int ret = 0;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
- struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
- GFP_KERNEL);
+ struct snd_pcm_runtime *runtime;
+ struct snd_soc_pcm_runtime *prtd;
+ struct i2s_dev_data *adata;
+ struct i2s_stream_instance *i2s_data;
+ int ret;
+
+ runtime = substream->runtime;
+ prtd = substream->private_data;
+ component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+ adata = dev_get_drvdata(component->dev);
+ i2s_data = kzalloc(sizeof(*i2s_data), GFP_KERNEL);
if (!i2s_data)
return -EINVAL;
@@ -299,74 +242,77 @@ static int acp3x_dma_open(struct snd_soc_component *component,
return ret;
}
- if (!adata->play_stream && !adata->capture_stream)
+ if (!adata->play_stream && !adata->capture_stream &&
+ adata->i2ssp_play_stream && !adata->i2ssp_capture_stream)
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
adata->play_stream = substream;
- else
+ adata->i2ssp_play_stream = substream;
+ } else {
adata->capture_stream = substream;
+ adata->i2ssp_capture_stream = substream;
+ }
i2s_data->acp3x_base = adata->acp3x_base;
runtime->private_data = i2s_data;
- return 0;
+ return ret;
}
-static u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction)
-{
- u64 byte_count;
-
- if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
- byte_count = rv_readl(rtd->acp3x_base +
- mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH);
- byte_count |= rv_readl(rtd->acp3x_base +
- mmACP_BT_TX_LINEARPOSITIONCNTR_LOW);
- } else {
- byte_count = rv_readl(rtd->acp3x_base +
- mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH);
- byte_count |= rv_readl(rtd->acp3x_base +
- mmACP_BT_RX_LINEARPOSITIONCNTR_LOW);
- }
- return byte_count;
-}
static int acp3x_dma_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- int status;
+ struct i2s_stream_instance *rtd;
+ struct snd_soc_pcm_runtime *prtd;
+ struct snd_soc_card *card;
+ struct acp3x_platform_info *pinfo;
u64 size;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct i2s_stream_instance *rtd = runtime->private_data;
+ prtd = substream->private_data;
+ card = prtd->card;
+ pinfo = snd_soc_card_get_drvdata(card);
+ rtd = substream->runtime->private_data;
if (!rtd)
return -EINVAL;
+ if (pinfo)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rtd->i2s_instance = pinfo->play_i2s_instance;
+ else
+ rtd->i2s_instance = pinfo->cap_i2s_instance;
+ else
+ pr_err("pinfo failed\n");
+
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));
- if (substream->dma_buffer.area) {
- rtd->dma_addr = substream->dma_buffer.addr;
- rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
- config_acp3x_dma(rtd, substream->stream);
- status = 0;
- } else {
- status = -ENOMEM;
- }
- return status;
+ rtd->dma_addr = substream->dma_buffer.addr;
+ rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
+ config_acp3x_dma(rtd, substream->stream);
+ return 0;
}
static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- u32 pos = 0;
- u32 buffersize = 0;
- u64 bytescount = 0;
- struct i2s_stream_instance *rtd =
- substream->runtime->private_data;
+ struct snd_soc_pcm_runtime *prtd;
+ struct snd_soc_card *card;
+ struct acp3x_platform_info *pinfo;
+ struct i2s_stream_instance *rtd;
+ u32 pos;
+ u32 buffersize;
+ u64 bytescount;
+
+ prtd = substream->private_data;
+ card = prtd->card;
+ rtd = substream->runtime->private_data;
+ pinfo = snd_soc_card_get_drvdata(card);
+ if (pinfo) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rtd->i2s_instance = pinfo->play_i2s_instance;
+ else
+ rtd->i2s_instance = pinfo->cap_i2s_instance;
+ }
buffersize = frames_to_bytes(substream->runtime,
substream->runtime->buffer_size);
@@ -381,17 +327,11 @@ static int acp3x_dma_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
struct device *parent = component->dev->parent;
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
- parent, MIN_BUFFER, MAX_BUFFER);
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+ parent, MIN_BUFFER, MAX_BUFFER);
return 0;
}
-static int acp3x_dma_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static int acp3x_dma_mmap(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
@@ -402,206 +342,35 @@ static int acp3x_dma_mmap(struct snd_soc_component *component,
static int acp3x_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct i2s_stream_instance *rtd = substream->runtime->private_data;
- struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
+ struct snd_soc_pcm_runtime *prtd;
+ struct i2s_dev_data *adata;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd = substream->private_data;
+ component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+ adata = dev_get_drvdata(component->dev);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
adata->play_stream = NULL;
- else
+ adata->i2ssp_play_stream = NULL;
+ } else {
adata->capture_stream = NULL;
+ adata->i2ssp_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)
+ if (!adata->play_stream && !adata->capture_stream &&
+ !adata->i2ssp_play_stream && !adata->i2ssp_capture_stream)
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
- kfree(rtd);
- return 0;
-}
-
-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:
- rtd->bytescount = acp_get_byte_count(rtd, substream->stream);
- 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;
-}
-
-static 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,
.open = acp3x_dma_open,
.close = acp3x_dma_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = acp3x_dma_hw_params,
- .hw_free = acp3x_dma_hw_free,
.pointer = acp3x_dma_pointer,
.mmap = acp3x_dma_mmap,
.pcm_construct = acp3x_dma_new,
@@ -609,10 +378,10 @@ static const struct snd_soc_component_driver acp3x_i2s_component = {
static int acp3x_audio_probe(struct platform_device *pdev)
{
- int status;
struct resource *res;
struct i2s_dev_data *adata;
unsigned int irqflags;
+ int status;
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "platform_data not retrieved\n");
@@ -622,7 +391,7 @@ static int acp3x_audio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
return -ENODEV;
}
@@ -632,6 +401,8 @@ static int acp3x_audio_probe(struct platform_device *pdev)
adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
+ if (!adata->acp3x_base)
+ return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -640,97 +411,81 @@ static int acp3x_audio_probe(struct platform_device *pdev)
}
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);
+ NULL, 0);
if (status) {
- dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
- goto dev_err;
+ dev_err(&pdev->dev, "Fail to register acp i2s component\n");
+ return -ENODEV;
}
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;
+ return -ENODEV;
}
- pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ pm_runtime_allow(&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);
+ struct i2s_dev_data *adata;
+ u32 val, reg_val, frmt_val;
- status = acp3x_init(adata->acp3x_base);
- if (status)
- return -ENODEV;
+ reg_val = 0;
+ frmt_val = 0;
+ adata = dev_get_drvdata(dev);
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);
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_ITER;
+ frmt_val = mmACP_BTTDM_TXFRMT;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_ITER;
+ frmt_val = mmACP_I2STDM_TXFRMT;
}
+ rv_writel((rtd->xfer_resolution << 3), rtd->acp3x_base + reg_val);
}
-
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);
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ reg_val = mmACP_BTTDM_IRER;
+ frmt_val = mmACP_BTTDM_RXFRMT;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ reg_val = mmACP_I2STDM_IRER;
+ frmt_val = mmACP_I2STDM_RXFRMT;
}
+ rv_writel((rtd->xfer_resolution << 3), rtd->acp3x_base + reg_val);
+ }
+ if (adata->tdm_mode == TDM_ENABLE) {
+ rv_writel(adata->tdm_fmt, adata->acp3x_base + frmt_val);
+ val = rv_readl(adata->acp3x_base + reg_val);
+ rv_writel(val | 0x2, adata->acp3x_base + reg_val);
}
-
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
@@ -738,14 +493,9 @@ static int acp3x_resume(struct device *dev)
static int acp3x_pcm_runtime_suspend(struct device *dev)
{
- int status;
- struct i2s_dev_data *adata = dev_get_drvdata(dev);
+ struct i2s_dev_data *adata;
- status = acp3x_deinit(adata->acp3x_base);
- if (status)
- dev_err(dev, "ACP de-init failed\n");
- else
- dev_info(dev, "ACP de-initialized\n");
+ adata = dev_get_drvdata(dev);
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
@@ -754,12 +504,10 @@ static int acp3x_pcm_runtime_suspend(struct device *dev)
static int acp3x_pcm_runtime_resume(struct device *dev)
{
- int status;
- struct i2s_dev_data *adata = dev_get_drvdata(dev);
+ struct i2s_dev_data *adata;
+
+ 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;
}
@@ -774,13 +522,14 @@ static struct platform_driver acp3x_dma_driver = {
.probe = acp3x_audio_probe,
.remove = acp3x_audio_remove,
.driver = {
- .name = "acp3x_rv_i2s",
+ .name = "acp3x_rv_i2s_dma",
.pm = &acp3x_pm_ops,
},
};
module_platform_driver(acp3x_dma_driver);
+MODULE_AUTHOR("[email protected]");
MODULE_AUTHOR("[email protected]");
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h
index 4f2cadd90a87..b6a80dc0b641 100644
--- a/sound/soc/amd/raven/acp3x.h
+++ b/sound/soc/amd/raven/acp3x.h
@@ -6,14 +6,28 @@
*/
#include "chip_offset_byte.h"
+#include <sound/pcm.h>
+#define I2S_SP_INSTANCE 0x01
+#define I2S_BT_INSTANCE 0x02
+#define TDM_ENABLE 1
+#define TDM_DISABLE 0
+
+#define ACP3x_DEVS 3
#define ACP3x_PHY_BASE_ADDRESS 0x1240000
#define ACP3x_I2S_MODE 0
#define ACP3x_REG_START 0x1240000
#define ACP3x_REG_END 0x1250200
+#define ACP3x_I2STDM_REG_START 0x1242400
+#define ACP3x_I2STDM_REG_END 0x1242410
+#define ACP3x_BT_TDM_REG_START 0x1242800
+#define ACP3x_BT_TDM_REG_END 0x1242810
#define I2S_MODE 0x04
+#define I2S_RX_THRESHOLD 27
+#define I2S_TX_THRESHOLD 28
#define BT_TX_THRESHOLD 26
#define BT_RX_THRESHOLD 25
+#define ACP_ERR_INTR_MASK 29
#define ACP3x_POWER_ON 0x00
#define ACP3x_POWER_ON_IN_PROGRESS 0x01
#define ACP3x_POWER_OFF 0x02
@@ -21,19 +35,28 @@
#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001
#define ACP_SRAM_PTE_OFFSET 0x02050000
+#define ACP_SRAM_SP_PB_PTE_OFFSET 0x0
+#define ACP_SRAM_SP_CP_PTE_OFFSET 0x100
+#define ACP_SRAM_BT_PB_PTE_OFFSET 0x200
+#define ACP_SRAM_BT_CP_PTE_OFFSET 0x300
#define PAGE_SIZE_4K_ENABLE 0x2
-#define MEM_WINDOW_START 0x4000000
-#define PLAYBACK_FIFO_ADDR_OFFSET 0x400
-#define CAPTURE_FIFO_ADDR_OFFSET 0x500
+#define I2S_SP_TX_MEM_WINDOW_START 0x4000000
+#define I2S_SP_RX_MEM_WINDOW_START 0x4020000
+#define I2S_BT_TX_MEM_WINDOW_START 0x4040000
+#define I2S_BT_RX_MEM_WINDOW_START 0x4060000
+#define SP_PB_FIFO_ADDR_OFFSET 0x500
+#define SP_CAPT_FIFO_ADDR_OFFSET 0x700
+#define BT_PB_FIFO_ADDR_OFFSET 0x900
+#define BT_CAPT_FIFO_ADDR_OFFSET 0xB00
#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 PLAYBACK_MAX_PERIOD_SIZE 8192
+#define PLAYBACK_MIN_PERIOD_SIZE 1024
#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 CAPTURE_MAX_PERIOD_SIZE 8192
+#define CAPTURE_MIN_PERIOD_SIZE 1024
#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
#define MIN_BUFFER MAX_BUFFER
@@ -45,7 +68,45 @@
#define SLOT_WIDTH_16 0x10
#define SLOT_WIDTH_24 0x18
#define SLOT_WIDTH_32 0x20
+#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01
+#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00
+#define ACP_PGFSM_STATUS_MASK 0x03
+#define ACP_POWERED_ON 0x00
+#define ACP_POWER_ON_IN_PROGRESS 0x01
+#define ACP_POWERED_OFF 0x02
+#define ACP_POWER_OFF_IN_PROGRESS 0x03
+
+struct acp3x_platform_info {
+ u16 play_i2s_instance;
+ u16 cap_i2s_instance;
+ u16 capture_channel;
+};
+struct i2s_dev_data {
+ bool tdm_mode;
+ unsigned int i2s_irq;
+ u16 i2s_instance;
+ u32 tdm_fmt;
+ u32 substream_type;
+ void __iomem *acp3x_base;
+ struct snd_pcm_substream *play_stream;
+ struct snd_pcm_substream *capture_stream;
+ struct snd_pcm_substream *i2ssp_play_stream;
+ struct snd_pcm_substream *i2ssp_capture_stream;
+};
+
+struct i2s_stream_instance {
+ u16 num_pages;
+ u16 i2s_instance;
+ u16 capture_channel;
+ u16 direction;
+ u16 channels;
+ u32 xfer_resolution;
+ u32 val;
+ dma_addr_t dma_addr;
+ u64 bytescount;
+ void __iomem *acp3x_base;
+};
static inline u32 rv_readl(void __iomem *base_addr)
{
@@ -56,3 +117,43 @@ static inline void rv_writel(u32 val, void __iomem *base_addr)
{
writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS);
}
+
+static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd,
+ int direction)
+{
+ u64 byte_count;
+
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ byte_count = rv_readl(rtd->acp3x_base +
+ mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH);
+ byte_count |= rv_readl(rtd->acp3x_base +
+ mmACP_BT_TX_LINEARPOSITIONCNTR_LOW);
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ byte_count = rv_readl(rtd->acp3x_base +
+ mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH);
+ byte_count |= rv_readl(rtd->acp3x_base +
+ mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
+ }
+
+ } else {
+ switch (rtd->i2s_instance) {
+ case I2S_BT_INSTANCE:
+ byte_count = rv_readl(rtd->acp3x_base +
+ mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH);
+ byte_count |= rv_readl(rtd->acp3x_base +
+ mmACP_BT_RX_LINEARPOSITIONCNTR_LOW);
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ byte_count = rv_readl(rtd->acp3x_base +
+ mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
+ byte_count |= rv_readl(rtd->acp3x_base +
+ mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
+ }
+ }
+ return byte_count;
+}
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
index facec2472b34..2f9f52905853 100644
--- a/sound/soc/amd/raven/pci-acp3x.c
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -9,6 +9,8 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
#include "acp3x.h"
@@ -16,17 +18,120 @@ struct acp3x_dev_data {
void __iomem *acp3x_base;
bool acp3x_audio_mode;
struct resource *res;
- struct platform_device *pdev;
+ struct platform_device *pdev[ACP3x_DEVS];
};
+static int acp3x_power_on(void __iomem *acp3x_base)
+{
+ u32 val;
+ int timeout;
+
+ val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
+
+ if (val == 0)
+ return val;
+
+ if (!((val & ACP_PGFSM_STATUS_MASK) ==
+ ACP_POWER_ON_IN_PROGRESS))
+ rv_writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
+ acp3x_base + mmACP_PGFSM_CONTROL);
+ timeout = 0;
+ while (++timeout < 500) {
+ val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
+ if (!val)
+ return 0;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+static int acp3x_power_off(void __iomem *acp3x_base)
+{
+ u32 val;
+ int timeout;
+
+ rv_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK,
+ acp3x_base + mmACP_PGFSM_CONTROL);
+ timeout = 0;
+ while (++timeout < 500) {
+ val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
+ if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF)
+ return 0;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+static int acp3x_reset(void __iomem *acp3x_base)
+{
+ u32 val;
+ int timeout;
+
+ rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
+ timeout = 0;
+ while (++timeout < 500) {
+ val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+ if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
+ break;
+ cpu_relax();
+ }
+ rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
+ timeout = 0;
+ while (++timeout < 500) {
+ val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+ if (!val)
+ return 0;
+ cpu_relax();
+ }
+ return -ETIMEDOUT;
+}
+
+static int acp3x_init(void __iomem *acp3x_base)
+{
+ int ret;
+
+ /* power on */
+ ret = acp3x_power_on(acp3x_base);
+ 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_off(acp3x_base);
+ if (ret) {
+ pr_err("ACP3x power off failed\n");
+ return ret;
+ }
+ return 0;
+}
+
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;
+ struct platform_device_info pdevinfo[ACP3x_DEVS];
unsigned int irqflags;
+ int ret, i;
+ u32 addr, val;
if (pci_enable_device(pci)) {
dev_err(&pci->dev, "pci_enable_device failed\n");
@@ -56,23 +161,27 @@ static int snd_acp3x_probe(struct pci_dev *pci,
irqflags = 0;
addr = pci_resource_start(pci, 0);
- adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
+ adata->acp3x_base = devm_ioremap(&pci->dev, addr,
+ pci_resource_len(pci, 0));
if (!adata->acp3x_base) {
ret = -ENOMEM;
- goto release_regions;
+ goto disable_msi;
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
+ ret = acp3x_init(adata->acp3x_base);
+ if (ret)
+ goto disable_msi;
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,
+ sizeof(struct resource) * 4,
GFP_KERNEL);
if (!adata->res) {
ret = -ENOMEM;
- goto unmap_mmio;
+ goto de_init;
}
adata->res[0].name = "acp3x_i2s_iomem";
@@ -80,40 +189,76 @@ static int snd_acp3x_probe(struct pci_dev *pci,
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->res[1].name = "acp3x_i2s_sp";
+ adata->res[1].flags = IORESOURCE_MEM;
+ adata->res[1].start = addr + ACP3x_I2STDM_REG_START;
+ adata->res[1].end = addr + ACP3x_I2STDM_REG_END;
+
+ adata->res[2].name = "acp3x_i2s_bt";
+ adata->res[2].flags = IORESOURCE_MEM;
+ adata->res[2].start = addr + ACP3x_BT_TDM_REG_START;
+ adata->res[2].end = addr + ACP3x_BT_TDM_REG_END;
+
+ adata->res[3].name = "acp3x_i2s_irq";
+ adata->res[3].flags = IORESOURCE_IRQ;
+ adata->res[3].start = pci->irq;
+ adata->res[3].end = adata->res[3].start;
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;
+ pdevinfo[0].name = "acp3x_rv_i2s_dma";
+ pdevinfo[0].id = 0;
+ pdevinfo[0].parent = &pci->dev;
+ pdevinfo[0].num_res = 4;
+ pdevinfo[0].res = &adata->res[0];
+ pdevinfo[0].data = &irqflags;
+ pdevinfo[0].size_data = sizeof(irqflags);
+
+ pdevinfo[1].name = "acp3x_i2s_playcap";
+ pdevinfo[1].id = 0;
+ pdevinfo[1].parent = &pci->dev;
+ pdevinfo[1].num_res = 1;
+ pdevinfo[1].res = &adata->res[1];
+
+ pdevinfo[2].name = "acp3x_i2s_playcap";
+ pdevinfo[2].id = 1;
+ pdevinfo[2].parent = &pci->dev;
+ pdevinfo[2].num_res = 1;
+ pdevinfo[2].res = &adata->res[2];
+ for (i = 0; i < ACP3x_DEVS; i++) {
+ adata->pdev[i] =
+ platform_device_register_full(&pdevinfo[i]);
+ if (IS_ERR(adata->pdev[i])) {
+ dev_err(&pci->dev, "cannot register %s device\n",
+ pdevinfo[i].name);
+ ret = PTR_ERR(adata->pdev[i]);
+ goto unregister_devs;
+ }
}
break;
default:
dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
ret = -ENODEV;
- goto unmap_mmio;
+ goto disable_msi;
}
+ pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
+ pm_runtime_use_autosuspend(&pci->dev);
+ pm_runtime_set_active(&pci->dev);
+ pm_runtime_put_noidle(&pci->dev);
+ pm_runtime_enable(&pci->dev);
+ pm_runtime_allow(&pci->dev);
return 0;
-unmap_mmio:
+unregister_devs:
+ if (val == I2S_MODE)
+ for (i = 0; i < ACP3x_DEVS; i++)
+ platform_device_unregister(adata->pdev[i]);
+de_init:
+ if (acp3x_deinit(adata->acp3x_base))
+ dev_err(&pci->dev, "ACP de-init failed\n");
+disable_msi:
pci_disable_msi(pci);
- iounmap(adata->acp3x_base);
release_regions:
pci_release_regions(pci);
disable_pci:
@@ -122,13 +267,56 @@ disable_pci:
return ret;
}
-static void snd_acp3x_remove(struct pci_dev *pci)
+static int snd_acp3x_suspend(struct device *dev)
+{
+ int ret;
+ struct acp3x_dev_data *adata;
+
+ adata = dev_get_drvdata(dev);
+ ret = acp3x_deinit(adata->acp3x_base);
+ if (ret)
+ dev_err(dev, "ACP de-init failed\n");
+ else
+ dev_dbg(dev, "ACP de-initialized\n");
+
+ return 0;
+}
+
+static int snd_acp3x_resume(struct device *dev)
{
- struct acp3x_dev_data *adata = pci_get_drvdata(pci);
+ int ret;
+ struct acp3x_dev_data *adata;
- platform_device_unregister(adata->pdev);
- iounmap(adata->acp3x_base);
+ adata = dev_get_drvdata(dev);
+ ret = acp3x_init(adata->acp3x_base);
+ if (ret) {
+ dev_err(dev, "ACP init failed\n");
+ return ret;
+ }
+ return 0;
+}
+static const struct dev_pm_ops acp3x_pm = {
+ .runtime_suspend = snd_acp3x_suspend,
+ .runtime_resume = snd_acp3x_resume,
+ .resume = snd_acp3x_resume,
+};
+
+static void snd_acp3x_remove(struct pci_dev *pci)
+{
+ struct acp3x_dev_data *adata;
+ int i, ret;
+
+ adata = pci_get_drvdata(pci);
+ if (adata->acp3x_audio_mode == ACP3x_I2S_MODE) {
+ for (i = 0; i < ACP3x_DEVS; i++)
+ platform_device_unregister(adata->pdev[i]);
+ }
+ ret = acp3x_deinit(adata->acp3x_base);
+ if (ret)
+ dev_err(&pci->dev, "ACP de-init failed\n");
+ pm_runtime_disable(&pci->dev);
+ pm_runtime_get_noresume(&pci->dev);
pci_disable_msi(pci);
pci_release_regions(pci);
pci_disable_device(pci);
@@ -147,10 +335,14 @@ static struct pci_driver acp3x_driver = {
.id_table = snd_acp3x_ids,
.probe = snd_acp3x_probe,
.remove = snd_acp3x_remove,
+ .driver = {
+ .pm = &acp3x_pm,
+ }
};
module_pci_driver(acp3x_driver);
+MODULE_AUTHOR("[email protected]");
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("AMD ACP3x PCI driver");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 18a2fd02fffe..59c1331a6984 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -379,7 +379,6 @@ static int atmel_pcm_close(struct snd_soc_component *component,
static const struct snd_soc_component_driver atmel_soc_platform = {
.open = atmel_pcm_open,
.close = atmel_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = atmel_pcm_hw_params,
.hw_free = atmel_pcm_hw_free,
.prepare = atmel_pcm_prepare,
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 4553108ec92a..8f855644c6b4 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -197,10 +197,6 @@ static int au1xpsc_pcm_hw_params(struct snd_soc_component *component,
struct au1xpsc_audio_dmadata *pcd;
int stype, ret;
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (ret < 0)
- goto out;
-
stype = substream->stream;
pcd = to_dmadata(substream, component);
@@ -232,13 +228,6 @@ out:
return ret;
}
-static int au1xpsc_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- snd_pcm_lib_free_pages(substream);
- return 0;
-}
-
static int au1xpsc_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -315,7 +304,7 @@ static int au1xpsc_pcm_new(struct snd_soc_component *component,
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
return 0;
@@ -326,9 +315,7 @@ static struct snd_soc_component_driver au1xpsc_soc_component = {
.name = DRV_NAME,
.open = au1xpsc_pcm_open,
.close = au1xpsc_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = au1xpsc_pcm_hw_params,
- .hw_free = au1xpsc_pcm_hw_free,
.prepare = au1xpsc_pcm_prepare,
.trigger = au1xpsc_pcm_trigger,
.pointer = au1xpsc_pcm_pointer,
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index 054dfda89d3e..c9a038a5e2d3 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -231,19 +231,10 @@ static int alchemy_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_hw_params *hw_params)
{
struct audio_stream *stream = ss_to_as(substream, component);
- int err;
-
- err = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
- err = au1000_setup_dma_link(stream,
- params_period_bytes(hw_params),
- params_periods(hw_params));
- if (err)
- snd_pcm_lib_free_pages(substream);
- return err;
+ return au1000_setup_dma_link(stream,
+ params_period_bytes(hw_params),
+ params_periods(hw_params));
}
static int alchemy_pcm_hw_free(struct snd_soc_component *component,
@@ -251,7 +242,7 @@ static int alchemy_pcm_hw_free(struct snd_soc_component *component,
{
struct audio_stream *stream = ss_to_as(substream, component);
au1000_release_dma_link(stream);
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}
static int alchemy_pcm_trigger(struct snd_soc_component *component,
@@ -292,8 +283,8 @@ static int alchemy_pcm_new(struct snd_soc_component *component,
{
struct snd_pcm *pcm = rtd->pcm;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- NULL, 65536, (4096 * 1024) - 1);
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ NULL, 65536, (4096 * 1024) - 1);
return 0;
}
@@ -302,7 +293,6 @@ static struct snd_soc_component_driver alchemy_pcm_soc_component = {
.name = DRV_NAME,
.open = alchemy_pcm_open,
.close = alchemy_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = alchemy_pcm_hw_params,
.hw_free = alchemy_pcm_hw_free,
.trigger = alchemy_pcm_trigger,
diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index c65408085c1d..3a80c613bc3f 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -818,7 +818,6 @@ static int cygnus_dma_new(struct snd_soc_component *component,
static struct snd_soc_component_driver cygnus_soc_platform = {
.open = cygnus_pcm_open,
.close = cygnus_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = cygnus_pcm_hw_params,
.hw_free = cygnus_pcm_hw_free,
.prepare = cygnus_pcm_prepare,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4abf37b5083f..986a31c68992 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -207,6 +207,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
select SND_SOC_WCD9335 if SLIMBUS
+ select SND_SOC_WCD934X if MFD_WCD934X
select SND_SOC_WL1273 if MFD_WL1273_CORE
select SND_SOC_WM0010 if SPI_MASTER
select SND_SOC_WM1250_EV1 if I2C
@@ -261,6 +262,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM9705 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
select SND_SOC_WM9712 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
select SND_SOC_WM9713 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
+ select SND_SOC_WSA881X if SOUNDWIRE
help
Normally ASoC codec drivers are only built if a machine driver which
uses them is also built since they are only usable with a machine
@@ -1275,6 +1277,13 @@ config SND_SOC_WCD9335
Qualcomm Technologies, Inc. (QTI) multimedia solutions,
including the MSM8996, MSM8976, and MSM8956 chipsets.
+config SND_SOC_WCD934X
+ tristate "WCD9340/WCD9341 Codec"
+ depends on MFD_WCD934X
+ help
+ The WCD9340/9341 is a audio codec IC Integrated in
+ Qualcomm SoCs like SDM845.
+
config SND_SOC_WL1273
tristate
@@ -1473,6 +1482,15 @@ config SND_SOC_WM9713
select REGMAP_AC97
select AC97_BUS_COMPAT if AC97_BUS_NEW
+config SND_SOC_WSA881X
+ tristate "WSA881X Codec"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ tristate
+ help
+ This enables support for Qualcomm WSA8810/WSA8815 Class-D
+ Smart Speaker Amplifier.
+
config SND_SOC_ZX_AUD96P22
tristate "ZTE ZX AUD96P22 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index ddfd07071925..495f7e2f63eb 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -220,6 +220,7 @@ snd-soc-uda1334-objs := uda1334.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
+snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm-adsp-objs := wm_adsp.o
snd-soc-wm0010-objs := wm0010.o
@@ -277,6 +278,7 @@ snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-wsa881x-objs := wsa881x.o
snd-soc-zx-aud96p22-objs := zx_aud96p22.o
# Amp
snd-soc-max9877-objs := max9877.o
@@ -509,6 +511,7 @@ obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o
+obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
@@ -566,6 +569,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
# Amp
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 7b17f39a6a10..c81bbef2367a 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -918,7 +918,7 @@ static int wov_pcm_hw_params(struct snd_soc_component *component,
priv->wov_burst_read = true;
mutex_unlock(&priv->wov_dma_lock);
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+ return 0;
}
static int wov_pcm_hw_free(struct snd_soc_component *component,
@@ -934,7 +934,7 @@ static int wov_pcm_hw_free(struct snd_soc_component *component,
cancel_delayed_work_sync(&priv->wov_copy_work);
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}
static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component,
@@ -950,8 +950,8 @@ static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component,
static int wov_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
- NULL, 0, 0);
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
+ NULL, 0, 0);
return 0;
}
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 55408c8fcb4e..e47758e4fb36 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -214,12 +214,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
CS42L51_POWER_CTL1, 2, 1,
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
- SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
- CS42L51_POWER_CTL1, 5, 1,
- cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
- SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
- CS42L51_POWER_CTL1, 6, 1,
- cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Left DAC", NULL, CS42L51_POWER_CTL1, 5, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Right DAC", NULL, CS42L51_POWER_CTL1, 6, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
/* analog/mic */
SND_SOC_DAPM_INPUT("AIN1L"),
@@ -255,6 +253,12 @@ static const struct snd_soc_dapm_route cs42l51_routes[] = {
{"HPL", NULL, "Left DAC"},
{"HPR", NULL, "Right DAC"},
+ {"Right DAC", NULL, "DAC Mux"},
+ {"Left DAC", NULL, "DAC Mux"},
+
+ {"DAC Mux", "Direct PCM", "Playback"},
+ {"DAC Mux", "DSP PCM", "Playback"},
+
{"Left ADC", NULL, "Left PGA"},
{"Right ADC", NULL, "Right PGA"},
diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c
index ece1276f38eb..513e2875e4c6 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -438,11 +438,13 @@ static const struct snd_kcontrol_new cs47l15_aec_loopback_mux[] = {
static const struct snd_soc_dapm_widget cs47l15_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT,
0, madera_sysclk_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK,
MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1,
- MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT,
+ 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index d396a8545d51..ba7aa6b31205 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -521,11 +521,13 @@ static const struct snd_kcontrol_new cs47l35_aec_loopback_mux[] = {
static const struct snd_soc_dapm_widget cs47l35_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT,
0, madera_sysclk_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK,
MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT,
- 0, NULL, 0),
+ 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0),
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index 32fe7ffb7526..f85581a97bdc 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -790,15 +790,18 @@ static const struct snd_kcontrol_new cs47l85_output_anc_src[] = {
static const struct snd_soc_dapm_widget cs47l85_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT,
0, madera_sysclk_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", MADERA_ASYNC_CLOCK_1,
- MADERA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+ MADERA_ASYNC_CLK_ENA_SHIFT, 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK,
MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", MADERA_OUTPUT_ASYNC_CLOCK,
MADERA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1,
- MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT,
+ 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index 67cac60a859d..c3b6f4d41005 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -744,15 +744,18 @@ static const struct snd_kcontrol_new cs47l90_output_anc_src[] = {
static const struct snd_soc_dapm_widget cs47l90_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT,
0, madera_sysclk_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", MADERA_ASYNC_CLOCK_1,
- MADERA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+ MADERA_ASYNC_CLK_ENA_SHIFT, 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK,
MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", MADERA_OUTPUT_ASYNC_CLOCK,
MADERA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1,
- MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT,
+ 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index d50f75f3b3e4..cbffcd84766d 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -163,6 +163,51 @@ static int cs47l92_adsp_power_ev(struct snd_soc_dapm_widget *w,
return wm_adsp_early_event(w, kcontrol, event);
}
+static int cs47l92_outclk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component);
+ struct madera_priv *priv = &cs47l92->core;
+ struct madera *madera = priv->madera;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(madera->regmap, MADERA_OUTPUT_RATE_1, &val);
+ if (ret) {
+ dev_err(madera->dev, "Failed to read OUTCLK source: %d\n", ret);
+ return ret;
+ }
+
+ val &= MADERA_OUT_CLK_SRC_MASK;
+
+ switch (val) {
+ case MADERA_OUTCLK_MCLK1:
+ case MADERA_OUTCLK_MCLK2:
+ case MADERA_OUTCLK_MCLK3:
+ val -= (MADERA_OUTCLK_MCLK1 - MADERA_MCLK1);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = clk_prepare_enable(madera->mclk[val].clk);
+ if (ret)
+ return ret;
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ clk_disable_unprepare(madera->mclk[val].clk);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return madera_domain_clk_ev(w, kcontrol, event);
+}
+
#define CS47L92_NG_SRC(name, base) \
SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
@@ -615,15 +660,18 @@ static const struct snd_kcontrol_new cs47l92_aec_loopback_mux =
static const struct snd_soc_dapm_widget cs47l92_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT,
0, madera_sysclk_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", MADERA_ASYNC_CLOCK_1,
- MADERA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+ MADERA_ASYNC_CLK_ENA_SHIFT, 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK,
MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", MADERA_OUTPUT_ASYNC_CLOCK,
MADERA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1,
- MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT,
+ 0, madera_clk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD2", 20, 0),
@@ -666,7 +714,7 @@ SND_SOC_DAPM_SUPPLY("ISRC2CLK", SND_SOC_NOPM,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("OUTCLK", SND_SOC_NOPM,
MADERA_DOM_GRP_OUT, 0,
- madera_domain_clk_ev,
+ cs47l92_outclk_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("SPDCLK", SND_SOC_NOPM,
MADERA_DOM_GRP_SPD, 0,
@@ -1959,10 +2007,8 @@ static int cs47l92_probe(struct platform_device *pdev)
goto error_dsp_irq;
ret = madera_init_bus_error_irq(&cs47l92->core, 0, wm_adsp2_bus_error);
- if (ret != 0) {
- wm_adsp2_remove(&cs47l92->core.adsp[0]);
+ if (ret != 0)
goto error_adsp;
- }
madera_init_fll(madera, 1, MADERA_FLL1_CONTROL_1 - 1,
&cs47l92->fll[0]);
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
index d454294c8d06..ae9e1c70ca57 100644
--- a/sound/soc/codecs/gtm601.c
+++ b/sound/soc/codecs/gtm601.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/device.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
@@ -47,6 +47,24 @@ static struct snd_soc_dai_driver gtm601_dai = {
},
};
+static struct snd_soc_dai_driver bm818_dai = {
+ .name = "bm818",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+};
+
static const struct snd_soc_component_driver soc_component_dev_gtm601 = {
.dapm_widgets = gtm601_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets),
@@ -60,17 +78,21 @@ static const struct snd_soc_component_driver soc_component_dev_gtm601 = {
static int gtm601_platform_probe(struct platform_device *pdev)
{
+ const struct snd_soc_dai_driver *dai_driver;
+
+ dai_driver = of_device_get_match_data(&pdev->dev);
+
return devm_snd_soc_register_component(&pdev->dev,
- &soc_component_dev_gtm601, &gtm601_dai, 1);
+ &soc_component_dev_gtm601,
+ (struct snd_soc_dai_driver *)dai_driver, 1);
}
-#if defined(CONFIG_OF)
static const struct of_device_id gtm601_codec_of_match[] = {
- { .compatible = "option,gtm601", },
+ { .compatible = "option,gtm601", .data = (void *)&gtm601_dai },
+ { .compatible = "broadmobi,bm818", .data = (void *)&bm818_dai },
{},
};
MODULE_DEVICE_TABLE(of, gtm601_codec_of_match);
-#endif
static struct platform_driver gtm601_codec_driver = {
.driver = {
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 6803d39e09a5..4e0f4afe6ddc 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -164,6 +164,19 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = {
.sig_bits = 24,
},
},
+{
+ .id = HDAC_HDMI_3_DAI_ID,
+ .name = "intel-hdmi-hifi4",
+ .ops = &hdac_hda_dai_ops,
+ .playback = {
+ .stream_name = "hifi4",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rates = STUB_HDMI_RATES,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+},
};
@@ -346,6 +359,9 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
case HDAC_HDMI_2_DAI_ID:
pcm_name = "HDMI 2";
break;
+ case HDAC_HDMI_3_DAI_ID:
+ pcm_name = "HDMI 3";
+ break;
default:
dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
return NULL;
diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h
index e145cec085b8..598b07d9b6fe 100644
--- a/sound/soc/codecs/hdac_hda.h
+++ b/sound/soc/codecs/hdac_hda.h
@@ -13,7 +13,8 @@ enum {
HDAC_HDMI_0_DAI_ID,
HDAC_HDMI_1_DAI_ID,
HDAC_HDMI_2_DAI_ID,
- HDAC_LAST_DAI_ID = HDAC_HDMI_2_DAI_ID,
+ HDAC_HDMI_3_DAI_ID,
+ HDAC_LAST_DAI_ID = HDAC_HDMI_3_DAI_ID,
};
struct hdac_hda_pcm {
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 18c173e6a13b..e6558475e006 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -115,16 +115,8 @@ 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 {
@@ -1374,12 +1366,11 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
return 0;
}
-#define INTEL_VENDOR_NID_0x2 0x02
-#define INTEL_VENDOR_NID_0x8 0x08
-#define INTEL_VENDOR_NID_0xb 0x0b
+#define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 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)
@@ -1566,26 +1557,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
static int hdac_hdmi_pin2port(void *aptr, int pin)
{
- 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;
+ return pin - 4; /* map NID 0x05 -> port #1 */
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@@ -1596,18 +1568,9 @@ 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;
- 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;
- }
+
+ /* Don't know how this mapping is derived */
+ hda_nid_t pin_nid = port + 0x04;
dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
@@ -2025,18 +1988,12 @@ 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_VENDOR_NID_0xb,
+ .vendor_nid = INTEL_GLK_VENDOR_NID,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
- .vendor_nid = INTEL_VENDOR_NID_0x8,
+ .vendor_nid = INTEL_VENDOR_NID,
};
static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
@@ -2216,8 +2173,6 @@ 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/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index f8b5b960e597..543363102d03 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -274,7 +274,8 @@ struct hdmi_codec_priv {
uint8_t eld[MAX_ELD_BYTES];
struct snd_pcm_chmap *chmap_info;
unsigned int chmap_idx;
- unsigned long busy;
+ struct mutex lock;
+ bool busy;
struct snd_soc_jack *jack;
unsigned int jack_status;
};
@@ -390,9 +391,10 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
int ret = 0;
- ret = test_and_set_bit(0, &hcp->busy);
- if (ret) {
+ mutex_lock(&hcp->lock);
+ if (hcp->busy) {
dev_err(dai->dev, "Only one simultaneous stream supported!\n");
+ mutex_unlock(&hcp->lock);
return -EINVAL;
}
@@ -405,21 +407,21 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (hcp->hcd.ops->get_eld) {
ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
hcp->eld, sizeof(hcp->eld));
+ if (ret)
+ goto err;
+
+ ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld);
+ if (ret)
+ goto err;
- if (!ret) {
- ret = snd_pcm_hw_constraint_eld(substream->runtime,
- hcp->eld);
- if (ret)
- goto err;
- }
/* Select chmap supported */
hdmi_codec_eld_chmap(hcp);
}
- return 0;
+
+ hcp->busy = true;
err:
- /* Release the exclusive lock on error */
- clear_bit(0, &hcp->busy);
+ mutex_unlock(&hcp->lock);
return ret;
}
@@ -431,7 +433,9 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
- clear_bit(0, &hcp->busy);
+ mutex_lock(&hcp->lock);
+ hcp->busy = false;
+ mutex_unlock(&hcp->lock);
}
static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
@@ -811,6 +815,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
return -ENOMEM;
hcp->hcd = *hcd;
+ mutex_init(&hcp->lock);
+
daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL);
if (!daidrv)
return -ENOMEM;
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index 52639811cc52..12dc468ae6bf 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -163,6 +163,48 @@ static const int madera_dsp_bus_error_irqs[MADERA_MAX_ADSP] = {
MADERA_IRQ_DSP7_BUS_ERR,
};
+int madera_clk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct madera_priv *priv = snd_soc_component_get_drvdata(component);
+ struct madera *madera = priv->madera;
+ unsigned int val;
+ int clk_idx;
+ int ret;
+
+ ret = regmap_read(madera->regmap, w->reg, &val);
+ if (ret) {
+ dev_err(madera->dev, "Failed to check clock source: %d\n", ret);
+ return ret;
+ }
+
+ switch ((val & MADERA_SYSCLK_SRC_MASK) >> MADERA_SYSCLK_SRC_SHIFT) {
+ case MADERA_CLK_SRC_MCLK1:
+ clk_idx = MADERA_MCLK1;
+ break;
+ case MADERA_CLK_SRC_MCLK2:
+ clk_idx = MADERA_MCLK2;
+ break;
+ case MADERA_CLK_SRC_MCLK3:
+ clk_idx = MADERA_MCLK3;
+ break;
+ default:
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return clk_prepare_enable(madera->mclk[clk_idx].clk);
+ case SND_SOC_DAPM_POST_PMD:
+ clk_disable_unprepare(madera->mclk[clk_idx].clk);
+ return 0;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(madera_clk_ev);
+
static void madera_spin_sysclk(struct madera_priv *priv)
{
struct madera *madera = priv->madera;
@@ -193,9 +235,16 @@ int madera_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
- madera_spin_sysclk(priv);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_PRE_PMD:
+ madera_spin_sysclk(priv);
+ break;
+ default:
+ break;
+ }
- return 0;
+ return madera_clk_ev(w, kcontrol, event);
}
EXPORT_SYMBOL_GPL(madera_sysclk_ev);
@@ -3809,11 +3858,75 @@ static bool madera_set_fll_phase_integrator(struct madera_fll *fll,
return reg_change;
}
+static int madera_set_fll_clks_reg(struct madera_fll *fll, bool ena,
+ unsigned int reg, unsigned int mask,
+ unsigned int shift)
+{
+ struct madera *madera = fll->madera;
+ unsigned int src;
+ struct clk *clk;
+ int ret;
+
+ ret = regmap_read(madera->regmap, reg, &src);
+ if (ret != 0) {
+ madera_fll_err(fll, "Failed to read current source: %d\n",
+ ret);
+ return ret;
+ }
+
+ src = (src & mask) >> shift;
+
+ switch (src) {
+ case MADERA_FLL_SRC_MCLK1:
+ clk = madera->mclk[MADERA_MCLK1].clk;
+ break;
+ case MADERA_FLL_SRC_MCLK2:
+ clk = madera->mclk[MADERA_MCLK2].clk;
+ break;
+ case MADERA_FLL_SRC_MCLK3:
+ clk = madera->mclk[MADERA_MCLK3].clk;
+ break;
+ default:
+ return 0;
+ }
+
+ if (ena) {
+ return clk_prepare_enable(clk);
+ } else {
+ clk_disable_unprepare(clk);
+ return 0;
+ }
+}
+
+static inline int madera_set_fll_clks(struct madera_fll *fll, int base, bool ena)
+{
+ return madera_set_fll_clks_reg(fll, ena,
+ base + MADERA_FLL_CONTROL_6_OFFS,
+ MADERA_FLL1_REFCLK_SRC_MASK,
+ MADERA_FLL1_REFCLK_DIV_SHIFT);
+}
+
+static inline int madera_set_fllao_clks(struct madera_fll *fll, int base, bool ena)
+{
+ return madera_set_fll_clks_reg(fll, ena,
+ base + MADERA_FLLAO_CONTROL_6_OFFS,
+ MADERA_FLL_AO_REFCLK_SRC_MASK,
+ MADERA_FLL_AO_REFCLK_SRC_SHIFT);
+}
+
+static inline int madera_set_fllhj_clks(struct madera_fll *fll, int base, bool ena)
+{
+ return madera_set_fll_clks_reg(fll, ena,
+ base + MADERA_FLL_CONTROL_1_OFFS,
+ CS47L92_FLL1_REFCLK_SRC_MASK,
+ CS47L92_FLL1_REFCLK_SRC_SHIFT);
+}
+
static void madera_disable_fll(struct madera_fll *fll)
{
struct madera *madera = fll->madera;
unsigned int sync_base;
- bool change;
+ bool ref_change, sync_change;
switch (madera->type) {
case CS47L35:
@@ -3831,18 +3944,23 @@ static void madera_disable_fll(struct madera_fll *fll)
MADERA_FLL1_FREERUN, MADERA_FLL1_FREERUN);
regmap_update_bits_check(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
- MADERA_FLL1_ENA, 0, &change);
- regmap_update_bits(madera->regmap,
- sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
- MADERA_FLL1_SYNC_ENA, 0);
+ MADERA_FLL1_ENA, 0, &ref_change);
+ regmap_update_bits_check(madera->regmap,
+ sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
+ MADERA_FLL1_SYNC_ENA, 0, &sync_change);
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
MADERA_FLL1_FREERUN, 0);
madera_wait_for_fll(fll, false);
- if (change)
+ if (sync_change)
+ madera_set_fll_clks(fll, sync_base, false);
+
+ if (ref_change) {
+ madera_set_fll_clks(fll, fll->base, false);
pm_runtime_put_autosuspend(madera->dev);
+ }
}
static int madera_enable_fll(struct madera_fll *fll)
@@ -3898,6 +4016,10 @@ static int madera_enable_fll(struct madera_fll *fll)
regmap_update_bits(fll->madera->regmap,
fll->base + MADERA_FLL_CONTROL_7_OFFS,
MADERA_FLL1_GAIN_MASK, 0);
+
+ if (sync_enabled > 0)
+ madera_set_fll_clks(fll, sync_base, false);
+ madera_set_fll_clks(fll, fll->base, false);
}
/* Apply SYNCCLK setting */
@@ -3976,11 +4098,15 @@ static int madera_enable_fll(struct madera_fll *fll)
if (!already_enabled)
pm_runtime_get_sync(madera->dev);
- if (have_sync)
+ if (have_sync) {
+ madera_set_fll_clks(fll, sync_base, true);
regmap_update_bits(madera->regmap,
sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
MADERA_FLL1_SYNC_ENA,
MADERA_FLL1_SYNC_ENA);
+ }
+
+ madera_set_fll_clks(fll, fll->base, true);
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
MADERA_FLL1_ENA, MADERA_FLL1_ENA);
@@ -4152,6 +4278,9 @@ static int madera_enable_fll_ao(struct madera_fll *fll,
fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);
+ if (already_enabled)
+ madera_set_fllao_clks(fll, fll->base, false);
+
for (i = 0; i < patch_size; i++) {
val = patch[i].def;
@@ -4165,6 +4294,8 @@ static int madera_enable_fll_ao(struct madera_fll *fll,
regmap_write(madera->regmap, patch[i].reg, val);
}
+ madera_set_fllao_clks(fll, fll->base, true);
+
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
MADERA_FLL_AO_ENA, MADERA_FLL_AO_ENA);
@@ -4208,8 +4339,10 @@ static int madera_disable_fll_ao(struct madera_fll *fll)
fll->base + MADERA_FLLAO_CONTROL_2_OFFS,
MADERA_FLL_AO_CTRL_UPD_MASK, 0);
- if (change)
+ if (change) {
+ madera_set_fllao_clks(fll, fll->base, false);
pm_runtime_put_autosuspend(madera->dev);
+ }
return 0;
}
@@ -4295,8 +4428,10 @@ static int madera_fllhj_disable(struct madera_fll *fll)
fll->base + MADERA_FLL_CONTROL_2_OFFS,
MADERA_FLL1_CTRL_UPD_MASK, 0);
- if (change)
+ if (change) {
+ madera_set_fllhj_clks(fll, fll->base, false);
pm_runtime_put_autosuspend(madera->dev);
+ }
return 0;
}
@@ -4468,6 +4603,9 @@ static int madera_fllhj_enable(struct madera_fll *fll)
MADERA_FLL1_HOLD_MASK,
MADERA_FLL1_HOLD_MASK);
+ if (already_enabled)
+ madera_set_fllhj_clks(fll, fll->base, false);
+
/* Apply refclk */
ret = madera_fllhj_apply(fll, fll->ref_freq);
if (ret) {
@@ -4479,6 +4617,8 @@ static int madera_fllhj_enable(struct madera_fll *fll)
CS47L92_FLL1_REFCLK_SRC_MASK,
fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT);
+ madera_set_fllhj_clks(fll, fll->base, true);
+
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
MADERA_FLL1_ENA_MASK,
diff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h
index 6d8938a3fb64..49a8f68ec43d 100644
--- a/sound/soc/codecs/madera.h
+++ b/sound/soc/codecs/madera.h
@@ -383,6 +383,8 @@ int madera_eq_coeff_put(struct snd_kcontrol *kcontrol,
int madera_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+int madera_clk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
int madera_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int madera_spk_ev(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index f6bf4cfbea23..ba0e3ba162f8 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -5,24 +5,149 @@
* Copyright 2011-2012 Maxim Integrated Products
*/
+#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/acpi.h>
-#include <linux/clk.h>
#include <sound/jack.h>
+#include <sound/max98090.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <sound/max98090.h>
#include "max98090.h"
+static void max98090_shdn_save_locked(struct max98090_priv *max98090)
+{
+ int shdn = 0;
+
+ /* saved_shdn, saved_count, SHDN are protected by card->dapm_mutex */
+ regmap_read(max98090->regmap, M98090_REG_DEVICE_SHUTDOWN, &shdn);
+ max98090->saved_shdn |= shdn;
+ ++max98090->saved_count;
+
+ if (shdn)
+ regmap_write(max98090->regmap, M98090_REG_DEVICE_SHUTDOWN, 0x0);
+}
+
+static void max98090_shdn_restore_locked(struct max98090_priv *max98090)
+{
+ /* saved_shdn, saved_count, SHDN are protected by card->dapm_mutex */
+ if (--max98090->saved_count == 0) {
+ if (max98090->saved_shdn) {
+ regmap_write(max98090->regmap,
+ M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK);
+ max98090->saved_shdn = 0;
+ }
+ }
+}
+
+static void max98090_shdn_save(struct max98090_priv *max98090)
+{
+ mutex_lock(&max98090->shdn_lock);
+ max98090_shdn_save_locked(max98090);
+}
+
+static void max98090_shdn_restore(struct max98090_priv *max98090)
+{
+ max98090_shdn_restore_locked(max98090);
+ mutex_unlock(&max98090->shdn_lock);
+}
+
+static int max98090_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct max98090_priv *max98090 =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ max98090_shdn_save(max98090);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ max98090_shdn_restore(max98090);
+
+ return ret;
+}
+
+static int max98090_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct max98090_priv *max98090 =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ max98090_shdn_save(max98090);
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+ max98090_shdn_restore(max98090);
+
+ return ret;
+}
+
+static int max98090_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct max98090_priv *max98090 =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ max98090_shdn_save(max98090);
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+ max98090_shdn_restore(max98090);
+
+ return ret;
+}
+
+static int max98090_bytes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct max98090_priv *max98090 =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ max98090_shdn_save(max98090);
+ ret = snd_soc_bytes_put(kcontrol, ucontrol);
+ max98090_shdn_restore(max98090);
+
+ return ret;
+}
+
+static int max98090_dapm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct max98090_priv *max98090 =
+ snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ case SND_SOC_DAPM_PRE_PMD:
+ max98090_shdn_save_locked(max98090);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ max98090_shdn_restore_locked(max98090);
+ break;
+ }
+
+ return 0;
+}
+
/* Allows for sparsely populated register maps */
static const struct reg_default max98090_reg[] = {
{ 0x00, 0x00 }, /* 00 Software Reset */
@@ -506,10 +631,13 @@ static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum,
max98090_pwr_perf_text);
static const struct snd_kcontrol_new max98090_snd_controls[] = {
- SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum),
+ SOC_ENUM_EXT("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
- SOC_SINGLE("DMIC MIC Comp Filter Config", M98090_REG_DIGITAL_MIC_CONFIG,
- M98090_DMIC_COMP_SHIFT, M98090_DMIC_COMP_NUM - 1, 0),
+ SOC_SINGLE_EXT("DMIC MIC Comp Filter Config",
+ M98090_REG_DIGITAL_MIC_CONFIG,
+ M98090_DMIC_COMP_SHIFT, M98090_DMIC_COMP_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
@@ -564,24 +692,34 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {
M98090_AVR_SHIFT, M98090_AVR_NUM - 1, 1,
max98090_av_tlv),
- SOC_ENUM("ADC Oversampling Rate", max98090_osr128_enum),
- SOC_SINGLE("ADC Quantizer Dither", M98090_REG_ADC_CONTROL,
- M98090_ADCDITHER_SHIFT, M98090_ADCDITHER_NUM - 1, 0),
- SOC_ENUM("ADC High Performance Mode", max98090_adchp_enum),
-
- SOC_SINGLE("DAC Mono Mode", M98090_REG_IO_CONFIGURATION,
- M98090_DMONO_SHIFT, M98090_DMONO_NUM - 1, 0),
- SOC_SINGLE("SDIN Mode", M98090_REG_IO_CONFIGURATION,
- M98090_SDIEN_SHIFT, M98090_SDIEN_NUM - 1, 0),
- SOC_SINGLE("SDOUT Mode", M98090_REG_IO_CONFIGURATION,
- M98090_SDOEN_SHIFT, M98090_SDOEN_NUM - 1, 0),
- SOC_SINGLE("SDOUT Hi-Z Mode", M98090_REG_IO_CONFIGURATION,
- M98090_HIZOFF_SHIFT, M98090_HIZOFF_NUM - 1, 1),
- SOC_ENUM("Filter Mode", max98090_mode_enum),
- SOC_SINGLE("Record Path DC Blocking", M98090_REG_FILTER_CONFIG,
- M98090_AHPF_SHIFT, M98090_AHPF_NUM - 1, 0),
- SOC_SINGLE("Playback Path DC Blocking", M98090_REG_FILTER_CONFIG,
- M98090_DHPF_SHIFT, M98090_DHPF_NUM - 1, 0),
+ SOC_ENUM_EXT("ADC Oversampling Rate", max98090_osr128_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_SINGLE_EXT("ADC Quantizer Dither", M98090_REG_ADC_CONTROL,
+ M98090_ADCDITHER_SHIFT, M98090_ADCDITHER_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_ENUM_EXT("ADC High Performance Mode", max98090_adchp_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+
+ SOC_SINGLE_EXT("DAC Mono Mode", M98090_REG_IO_CONFIGURATION,
+ M98090_DMONO_SHIFT, M98090_DMONO_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_SINGLE_EXT("SDIN Mode", M98090_REG_IO_CONFIGURATION,
+ M98090_SDIEN_SHIFT, M98090_SDIEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_SINGLE_EXT("SDOUT Mode", M98090_REG_IO_CONFIGURATION,
+ M98090_SDOEN_SHIFT, M98090_SDOEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_SINGLE_EXT("SDOUT Hi-Z Mode", M98090_REG_IO_CONFIGURATION,
+ M98090_HIZOFF_SHIFT, M98090_HIZOFF_NUM - 1, 1,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_ENUM_EXT("Filter Mode", max98090_mode_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_SINGLE_EXT("Record Path DC Blocking", M98090_REG_FILTER_CONFIG,
+ M98090_AHPF_SHIFT, M98090_AHPF_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_SINGLE_EXT("Playback Path DC Blocking", M98090_REG_FILTER_CONFIG,
+ M98090_DHPF_SHIFT, M98090_DHPF_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
SOC_SINGLE_TLV("Digital BQ Volume", M98090_REG_ADC_BIQUAD_LEVEL,
M98090_AVBQ_SHIFT, M98090_AVBQ_NUM - 1, 1, max98090_dv_tlv),
SOC_SINGLE_EXT_TLV("Digital Sidetone Volume",
@@ -594,13 +732,17 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {
SOC_SINGLE_TLV("Digital Volume", M98090_REG_DAI_PLAYBACK_LEVEL,
M98090_DV_SHIFT, M98090_DV_NUM - 1, 1,
max98090_dv_tlv),
- SND_SOC_BYTES("EQ Coefficients", M98090_REG_EQUALIZER_BASE, 105),
- SOC_SINGLE("Digital EQ 3 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
- M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0),
- SOC_SINGLE("Digital EQ 5 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
- M98090_EQ5BANDEN_SHIFT, M98090_EQ5BANDEN_NUM - 1, 0),
- SOC_SINGLE("Digital EQ 7 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
- M98090_EQ7BANDEN_SHIFT, M98090_EQ7BANDEN_NUM - 1, 0),
+ SND_SOC_BYTES_E("EQ Coefficients", M98090_REG_EQUALIZER_BASE, 105,
+ snd_soc_bytes_get, max98090_bytes_put),
+ SOC_SINGLE_EXT("Digital EQ 3 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
+ M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_SINGLE_EXT("Digital EQ 5 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
+ M98090_EQ5BANDEN_SHIFT, M98090_EQ5BANDEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_SINGLE_EXT("Digital EQ 7 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
+ M98090_EQ7BANDEN_SHIFT, M98090_EQ7BANDEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
SOC_SINGLE("Digital EQ Clipping Detection", M98090_REG_DAI_PLAYBACK_LEVEL_EQ,
M98090_EQCLPN_SHIFT, M98090_EQCLPN_NUM - 1,
1),
@@ -608,25 +750,34 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {
M98090_DVEQ_SHIFT, M98090_DVEQ_NUM - 1, 1,
max98090_dv_tlv),
- SOC_SINGLE("ALC Enable", M98090_REG_DRC_TIMING,
- M98090_DRCEN_SHIFT, M98090_DRCEN_NUM - 1, 0),
- SOC_ENUM("ALC Attack Time", max98090_drcatk_enum),
- SOC_ENUM("ALC Release Time", max98090_drcrls_enum),
+ SOC_SINGLE_EXT("ALC Enable", M98090_REG_DRC_TIMING,
+ M98090_DRCEN_SHIFT, M98090_DRCEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
+ SOC_ENUM_EXT("ALC Attack Time", max98090_drcatk_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_ENUM_EXT("ALC Release Time", max98090_drcrls_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
SOC_SINGLE_TLV("ALC Make Up Volume", M98090_REG_DRC_GAIN,
M98090_DRCG_SHIFT, M98090_DRCG_NUM - 1, 0,
max98090_alcmakeup_tlv),
- SOC_ENUM("ALC Compression Ratio", max98090_alccmp_enum),
- SOC_ENUM("ALC Expansion Ratio", max98090_drcexp_enum),
- SOC_SINGLE_TLV("ALC Compression Threshold Volume",
+ SOC_ENUM_EXT("ALC Compression Ratio", max98090_alccmp_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_ENUM_EXT("ALC Expansion Ratio", max98090_drcexp_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_SINGLE_EXT_TLV("ALC Compression Threshold Volume",
M98090_REG_DRC_COMPRESSOR, M98090_DRCTHC_SHIFT,
- M98090_DRCTHC_NUM - 1, 1, max98090_alccomp_tlv),
- SOC_SINGLE_TLV("ALC Expansion Threshold Volume",
+ M98090_DRCTHC_NUM - 1, 1,
+ snd_soc_get_volsw, max98090_put_volsw, max98090_alccomp_tlv),
+ SOC_SINGLE_EXT_TLV("ALC Expansion Threshold Volume",
M98090_REG_DRC_EXPANDER, M98090_DRCTHE_SHIFT,
- M98090_DRCTHE_NUM - 1, 1, max98090_drcexp_tlv),
+ M98090_DRCTHE_NUM - 1, 1,
+ snd_soc_get_volsw, max98090_put_volsw, max98090_drcexp_tlv),
- SOC_ENUM("DAC HP Playback Performance Mode",
- max98090_dac_perfmode_enum),
- SOC_ENUM("DAC High Performance Mode", max98090_dachp_enum),
+ SOC_ENUM_EXT("DAC HP Playback Performance Mode",
+ max98090_dac_perfmode_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_ENUM_EXT("DAC High Performance Mode", max98090_dachp_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
SOC_SINGLE_TLV("Headphone Left Mixer Volume",
M98090_REG_HP_CONTROL, M98090_MIXHPLG_SHIFT,
@@ -684,9 +835,12 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {
SOC_SINGLE("Volume Adjustment Smoothing", M98090_REG_LEVEL_CONTROL,
M98090_VSENN_SHIFT, M98090_VSENN_NUM - 1, 1),
- SND_SOC_BYTES("Biquad Coefficients", M98090_REG_RECORD_BIQUAD_BASE, 15),
- SOC_SINGLE("Biquad Switch", M98090_REG_DSP_FILTER_ENABLE,
- M98090_ADCBQEN_SHIFT, M98090_ADCBQEN_NUM - 1, 0),
+ SND_SOC_BYTES_E("Biquad Coefficients",
+ M98090_REG_RECORD_BIQUAD_BASE, 15,
+ snd_soc_bytes_get, max98090_bytes_put),
+ SOC_SINGLE_EXT("Biquad Switch", M98090_REG_DSP_FILTER_ENABLE,
+ M98090_ADCBQEN_SHIFT, M98090_ADCBQEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
};
static const struct snd_kcontrol_new max98091_snd_controls[] = {
@@ -695,10 +849,12 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
M98090_DMIC34_ZEROPAD_SHIFT,
M98090_DMIC34_ZEROPAD_NUM - 1, 0),
- SOC_ENUM("Filter DMIC34 Mode", max98090_filter_dmic34mode_enum),
- SOC_SINGLE("DMIC34 DC Blocking", M98090_REG_FILTER_CONFIG,
+ SOC_ENUM_EXT("Filter DMIC34 Mode", max98090_filter_dmic34mode_enum,
+ snd_soc_get_enum_double, max98090_put_enum_double),
+ SOC_SINGLE_EXT("DMIC34 DC Blocking", M98090_REG_FILTER_CONFIG,
M98090_FLT_DMIC34HPF_SHIFT,
- M98090_FLT_DMIC34HPF_NUM - 1, 0),
+ M98090_FLT_DMIC34HPF_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
SOC_SINGLE_TLV("DMIC3 Boost Volume", M98090_REG_DMIC3_VOLUME,
M98090_DMIC_AV3G_SHIFT, M98090_DMIC_AV3G_NUM - 1, 0,
@@ -716,8 +872,9 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
SND_SOC_BYTES("DMIC34 Biquad Coefficients",
M98090_REG_DMIC34_BIQUAD_BASE, 15),
- SOC_SINGLE("DMIC34 Biquad Switch", M98090_REG_DSP_FILTER_ENABLE,
- M98090_DMIC34BQEN_SHIFT, M98090_DMIC34BQEN_NUM - 1, 0),
+ SOC_SINGLE_EXT("DMIC34 Biquad Switch", M98090_REG_DSP_FILTER_ENABLE,
+ M98090_DMIC34BQEN_SHIFT, M98090_DMIC34BQEN_NUM - 1, 0,
+ snd_soc_get_volsw, max98090_put_volsw),
SOC_SINGLE_TLV("DMIC34 BQ PreAttenuation Volume",
M98090_REG_DMIC34_BQ_PREATTEN, M98090_AV34BQ_SHIFT,
@@ -771,19 +928,6 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static int max98090_shdn_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
-
- if (event & SND_SOC_DAPM_POST_PMU)
- max98090->shdn_pending = true;
-
- return 0;
-
-}
-
static const char *mic1_mux_text[] = { "IN12", "IN56" };
static SOC_ENUM_SINGLE_DECL(mic1_mux_enum,
@@ -884,10 +1028,14 @@ static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum,
lten_mux_text);
static const struct snd_kcontrol_new max98090_ltenl_mux =
- SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum);
+ SOC_DAPM_ENUM_EXT("LTENL Mux", ltenl_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ max98090_dapm_put_enum_double);
static const struct snd_kcontrol_new max98090_ltenr_mux =
- SOC_DAPM_ENUM("LTENR Mux", ltenr_mux_enum);
+ SOC_DAPM_ENUM_EXT("LTENR Mux", ltenr_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ max98090_dapm_put_enum_double);
static const char *lben_mux_text[] = { "Normal", "Loopback" };
@@ -902,10 +1050,14 @@ static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum,
lben_mux_text);
static const struct snd_kcontrol_new max98090_lbenl_mux =
- SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum);
+ SOC_DAPM_ENUM_EXT("LBENL Mux", lbenl_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ max98090_dapm_put_enum_double);
static const struct snd_kcontrol_new max98090_lbenr_mux =
- SOC_DAPM_ENUM("LBENR Mux", lbenr_mux_enum);
+ SOC_DAPM_ENUM_EXT("LBENR Mux", lbenr_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ max98090_dapm_put_enum_double);
static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" };
@@ -1072,21 +1224,25 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("IN56"),
SND_SOC_DAPM_SUPPLY("MICBIAS", M98090_REG_INPUT_ENABLE,
- M98090_MBEN_SHIFT, 0, NULL, 0),
+ M98090_MBEN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_SUPPLY("SHDN", M98090_REG_DEVICE_SHUTDOWN,
M98090_SHDNN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("SDIEN", M98090_REG_IO_CONFIGURATION,
- M98090_SDIEN_SHIFT, 0, NULL, 0),
+ M98090_SDIEN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION,
- M98090_SDOEN_SHIFT, 0, NULL, 0),
+ M98090_SDOEN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMICL_SHIFT, 0, max98090_shdn_event,
- SND_SOC_DAPM_POST_PMU),
+ M98090_DIGMICL_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMICR_SHIFT, 0, max98090_shdn_event,
- SND_SOC_DAPM_POST_PMU),
+ M98090_DIGMICR_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG,
- M98090_AHPF_SHIFT, 0, NULL, 0),
+ M98090_AHPF_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
/*
* Note: Sysclk and misc power supplies are taken care of by SHDN
@@ -1116,10 +1272,12 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
&max98090_lineb_mixer_controls[0],
ARRAY_SIZE(max98090_lineb_mixer_controls)),
- SND_SOC_DAPM_PGA("LINEA Input", M98090_REG_INPUT_ENABLE,
- M98090_LINEAEN_SHIFT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("LINEB Input", M98090_REG_INPUT_ENABLE,
- M98090_LINEBEN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("LINEA Input", M98090_REG_INPUT_ENABLE,
+ M98090_LINEAEN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEB Input", M98090_REG_INPUT_ENABLE,
+ M98090_LINEBEN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
&max98090_left_adc_mixer_controls[0],
@@ -1130,11 +1288,11 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
ARRAY_SIZE(max98090_right_adc_mixer_controls)),
SND_SOC_DAPM_ADC_E("ADCL", NULL, M98090_REG_INPUT_ENABLE,
- M98090_ADLEN_SHIFT, 0, max98090_shdn_event,
- SND_SOC_DAPM_POST_PMU),
+ M98090_ADLEN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_ADC_E("ADCR", NULL, M98090_REG_INPUT_ENABLE,
- M98090_ADREN_SHIFT, 0, max98090_shdn_event,
- SND_SOC_DAPM_POST_PMU),
+ M98090_ADREN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0,
SND_SOC_NOPM, 0, 0),
@@ -1162,10 +1320,12 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_DAC("DACL", NULL, M98090_REG_OUTPUT_ENABLE,
- M98090_DALEN_SHIFT, 0),
- SND_SOC_DAPM_DAC("DACR", NULL, M98090_REG_OUTPUT_ENABLE,
- M98090_DAREN_SHIFT, 0),
+ SND_SOC_DAPM_DAC_E("DACL", NULL, M98090_REG_OUTPUT_ENABLE,
+ M98090_DALEN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("DACR", NULL, M98090_REG_OUTPUT_ENABLE,
+ M98090_DAREN_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
&max98090_left_hp_mixer_controls[0],
@@ -1200,20 +1360,26 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_MUX("MIXHPRSEL Mux", SND_SOC_NOPM, 0, 0,
&max98090_mixhprsel_mux),
- SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE,
- M98090_HPLEN_SHIFT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP Right Out", M98090_REG_OUTPUT_ENABLE,
- M98090_HPREN_SHIFT, 0, NULL, 0),
-
- SND_SOC_DAPM_PGA("SPK Left Out", M98090_REG_OUTPUT_ENABLE,
- M98090_SPLEN_SHIFT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("SPK Right Out", M98090_REG_OUTPUT_ENABLE,
- M98090_SPREN_SHIFT, 0, NULL, 0),
-
- SND_SOC_DAPM_PGA("RCV Left Out", M98090_REG_OUTPUT_ENABLE,
- M98090_RCVLEN_SHIFT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("RCV Right Out", M98090_REG_OUTPUT_ENABLE,
- M98090_RCVREN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("HP Left Out", M98090_REG_OUTPUT_ENABLE,
+ M98090_HPLEN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HP Right Out", M98090_REG_OUTPUT_ENABLE,
+ M98090_HPREN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("SPK Left Out", M98090_REG_OUTPUT_ENABLE,
+ M98090_SPLEN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_PGA_E("SPK Right Out", M98090_REG_OUTPUT_ENABLE,
+ M98090_SPREN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("RCV Left Out", M98090_REG_OUTPUT_ENABLE,
+ M98090_RCVLEN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_PGA_E("RCV Right Out", M98090_REG_OUTPUT_ENABLE,
+ M98090_RCVREN_SHIFT, 0, NULL, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_OUTPUT("HPL"),
SND_SOC_DAPM_OUTPUT("HPR"),
@@ -1228,9 +1394,11 @@ static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("DMIC4"),
SND_SOC_DAPM_SUPPLY("DMIC3_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMIC3_SHIFT, 0, NULL, 0),
+ M98090_DIGMIC3_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_SUPPLY("DMIC4_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMIC4_SHIFT, 0, NULL, 0),
+ M98090_DIGMIC4_SHIFT, 0, max98090_dapm_event,
+ SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
};
static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
@@ -1501,6 +1669,11 @@ static void max98090_configure_bclk(struct snd_soc_component *component)
return;
}
+ /*
+ * Master mode: no need to save and restore SHDN for the following
+ * sensitive registers.
+ */
+
/* Check for supported PCLK to LRCLK ratios */
for (i = 0; i < ARRAY_SIZE(pclk_rates); i++) {
if ((pclk_rates[i] == max98090->sysclk) &&
@@ -1587,12 +1760,14 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* Set to slave mode PLL - MAS mode off */
+ max98090_shdn_save(max98090);
snd_soc_component_write(component,
M98090_REG_CLOCK_RATIO_NI_MSB, 0x00);
snd_soc_component_write(component,
M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK, 0);
+ max98090_shdn_restore(max98090);
max98090->master = false;
break;
case SND_SOC_DAIFMT_CBM_CFM:
@@ -1618,7 +1793,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
dev_err(component->dev, "DAI clock mode unsupported");
return -EINVAL;
}
+ max98090_shdn_save(max98090);
snd_soc_component_write(component, M98090_REG_MASTER_MODE, regval);
+ max98090_shdn_restore(max98090);
regval = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -1663,8 +1840,10 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
if (max98090->tdm_slots > 1)
regval ^= M98090_BCI_MASK;
+ max98090_shdn_save(max98090);
snd_soc_component_write(component,
M98090_REG_INTERFACE_FORMAT, regval);
+ max98090_shdn_restore(max98090);
}
return 0;
@@ -1676,6 +1855,7 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
struct snd_soc_component *component = codec_dai->component;
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct max98090_cdata *cdata;
+
cdata = &max98090->dai[0];
if (slots < 0 || slots > 4)
@@ -1685,6 +1865,7 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
max98090->tdm_width = slot_width;
if (max98090->tdm_slots > 1) {
+ max98090_shdn_save(max98090);
/* SLOTL SLOTR SLOTDLY */
snd_soc_component_write(component, M98090_REG_TDM_FORMAT,
0 << M98090_TDM_SLOTL_SHIFT |
@@ -1695,6 +1876,7 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
snd_soc_component_update_bits(component, M98090_REG_TDM_CONTROL,
M98090_TDM_MASK,
M98090_TDM_MASK);
+ max98090_shdn_restore(max98090);
}
/*
@@ -1894,6 +2076,7 @@ static int max98090_configure_dmic(struct max98090_priv *max98090,
dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq;
dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i];
+ max98090_shdn_save(max98090);
regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE,
M98090_MICCLK_MASK,
micclk_index << M98090_MICCLK_SHIFT);
@@ -1902,6 +2085,7 @@ static int max98090_configure_dmic(struct max98090_priv *max98090,
M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK,
dmic_comp << M98090_DMIC_COMP_SHIFT |
dmic_freq << M98090_DMIC_FREQ_SHIFT);
+ max98090_shdn_restore(max98090);
return 0;
}
@@ -1938,8 +2122,10 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
switch (params_width(params)) {
case 16:
+ max98090_shdn_save(max98090);
snd_soc_component_update_bits(component, M98090_REG_INTERFACE_FORMAT,
M98090_WS_MASK, 0);
+ max98090_shdn_restore(max98090);
break;
default:
return -EINVAL;
@@ -1950,6 +2136,7 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
cdata->rate = max98090->lrclk;
+ max98090_shdn_save(max98090);
/* Update filter mode */
if (max98090->lrclk < 24000)
snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
@@ -1965,6 +2152,7 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
else
snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
M98090_DHF_MASK, M98090_DHF_MASK);
+ max98090_shdn_restore(max98090);
max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
max98090->lrclk);
@@ -1995,6 +2183,7 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
* 0x02 (when master clk is 20MHz to 40MHz)..
* 0x03 (when master clk is 40MHz to 60MHz)..
*/
+ max98090_shdn_save(max98090);
if ((freq >= 10000000) && (freq <= 20000000)) {
snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV1);
@@ -2009,8 +2198,10 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
max98090->pclk = freq >> 2;
} else {
dev_err(component->dev, "Invalid master clock frequency\n");
+ max98090_shdn_restore(max98090);
return -EINVAL;
}
+ max98090_shdn_restore(max98090);
max98090->sysclk = freq;
@@ -2103,26 +2294,42 @@ static void max98090_pll_det_disable_work(struct work_struct *work)
M98090_IULK_MASK, 0);
}
-static void max98090_pll_work(struct work_struct *work)
+static void max98090_pll_work(struct max98090_priv *max98090)
{
- struct max98090_priv *max98090 =
- container_of(work, struct max98090_priv, pll_work);
struct snd_soc_component *component = max98090->component;
+ unsigned int pll;
+ int i;
if (!snd_soc_component_is_active(component))
return;
dev_info_ratelimited(component->dev, "PLL unlocked\n");
+ /*
+ * As the datasheet suggested, the maximum PLL lock time should be
+ * 7 msec. The workaround resets the codec softly by toggling SHDN
+ * off and on if PLL failed to lock for 10 msec. Notably, there is
+ * no suggested hold time for SHDN off.
+ */
+
/* Toggle shutdown OFF then ON */
+ mutex_lock(&max98090->shdn_lock);
snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
M98090_SHDNN_MASK, 0);
- msleep(10);
snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+ mutex_unlock(&max98090->shdn_lock);
+
+ for (i = 0; i < 10; ++i) {
+ /* Give PLL time to lock */
+ usleep_range(1000, 1200);
- /* Give PLL time to lock */
- msleep(10);
+ /* Check lock status */
+ pll = snd_soc_component_read32(
+ component, M98090_REG_DEVICE_STATUS);
+ if (!(pll & M98090_ULK_MASK))
+ break;
+ }
}
static void max98090_jack_work(struct work_struct *work)
@@ -2259,7 +2466,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
if (active & M98090_ULK_MASK) {
dev_dbg(component->dev, "M98090_ULK_MASK\n");
- schedule_work(&max98090->pll_work);
+ max98090_pll_work(max98090);
}
if (active & M98090_JDET_MASK) {
@@ -2422,7 +2629,6 @@ static int max98090_probe(struct snd_soc_component *component)
max98090_pll_det_enable_work);
INIT_WORK(&max98090->pll_det_disable_work,
max98090_pll_det_disable_work);
- INIT_WORK(&max98090->pll_work, max98090_pll_work);
/* Enable jack detection */
snd_soc_component_write(component, M98090_REG_JACK_DETECT,
@@ -2435,7 +2641,12 @@ static int max98090_probe(struct snd_soc_component *component)
*/
snd_soc_component_read32(component, M98090_REG_DEVICE_STATUS);
- /* High Performance is default */
+ /*
+ * SHDN should be 0 at the point, no need to save/restore for the
+ * following registers.
+ *
+ * High Performance is default
+ */
snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
M98090_DACHP_MASK,
1 << M98090_DACHP_SHIFT);
@@ -2446,7 +2657,12 @@ static int max98090_probe(struct snd_soc_component *component)
M98090_ADCHP_MASK,
1 << M98090_ADCHP_SHIFT);
- /* Turn on VCM bandgap reference */
+ /*
+ * SHDN should be 0 at the point, no need to save/restore for the
+ * following registers.
+ *
+ * Turn on VCM bandgap reference
+ */
snd_soc_component_write(component, M98090_REG_BIAS_CONTROL,
M98090_VCM_MODE_MASK);
@@ -2475,29 +2691,12 @@ static void max98090_remove(struct snd_soc_component *component)
cancel_delayed_work_sync(&max98090->jack_work);
cancel_delayed_work_sync(&max98090->pll_det_enable_work);
cancel_work_sync(&max98090->pll_det_disable_work);
- cancel_work_sync(&max98090->pll_work);
max98090->component = NULL;
}
-static void max98090_seq_notifier(struct snd_soc_component *component,
- enum snd_soc_dapm_type event, int subseq)
-{
- struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
-
- if (max98090->shdn_pending) {
- snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
- M98090_SHDNN_MASK, 0);
- msleep(40);
- snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
- M98090_SHDNN_MASK, M98090_SHDNN_MASK);
- max98090->shdn_pending = false;
- }
-}
-
static const struct snd_soc_component_driver soc_component_dev_max98090 = {
.probe = max98090_probe,
.remove = max98090_remove,
- .seq_notifier = max98090_seq_notifier,
.set_bias_level = max98090_set_bias_level,
.idle_bias_on = 1,
.use_pmdown_time = 1,
@@ -2532,6 +2731,8 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
if (max98090 == NULL)
return -ENOMEM;
+ mutex_init(&max98090->shdn_lock);
+
if (ACPI_HANDLE(&i2c->dev)) {
acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
&i2c->dev);
@@ -2639,17 +2840,12 @@ static int max98090_resume(struct device *dev)
return 0;
}
-
-static int max98090_suspend(struct device *dev)
-{
- return 0;
-}
#endif
static const struct dev_pm_ops max98090_pm = {
SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
max98090_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(max98090_suspend, max98090_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume)
};
static const struct i2c_device_id max98090_i2c_id[] = {
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index 57965cd678b4..dabd8be34a01 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1530,7 +1530,6 @@ struct max98090_priv {
struct delayed_work jack_work;
struct delayed_work pll_det_enable_work;
struct work_struct pll_det_disable_work;
- struct work_struct pll_work;
struct snd_soc_jack *jack;
unsigned int dai_fmt;
int tdm_slots;
@@ -1540,7 +1539,9 @@ struct max98090_priv {
unsigned int pa2en;
unsigned int sidetone;
bool master;
- bool shdn_pending;
+ struct mutex shdn_lock;
+ int saved_count;
+ int saved_shdn;
};
int max98090_mic_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index f1b7b947ecbd..1a25a3787935 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -215,11 +215,9 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component,
{
struct rt5514_dsp *rt5514_dsp =
snd_soc_component_get_drvdata(component);
- int ret;
u8 buf[8];
mutex_lock(&rt5514_dsp->dma_lock);
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
rt5514_dsp->substream = substream;
rt5514_dsp->dma_offset = 0;
@@ -230,7 +228,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component,
mutex_unlock(&rt5514_dsp->dma_lock);
- return ret;
+ return 0;
}
static int rt5514_spi_hw_free(struct snd_soc_component *component,
@@ -245,7 +243,7 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component,
cancel_delayed_work_sync(&rt5514_dsp->copy_work);
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}
static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
@@ -294,8 +292,8 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
static int rt5514_spi_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
- NULL, 0, 0);
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
+ NULL, 0, 0);
return 0;
}
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 7810b1d7de32..3f40d2751833 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -132,14 +132,12 @@ static int rt5677_spi_hw_params(
{
struct rt5677_dsp *rt5677_dsp =
snd_soc_component_get_drvdata(component);
- int ret;
mutex_lock(&rt5677_dsp->dma_lock);
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
rt5677_dsp->substream = substream;
mutex_unlock(&rt5677_dsp->dma_lock);
- return ret;
+ return 0;
}
static int rt5677_spi_hw_free(
@@ -153,7 +151,7 @@ static int rt5677_spi_hw_free(
rt5677_dsp->substream = NULL;
mutex_unlock(&rt5677_dsp->dma_lock);
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}
static int rt5677_spi_prepare(
@@ -376,8 +374,8 @@ done:
static int rt5677_spi_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
- NULL, 0, 0);
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
+ NULL, 0, 0);
return 0;
}
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h
index 3af36ec928e9..088b77931727 100644
--- a/sound/soc/codecs/rt5677-spi.h
+++ b/sound/soc/codecs/rt5677-spi.h
@@ -9,9 +9,25 @@
#ifndef __RT5677_SPI_H__
#define __RT5677_SPI_H__
+#if IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI)
int rt5677_spi_read(u32 addr, void *rxbuf, size_t len);
int rt5677_spi_write(u32 addr, const void *txbuf, size_t len);
int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw);
void rt5677_spi_hotword_detected(void);
+#else
+static inline int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
+{
+ return -EINVAL;
+}
+static inline int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
+{
+ return -EINVAL;
+}
+static inline int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw)
+{
+ return -EINVAL;
+}
+static inline void rt5677_spi_hotword_detected(void){}
+#endif
#endif /* __RT5677_SPI_H__ */
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index b1713fffa3eb..ae6f6121bc1b 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -73,6 +73,7 @@ struct rt5682_priv {
static const struct reg_sequence patch_list[] = {
{RT5682_HP_IMP_SENS_CTRL_19, 0x1000},
{RT5682_DAC_ADC_DIG_VOL1, 0xa020},
+ {RT5682_I2C_CTRL, 0x000f},
};
static const struct reg_default rt5682_reg[] = {
@@ -2474,6 +2475,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
mutex_lock(&rt5682->calibrate_mutex);
rt5682_reset(rt5682->regmap);
+ regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af);
usleep_range(15000, 20000);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af);
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index f6f19fdc72f5..31daa60695bd 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -262,6 +262,25 @@ static SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2,
static SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4,
mic_select_text);
+static const char * const hp_poweron_time_text[] = {
+ "0us", "15.3us", "153us", "1.53ms", "15.3ms", "76.2ms",
+ "153ms", "304ms", "610ms", "1.22s", "3.04s", "6.1s" };
+
+static SOC_ENUM_SINGLE_DECL(hp_poweron_time_enum, AIC31XX_HPPOP, 3,
+ hp_poweron_time_text);
+
+static const char * const hp_rampup_step_text[] = {
+ "0ms", "0.98ms", "1.95ms", "3.9ms" };
+
+static SOC_ENUM_SINGLE_DECL(hp_rampup_step_enum, AIC31XX_HPPOP, 1,
+ hp_rampup_step_text);
+
+static const char * const vol_soft_step_mode_text[] = {
+ "fast", "slow", "disabled" };
+
+static SOC_ENUM_SINGLE_DECL(vol_soft_step_mode_enum, AIC31XX_DACSETUP, 0,
+ vol_soft_step_mode_text);
+
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0);
static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0);
@@ -285,6 +304,16 @@ static const struct snd_kcontrol_new common31xx_snd_controls[] = {
SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
+
+ /* HP de-pop control: apply power not immediately but via ramp
+ * function with these psarameters. Note that power up sequence
+ * has to wait for this to complete; this is implemented by
+ * polling HP driver status in aic31xx_dapm_power_event()
+ */
+ SOC_ENUM("HP Output Driver Power-On time", hp_poweron_time_enum),
+ SOC_ENUM("HP Output Driver Ramp-up step", hp_rampup_step_enum),
+
+ SOC_ENUM("Volume Soft Stepping", vol_soft_step_mode_enum),
};
static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
@@ -357,6 +386,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
unsigned int reg = AIC31XX_DACFLAG1;
unsigned int mask;
+ unsigned int timeout = 500 * USEC_PER_MSEC;
switch (WIDGET_BIT(w->reg, w->shift)) {
case WIDGET_BIT(AIC31XX_DACSETUP, 7):
@@ -367,9 +397,13 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
break;
case WIDGET_BIT(AIC31XX_HPDRIVER, 7):
mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
+ if (event == SND_SOC_DAPM_POST_PMU)
+ timeout = 7 * USEC_PER_SEC;
break;
case WIDGET_BIT(AIC31XX_HPDRIVER, 6):
mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
+ if (event == SND_SOC_DAPM_POST_PMU)
+ timeout = 7 * USEC_PER_SEC;
break;
case WIDGET_BIT(AIC31XX_SPKAMP, 7):
mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
@@ -389,9 +423,11 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
+ return aic31xx_wait_bits(aic31xx, reg, mask, mask,
+ 5000, timeout / 5000);
case SND_SOC_DAPM_POST_PMD:
- return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
+ return aic31xx_wait_bits(aic31xx, reg, mask, 0,
+ 5000, timeout / 5000);
default:
dev_dbg(component->dev,
"Unhandled dapm widget event %d from %s\n",
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 83a8c7604cc3..0523884cee74 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -218,9 +218,6 @@ struct aic31xx_pdata {
#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10
#define AIC31XX_GPIO1_SDOUT 0x11
-/* AIC31XX_DACSETUP */
-#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
-
/* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
new file mode 100644
index 000000000000..158e878abd6c
--- /dev/null
+++ b/sound/soc/codecs/wcd934x.c
@@ -0,0 +1,5084 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019, Linaro Limited
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/wcd934x/registers.h>
+#include <linux/mfd/wcd934x/wcd934x.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/slimbus.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "wcd-clsh-v2.h"
+
+#define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+/* Fractional Rates */
+#define WCD934X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400)
+#define WCD934X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+/* slave port water mark level
+ * (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
+ */
+#define SLAVE_PORT_WATER_MARK_6BYTES 0
+#define SLAVE_PORT_WATER_MARK_9BYTES 1
+#define SLAVE_PORT_WATER_MARK_12BYTES 2
+#define SLAVE_PORT_WATER_MARK_15BYTES 3
+#define SLAVE_PORT_WATER_MARK_SHIFT 1
+#define SLAVE_PORT_ENABLE 1
+#define SLAVE_PORT_DISABLE 0
+#define WCD934X_SLIM_WATER_MARK_VAL \
+ ((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \
+ (SLAVE_PORT_ENABLE))
+
+#define WCD934X_SLIM_NUM_PORT_REG 3
+#define WCD934X_SLIM_PGD_PORT_INT_TX_EN0 (WCD934X_SLIM_PGD_PORT_INT_EN0 + 2)
+#define WCD934X_SLIM_IRQ_OVERFLOW BIT(0)
+#define WCD934X_SLIM_IRQ_UNDERFLOW BIT(1)
+#define WCD934X_SLIM_IRQ_PORT_CLOSED BIT(2)
+
+#define WCD934X_MCLK_CLK_12P288MHZ 12288000
+#define WCD934X_MCLK_CLK_9P6MHZ 9600000
+
+/* Only valid for 9.6 MHz mclk */
+#define WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ 2400000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ 4800000
+
+/* Only valid for 12.288 MHz mclk */
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ 4096000
+
+#define WCD934X_DMIC_CLK_DIV_2 0x0
+#define WCD934X_DMIC_CLK_DIV_3 0x1
+#define WCD934X_DMIC_CLK_DIV_4 0x2
+#define WCD934X_DMIC_CLK_DIV_6 0x3
+#define WCD934X_DMIC_CLK_DIV_8 0x4
+#define WCD934X_DMIC_CLK_DIV_16 0x5
+#define WCD934X_DMIC_CLK_DRIVE_DEFAULT 0x02
+
+#define TX_HPF_CUT_OFF_FREQ_MASK 0x60
+#define CF_MIN_3DB_4HZ 0x0
+#define CF_MIN_3DB_75HZ 0x1
+#define CF_MIN_3DB_150HZ 0x2
+
+#define WCD934X_RX_START 16
+#define WCD934X_NUM_INTERPOLATORS 9
+#define WCD934X_RX_PATH_CTL_OFFSET 20
+#define WCD934X_MAX_VALID_ADC_MUX 13
+#define WCD934X_INVALID_ADC_MUX 9
+
+#define WCD934X_SLIM_RX_CH(p) \
+ {.port = p + WCD934X_RX_START, .shift = p,}
+
+#define WCD934X_SLIM_TX_CH(p) \
+ {.port = p, .shift = p,}
+
+/* Feature masks to distinguish codec version */
+#define DSD_DISABLED_MASK 0
+#define SLNQ_DISABLED_MASK 1
+
+#define DSD_DISABLED BIT(DSD_DISABLED_MASK)
+#define SLNQ_DISABLED BIT(SLNQ_DISABLED_MASK)
+
+/* As fine version info cannot be retrieved before wcd probe.
+ * Define three coarse versions for possible future use before wcd probe.
+ */
+#define WCD_VERSION_WCD9340_1_0 0x400
+#define WCD_VERSION_WCD9341_1_0 0x410
+#define WCD_VERSION_WCD9340_1_1 0x401
+#define WCD_VERSION_WCD9341_1_1 0x411
+#define WCD934X_AMIC_PWR_LEVEL_LP 0
+#define WCD934X_AMIC_PWR_LEVEL_DEFAULT 1
+#define WCD934X_AMIC_PWR_LEVEL_HP 2
+#define WCD934X_AMIC_PWR_LEVEL_HYBRID 3
+#define WCD934X_AMIC_PWR_LVL_MASK 0x60
+#define WCD934X_AMIC_PWR_LVL_SHIFT 0x5
+
+#define WCD934X_DEC_PWR_LVL_MASK 0x06
+#define WCD934X_DEC_PWR_LVL_LP 0x02
+#define WCD934X_DEC_PWR_LVL_HP 0x04
+#define WCD934X_DEC_PWR_LVL_DF 0x00
+#define WCD934X_DEC_PWR_LVL_HYBRID WCD934X_DEC_PWR_LVL_DF
+
+#define WCD934X_DEF_MICBIAS_MV 1800
+#define WCD934X_MAX_MICBIAS_MV 2850
+
+#define WCD_IIR_FILTER_SIZE (sizeof(u32) * BAND_MAX)
+
+#define WCD_IIR_FILTER_CTL(xname, iidx, bidx) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = wcd934x_iir_filter_info, \
+ .get = wcd934x_get_iir_band_audio_mixer, \
+ .put = wcd934x_put_iir_band_audio_mixer, \
+ .private_value = (unsigned long)&(struct wcd_iir_filter_ctl) { \
+ .iir_idx = iidx, \
+ .band_idx = bidx, \
+ .bytes_ext = {.max = WCD_IIR_FILTER_SIZE, }, \
+ } \
+}
+
+#define WCD934X_INTERPOLATOR_PATH(id) \
+ {"RX INT" #id "_1 MIX1 INP0", "RX0", "SLIM RX0"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX1", "SLIM RX1"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX2", "SLIM RX2"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX3", "SLIM RX3"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX4", "SLIM RX4"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX5", "SLIM RX5"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX6", "SLIM RX6"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "RX7", "SLIM RX7"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "IIR0", "IIR0"}, \
+ {"RX INT" #id "_1 MIX1 INP0", "IIR1", "IIR1"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX0", "SLIM RX0"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX1", "SLIM RX1"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX2", "SLIM RX2"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX3", "SLIM RX3"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX4", "SLIM RX4"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX5", "SLIM RX5"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX6", "SLIM RX6"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "RX7", "SLIM RX7"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "IIR0", "IIR0"}, \
+ {"RX INT" #id "_1 MIX1 INP1", "IIR1", "IIR1"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX0", "SLIM RX0"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX1", "SLIM RX1"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX2", "SLIM RX2"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX3", "SLIM RX3"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX4", "SLIM RX4"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX5", "SLIM RX5"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX6", "SLIM RX6"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "RX7", "SLIM RX7"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "IIR0", "IIR0"}, \
+ {"RX INT" #id "_1 MIX1 INP2", "IIR1", "IIR1"}, \
+ {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP0"}, \
+ {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP1"}, \
+ {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP2"}, \
+ {"RX INT" #id "_2 MUX", "RX0", "SLIM RX0"}, \
+ {"RX INT" #id "_2 MUX", "RX1", "SLIM RX1"}, \
+ {"RX INT" #id "_2 MUX", "RX2", "SLIM RX2"}, \
+ {"RX INT" #id "_2 MUX", "RX3", "SLIM RX3"}, \
+ {"RX INT" #id "_2 MUX", "RX4", "SLIM RX4"}, \
+ {"RX INT" #id "_2 MUX", "RX5", "SLIM RX5"}, \
+ {"RX INT" #id "_2 MUX", "RX6", "SLIM RX6"}, \
+ {"RX INT" #id "_2 MUX", "RX7", "SLIM RX7"}, \
+ {"RX INT" #id "_2 MUX", NULL, "INT" #id "_CLK"}, \
+ {"RX INT" #id "_2 MUX", NULL, "DSMDEM" #id "_CLK"}, \
+ {"RX INT" #id "_2 INTERP", NULL, "RX INT" #id "_2 MUX"}, \
+ {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_2 INTERP"}, \
+ {"RX INT" #id "_1 INTERP", NULL, "RX INT" #id "_1 MIX1"}, \
+ {"RX INT" #id "_1 INTERP", NULL, "INT" #id "_CLK"}, \
+ {"RX INT" #id "_1 INTERP", NULL, "DSMDEM" #id "_CLK"}, \
+ {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_1 INTERP"}
+
+#define WCD934X_INTERPOLATOR_MIX2(id) \
+ {"RX INT" #id " MIX2", NULL, "RX INT" #id " SEC MIX"}, \
+ {"RX INT" #id " MIX2", NULL, "RX INT" #id " MIX2 INP"}
+
+#define WCD934X_SLIM_RX_AIF_PATH(id) \
+ {"SLIM RX"#id" MUX", "AIF1_PB", "AIF1 PB"}, \
+ {"SLIM RX"#id" MUX", "AIF2_PB", "AIF2 PB"}, \
+ {"SLIM RX"#id" MUX", "AIF3_PB", "AIF3 PB"}, \
+ {"SLIM RX"#id" MUX", "AIF4_PB", "AIF4 PB"}, \
+ {"SLIM RX"#id, NULL, "SLIM RX"#id" MUX"}
+
+#define WCD934X_ADC_MUX(id) \
+ {"ADC MUX" #id, "DMIC", "DMIC MUX" #id }, \
+ {"ADC MUX" #id, "AMIC", "AMIC MUX" #id }, \
+ {"DMIC MUX" #id, "DMIC0", "DMIC0"}, \
+ {"DMIC MUX" #id, "DMIC1", "DMIC1"}, \
+ {"DMIC MUX" #id, "DMIC2", "DMIC2"}, \
+ {"DMIC MUX" #id, "DMIC3", "DMIC3"}, \
+ {"DMIC MUX" #id, "DMIC4", "DMIC4"}, \
+ {"DMIC MUX" #id, "DMIC5", "DMIC5"}, \
+ {"AMIC MUX" #id, "ADC1", "ADC1"}, \
+ {"AMIC MUX" #id, "ADC2", "ADC2"}, \
+ {"AMIC MUX" #id, "ADC3", "ADC3"}, \
+ {"AMIC MUX" #id, "ADC4", "ADC4"}
+
+#define WCD934X_IIR_INP_MUX(id) \
+ {"IIR" #id, NULL, "IIR" #id " INP0 MUX"}, \
+ {"IIR" #id " INP0 MUX", "DEC0", "ADC MUX0"}, \
+ {"IIR" #id " INP0 MUX", "DEC1", "ADC MUX1"}, \
+ {"IIR" #id " INP0 MUX", "DEC2", "ADC MUX2"}, \
+ {"IIR" #id " INP0 MUX", "DEC3", "ADC MUX3"}, \
+ {"IIR" #id " INP0 MUX", "DEC4", "ADC MUX4"}, \
+ {"IIR" #id " INP0 MUX", "DEC5", "ADC MUX5"}, \
+ {"IIR" #id " INP0 MUX", "DEC6", "ADC MUX6"}, \
+ {"IIR" #id " INP0 MUX", "DEC7", "ADC MUX7"}, \
+ {"IIR" #id " INP0 MUX", "DEC8", "ADC MUX8"}, \
+ {"IIR" #id " INP0 MUX", "RX0", "SLIM RX0"}, \
+ {"IIR" #id " INP0 MUX", "RX1", "SLIM RX1"}, \
+ {"IIR" #id " INP0 MUX", "RX2", "SLIM RX2"}, \
+ {"IIR" #id " INP0 MUX", "RX3", "SLIM RX3"}, \
+ {"IIR" #id " INP0 MUX", "RX4", "SLIM RX4"}, \
+ {"IIR" #id " INP0 MUX", "RX5", "SLIM RX5"}, \
+ {"IIR" #id " INP0 MUX", "RX6", "SLIM RX6"}, \
+ {"IIR" #id " INP0 MUX", "RX7", "SLIM RX7"}, \
+ {"IIR" #id, NULL, "IIR" #id " INP1 MUX"}, \
+ {"IIR" #id " INP1 MUX", "DEC0", "ADC MUX0"}, \
+ {"IIR" #id " INP1 MUX", "DEC1", "ADC MUX1"}, \
+ {"IIR" #id " INP1 MUX", "DEC2", "ADC MUX2"}, \
+ {"IIR" #id " INP1 MUX", "DEC3", "ADC MUX3"}, \
+ {"IIR" #id " INP1 MUX", "DEC4", "ADC MUX4"}, \
+ {"IIR" #id " INP1 MUX", "DEC5", "ADC MUX5"}, \
+ {"IIR" #id " INP1 MUX", "DEC6", "ADC MUX6"}, \
+ {"IIR" #id " INP1 MUX", "DEC7", "ADC MUX7"}, \
+ {"IIR" #id " INP1 MUX", "DEC8", "ADC MUX8"}, \
+ {"IIR" #id " INP1 MUX", "RX0", "SLIM RX0"}, \
+ {"IIR" #id " INP1 MUX", "RX1", "SLIM RX1"}, \
+ {"IIR" #id " INP1 MUX", "RX2", "SLIM RX2"}, \
+ {"IIR" #id " INP1 MUX", "RX3", "SLIM RX3"}, \
+ {"IIR" #id " INP1 MUX", "RX4", "SLIM RX4"}, \
+ {"IIR" #id " INP1 MUX", "RX5", "SLIM RX5"}, \
+ {"IIR" #id " INP1 MUX", "RX6", "SLIM RX6"}, \
+ {"IIR" #id " INP1 MUX", "RX7", "SLIM RX7"}, \
+ {"IIR" #id, NULL, "IIR" #id " INP2 MUX"}, \
+ {"IIR" #id " INP2 MUX", "DEC0", "ADC MUX0"}, \
+ {"IIR" #id " INP2 MUX", "DEC1", "ADC MUX1"}, \
+ {"IIR" #id " INP2 MUX", "DEC2", "ADC MUX2"}, \
+ {"IIR" #id " INP2 MUX", "DEC3", "ADC MUX3"}, \
+ {"IIR" #id " INP2 MUX", "DEC4", "ADC MUX4"}, \
+ {"IIR" #id " INP2 MUX", "DEC5", "ADC MUX5"}, \
+ {"IIR" #id " INP2 MUX", "DEC6", "ADC MUX6"}, \
+ {"IIR" #id " INP2 MUX", "DEC7", "ADC MUX7"}, \
+ {"IIR" #id " INP2 MUX", "DEC8", "ADC MUX8"}, \
+ {"IIR" #id " INP2 MUX", "RX0", "SLIM RX0"}, \
+ {"IIR" #id " INP2 MUX", "RX1", "SLIM RX1"}, \
+ {"IIR" #id " INP2 MUX", "RX2", "SLIM RX2"}, \
+ {"IIR" #id " INP2 MUX", "RX3", "SLIM RX3"}, \
+ {"IIR" #id " INP2 MUX", "RX4", "SLIM RX4"}, \
+ {"IIR" #id " INP2 MUX", "RX5", "SLIM RX5"}, \
+ {"IIR" #id " INP2 MUX", "RX6", "SLIM RX6"}, \
+ {"IIR" #id " INP2 MUX", "RX7", "SLIM RX7"}, \
+ {"IIR" #id, NULL, "IIR" #id " INP3 MUX"}, \
+ {"IIR" #id " INP3 MUX", "DEC0", "ADC MUX0"}, \
+ {"IIR" #id " INP3 MUX", "DEC1", "ADC MUX1"}, \
+ {"IIR" #id " INP3 MUX", "DEC2", "ADC MUX2"}, \
+ {"IIR" #id " INP3 MUX", "DEC3", "ADC MUX3"}, \
+ {"IIR" #id " INP3 MUX", "DEC4", "ADC MUX4"}, \
+ {"IIR" #id " INP3 MUX", "DEC5", "ADC MUX5"}, \
+ {"IIR" #id " INP3 MUX", "DEC6", "ADC MUX6"}, \
+ {"IIR" #id " INP3 MUX", "DEC7", "ADC MUX7"}, \
+ {"IIR" #id " INP3 MUX", "DEC8", "ADC MUX8"}, \
+ {"IIR" #id " INP3 MUX", "RX0", "SLIM RX0"}, \
+ {"IIR" #id " INP3 MUX", "RX1", "SLIM RX1"}, \
+ {"IIR" #id " INP3 MUX", "RX2", "SLIM RX2"}, \
+ {"IIR" #id " INP3 MUX", "RX3", "SLIM RX3"}, \
+ {"IIR" #id " INP3 MUX", "RX4", "SLIM RX4"}, \
+ {"IIR" #id " INP3 MUX", "RX5", "SLIM RX5"}, \
+ {"IIR" #id " INP3 MUX", "RX6", "SLIM RX6"}, \
+ {"IIR" #id " INP3 MUX", "RX7", "SLIM RX7"}
+
+#define WCD934X_SLIM_TX_AIF_PATH(id) \
+ {"AIF1_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id }, \
+ {"AIF2_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id }, \
+ {"AIF3_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id }, \
+ {"SLIM TX" #id, NULL, "CDC_IF TX" #id " MUX"}
+
+enum {
+ MIC_BIAS_1 = 1,
+ MIC_BIAS_2,
+ MIC_BIAS_3,
+ MIC_BIAS_4
+};
+
+enum {
+ SIDO_SOURCE_INTERNAL,
+ SIDO_SOURCE_RCO_BG,
+};
+
+enum {
+ INTERP_EAR = 0,
+ INTERP_HPHL,
+ INTERP_HPHR,
+ INTERP_LO1,
+ INTERP_LO2,
+ INTERP_LO3_NA, /* LO3 not avalible in Tavil */
+ INTERP_LO4_NA,
+ INTERP_SPKR1, /*INT7 WSA Speakers via soundwire */
+ INTERP_SPKR2, /*INT8 WSA Speakers via soundwire */
+ INTERP_MAX,
+};
+
+enum {
+ WCD934X_RX0 = 0,
+ WCD934X_RX1,
+ WCD934X_RX2,
+ WCD934X_RX3,
+ WCD934X_RX4,
+ WCD934X_RX5,
+ WCD934X_RX6,
+ WCD934X_RX7,
+ WCD934X_RX8,
+ WCD934X_RX9,
+ WCD934X_RX10,
+ WCD934X_RX11,
+ WCD934X_RX12,
+ WCD934X_RX_MAX,
+};
+
+enum {
+ WCD934X_TX0 = 0,
+ WCD934X_TX1,
+ WCD934X_TX2,
+ WCD934X_TX3,
+ WCD934X_TX4,
+ WCD934X_TX5,
+ WCD934X_TX6,
+ WCD934X_TX7,
+ WCD934X_TX8,
+ WCD934X_TX9,
+ WCD934X_TX10,
+ WCD934X_TX11,
+ WCD934X_TX12,
+ WCD934X_TX13,
+ WCD934X_TX14,
+ WCD934X_TX15,
+ WCD934X_TX_MAX,
+};
+
+struct wcd934x_slim_ch {
+ u32 ch_num;
+ u16 port;
+ u16 shift;
+ struct list_head list;
+};
+
+static const struct wcd934x_slim_ch wcd934x_tx_chs[WCD934X_TX_MAX] = {
+ WCD934X_SLIM_TX_CH(0),
+ WCD934X_SLIM_TX_CH(1),
+ WCD934X_SLIM_TX_CH(2),
+ WCD934X_SLIM_TX_CH(3),
+ WCD934X_SLIM_TX_CH(4),
+ WCD934X_SLIM_TX_CH(5),
+ WCD934X_SLIM_TX_CH(6),
+ WCD934X_SLIM_TX_CH(7),
+ WCD934X_SLIM_TX_CH(8),
+ WCD934X_SLIM_TX_CH(9),
+ WCD934X_SLIM_TX_CH(10),
+ WCD934X_SLIM_TX_CH(11),
+ WCD934X_SLIM_TX_CH(12),
+ WCD934X_SLIM_TX_CH(13),
+ WCD934X_SLIM_TX_CH(14),
+ WCD934X_SLIM_TX_CH(15),
+};
+
+static const struct wcd934x_slim_ch wcd934x_rx_chs[WCD934X_RX_MAX] = {
+ WCD934X_SLIM_RX_CH(0), /* 16 */
+ WCD934X_SLIM_RX_CH(1), /* 17 */
+ WCD934X_SLIM_RX_CH(2),
+ WCD934X_SLIM_RX_CH(3),
+ WCD934X_SLIM_RX_CH(4),
+ WCD934X_SLIM_RX_CH(5),
+ WCD934X_SLIM_RX_CH(6),
+ WCD934X_SLIM_RX_CH(7),
+ WCD934X_SLIM_RX_CH(8),
+ WCD934X_SLIM_RX_CH(9),
+ WCD934X_SLIM_RX_CH(10),
+ WCD934X_SLIM_RX_CH(11),
+ WCD934X_SLIM_RX_CH(12),
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+ IIR0 = 0,
+ IIR1,
+ IIR_MAX,
+};
+
+/* Each IIR has 5 Filter Stages */
+enum {
+ BAND1 = 0,
+ BAND2,
+ BAND3,
+ BAND4,
+ BAND5,
+ BAND_MAX,
+};
+
+enum {
+ COMPANDER_1, /* HPH_L */
+ COMPANDER_2, /* HPH_R */
+ COMPANDER_3, /* LO1_DIFF */
+ COMPANDER_4, /* LO2_DIFF */
+ COMPANDER_5, /* LO3_SE - not used in Tavil */
+ COMPANDER_6, /* LO4_SE - not used in Tavil */
+ COMPANDER_7, /* SWR SPK CH1 */
+ COMPANDER_8, /* SWR SPK CH2 */
+ COMPANDER_MAX,
+};
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ AIF2_PB,
+ AIF2_CAP,
+ AIF3_PB,
+ AIF3_CAP,
+ AIF4_PB,
+ AIF4_VIFEED,
+ AIF4_MAD_TX,
+ NUM_CODEC_DAIS,
+};
+
+enum {
+ INTn_1_INP_SEL_ZERO = 0,
+ INTn_1_INP_SEL_DEC0,
+ INTn_1_INP_SEL_DEC1,
+ INTn_1_INP_SEL_IIR0,
+ INTn_1_INP_SEL_IIR1,
+ INTn_1_INP_SEL_RX0,
+ INTn_1_INP_SEL_RX1,
+ INTn_1_INP_SEL_RX2,
+ INTn_1_INP_SEL_RX3,
+ INTn_1_INP_SEL_RX4,
+ INTn_1_INP_SEL_RX5,
+ INTn_1_INP_SEL_RX6,
+ INTn_1_INP_SEL_RX7,
+};
+
+enum {
+ INTn_2_INP_SEL_ZERO = 0,
+ INTn_2_INP_SEL_RX0,
+ INTn_2_INP_SEL_RX1,
+ INTn_2_INP_SEL_RX2,
+ INTn_2_INP_SEL_RX3,
+ INTn_2_INP_SEL_RX4,
+ INTn_2_INP_SEL_RX5,
+ INTn_2_INP_SEL_RX6,
+ INTn_2_INP_SEL_RX7,
+ INTn_2_INP_SEL_PROXIMITY,
+};
+
+enum {
+ INTERP_MAIN_PATH,
+ INTERP_MIX_PATH,
+};
+
+struct interp_sample_rate {
+ int sample_rate;
+ int rate_val;
+};
+
+static struct interp_sample_rate sr_val_tbl[] = {
+ {8000, 0x0},
+ {16000, 0x1},
+ {32000, 0x3},
+ {48000, 0x4},
+ {96000, 0x5},
+ {192000, 0x6},
+ {384000, 0x7},
+ {44100, 0x9},
+ {88200, 0xA},
+ {176400, 0xB},
+ {352800, 0xC},
+};
+
+struct wcd_slim_codec_dai_data {
+ struct list_head slim_ch_list;
+ struct slim_stream_config sconfig;
+ struct slim_stream_runtime *sruntime;
+};
+
+static const struct regmap_range_cfg wcd934x_ifc_ranges[] = {
+ {
+ .name = "WCD9335-IFC-DEV",
+ .range_min = 0x0,
+ .range_max = 0xffff,
+ .selector_reg = 0x800,
+ .selector_mask = 0xfff,
+ .selector_shift = 0,
+ .window_start = 0x800,
+ .window_len = 0x400,
+ },
+};
+
+static struct regmap_config wcd934x_ifc_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xffff,
+ .ranges = wcd934x_ifc_ranges,
+ .num_ranges = ARRAY_SIZE(wcd934x_ifc_ranges),
+};
+
+struct wcd934x_codec {
+ struct device *dev;
+ struct clk_hw hw;
+ struct clk *extclk;
+ struct regmap *regmap;
+ struct regmap *if_regmap;
+ struct slim_device *sdev;
+ struct slim_device *sidev;
+ struct wcd_clsh_ctrl *clsh_ctrl;
+ struct snd_soc_component *component;
+ struct wcd934x_slim_ch rx_chs[WCD934X_RX_MAX];
+ struct wcd934x_slim_ch tx_chs[WCD934X_TX_MAX];
+ struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS];
+ int rate;
+ u32 version;
+ u32 hph_mode;
+ int num_rx_port;
+ int num_tx_port;
+ u32 tx_port_value[WCD934X_TX_MAX];
+ u32 rx_port_value[WCD934X_RX_MAX];
+ int sido_input_src;
+ int dmic_0_1_clk_cnt;
+ int dmic_2_3_clk_cnt;
+ int dmic_4_5_clk_cnt;
+ int dmic_sample_rate;
+ int comp_enabled[COMPANDER_MAX];
+ int sysclk_users;
+ struct mutex sysclk_mutex;
+};
+
+#define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw)
+
+struct wcd_iir_filter_ctl {
+ unsigned int iir_idx;
+ unsigned int band_idx;
+ struct soc_bytes_ext bytes_ext;
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static const DECLARE_TLV_DB_SCALE(ear_pa_gain, 0, 150, 0);
+
+/* Cutoff frequency for high pass filter */
+static const char * const cf_text[] = {
+ "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ"
+};
+
+static const char * const rx_cf_text[] = {
+ "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ",
+ "CF_NEG_3DB_0P48HZ"
+};
+
+static const char * const rx_hph_mode_mux_text[] = {
+ "Class H Invalid", "Class-H Hi-Fi", "Class-H Low Power", "Class-AB",
+ "Class-H Hi-Fi Low Power"
+};
+
+static const char *const slim_rx_mux_text[] = {
+ "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB",
+};
+
+static const char * const rx_int0_7_mix_mux_text[] = {
+ "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+ "RX6", "RX7", "PROXIMITY"
+};
+
+static const char * const rx_int_mix_mux_text[] = {
+ "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+ "RX6", "RX7"
+};
+
+static const char * const rx_prim_mix_text[] = {
+ "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+ "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_sidetone_mix_text[] = {
+ "ZERO", "SRC0", "SRC1", "SRC_SUM"
+};
+
+static const char * const iir_inp_mux_text[] = {
+ "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6",
+ "DEC7", "DEC8", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+ "NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_1_interp_mux_text[] = {
+ "ZERO", "RX INT0_1 MIX1",
+};
+
+static const char * const rx_int1_1_interp_mux_text[] = {
+ "ZERO", "RX INT1_1 MIX1",
+};
+
+static const char * const rx_int2_1_interp_mux_text[] = {
+ "ZERO", "RX INT2_1 MIX1",
+};
+
+static const char * const rx_int3_1_interp_mux_text[] = {
+ "ZERO", "RX INT3_1 MIX1",
+};
+
+static const char * const rx_int4_1_interp_mux_text[] = {
+ "ZERO", "RX INT4_1 MIX1",
+};
+
+static const char * const rx_int7_1_interp_mux_text[] = {
+ "ZERO", "RX INT7_1 MIX1",
+};
+
+static const char * const rx_int8_1_interp_mux_text[] = {
+ "ZERO", "RX INT8_1 MIX1",
+};
+
+static const char * const rx_int0_2_interp_mux_text[] = {
+ "ZERO", "RX INT0_2 MUX",
+};
+
+static const char * const rx_int1_2_interp_mux_text[] = {
+ "ZERO", "RX INT1_2 MUX",
+};
+
+static const char * const rx_int2_2_interp_mux_text[] = {
+ "ZERO", "RX INT2_2 MUX",
+};
+
+static const char * const rx_int3_2_interp_mux_text[] = {
+ "ZERO", "RX INT3_2 MUX",
+};
+
+static const char * const rx_int4_2_interp_mux_text[] = {
+ "ZERO", "RX INT4_2 MUX",
+};
+
+static const char * const rx_int7_2_interp_mux_text[] = {
+ "ZERO", "RX INT7_2 MUX",
+};
+
+static const char * const rx_int8_2_interp_mux_text[] = {
+ "ZERO", "RX INT8_2 MUX",
+};
+
+static const char * const dmic_mux_text[] = {
+ "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5"
+};
+
+static const char * const amic_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4"
+};
+
+static const char * const amic4_5_sel_text[] = {
+ "AMIC4", "AMIC5"
+};
+
+static const char * const adc_mux_text[] = {
+ "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2"
+};
+
+static const char * const cdc_if_tx0_mux_text[] = {
+ "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192"
+};
+
+static const char * const cdc_if_tx1_mux_text[] = {
+ "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192"
+};
+
+static const char * const cdc_if_tx2_mux_text[] = {
+ "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192"
+};
+
+static const char * const cdc_if_tx3_mux_text[] = {
+ "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192"
+};
+
+static const char * const cdc_if_tx4_mux_text[] = {
+ "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192"
+};
+
+static const char * const cdc_if_tx5_mux_text[] = {
+ "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192"
+};
+
+static const char * const cdc_if_tx6_mux_text[] = {
+ "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192"
+};
+
+static const char * const cdc_if_tx7_mux_text[] = {
+ "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192"
+};
+
+static const char * const cdc_if_tx8_mux_text[] = {
+ "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192"
+};
+
+static const char * const cdc_if_tx9_mux_text[] = {
+ "ZERO", "DEC7", "DEC7_192"
+};
+
+static const char * const cdc_if_tx10_mux_text[] = {
+ "ZERO", "DEC6", "DEC6_192"
+};
+
+static const char * const cdc_if_tx11_mux_text[] = {
+ "DEC_0_5", "DEC_9_12", "MAD_AUDIO", "MAD_BRDCST"
+};
+
+static const char * const cdc_if_tx11_inp1_mux_text[] = {
+ "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4",
+ "DEC5", "RX_MIX_TX5", "DEC9_10", "DEC11_12"
+};
+
+static const char * const cdc_if_tx13_mux_text[] = {
+ "CDC_DEC_5", "MAD_BRDCST"
+};
+
+static const char * const cdc_if_tx13_inp1_mux_text[] = {
+ "ZERO", "DEC5", "DEC5_192"
+};
+
+static const struct soc_enum cf_dec0_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec5_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec6_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec7_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec8_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_int0_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int1_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int2_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int3_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int4_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int7_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int8_1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
+ rx_hph_mode_mux_text);
+
+static const struct soc_enum slim_rx_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct soc_enum rx_int0_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10,
+ rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int1_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int2_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int3_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int4_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int7_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10,
+ rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int8_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int0_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_mix2_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0, 4,
+ rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int1_mix2_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, 4,
+ rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int2_mix2_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, 4,
+ rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int3_mix2_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, 4,
+ rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int4_mix2_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0, 4,
+ rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int7_mix2_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 2, 4,
+ rx_sidetone_mix_text);
+
+static const struct soc_enum iir0_inp0_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir0_inp1_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir0_inp2_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir0_inp3_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp0_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp2_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp3_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3,
+ 0, 18, iir_inp_mux_text);
+
+static const struct soc_enum rx_int0_dem_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX0_RX_PATH_SEC0, 0,
+ ARRAY_SIZE(rx_int_dem_inp_mux_text),
+ rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int1_dem_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX1_RX_PATH_SEC0, 0,
+ ARRAY_SIZE(rx_int_dem_inp_mux_text),
+ rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int2_dem_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_RX2_RX_PATH_SEC0, 0,
+ ARRAY_SIZE(rx_int_dem_inp_mux_text),
+ rx_int_dem_inp_mux_text);
+
+static const struct soc_enum tx_adc_mux0_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux2_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux3_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux4_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 2,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux5_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 2,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux6_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 2,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux7_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 2,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+static const struct soc_enum tx_adc_mux8_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 4,
+ ARRAY_SIZE(adc_mux_text), adc_mux_text);
+
+static const struct soc_enum rx_int0_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2,
+ rx_int0_1_interp_mux_text);
+
+static const struct soc_enum rx_int1_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2,
+ rx_int1_1_interp_mux_text);
+
+static const struct soc_enum rx_int2_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2,
+ rx_int2_1_interp_mux_text);
+
+static const struct soc_enum rx_int3_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int3_1_interp_mux_text);
+
+static const struct soc_enum rx_int4_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int4_1_interp_mux_text);
+
+static const struct soc_enum rx_int7_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int7_1_interp_mux_text);
+
+static const struct soc_enum rx_int8_1_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int8_1_interp_mux_text);
+
+static const struct soc_enum rx_int0_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int0_2_interp_mux_text);
+
+static const struct soc_enum rx_int1_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int1_2_interp_mux_text);
+
+static const struct soc_enum rx_int2_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int2_2_interp_mux_text);
+
+static const struct soc_enum rx_int3_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int3_2_interp_mux_text);
+
+static const struct soc_enum rx_int4_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int4_2_interp_mux_text);
+
+static const struct soc_enum rx_int7_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int7_2_interp_mux_text);
+
+static const struct soc_enum rx_int8_2_interp_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_int8_2_interp_mux_text);
+
+static const struct soc_enum tx_dmic_mux0_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux2_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux3_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux4_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux5_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux6_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux7_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux8_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7,
+ dmic_mux_text);
+
+static const struct soc_enum tx_amic_mux0_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux1_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux2_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux3_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux4_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux5_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux6_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux7_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 5,
+ amic_mux_text);
+static const struct soc_enum tx_amic_mux8_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 5,
+ amic_mux_text);
+
+static const struct soc_enum tx_amic4_5_enum =
+ SOC_ENUM_SINGLE(WCD934X_TX_NEW_AMIC_4_5_SEL, 7, 2, amic4_5_sel_text);
+
+static const struct soc_enum cdc_if_tx0_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 0,
+ ARRAY_SIZE(cdc_if_tx0_mux_text), cdc_if_tx0_mux_text);
+static const struct soc_enum cdc_if_tx1_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 2,
+ ARRAY_SIZE(cdc_if_tx1_mux_text), cdc_if_tx1_mux_text);
+static const struct soc_enum cdc_if_tx2_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 4,
+ ARRAY_SIZE(cdc_if_tx2_mux_text), cdc_if_tx2_mux_text);
+static const struct soc_enum cdc_if_tx3_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 6,
+ ARRAY_SIZE(cdc_if_tx3_mux_text), cdc_if_tx3_mux_text);
+static const struct soc_enum cdc_if_tx4_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 0,
+ ARRAY_SIZE(cdc_if_tx4_mux_text), cdc_if_tx4_mux_text);
+static const struct soc_enum cdc_if_tx5_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 2,
+ ARRAY_SIZE(cdc_if_tx5_mux_text), cdc_if_tx5_mux_text);
+static const struct soc_enum cdc_if_tx6_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 4,
+ ARRAY_SIZE(cdc_if_tx6_mux_text), cdc_if_tx6_mux_text);
+static const struct soc_enum cdc_if_tx7_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 6,
+ ARRAY_SIZE(cdc_if_tx7_mux_text), cdc_if_tx7_mux_text);
+static const struct soc_enum cdc_if_tx8_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 0,
+ ARRAY_SIZE(cdc_if_tx8_mux_text), cdc_if_tx8_mux_text);
+static const struct soc_enum cdc_if_tx9_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 2,
+ ARRAY_SIZE(cdc_if_tx9_mux_text), cdc_if_tx9_mux_text);
+static const struct soc_enum cdc_if_tx10_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 4,
+ ARRAY_SIZE(cdc_if_tx10_mux_text), cdc_if_tx10_mux_text);
+static const struct soc_enum cdc_if_tx11_inp1_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 0,
+ ARRAY_SIZE(cdc_if_tx11_inp1_mux_text),
+ cdc_if_tx11_inp1_mux_text);
+static const struct soc_enum cdc_if_tx11_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0,
+ ARRAY_SIZE(cdc_if_tx11_mux_text), cdc_if_tx11_mux_text);
+static const struct soc_enum cdc_if_tx13_inp1_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 4,
+ ARRAY_SIZE(cdc_if_tx13_inp1_mux_text),
+ cdc_if_tx13_inp1_mux_text);
+static const struct soc_enum cdc_if_tx13_mux_enum =
+ SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0,
+ ARRAY_SIZE(cdc_if_tx13_mux_text), cdc_if_tx13_mux_text);
+
+static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src)
+{
+ if (sido_src == wcd->sido_input_src)
+ return 0;
+
+ if (sido_src == SIDO_SOURCE_INTERNAL) {
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL,
+ WCD934X_ANA_BUCK_HI_ACCU_EN_MASK, 0);
+ usleep_range(100, 110);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL,
+ WCD934X_ANA_BUCK_HI_ACCU_PRE_ENX_MASK, 0x0);
+ usleep_range(100, 110);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_RCO,
+ WCD934X_ANA_RCO_BG_EN_MASK, 0);
+ usleep_range(100, 110);
+ } else if (sido_src == SIDO_SOURCE_RCO_BG) {
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_RCO,
+ WCD934X_ANA_RCO_BG_EN_MASK,
+ WCD934X_ANA_RCO_BG_ENABLE);
+ usleep_range(100, 110);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL,
+ WCD934X_ANA_BUCK_PRE_EN1_MASK,
+ WCD934X_ANA_BUCK_PRE_EN1_ENABLE);
+ usleep_range(100, 110);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL,
+ WCD934X_ANA_BUCK_PRE_EN2_MASK,
+ WCD934X_ANA_BUCK_PRE_EN2_ENABLE);
+ usleep_range(100, 110);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL,
+ WCD934X_ANA_BUCK_HI_ACCU_EN_MASK,
+ WCD934X_ANA_BUCK_HI_ACCU_ENABLE);
+ usleep_range(100, 110);
+ }
+ wcd->sido_input_src = sido_src;
+
+ return 0;
+}
+
+static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd)
+{
+ mutex_lock(&wcd->sysclk_mutex);
+
+ if (++wcd->sysclk_users != 1) {
+ mutex_unlock(&wcd->sysclk_mutex);
+ return 0;
+ }
+ mutex_unlock(&wcd->sysclk_mutex);
+
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
+ WCD934X_ANA_BIAS_EN_MASK,
+ WCD934X_ANA_BIAS_EN);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
+ WCD934X_ANA_PRECHRG_EN_MASK,
+ WCD934X_ANA_PRECHRG_EN);
+ /*
+ * 1ms delay is required after pre-charge is enabled
+ * as per HW requirement
+ */
+ usleep_range(1000, 1100);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
+ WCD934X_ANA_PRECHRG_EN_MASK, 0);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
+ WCD934X_ANA_PRECHRG_MODE_MASK, 0);
+
+ /*
+ * In data clock contrl register is changed
+ * to CLK_SYS_MCLK_PRG
+ */
+
+ regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+ WCD934X_EXT_CLK_BUF_EN_MASK,
+ WCD934X_EXT_CLK_BUF_EN);
+ regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+ WCD934X_EXT_CLK_DIV_RATIO_MASK,
+ WCD934X_EXT_CLK_DIV_BY_2);
+ regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+ WCD934X_MCLK_SRC_MASK,
+ WCD934X_MCLK_SRC_EXT_CLK);
+ regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+ WCD934X_MCLK_EN_MASK, WCD934X_MCLK_EN);
+ regmap_update_bits(wcd->regmap,
+ WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+ WCD934X_CDC_FS_MCLK_CNT_EN_MASK,
+ WCD934X_CDC_FS_MCLK_CNT_ENABLE);
+ regmap_update_bits(wcd->regmap,
+ WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+ WCD934X_MCLK_EN_MASK,
+ WCD934X_MCLK_EN);
+ regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_GATE,
+ WCD934X_CODEC_RPM_CLK_GATE_MASK, 0x0);
+ /*
+ * 10us sleep is required after clock is enabled
+ * as per HW requirement
+ */
+ usleep_range(10, 15);
+
+ wcd934x_set_sido_input_src(wcd, SIDO_SOURCE_RCO_BG);
+
+ return 0;
+}
+
+static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd)
+{
+ mutex_lock(&wcd->sysclk_mutex);
+ if (--wcd->sysclk_users != 0) {
+ mutex_unlock(&wcd->sysclk_mutex);
+ return 0;
+ }
+ mutex_unlock(&wcd->sysclk_mutex);
+
+ regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+ WCD934X_EXT_CLK_BUF_EN_MASK |
+ WCD934X_MCLK_EN_MASK, 0x0);
+ wcd934x_set_sido_input_src(wcd, SIDO_SOURCE_INTERNAL);
+
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
+ WCD934X_ANA_BIAS_EN_MASK, 0);
+ regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
+ WCD934X_ANA_PRECHRG_EN_MASK, 0);
+
+ return 0;
+}
+
+static int __wcd934x_cdc_mclk_enable(struct wcd934x_codec *wcd, bool enable)
+{
+ int ret = 0;
+
+ if (enable) {
+ ret = clk_prepare_enable(wcd->extclk);
+
+ if (ret) {
+ dev_err(wcd->dev, "%s: ext clk enable failed\n",
+ __func__);
+ return ret;
+ }
+ ret = wcd934x_enable_ana_bias_and_sysclk(wcd);
+ } else {
+ int val;
+
+ regmap_read(wcd->regmap, WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+ &val);
+
+ /* Don't disable clock if soundwire using it.*/
+ if (val & WCD934X_CDC_SWR_CLK_EN_MASK)
+ return 0;
+
+ wcd934x_disable_ana_bias_and_syclk(wcd);
+ clk_disable_unprepare(wcd->extclk);
+ }
+
+ return ret;
+}
+
+static int wcd934x_codec_enable_mclk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return __wcd934x_cdc_mclk_enable(wcd, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return __wcd934x_cdc_mclk_enable(wcd, false);
+ }
+
+ return 0;
+}
+
+static int wcd934x_get_version(struct wcd934x_codec *wcd)
+{
+ int val1, val2, ver, ret;
+ struct regmap *regmap;
+ u16 id_minor;
+ u32 version_mask = 0;
+
+ regmap = wcd->regmap;
+ ver = 0;
+
+ ret = regmap_bulk_read(regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+ (u8 *)&id_minor, sizeof(u16));
+
+ if (ret)
+ return ret;
+
+ regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1);
+ regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2);
+
+ version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK;
+ version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK;
+
+ switch (version_mask) {
+ case DSD_DISABLED | SLNQ_DISABLED:
+ if (id_minor == 0)
+ ver = WCD_VERSION_WCD9340_1_0;
+ else if (id_minor == 0x01)
+ ver = WCD_VERSION_WCD9340_1_1;
+ break;
+ case SLNQ_DISABLED:
+ if (id_minor == 0)
+ ver = WCD_VERSION_WCD9341_1_0;
+ else if (id_minor == 0x01)
+ ver = WCD_VERSION_WCD9341_1_1;
+ break;
+ }
+
+ wcd->version = ver;
+ dev_info(wcd->dev, "WCD934X Minor:0x%x Version:0x%x\n", id_minor, ver);
+
+ return 0;
+}
+
+static void wcd934x_enable_efuse_sensing(struct wcd934x_codec *wcd)
+{
+ int rc, val;
+
+ __wcd934x_cdc_mclk_enable(wcd, true);
+
+ regmap_update_bits(wcd->regmap,
+ WCD934X_CHIP_TIER_CTRL_EFUSE_CTL,
+ WCD934X_EFUSE_SENSE_STATE_MASK,
+ WCD934X_EFUSE_SENSE_STATE_DEF);
+ regmap_update_bits(wcd->regmap,
+ WCD934X_CHIP_TIER_CTRL_EFUSE_CTL,
+ WCD934X_EFUSE_SENSE_EN_MASK,
+ WCD934X_EFUSE_SENSE_ENABLE);
+ /*
+ * 5ms sleep required after enabling efuse control
+ * before checking the status.
+ */
+ usleep_range(5000, 5500);
+ wcd934x_set_sido_input_src(wcd, SIDO_SOURCE_RCO_BG);
+
+ rc = regmap_read(wcd->regmap,
+ WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
+ if (rc || (!(val & 0x01)))
+ WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n",
+ __func__, val, rc);
+
+ __wcd934x_cdc_mclk_enable(wcd, false);
+}
+
+static int wcd934x_swrm_clock(struct wcd934x_codec *wcd, bool enable)
+{
+ if (enable) {
+ __wcd934x_cdc_mclk_enable(wcd, true);
+ regmap_update_bits(wcd->regmap,
+ WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+ WCD934X_CDC_SWR_CLK_EN_MASK,
+ WCD934X_CDC_SWR_CLK_ENABLE);
+ } else {
+ regmap_update_bits(wcd->regmap,
+ WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+ WCD934X_CDC_SWR_CLK_EN_MASK, 0);
+ __wcd934x_cdc_mclk_enable(wcd, false);
+ }
+
+ return 0;
+}
+
+static int wcd934x_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+ u8 rate_val, u32 rate)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ struct wcd934x_slim_ch *ch;
+ u8 cfg0, cfg1, inp0_sel, inp1_sel, inp2_sel;
+ int inp, j;
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+ inp = ch->shift + INTn_1_INP_SEL_RX0;
+ /*
+ * Loop through all interpolator MUX inputs and find out
+ * to which interpolator input, the slim rx port
+ * is connected
+ */
+ for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) {
+ /* Interpolators 5 and 6 are not aviliable in Tavil */
+ if (j == INTERP_LO3_NA || j == INTERP_LO4_NA)
+ continue;
+
+ cfg0 = snd_soc_component_read32(comp,
+ WCD934X_CDC_RX_INP_MUX_RX_INT_CFG0(j));
+ cfg1 = snd_soc_component_read32(comp,
+ WCD934X_CDC_RX_INP_MUX_RX_INT_CFG1(j));
+
+ inp0_sel = cfg0 &
+ WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+ inp1_sel = (cfg0 >> 4) &
+ WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+ inp2_sel = (cfg1 >> 4) &
+ WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+
+ if ((inp0_sel == inp) || (inp1_sel == inp) ||
+ (inp2_sel == inp)) {
+ /* rate is in Hz */
+ /*
+ * Ear and speaker primary path does not support
+ * native sample rates
+ */
+ if ((j == INTERP_EAR || j == INTERP_SPKR1 ||
+ j == INTERP_SPKR2) && rate == 44100)
+ dev_err(wcd->dev,
+ "Cannot set 44.1KHz on INT%d\n",
+ j);
+ else
+ snd_soc_component_update_bits(comp,
+ WCD934X_CDC_RX_PATH_CTL(j),
+ WCD934X_CDC_MIX_PCM_RATE_MASK,
+ rate_val);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int wcd934x_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+ int rate_val, u32 rate)
+{
+ struct snd_soc_component *component = dai->component;
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+ struct wcd934x_slim_ch *ch;
+ int val, j;
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+ for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) {
+ /* Interpolators 5 and 6 are not aviliable in Tavil */
+ if (j == INTERP_LO3_NA || j == INTERP_LO4_NA)
+ continue;
+ val = snd_soc_component_read32(component,
+ WCD934X_CDC_RX_INP_MUX_RX_INT_CFG1(j)) &
+ WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+
+ if (val == (ch->shift + INTn_2_INP_SEL_RX0)) {
+ /*
+ * Ear mix path supports only 48, 96, 192,
+ * 384KHz only
+ */
+ if ((j == INTERP_EAR) &&
+ (rate_val < 0x4 ||
+ rate_val > 0x7)) {
+ dev_err(component->dev,
+ "Invalid rate for AIF_PB DAI(%d)\n",
+ dai->id);
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD934X_CDC_RX_PATH_MIX_CTL(j),
+ WCD934X_CDC_MIX_PCM_RATE_MASK,
+ rate_val);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int wcd934x_set_interpolator_rate(struct snd_soc_dai *dai,
+ u32 sample_rate)
+{
+ int rate_val = 0;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) {
+ if (sample_rate == sr_val_tbl[i].sample_rate) {
+ rate_val = sr_val_tbl[i].rate_val;
+ break;
+ }
+ }
+ if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) {
+ dev_err(dai->dev, "Unsupported sample rate: %d\n", sample_rate);
+ return -EINVAL;
+ }
+
+ ret = wcd934x_set_prim_interpolator_rate(dai, (u8)rate_val,
+ sample_rate);
+ if (ret)
+ return ret;
+ ret = wcd934x_set_mix_interpolator_rate(dai, (u8)rate_val,
+ sample_rate);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int wcd934x_set_decimator_rate(struct snd_soc_dai *dai,
+ u8 rate_val, u32 rate)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(comp);
+ u8 shift = 0, shift_val = 0, tx_mux_sel;
+ struct wcd934x_slim_ch *ch;
+ int tx_port, tx_port_reg;
+ int decimator = -1;
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+ tx_port = ch->port;
+ /* Find the SB TX MUX input - which decimator is connected */
+ switch (tx_port) {
+ case 0 ... 3:
+ tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0;
+ shift = (tx_port << 1);
+ shift_val = 0x03;
+ break;
+ case 4 ... 7:
+ tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1;
+ shift = ((tx_port - 4) << 1);
+ shift_val = 0x03;
+ break;
+ case 8 ... 10:
+ tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2;
+ shift = ((tx_port - 8) << 1);
+ shift_val = 0x03;
+ break;
+ case 11:
+ tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3;
+ shift = 0;
+ shift_val = 0x0F;
+ break;
+ case 13:
+ tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3;
+ shift = 4;
+ shift_val = 0x03;
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid SLIM TX%u port DAI ID:%d\n",
+ tx_port, dai->id);
+ return -EINVAL;
+ }
+
+ tx_mux_sel = snd_soc_component_read32(comp, tx_port_reg) &
+ (shift_val << shift);
+
+ tx_mux_sel = tx_mux_sel >> shift;
+ switch (tx_port) {
+ case 0 ... 8:
+ if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3))
+ decimator = tx_port;
+ break;
+ case 9 ... 10:
+ if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+ decimator = ((tx_port == 9) ? 7 : 6);
+ break;
+ case 11:
+ if ((tx_mux_sel >= 1) && (tx_mux_sel < 7))
+ decimator = tx_mux_sel - 1;
+ break;
+ case 13:
+ if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+ decimator = 5;
+ break;
+ default:
+ dev_err(wcd->dev, "ERROR: Invalid tx_port: %d\n",
+ tx_port);
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(comp,
+ WCD934X_CDC_TX_PATH_CTL(decimator),
+ WCD934X_CDC_TX_PATH_CTL_PCM_RATE_MASK,
+ rate_val);
+ }
+
+ return 0;
+}
+
+static int wcd934x_slim_set_hw_params(struct wcd934x_codec *wcd,
+ struct wcd_slim_codec_dai_data *dai_data,
+ int direction)
+{
+ struct list_head *slim_ch_list = &dai_data->slim_ch_list;
+ struct slim_stream_config *cfg = &dai_data->sconfig;
+ struct wcd934x_slim_ch *ch;
+ u16 payload = 0;
+ int ret, i;
+
+ cfg->ch_count = 0;
+ cfg->direction = direction;
+ cfg->port_mask = 0;
+
+ /* Configure slave interface device */
+ list_for_each_entry(ch, slim_ch_list, list) {
+ cfg->ch_count++;
+ payload |= 1 << ch->shift;
+ cfg->port_mask |= BIT(ch->port);
+ }
+
+ cfg->chs = kcalloc(cfg->ch_count, sizeof(unsigned int), GFP_KERNEL);
+ if (!cfg->chs)
+ return -ENOMEM;
+
+ i = 0;
+ list_for_each_entry(ch, slim_ch_list, list) {
+ cfg->chs[i++] = ch->ch_num;
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* write to interface device */
+ ret = regmap_write(wcd->if_regmap,
+ WCD934X_SLIM_PGD_RX_PORT_MULTI_CHNL_0(ch->port),
+ payload);
+
+ if (ret < 0)
+ goto err;
+
+ /* configure the slave port for water mark and enable*/
+ ret = regmap_write(wcd->if_regmap,
+ WCD934X_SLIM_PGD_RX_PORT_CFG(ch->port),
+ WCD934X_SLIM_WATER_MARK_VAL);
+ if (ret < 0)
+ goto err;
+ } else {
+ ret = regmap_write(wcd->if_regmap,
+ WCD934X_SLIM_PGD_TX_PORT_MULTI_CHNL_0(ch->port),
+ payload & 0x00FF);
+ if (ret < 0)
+ goto err;
+
+ /* ports 8,9 */
+ ret = regmap_write(wcd->if_regmap,
+ WCD934X_SLIM_PGD_TX_PORT_MULTI_CHNL_1(ch->port),
+ (payload & 0xFF00) >> 8);
+ if (ret < 0)
+ goto err;
+
+ /* configure the slave port for water mark and enable*/
+ ret = regmap_write(wcd->if_regmap,
+ WCD934X_SLIM_PGD_TX_PORT_CFG(ch->port),
+ WCD934X_SLIM_WATER_MARK_VAL);
+
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ dai_data->sruntime = slim_stream_allocate(wcd->sdev, "WCD934x-SLIM");
+
+ return 0;
+
+err:
+ dev_err(wcd->dev, "Error Setting slim hw params\n");
+ kfree(cfg->chs);
+ cfg->chs = NULL;
+
+ return ret;
+}
+
+static int wcd934x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wcd934x_codec *wcd;
+ int ret, tx_fs_rate = 0;
+
+ wcd = snd_soc_component_get_drvdata(dai->component);
+
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ ret = wcd934x_set_interpolator_rate(dai, params_rate(params));
+ if (ret) {
+ dev_err(wcd->dev, "cannot set sample rate: %u\n",
+ params_rate(params));
+ return ret;
+ }
+ switch (params_width(params)) {
+ case 16 ... 24:
+ wcd->dai[dai->id].sconfig.bps = params_width(params);
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid format 0x%x\n",
+ params_width(params));
+ return -EINVAL;
+ }
+ break;
+
+ case SNDRV_PCM_STREAM_CAPTURE:
+ switch (params_rate(params)) {
+ case 8000:
+ tx_fs_rate = 0;
+ break;
+ case 16000:
+ tx_fs_rate = 1;
+ break;
+ case 32000:
+ tx_fs_rate = 3;
+ break;
+ case 48000:
+ tx_fs_rate = 4;
+ break;
+ case 96000:
+ tx_fs_rate = 5;
+ break;
+ case 192000:
+ tx_fs_rate = 6;
+ break;
+ case 384000:
+ tx_fs_rate = 7;
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid TX sample rate: %d\n",
+ params_rate(params));
+ return -EINVAL;
+
+ };
+
+ ret = wcd934x_set_decimator_rate(dai, tx_fs_rate,
+ params_rate(params));
+ if (ret < 0) {
+ dev_err(wcd->dev, "Cannot set TX Decimator rate\n");
+ return ret;
+ }
+ switch (params_width(params)) {
+ case 16 ... 32:
+ wcd->dai[dai->id].sconfig.bps = params_width(params);
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid format 0x%x\n",
+ params_width(params));
+ return -EINVAL;
+ };
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid stream type %d\n",
+ substream->stream);
+ return -EINVAL;
+ };
+
+ wcd->dai[dai->id].sconfig.rate = params_rate(params);
+ wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
+
+ return 0;
+}
+
+static int wcd934x_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd_slim_codec_dai_data *dai_data;
+ struct wcd934x_codec *wcd;
+
+ wcd = snd_soc_component_get_drvdata(dai->component);
+
+ dai_data = &wcd->dai[dai->id];
+
+ kfree(dai_data->sconfig.chs);
+
+ return 0;
+}
+
+static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct wcd_slim_codec_dai_data *dai_data;
+ struct wcd934x_codec *wcd;
+ struct slim_stream_config *cfg;
+
+ wcd = snd_soc_component_get_drvdata(dai->component);
+
+ dai_data = &wcd->dai[dai->id];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ cfg = &dai_data->sconfig;
+ slim_stream_prepare(dai_data->sruntime, cfg);
+ slim_stream_enable(dai_data->sruntime);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ slim_stream_unprepare(dai_data->sruntime);
+ slim_stream_disable(dai_data->sruntime);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ struct wcd934x_codec *wcd;
+ int i;
+
+ wcd = snd_soc_component_get_drvdata(dai->component);
+
+ if (!tx_slot || !rx_slot) {
+ dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n",
+ tx_slot, rx_slot);
+ return -EINVAL;
+ }
+
+ if (wcd->rx_chs) {
+ wcd->num_rx_port = rx_num;
+ for (i = 0; i < rx_num; i++) {
+ wcd->rx_chs[i].ch_num = rx_slot[i];
+ INIT_LIST_HEAD(&wcd->rx_chs[i].list);
+ }
+ }
+
+ if (wcd->tx_chs) {
+ wcd->num_tx_port = tx_num;
+ for (i = 0; i < tx_num; i++) {
+ wcd->tx_chs[i].ch_num = tx_slot[i];
+ INIT_LIST_HEAD(&wcd->tx_chs[i].list);
+ }
+ }
+
+ return 0;
+}
+
+static int wcd934x_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ struct wcd934x_slim_ch *ch;
+ struct wcd934x_codec *wcd;
+ int i = 0;
+
+ wcd = snd_soc_component_get_drvdata(dai->component);
+
+ switch (dai->id) {
+ case AIF1_PB:
+ case AIF2_PB:
+ case AIF3_PB:
+ case AIF4_PB:
+ if (!rx_slot || !rx_num) {
+ dev_err(wcd->dev, "Invalid rx_slot %p or rx_num %p\n",
+ rx_slot, rx_num);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list)
+ rx_slot[i++] = ch->ch_num;
+
+ *rx_num = i;
+ break;
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ if (!tx_slot || !tx_num) {
+ dev_err(wcd->dev, "Invalid tx_slot %p or tx_num %p\n",
+ tx_slot, tx_num);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list)
+ tx_slot[i++] = ch->ch_num;
+
+ *tx_num = i;
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id);
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops wcd934x_dai_ops = {
+ .hw_params = wcd934x_hw_params,
+ .hw_free = wcd934x_hw_free,
+ .trigger = wcd934x_trigger,
+ .set_channel_map = wcd934x_set_channel_map,
+ .get_channel_map = wcd934x_get_channel_map,
+};
+
+static struct snd_soc_dai_driver wcd934x_slim_dais[] = {
+ [0] = {
+ .name = "wcd934x_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+ .formats = WCD934X_FORMATS_S16_S24_LE,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+ [1] = {
+ .name = "wcd934x_tx1",
+ .id = AIF1_CAP,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD934X_RATES_MASK,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+ [2] = {
+ .name = "wcd934x_rx2",
+ .id = AIF2_PB,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+ .formats = WCD934X_FORMATS_S16_S24_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+ [3] = {
+ .name = "wcd934x_tx2",
+ .id = AIF2_CAP,
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .rates = WCD934X_RATES_MASK,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+ [4] = {
+ .name = "wcd934x_rx3",
+ .id = AIF3_PB,
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+ .formats = WCD934X_FORMATS_S16_S24_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+ [5] = {
+ .name = "wcd934x_tx3",
+ .id = AIF3_CAP,
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .rates = WCD934X_RATES_MASK,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+ [6] = {
+ .name = "wcd934x_rx4",
+ .id = AIF4_PB,
+ .playback = {
+ .stream_name = "AIF4 Playback",
+ .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+ .formats = WCD934X_FORMATS_S16_S24_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd934x_dai_ops,
+ },
+};
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+ return wcd934x_swrm_clock(to_wcd934x_codec(hw), true);
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+ wcd934x_swrm_clock(to_wcd934x_codec(hw), false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct wcd934x_codec *wcd = to_wcd934x_codec(hw);
+ int ret, val;
+
+ regmap_read(wcd->regmap, WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, &val);
+ ret = val & WCD934X_CDC_SWR_CLK_EN_MASK;
+
+ return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+ .prepare = swclk_gate_enable,
+ .unprepare = swclk_gate_disable,
+ .is_enabled = swclk_gate_is_enabled,
+ .recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd)
+{
+ struct clk *parent = wcd->extclk;
+ struct device *dev = wcd->dev;
+ struct device_node *np = dev->parent->of_node;
+ const char *parent_clk_name = NULL;
+ const char *clk_name = "mclk";
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ if (of_property_read_u32(np, "clock-frequency", &wcd->rate))
+ return NULL;
+
+ parent_clk_name = __clk_get_name(parent);
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = &swclk_gate_ops;
+ init.flags = 0;
+ init.parent_names = &parent_clk_name;
+ init.num_parents = 1;
+ wcd->hw.init = &init;
+
+ hw = &wcd->hw;
+ ret = clk_hw_register(wcd->dev->parent, hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+ return NULL;
+}
+
+static int wcd934x_get_micbias_val(struct device *dev, const char *micbias)
+{
+ int mv;
+
+ if (of_property_read_u32(dev->parent->of_node, micbias, &mv)) {
+ dev_err(dev, "%s value not found, using default\n", micbias);
+ mv = WCD934X_DEF_MICBIAS_MV;
+ } else {
+ /* convert it to milli volts */
+ mv = mv/1000;
+ }
+
+ if (mv < 1000 || mv > 2850) {
+ dev_err(dev, "%s value not in valid range, using default\n",
+ micbias);
+ mv = WCD934X_DEF_MICBIAS_MV;
+ }
+
+ return (mv - 1000) / 50;
+}
+
+static int wcd934x_init_dmic(struct snd_soc_component *comp)
+{
+ int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ u32 def_dmic_rate, dmic_clk_drv;
+
+ vout_ctl_1 = wcd934x_get_micbias_val(comp->dev,
+ "qcom,micbias1-microvolt");
+ vout_ctl_2 = wcd934x_get_micbias_val(comp->dev,
+ "qcom,micbias2-microvolt");
+ vout_ctl_3 = wcd934x_get_micbias_val(comp->dev,
+ "qcom,micbias3-microvolt");
+ vout_ctl_4 = wcd934x_get_micbias_val(comp->dev,
+ "qcom,micbias4-microvolt");
+
+ snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1,
+ WCD934X_MICB_VAL_MASK, vout_ctl_1);
+ snd_soc_component_update_bits(comp, WCD934X_ANA_MICB2,
+ WCD934X_MICB_VAL_MASK, vout_ctl_2);
+ snd_soc_component_update_bits(comp, WCD934X_ANA_MICB3,
+ WCD934X_MICB_VAL_MASK, vout_ctl_3);
+ snd_soc_component_update_bits(comp, WCD934X_ANA_MICB4,
+ WCD934X_MICB_VAL_MASK, vout_ctl_4);
+
+ if (wcd->rate == WCD934X_MCLK_CLK_9P6MHZ)
+ def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+ else
+ def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ;
+
+ wcd->dmic_sample_rate = def_dmic_rate;
+
+ dmic_clk_drv = 0;
+ snd_soc_component_update_bits(comp, WCD934X_TEST_DEBUG_PAD_DRVCTL_0,
+ 0x0C, dmic_clk_drv << 2);
+
+ return 0;
+}
+
+static void wcd934x_hw_init(struct wcd934x_codec *wcd)
+{
+ struct regmap *rm = wcd->regmap;
+
+ /* set SPKR rate to FS_2P4_3P072 */
+ regmap_update_bits(rm, WCD934X_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08);
+ regmap_update_bits(rm, WCD934X_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08);
+
+ /* Take DMICs out of reset */
+ regmap_update_bits(rm, WCD934X_CPE_SS_DMIC_CFG, 0x80, 0x00);
+}
+
+static int wcd934x_comp_init(struct snd_soc_component *component)
+{
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+
+ wcd934x_hw_init(wcd);
+ wcd934x_enable_efuse_sensing(wcd);
+ wcd934x_get_version(wcd);
+
+ return 0;
+}
+
+static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data)
+{
+ struct wcd934x_codec *wcd = data;
+ unsigned long status = 0;
+ int i, j, port_id;
+ unsigned int val, int_val = 0;
+ irqreturn_t ret = IRQ_NONE;
+ bool tx;
+ unsigned short reg = 0;
+
+ for (i = WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+ i <= WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+ regmap_read(wcd->if_regmap, i, &val);
+ status |= ((u32)val << (8 * j));
+ }
+
+ for_each_set_bit(j, &status, 32) {
+ tx = false;
+ port_id = j;
+
+ if (j >= 16) {
+ tx = true;
+ port_id = j - 16;
+ }
+
+ regmap_read(wcd->if_regmap,
+ WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val);
+ if (val) {
+ if (!tx)
+ reg = WCD934X_SLIM_PGD_PORT_INT_EN0 +
+ (port_id / 8);
+ else
+ reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 +
+ (port_id / 8);
+ regmap_read(wcd->if_regmap, reg, &int_val);
+ }
+
+ if (val & WCD934X_SLIM_IRQ_OVERFLOW)
+ dev_err_ratelimited(wcd->dev,
+ "overflow error on %s port %d, value %x\n",
+ (tx ? "TX" : "RX"), port_id, val);
+
+ if (val & WCD934X_SLIM_IRQ_UNDERFLOW)
+ dev_err_ratelimited(wcd->dev,
+ "underflow error on %s port %d, value %x\n",
+ (tx ? "TX" : "RX"), port_id, val);
+
+ if ((val & WCD934X_SLIM_IRQ_OVERFLOW) ||
+ (val & WCD934X_SLIM_IRQ_UNDERFLOW)) {
+ if (!tx)
+ reg = WCD934X_SLIM_PGD_PORT_INT_EN0 +
+ (port_id / 8);
+ else
+ reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 +
+ (port_id / 8);
+ regmap_read(
+ wcd->if_regmap, reg, &int_val);
+ if (int_val & (1 << (port_id % 8))) {
+ int_val = int_val ^ (1 << (port_id % 8));
+ regmap_write(wcd->if_regmap,
+ reg, int_val);
+ }
+ }
+
+ if (val & WCD934X_SLIM_IRQ_PORT_CLOSED)
+ dev_err_ratelimited(wcd->dev,
+ "Port Closed %s port %d, value %x\n",
+ (tx ? "TX" : "RX"), port_id, val);
+
+ regmap_write(wcd->if_regmap,
+ WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0 + (j / 8),
+ BIT(j % 8));
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int wcd934x_comp_probe(struct snd_soc_component *component)
+{
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+ int i;
+
+ snd_soc_component_init_regmap(component, wcd->regmap);
+ wcd->component = component;
+
+ /* Class-H Init*/
+ wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version);
+ if (IS_ERR(wcd->clsh_ctrl))
+ return PTR_ERR(wcd->clsh_ctrl);
+
+ /* Default HPH Mode to Class-H Low HiFi */
+ wcd->hph_mode = CLS_H_LOHIFI;
+
+ wcd934x_comp_init(component);
+
+ for (i = 0; i < NUM_CODEC_DAIS; i++)
+ INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list);
+
+ wcd934x_init_dmic(component);
+ return 0;
+}
+
+static void wcd934x_comp_remove(struct snd_soc_component *comp)
+{
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+
+ wcd_clsh_ctrl_free(wcd->clsh_ctrl);
+}
+
+static int wcd934x_comp_set_sysclk(struct snd_soc_component *comp,
+ int clk_id, int source,
+ unsigned int freq, int dir)
+{
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ int val = WCD934X_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ;
+
+ wcd->rate = freq;
+
+ if (wcd->rate == WCD934X_MCLK_CLK_12P288MHZ)
+ val = WCD934X_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ;
+
+ snd_soc_component_update_bits(comp, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ WCD934X_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+ val);
+
+ return clk_set_rate(wcd->extclk, freq);
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
+ int iir_idx, int band_idx, int coeff_idx)
+{
+ u32 value = 0;
+ int reg, b2_reg;
+
+ /* Address does not automatically update if reading */
+ reg = WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+ b2_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+
+ snd_soc_component_write(component, reg,
+ ((band_idx * BAND_MAX + coeff_idx) *
+ sizeof(uint32_t)) & 0x7F);
+
+ value |= snd_soc_component_read32(component, b2_reg);
+ snd_soc_component_write(component, reg,
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 1) & 0x7F);
+
+ value |= (snd_soc_component_read32(component, b2_reg) << 8);
+ snd_soc_component_write(component, reg,
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 2) & 0x7F);
+
+ value |= (snd_soc_component_read32(component, b2_reg) << 16);
+ snd_soc_component_write(component, reg,
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 3) & 0x7F);
+
+ /* Mask bits top 2 bits since they are reserved */
+ value |= (snd_soc_component_read32(component, b2_reg) << 24);
+ return value;
+}
+
+static void set_iir_band_coeff(struct snd_soc_component *component,
+ int iir_idx, int band_idx, uint32_t value)
+{
+ int reg = WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+
+ snd_soc_component_write(component, reg, (value & 0xFF));
+ snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
+ snd_soc_component_write(component, reg, (value >> 16) & 0xFF);
+ /* Mask top 2 bits, 7-8 are reserved */
+ snd_soc_component_write(component, reg, (value >> 24) & 0x3F);
+}
+
+static int wcd934x_put_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd_iir_filter_ctl *ctl =
+ (struct wcd_iir_filter_ctl *)kcontrol->private_value;
+ struct soc_bytes_ext *params = &ctl->bytes_ext;
+ int iir_idx = ctl->iir_idx;
+ int band_idx = ctl->band_idx;
+ u32 coeff[BAND_MAX];
+ int reg = WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+
+ memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
+
+ /* Mask top bit it is reserved */
+ /* Updates addr automatically for each B2 write */
+ snd_soc_component_write(component, reg, (band_idx * BAND_MAX *
+ sizeof(uint32_t)) & 0x7F);
+
+ set_iir_band_coeff(component, iir_idx, band_idx, coeff[0]);
+ set_iir_band_coeff(component, iir_idx, band_idx, coeff[1]);
+ set_iir_band_coeff(component, iir_idx, band_idx, coeff[2]);
+ set_iir_band_coeff(component, iir_idx, band_idx, coeff[3]);
+ set_iir_band_coeff(component, iir_idx, band_idx, coeff[4]);
+
+ return 0;
+}
+
+static int wcd934x_get_iir_band_audio_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd_iir_filter_ctl *ctl =
+ (struct wcd_iir_filter_ctl *)kcontrol->private_value;
+ struct soc_bytes_ext *params = &ctl->bytes_ext;
+ int iir_idx = ctl->iir_idx;
+ int band_idx = ctl->band_idx;
+ u32 coeff[BAND_MAX];
+
+ coeff[0] = get_iir_band_coeff(component, iir_idx, band_idx, 0);
+ coeff[1] = get_iir_band_coeff(component, iir_idx, band_idx, 1);
+ coeff[2] = get_iir_band_coeff(component, iir_idx, band_idx, 2);
+ coeff[3] = get_iir_band_coeff(component, iir_idx, band_idx, 3);
+ coeff[4] = get_iir_band_coeff(component, iir_idx, band_idx, 4);
+
+ memcpy(ucontrol->value.bytes.data, &coeff[0], params->max);
+
+ return 0;
+}
+
+static int wcd934x_iir_filter_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *ucontrol)
+{
+ struct wcd_iir_filter_ctl *ctl =
+ (struct wcd_iir_filter_ctl *)kcontrol->private_value;
+ struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+ ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ ucontrol->count = params->max;
+
+ return 0;
+}
+
+static int wcd934x_compander_get(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ int comp = ((struct soc_mixer_control *)kc->private_value)->shift;
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+
+ ucontrol->value.integer.value[0] = wcd->comp_enabled[comp];
+
+ return 0;
+}
+
+static int wcd934x_compander_set(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+ int comp = ((struct soc_mixer_control *)kc->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+ int sel;
+
+ wcd->comp_enabled[comp] = value;
+ sel = value ? WCD934X_HPH_GAIN_SRC_SEL_COMPANDER :
+ WCD934X_HPH_GAIN_SRC_SEL_REGISTER;
+
+ /* Any specific register configuration for compander */
+ switch (comp) {
+ case COMPANDER_1:
+ /* Set Gain Source Select based on compander enable/disable */
+ snd_soc_component_update_bits(component, WCD934X_HPH_L_EN,
+ WCD934X_HPH_GAIN_SRC_SEL_MASK,
+ sel);
+ break;
+ case COMPANDER_2:
+ snd_soc_component_update_bits(component, WCD934X_HPH_R_EN,
+ WCD934X_HPH_GAIN_SRC_SEL_MASK,
+ sel);
+ break;
+ case COMPANDER_3:
+ case COMPANDER_4:
+ case COMPANDER_7:
+ case COMPANDER_8:
+ break;
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_rx_hph_mode_get(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+
+ ucontrol->value.enumerated.item[0] = wcd->hph_mode;
+
+ return 0;
+}
+
+static int wcd934x_rx_hph_mode_put(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+ u32 mode_val;
+
+ mode_val = ucontrol->value.enumerated.item[0];
+
+ if (mode_val == 0) {
+ dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n");
+ mode_val = CLS_H_LOHIFI;
+ }
+ wcd->hph_mode = mode_val;
+
+ return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(dapm->dev);
+
+ ucontrol->value.enumerated.item[0] = wcd->rx_port_value[w->shift];
+
+ return 0;
+}
+
+static int slim_rx_mux_put(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(w->dapm->dev);
+ struct soc_enum *e = (struct soc_enum *)kc->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+ u32 port_id = w->shift;
+
+ if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
+
+ switch (wcd->rx_port_value[port_id]) {
+ case 0:
+ list_del_init(&wcd->rx_chs[port_id].list);
+ break;
+ case 1:
+ list_add_tail(&wcd->rx_chs[port_id].list,
+ &wcd->dai[AIF1_PB].slim_ch_list);
+ break;
+ case 2:
+ list_add_tail(&wcd->rx_chs[port_id].list,
+ &wcd->dai[AIF2_PB].slim_ch_list);
+ break;
+ case 3:
+ list_add_tail(&wcd->rx_chs[port_id].list,
+ &wcd->dai[AIF3_PB].slim_ch_list);
+ break;
+ case 4:
+ list_add_tail(&wcd->rx_chs[port_id].list,
+ &wcd->dai[AIF4_PB].slim_ch_list);
+ break;
+ default:
+ dev_err(wcd->dev, "Unknown AIF %d\n",
+ wcd->rx_port_value[port_id]);
+ goto err;
+ }
+
+ snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id],
+ e, update);
+
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static int wcd934x_int_dem_inp_mux_put(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kc->private_value;
+ struct snd_soc_component *component;
+ int reg, val, ret;
+
+ component = snd_soc_dapm_kcontrol_component(kc);
+ val = ucontrol->value.enumerated.item[0];
+ if (e->reg == WCD934X_CDC_RX0_RX_PATH_SEC0)
+ reg = WCD934X_CDC_RX0_RX_PATH_CFG0;
+ else if (e->reg == WCD934X_CDC_RX1_RX_PATH_SEC0)
+ reg = WCD934X_CDC_RX1_RX_PATH_CFG0;
+ else if (e->reg == WCD934X_CDC_RX2_RX_PATH_SEC0)
+ reg = WCD934X_CDC_RX2_RX_PATH_CFG0;
+ else
+ return -EINVAL;
+
+ /* Set Look Ahead Delay */
+ if (val)
+ snd_soc_component_update_bits(component, reg,
+ WCD934X_RX_DLY_ZN_EN_MASK,
+ WCD934X_RX_DLY_ZN_ENABLE);
+ else
+ snd_soc_component_update_bits(component, reg,
+ WCD934X_RX_DLY_ZN_EN_MASK,
+ WCD934X_RX_DLY_ZN_DISABLE);
+
+ ret = snd_soc_dapm_put_enum_double(kc, ucontrol);
+
+ return ret;
+}
+
+static int wcd934x_dec_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val;
+ u16 mic_sel_reg = 0;
+ u8 mic_sel;
+
+ comp = snd_soc_dapm_kcontrol_component(kcontrol);
+
+ val = ucontrol->value.enumerated.item[0];
+ if (val > e->items - 1)
+ return -EINVAL;
+
+ switch (e->reg) {
+ case WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1:
+ if (e->shift_l == 0)
+ mic_sel_reg = WCD934X_CDC_TX0_TX_PATH_CFG0;
+ else if (e->shift_l == 2)
+ mic_sel_reg = WCD934X_CDC_TX4_TX_PATH_CFG0;
+ else if (e->shift_l == 4)
+ mic_sel_reg = WCD934X_CDC_TX8_TX_PATH_CFG0;
+ break;
+ case WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1:
+ if (e->shift_l == 0)
+ mic_sel_reg = WCD934X_CDC_TX1_TX_PATH_CFG0;
+ else if (e->shift_l == 2)
+ mic_sel_reg = WCD934X_CDC_TX5_TX_PATH_CFG0;
+ break;
+ case WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1:
+ if (e->shift_l == 0)
+ mic_sel_reg = WCD934X_CDC_TX2_TX_PATH_CFG0;
+ else if (e->shift_l == 2)
+ mic_sel_reg = WCD934X_CDC_TX6_TX_PATH_CFG0;
+ break;
+ case WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1:
+ if (e->shift_l == 0)
+ mic_sel_reg = WCD934X_CDC_TX3_TX_PATH_CFG0;
+ else if (e->shift_l == 2)
+ mic_sel_reg = WCD934X_CDC_TX7_TX_PATH_CFG0;
+ break;
+ default:
+ dev_err(comp->dev, "%s: e->reg: 0x%x not expected\n",
+ __func__, e->reg);
+ return -EINVAL;
+ }
+
+ /* ADC: 0, DMIC: 1 */
+ mic_sel = val ? 0x0 : 0x1;
+ if (mic_sel_reg)
+ snd_soc_component_update_bits(comp, mic_sel_reg, BIT(7),
+ mic_sel << 7);
+
+ return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new rx_int0_2_mux =
+ SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_2_mux =
+ SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_2_mux =
+ SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_2_mux =
+ SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_2_mux =
+ SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_2_mux =
+ SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_2_mux =
+ SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_mix2_inp_mux =
+ SOC_DAPM_ENUM("RX INT0 MIX2 INP Mux", rx_int0_mix2_inp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int1_mix2_inp_mux =
+ SOC_DAPM_ENUM("RX INT1 MIX2 INP Mux", rx_int1_mix2_inp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int2_mix2_inp_mux =
+ SOC_DAPM_ENUM("RX INT2 MIX2 INP Mux", rx_int2_mix2_inp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int3_mix2_inp_mux =
+ SOC_DAPM_ENUM("RX INT3 MIX2 INP Mux", rx_int3_mix2_inp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int4_mix2_inp_mux =
+ SOC_DAPM_ENUM("RX INT4 MIX2 INP Mux", rx_int4_mix2_inp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int7_mix2_inp_mux =
+ SOC_DAPM_ENUM("RX INT7 MIX2 INP Mux", rx_int7_mix2_inp_mux_enum);
+
+static const struct snd_kcontrol_new iir0_inp0_mux =
+ SOC_DAPM_ENUM("IIR0 INP0 Mux", iir0_inp0_mux_enum);
+static const struct snd_kcontrol_new iir0_inp1_mux =
+ SOC_DAPM_ENUM("IIR0 INP1 Mux", iir0_inp1_mux_enum);
+static const struct snd_kcontrol_new iir0_inp2_mux =
+ SOC_DAPM_ENUM("IIR0 INP2 Mux", iir0_inp2_mux_enum);
+static const struct snd_kcontrol_new iir0_inp3_mux =
+ SOC_DAPM_ENUM("IIR0 INP3 Mux", iir0_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp0_mux =
+ SOC_DAPM_ENUM("IIR1 INP0 Mux", iir1_inp0_mux_enum);
+static const struct snd_kcontrol_new iir1_inp1_mux =
+ SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+static const struct snd_kcontrol_new iir1_inp2_mux =
+ SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum);
+static const struct snd_kcontrol_new iir1_inp3_mux =
+ SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum);
+
+static const struct snd_kcontrol_new slim_rx_mux[WCD934X_RX_MAX] = {
+ SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static const struct snd_kcontrol_new rx_int1_asrc_switch[] = {
+ SOC_DAPM_SINGLE("HPHL Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int2_asrc_switch[] = {
+ SOC_DAPM_SINGLE("HPHR Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int3_asrc_switch[] = {
+ SOC_DAPM_SINGLE("LO1 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int4_asrc_switch[] = {
+ SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int0_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ wcd934x_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ wcd934x_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int2_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ wcd934x_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int0_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT0_1 INTERP Mux", rx_int0_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT1_1 INTERP Mux", rx_int1_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT2_1 INTERP Mux", rx_int2_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT3_1 INTERP Mux", rx_int3_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT4_1 INTERP Mux", rx_int4_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT7_1 INTERP Mux", rx_int7_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_interp_mux =
+ SOC_DAPM_ENUM("RX INT8_1 INTERP Mux", rx_int8_1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int0_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT0_2 INTERP Mux", rx_int0_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int1_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT1_2 INTERP Mux", rx_int1_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int2_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT2_2 INTERP Mux", rx_int2_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int3_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT3_2 INTERP Mux", rx_int3_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int4_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT4_2 INTERP Mux", rx_int4_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int7_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT7_2 INTERP Mux", rx_int7_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int8_2_interp_mux =
+ SOC_DAPM_ENUM("RX INT8_2 INTERP Mux", rx_int8_2_interp_mux_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux0 =
+ SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux1 =
+ SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux2 =
+ SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux3 =
+ SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux4 =
+ SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux5 =
+ SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux6 =
+ SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux7 =
+ SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux8 =
+ SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux0 =
+ SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux1 =
+ SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux2 =
+ SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux3 =
+ SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux4 =
+ SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux5 =
+ SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux6 =
+ SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux7 =
+ SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux8 =
+ SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum);
+
+static const struct snd_kcontrol_new tx_amic4_5 =
+ SOC_DAPM_ENUM("AMIC4_5 SEL Mux", tx_amic4_5_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux0_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux1_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux2_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux3_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux4_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux5_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux6_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux7_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+static const struct snd_kcontrol_new tx_adc_mux8_mux =
+ SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_enum,
+ snd_soc_dapm_get_enum_double, wcd934x_dec_enum_put);
+
+static const struct snd_kcontrol_new cdc_if_tx0_mux =
+ SOC_DAPM_ENUM("CDC_IF TX0 MUX Mux", cdc_if_tx0_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx1_mux =
+ SOC_DAPM_ENUM("CDC_IF TX1 MUX Mux", cdc_if_tx1_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx2_mux =
+ SOC_DAPM_ENUM("CDC_IF TX2 MUX Mux", cdc_if_tx2_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx3_mux =
+ SOC_DAPM_ENUM("CDC_IF TX3 MUX Mux", cdc_if_tx3_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx4_mux =
+ SOC_DAPM_ENUM("CDC_IF TX4 MUX Mux", cdc_if_tx4_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx5_mux =
+ SOC_DAPM_ENUM("CDC_IF TX5 MUX Mux", cdc_if_tx5_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx6_mux =
+ SOC_DAPM_ENUM("CDC_IF TX6 MUX Mux", cdc_if_tx6_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx7_mux =
+ SOC_DAPM_ENUM("CDC_IF TX7 MUX Mux", cdc_if_tx7_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx8_mux =
+ SOC_DAPM_ENUM("CDC_IF TX8 MUX Mux", cdc_if_tx8_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx9_mux =
+ SOC_DAPM_ENUM("CDC_IF TX9 MUX Mux", cdc_if_tx9_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx10_mux =
+ SOC_DAPM_ENUM("CDC_IF TX10 MUX Mux", cdc_if_tx10_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx11_mux =
+ SOC_DAPM_ENUM("CDC_IF TX11 MUX Mux", cdc_if_tx11_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx11_inp1_mux =
+ SOC_DAPM_ENUM("CDC_IF TX11 INP1 MUX Mux", cdc_if_tx11_inp1_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx13_mux =
+ SOC_DAPM_ENUM("CDC_IF TX13 MUX Mux", cdc_if_tx13_mux_enum);
+static const struct snd_kcontrol_new cdc_if_tx13_inp1_mux =
+ SOC_DAPM_ENUM("CDC_IF TX13 INP1 MUX Mux", cdc_if_tx13_inp1_mux_enum);
+
+static int slim_tx_mixer_get(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(dapm->dev);
+ struct soc_mixer_control *mixer =
+ (struct soc_mixer_control *)kc->private_value;
+ int port_id = mixer->shift;
+
+ ucontrol->value.integer.value[0] = wcd->tx_port_value[port_id];
+
+ return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
+ struct wcd934x_codec *wcd = dev_get_drvdata(widget->dapm->dev);
+ struct snd_soc_dapm_update *update = NULL;
+ struct soc_mixer_control *mixer =
+ (struct soc_mixer_control *)kc->private_value;
+ int enable = ucontrol->value.integer.value[0];
+ int dai_id = widget->shift;
+ int port_id = mixer->shift;
+
+ /* only add to the list if value not set */
+ if (enable == wcd->tx_port_value[port_id])
+ return 0;
+
+ wcd->tx_port_value[port_id] = enable;
+
+ if (enable)
+ list_add_tail(&wcd->tx_chs[port_id].list,
+ &wcd->dai[dai_id].slim_ch_list);
+ else
+ list_del_init(&wcd->tx_chs[port_id].list);
+
+ snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new aif1_slim_cap_mixer[] = {
+ SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif2_slim_cap_mixer[] = {
+ SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif3_slim_cap_mixer[] = {
+ SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new wcd934x_snd_controls[] = {
+ /* Gain Controls */
+ SOC_SINGLE_TLV("EAR PA Volume", WCD934X_ANA_EAR, 4, 4, 1, ear_pa_gain),
+ SOC_SINGLE_TLV("HPHL Volume", WCD934X_HPH_L_EN, 0, 24, 1, line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", WCD934X_HPH_R_EN, 0, 24, 1, line_gain),
+ SOC_SINGLE_TLV("LINEOUT1 Volume", WCD934X_DIFF_LO_LO1_COMPANDER,
+ 3, 16, 1, line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", WCD934X_DIFF_LO_LO2_COMPANDER,
+ 3, 16, 1, line_gain),
+
+ SOC_SINGLE_TLV("ADC1 Volume", WCD934X_ANA_AMIC1, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", WCD934X_ANA_AMIC2, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", WCD934X_ANA_AMIC3, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", WCD934X_ANA_AMIC4, 0, 20, 0, analog_gain),
+
+ SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL,
+ -84, 40, digital_gain), /* -84dB min - 40dB max */
+ SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume",
+ WCD934X_CDC_RX0_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume",
+ WCD934X_CDC_RX1_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume",
+ WCD934X_CDC_RX2_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume",
+ WCD934X_CDC_RX3_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume",
+ WCD934X_CDC_RX4_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume",
+ WCD934X_CDC_RX7_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume",
+ WCD934X_CDC_RX8_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+
+ SOC_SINGLE_S8_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL,
+ -84, 40, digital_gain),
+
+ SOC_SINGLE_S8_TLV("IIR0 INP0 Volume",
+ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR0 INP1 Volume",
+ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR0 INP2 Volume",
+ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR0 INP3 Volume",
+ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP0 Volume",
+ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
+ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
+ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
+ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40,
+ digital_gain),
+
+ SOC_ENUM("TX0 HPF cut off", cf_dec0_enum),
+ SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+ SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+ SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+ SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+ SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
+ SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
+ SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
+ SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
+
+ SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
+ SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
+ SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
+ SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum),
+ SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum),
+ SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum),
+ SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum),
+ SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum),
+ SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum),
+ SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum),
+ SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum),
+ SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum),
+ SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum),
+ SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum),
+
+ SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+ wcd934x_rx_hph_mode_get, wcd934x_rx_hph_mode_put),
+
+ SOC_SINGLE("IIR1 Band1 Switch", WCD934X_CDC_SIDETONE_IIR0_IIR_CTL,
+ 0, 1, 0),
+ SOC_SINGLE("IIR1 Band2 Switch", WCD934X_CDC_SIDETONE_IIR0_IIR_CTL,
+ 1, 1, 0),
+ SOC_SINGLE("IIR1 Band3 Switch", WCD934X_CDC_SIDETONE_IIR0_IIR_CTL,
+ 2, 1, 0),
+ SOC_SINGLE("IIR1 Band4 Switch", WCD934X_CDC_SIDETONE_IIR0_IIR_CTL,
+ 3, 1, 0),
+ SOC_SINGLE("IIR1 Band5 Switch", WCD934X_CDC_SIDETONE_IIR0_IIR_CTL,
+ 4, 1, 0),
+ SOC_SINGLE("IIR2 Band1 Switch", WCD934X_CDC_SIDETONE_IIR1_IIR_CTL,
+ 0, 1, 0),
+ SOC_SINGLE("IIR2 Band2 Switch", WCD934X_CDC_SIDETONE_IIR1_IIR_CTL,
+ 1, 1, 0),
+ SOC_SINGLE("IIR2 Band3 Switch", WCD934X_CDC_SIDETONE_IIR1_IIR_CTL,
+ 2, 1, 0),
+ SOC_SINGLE("IIR2 Band4 Switch", WCD934X_CDC_SIDETONE_IIR1_IIR_CTL,
+ 3, 1, 0),
+ SOC_SINGLE("IIR2 Band5 Switch", WCD934X_CDC_SIDETONE_IIR1_IIR_CTL,
+ 4, 1, 0),
+ WCD_IIR_FILTER_CTL("IIR0 Band1", IIR0, BAND1),
+ WCD_IIR_FILTER_CTL("IIR0 Band2", IIR0, BAND2),
+ WCD_IIR_FILTER_CTL("IIR0 Band3", IIR0, BAND3),
+ WCD_IIR_FILTER_CTL("IIR0 Band4", IIR0, BAND4),
+ WCD_IIR_FILTER_CTL("IIR0 Band5", IIR0, BAND5),
+
+ WCD_IIR_FILTER_CTL("IIR1 Band1", IIR1, BAND1),
+ WCD_IIR_FILTER_CTL("IIR1 Band2", IIR1, BAND2),
+ WCD_IIR_FILTER_CTL("IIR1 Band3", IIR1, BAND3),
+ WCD_IIR_FILTER_CTL("IIR1 Band4", IIR1, BAND4),
+ WCD_IIR_FILTER_CTL("IIR1 Band5", IIR1, BAND5),
+
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+ wcd934x_compander_get, wcd934x_compander_set),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+ wcd934x_compander_get, wcd934x_compander_set),
+ SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0,
+ wcd934x_compander_get, wcd934x_compander_set),
+ SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0,
+ wcd934x_compander_get, wcd934x_compander_set),
+ SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0,
+ wcd934x_compander_get, wcd934x_compander_set),
+ SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0,
+ wcd934x_compander_get, wcd934x_compander_set),
+};
+
+static void wcd934x_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai,
+ struct snd_soc_component *component)
+{
+ int port_num = 0;
+ unsigned short reg = 0;
+ unsigned int val = 0;
+ struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+ struct wcd934x_slim_ch *ch;
+
+ list_for_each_entry(ch, &dai->slim_ch_list, list) {
+ if (ch->port >= WCD934X_RX_START) {
+ port_num = ch->port - WCD934X_RX_START;
+ reg = WCD934X_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
+ } else {
+ port_num = ch->port;
+ reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+ }
+
+ regmap_read(wcd->if_regmap, reg, &val);
+ if (!(val & BIT(port_num % 8)))
+ regmap_write(wcd->if_regmap, reg,
+ val | BIT(port_num % 8));
+ }
+}
+
+static int wcd934x_codec_enable_slim(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(comp);
+ struct wcd_slim_codec_dai_data *dai = &wcd->dai[w->shift];
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ wcd934x_codec_enable_int_port(dai, comp);
+ break;
+ }
+
+ return 0;
+}
+
+static void wcd934x_codec_hd2_control(struct snd_soc_component *component,
+ u16 interp_idx, int event)
+{
+ u16 hd2_scale_reg;
+ u16 hd2_enable_reg = 0;
+
+ switch (interp_idx) {
+ case INTERP_HPHL:
+ hd2_scale_reg = WCD934X_CDC_RX1_RX_PATH_SEC3;
+ hd2_enable_reg = WCD934X_CDC_RX1_RX_PATH_CFG0;
+ break;
+ case INTERP_HPHR:
+ hd2_scale_reg = WCD934X_CDC_RX2_RX_PATH_SEC3;
+ hd2_enable_reg = WCD934X_CDC_RX2_RX_PATH_CFG0;
+ break;
+ default:
+ return;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, hd2_scale_reg,
+ WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_MASK,
+ WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_0P3125);
+ snd_soc_component_update_bits(component, hd2_enable_reg,
+ WCD934X_CDC_RX_PATH_CFG_HD2_EN_MASK,
+ WCD934X_CDC_RX_PATH_CFG_HD2_ENABLE);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, hd2_enable_reg,
+ WCD934X_CDC_RX_PATH_CFG_HD2_EN_MASK,
+ WCD934X_CDC_RX_PATH_CFG_HD2_DISABLE);
+ snd_soc_component_update_bits(component, hd2_scale_reg,
+ WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_MASK,
+ WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000);
+ }
+}
+
+static void wcd934x_codec_hphdelay_lutbypass(struct snd_soc_component *comp,
+ u16 interp_idx, int event)
+{
+ u8 hph_dly_mask;
+ u16 hph_lut_bypass_reg = 0;
+ u16 hph_comp_ctrl7 = 0;
+
+ switch (interp_idx) {
+ case INTERP_HPHL:
+ hph_dly_mask = 1;
+ hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHL_COMP_LUT;
+ hph_comp_ctrl7 = WCD934X_CDC_COMPANDER1_CTL7;
+ break;
+ case INTERP_HPHR:
+ hph_dly_mask = 2;
+ hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHR_COMP_LUT;
+ hph_comp_ctrl7 = WCD934X_CDC_COMPANDER2_CTL7;
+ break;
+ default:
+ return;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(comp, WCD934X_CDC_CLSH_TEST0,
+ hph_dly_mask, 0x0);
+ snd_soc_component_update_bits(comp, hph_lut_bypass_reg,
+ WCD934X_HPH_LUT_BYPASS_MASK,
+ WCD934X_HPH_LUT_BYPASS_ENABLE);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(comp, WCD934X_CDC_CLSH_TEST0,
+ hph_dly_mask, hph_dly_mask);
+ snd_soc_component_update_bits(comp, hph_lut_bypass_reg,
+ WCD934X_HPH_LUT_BYPASS_MASK,
+ WCD934X_HPH_LUT_BYPASS_DISABLE);
+ }
+}
+
+static int wcd934x_config_compander(struct snd_soc_component *comp,
+ int interp_n, int event)
+{
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ int compander;
+ u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+ /* EAR does not have compander */
+ if (!interp_n)
+ return 0;
+
+ compander = interp_n - 1;
+ if (!wcd->comp_enabled[compander])
+ return 0;
+
+ comp_ctl0_reg = WCD934X_CDC_COMPANDER1_CTL0 + (compander * 8);
+ rx_path_cfg0_reg = WCD934X_CDC_RX1_RX_PATH_CFG0 + (compander * 20);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable Compander Clock */
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_CLK_EN_MASK,
+ WCD934X_COMP_CLK_ENABLE);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_SOFT_RST_MASK,
+ WCD934X_COMP_SOFT_RST_ENABLE);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_SOFT_RST_MASK,
+ WCD934X_COMP_SOFT_RST_DISABLE);
+ snd_soc_component_update_bits(comp, rx_path_cfg0_reg,
+ WCD934X_HPH_CMP_EN_MASK,
+ WCD934X_HPH_CMP_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(comp, rx_path_cfg0_reg,
+ WCD934X_HPH_CMP_EN_MASK,
+ WCD934X_HPH_CMP_DISABLE);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_HALT_MASK,
+ WCD934X_COMP_HALT);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_SOFT_RST_MASK,
+ WCD934X_COMP_SOFT_RST_ENABLE);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_SOFT_RST_MASK,
+ WCD934X_COMP_SOFT_RST_DISABLE);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_CLK_EN_MASK, 0x0);
+ snd_soc_component_update_bits(comp, comp_ctl0_reg,
+ WCD934X_COMP_SOFT_RST_MASK, 0x0);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd934x_codec_enable_interp_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ int interp_idx = w->shift;
+ u16 main_reg = WCD934X_CDC_RX0_RX_PATH_CTL + (interp_idx * 20);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Clk enable */
+ snd_soc_component_update_bits(comp, main_reg,
+ WCD934X_RX_CLK_EN_MASK,
+ WCD934X_RX_CLK_ENABLE);
+ wcd934x_codec_hd2_control(comp, interp_idx, event);
+ wcd934x_codec_hphdelay_lutbypass(comp, interp_idx, event);
+ wcd934x_config_compander(comp, interp_idx, event);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd934x_config_compander(comp, interp_idx, event);
+ wcd934x_codec_hphdelay_lutbypass(comp, interp_idx, event);
+ wcd934x_codec_hd2_control(comp, interp_idx, event);
+ /* Clk Disable */
+ snd_soc_component_update_bits(comp, main_reg,
+ WCD934X_RX_CLK_EN_MASK, 0);
+ /* Reset enable and disable */
+ snd_soc_component_update_bits(comp, main_reg,
+ WCD934X_RX_RESET_MASK,
+ WCD934X_RX_RESET_ENABLE);
+ snd_soc_component_update_bits(comp, main_reg,
+ WCD934X_RX_RESET_MASK,
+ WCD934X_RX_RESET_DISABLE);
+ /* Reset rate to 48K*/
+ snd_soc_component_update_bits(comp, main_reg,
+ WCD934X_RX_PCM_RATE_MASK,
+ WCD934X_RX_PCM_RATE_F_48K);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd934x_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ int offset_val = 0;
+ u16 gain_reg, mix_reg;
+ int val = 0;
+
+ gain_reg = WCD934X_CDC_RX0_RX_VOL_MIX_CTL +
+ (w->shift * WCD934X_RX_PATH_CTL_OFFSET);
+ mix_reg = WCD934X_CDC_RX0_RX_PATH_MIX_CTL +
+ (w->shift * WCD934X_RX_PATH_CTL_OFFSET);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Clk enable */
+ snd_soc_component_update_bits(comp, mix_reg,
+ WCD934X_CDC_RX_MIX_CLK_EN_MASK,
+ WCD934X_CDC_RX_MIX_CLK_ENABLE);
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ val = snd_soc_component_read32(comp, gain_reg);
+ val += offset_val;
+ snd_soc_component_write(comp, gain_reg, val);
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ int reg = w->reg;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* B1 GAIN */
+ snd_soc_component_write(comp, reg,
+ snd_soc_component_read32(comp, reg));
+ /* B2 GAIN */
+ reg++;
+ snd_soc_component_write(comp, reg,
+ snd_soc_component_read32(comp, reg));
+ /* B3 GAIN */
+ reg++;
+ snd_soc_component_write(comp, reg,
+ snd_soc_component_read32(comp, reg));
+ /* B4 GAIN */
+ reg++;
+ snd_soc_component_write(comp, reg,
+ snd_soc_component_read32(comp, reg));
+ /* B5 GAIN */
+ reg++;
+ snd_soc_component_write(comp, reg,
+ snd_soc_component_read32(comp, reg));
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int wcd934x_codec_enable_main_path(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ u16 gain_reg;
+
+ gain_reg = WCD934X_CDC_RX0_RX_VOL_CTL + (w->shift *
+ WCD934X_RX_PATH_CTL_OFFSET);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_component_write(comp, gain_reg,
+ snd_soc_component_read32(comp, gain_reg));
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Disable AutoChop timer during power up */
+ snd_soc_component_update_bits(comp,
+ WCD934X_HPH_NEW_INT_HPH_TIMER1,
+ WCD934X_HPH_AUTOCHOP_TIMER_EN_MASK, 0x0);
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_EAR, CLS_H_NORMAL);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_EAR, CLS_H_NORMAL);
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ int hph_mode = wcd->hph_mode;
+ u8 dem_inp;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Read DEM INP Select */
+ dem_inp = snd_soc_component_read32(comp,
+ WCD934X_CDC_RX1_RX_PATH_SEC0) & 0x03;
+
+ if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+ (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+ return -EINVAL;
+ }
+ if (hph_mode != CLS_H_LP)
+ /* Ripple freq control enable */
+ snd_soc_component_update_bits(comp,
+ WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+ WCD934X_SIDO_RIPPLE_FREQ_EN_MASK,
+ WCD934X_SIDO_RIPPLE_FREQ_ENABLE);
+ /* Disable AutoChop timer during power up */
+ snd_soc_component_update_bits(comp,
+ WCD934X_HPH_NEW_INT_HPH_TIMER1,
+ WCD934X_HPH_AUTOCHOP_TIMER_EN_MASK, 0x0);
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHL, hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 1000us required as per HW requirement */
+ usleep_range(1000, 1100);
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHL, hph_mode);
+ if (hph_mode != CLS_H_LP)
+ /* Ripple freq control disable */
+ snd_soc_component_update_bits(comp,
+ WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+ WCD934X_SIDO_RIPPLE_FREQ_EN_MASK, 0x0);
+
+ break;
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ int hph_mode = wcd->hph_mode;
+ u8 dem_inp;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ dem_inp = snd_soc_component_read32(comp,
+ WCD934X_CDC_RX2_RX_PATH_SEC0) & 0x03;
+ if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+ (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+ return -EINVAL;
+ }
+ if (hph_mode != CLS_H_LP)
+ /* Ripple freq control enable */
+ snd_soc_component_update_bits(comp,
+ WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+ WCD934X_SIDO_RIPPLE_FREQ_EN_MASK,
+ WCD934X_SIDO_RIPPLE_FREQ_ENABLE);
+ /* Disable AutoChop timer during power up */
+ snd_soc_component_update_bits(comp,
+ WCD934X_HPH_NEW_INT_HPH_TIMER1,
+ WCD934X_HPH_AUTOCHOP_TIMER_EN_MASK, 0x0);
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHR,
+ hph_mode);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 1000us required as per HW requirement */
+ usleep_range(1000, 1100);
+
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHR, hph_mode);
+ if (hph_mode != CLS_H_LP)
+ /* Ripple freq control disable */
+ snd_soc_component_update_bits(comp,
+ WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+ WCD934X_SIDO_RIPPLE_FREQ_EN_MASK, 0x0);
+ break;
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_lineout_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_LO, CLS_AB);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_LO, CLS_AB);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd934x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 7ms sleep is required after PA is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is needed.
+ */
+ usleep_range(20000, 20100);
+
+ snd_soc_component_update_bits(comp, WCD934X_HPH_L_TEST,
+ WCD934X_HPH_OCP_DET_MASK,
+ WCD934X_HPH_OCP_DET_ENABLE);
+ /* Remove Mute on primary path */
+ snd_soc_component_update_bits(comp, WCD934X_CDC_RX1_RX_PATH_CTL,
+ WCD934X_RX_PATH_PGA_MUTE_EN_MASK,
+ 0);
+ /* Enable GM3 boost */
+ snd_soc_component_update_bits(comp, WCD934X_HPH_CNP_WG_CTL,
+ WCD934X_HPH_GM3_BOOST_EN_MASK,
+ WCD934X_HPH_GM3_BOOST_ENABLE);
+ /* Enable AutoChop timer at the end of power up */
+ snd_soc_component_update_bits(comp,
+ WCD934X_HPH_NEW_INT_HPH_TIMER1,
+ WCD934X_HPH_AUTOCHOP_TIMER_EN_MASK,
+ WCD934X_HPH_AUTOCHOP_TIMER_ENABLE);
+ /* Remove mix path mute */
+ snd_soc_component_update_bits(comp,
+ WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+ WCD934X_CDC_RX_PGA_MUTE_EN_MASK, 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Enable DSD Mute before PA disable */
+ snd_soc_component_update_bits(comp, WCD934X_HPH_L_TEST,
+ WCD934X_HPH_OCP_DET_MASK,
+ WCD934X_HPH_OCP_DET_DISABLE);
+ snd_soc_component_update_bits(comp, WCD934X_CDC_RX1_RX_PATH_CTL,
+ WCD934X_RX_PATH_PGA_MUTE_EN_MASK,
+ WCD934X_RX_PATH_PGA_MUTE_ENABLE);
+ snd_soc_component_update_bits(comp,
+ WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+ WCD934X_RX_PATH_PGA_MUTE_EN_MASK,
+ WCD934X_RX_PATH_PGA_MUTE_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 5ms sleep is required after PA disable. If compander is
+ * disabled, then 20ms delay is needed after PA disable.
+ */
+ usleep_range(20000, 20100);
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 7ms sleep is required after PA is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is needed.
+ */
+ usleep_range(20000, 20100);
+ snd_soc_component_update_bits(comp, WCD934X_HPH_R_TEST,
+ WCD934X_HPH_OCP_DET_MASK,
+ WCD934X_HPH_OCP_DET_ENABLE);
+ /* Remove mute */
+ snd_soc_component_update_bits(comp, WCD934X_CDC_RX2_RX_PATH_CTL,
+ WCD934X_RX_PATH_PGA_MUTE_EN_MASK,
+ 0);
+ /* Enable GM3 boost */
+ snd_soc_component_update_bits(comp, WCD934X_HPH_CNP_WG_CTL,
+ WCD934X_HPH_GM3_BOOST_EN_MASK,
+ WCD934X_HPH_GM3_BOOST_ENABLE);
+ /* Enable AutoChop timer at the end of power up */
+ snd_soc_component_update_bits(comp,
+ WCD934X_HPH_NEW_INT_HPH_TIMER1,
+ WCD934X_HPH_AUTOCHOP_TIMER_EN_MASK,
+ WCD934X_HPH_AUTOCHOP_TIMER_ENABLE);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_component_read32(comp,
+ WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) & 0x10)
+ snd_soc_component_update_bits(comp,
+ WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+ WCD934X_CDC_RX_PGA_MUTE_EN_MASK,
+ WCD934X_CDC_RX_PGA_MUTE_DISABLE);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_component_update_bits(comp, WCD934X_HPH_R_TEST,
+ WCD934X_HPH_OCP_DET_MASK,
+ WCD934X_HPH_OCP_DET_DISABLE);
+ snd_soc_component_update_bits(comp, WCD934X_CDC_RX2_RX_PATH_CTL,
+ WCD934X_RX_PATH_PGA_MUTE_EN_MASK,
+ WCD934X_RX_PATH_PGA_MUTE_ENABLE);
+ snd_soc_component_update_bits(comp,
+ WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+ WCD934X_CDC_RX_PGA_MUTE_EN_MASK,
+ WCD934X_CDC_RX_PGA_MUTE_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 5ms sleep is required after PA disable. If compander is
+ * disabled, then 20ms delay is needed after PA disable.
+ */
+ usleep_range(20000, 20100);
+ break;
+ };
+
+ return 0;
+}
+
+static u32 wcd934x_get_dmic_sample_rate(struct snd_soc_component *comp,
+ unsigned int dmic,
+ struct wcd934x_codec *wcd)
+{
+ u8 tx_stream_fs;
+ u8 adc_mux_index = 0, adc_mux_sel = 0;
+ bool dec_found = false;
+ u16 adc_mux_ctl_reg, tx_fs_reg;
+ u32 dmic_fs;
+
+ while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) {
+ if (adc_mux_index < 4) {
+ adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+ (adc_mux_index * 2);
+ } else if (adc_mux_index < WCD934X_INVALID_ADC_MUX) {
+ adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+ adc_mux_index - 4;
+ } else if (adc_mux_index == WCD934X_INVALID_ADC_MUX) {
+ ++adc_mux_index;
+ continue;
+ }
+ adc_mux_sel = ((snd_soc_component_read32(comp, adc_mux_ctl_reg)
+ & 0xF8) >> 3) - 1;
+
+ if (adc_mux_sel == dmic) {
+ dec_found = true;
+ break;
+ }
+
+ ++adc_mux_index;
+ }
+
+ if (dec_found && adc_mux_index <= 8) {
+ tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index);
+ tx_stream_fs = snd_soc_component_read32(comp, tx_fs_reg) & 0x0F;
+ if (tx_stream_fs <= 4) {
+ if (wcd->dmic_sample_rate <=
+ WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ)
+ dmic_fs = wcd->dmic_sample_rate;
+ else
+ dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ;
+ } else
+ dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+ } else {
+ dmic_fs = wcd->dmic_sample_rate;
+ }
+
+ return dmic_fs;
+}
+
+static u8 wcd934x_get_dmic_clk_val(struct snd_soc_component *comp,
+ u32 mclk_rate, u32 dmic_clk_rate)
+{
+ u32 div_factor;
+ u8 dmic_ctl_val;
+
+ /* Default value to return in case of error */
+ if (mclk_rate == WCD934X_MCLK_CLK_9P6MHZ)
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2;
+ else
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3;
+
+ if (dmic_clk_rate == 0) {
+ dev_err(comp->dev,
+ "%s: dmic_sample_rate cannot be 0\n",
+ __func__);
+ goto done;
+ }
+
+ div_factor = mclk_rate / dmic_clk_rate;
+ switch (div_factor) {
+ case 2:
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2;
+ break;
+ case 3:
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3;
+ break;
+ case 4:
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_4;
+ break;
+ case 6:
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_6;
+ break;
+ case 8:
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_8;
+ break;
+ case 16:
+ dmic_ctl_val = WCD934X_DMIC_CLK_DIV_16;
+ break;
+ default:
+ dev_err(comp->dev,
+ "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
+ __func__, div_factor, mclk_rate, dmic_clk_rate);
+ break;
+ }
+
+done:
+ return dmic_ctl_val;
+}
+
+static int wcd934x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ u8 dmic_clk_en = 0x01;
+ u16 dmic_clk_reg;
+ s32 *dmic_clk_cnt;
+ u8 dmic_rate_val, dmic_rate_shift = 1;
+ unsigned int dmic;
+ u32 dmic_sample_rate;
+ int ret;
+ char *wname;
+
+ wname = strpbrk(w->name, "012345");
+ if (!wname) {
+ dev_err(comp->dev, "%s: widget not found\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = kstrtouint(wname, 10, &dmic);
+ if (ret < 0) {
+ dev_err(comp->dev, "%s: Invalid DMIC line on the codec\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (dmic) {
+ case 0:
+ case 1:
+ dmic_clk_cnt = &wcd->dmic_0_1_clk_cnt;
+ dmic_clk_reg = WCD934X_CPE_SS_DMIC0_CTL;
+ break;
+ case 2:
+ case 3:
+ dmic_clk_cnt = &wcd->dmic_2_3_clk_cnt;
+ dmic_clk_reg = WCD934X_CPE_SS_DMIC1_CTL;
+ break;
+ case 4:
+ case 5:
+ dmic_clk_cnt = &wcd->dmic_4_5_clk_cnt;
+ dmic_clk_reg = WCD934X_CPE_SS_DMIC2_CTL;
+ break;
+ default:
+ dev_err(comp->dev, "%s: Invalid DMIC Selection\n",
+ __func__);
+ return -EINVAL;
+ };
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ dmic_sample_rate = wcd934x_get_dmic_sample_rate(comp, dmic,
+ wcd);
+ dmic_rate_val = wcd934x_get_dmic_clk_val(comp, wcd->rate,
+ dmic_sample_rate);
+ (*dmic_clk_cnt)++;
+ if (*dmic_clk_cnt == 1) {
+ dmic_rate_val = dmic_rate_val << dmic_rate_shift;
+ snd_soc_component_update_bits(comp, dmic_clk_reg,
+ WCD934X_DMIC_RATE_MASK,
+ dmic_rate_val);
+ snd_soc_component_update_bits(comp, dmic_clk_reg,
+ dmic_clk_en, dmic_clk_en);
+ }
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ (*dmic_clk_cnt)--;
+ if (*dmic_clk_cnt == 0)
+ snd_soc_component_update_bits(comp, dmic_clk_reg,
+ dmic_clk_en, 0);
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd934x_codec_find_amic_input(struct snd_soc_component *comp,
+ int adc_mux_n)
+{
+ u16 mask, shift, adc_mux_in_reg;
+ u16 amic_mux_sel_reg;
+ bool is_amic;
+
+ if (adc_mux_n < 0 || adc_mux_n > WCD934X_MAX_VALID_ADC_MUX ||
+ adc_mux_n == WCD934X_INVALID_ADC_MUX)
+ return 0;
+
+ if (adc_mux_n < 3) {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+ adc_mux_n;
+ mask = 0x03;
+ shift = 0;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+ 2 * adc_mux_n;
+ } else if (adc_mux_n < 4) {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1;
+ mask = 0x03;
+ shift = 0;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+ 2 * adc_mux_n;
+ } else if (adc_mux_n < 7) {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+ (adc_mux_n - 4);
+ mask = 0x0C;
+ shift = 2;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+ adc_mux_n - 4;
+ } else if (adc_mux_n < 8) {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1;
+ mask = 0x0C;
+ shift = 2;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+ adc_mux_n - 4;
+ } else if (adc_mux_n < 12) {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+ ((adc_mux_n == 8) ? (adc_mux_n - 8) :
+ (adc_mux_n - 9));
+ mask = 0x30;
+ shift = 4;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+ adc_mux_n - 4;
+ } else if (adc_mux_n < 13) {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1;
+ mask = 0x30;
+ shift = 4;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+ adc_mux_n - 4;
+ } else {
+ adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1;
+ mask = 0xC0;
+ shift = 6;
+ amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+ adc_mux_n - 4;
+ }
+
+ is_amic = (((snd_soc_component_read32(comp, adc_mux_in_reg)
+ & mask) >> shift) == 1);
+ if (!is_amic)
+ return 0;
+
+ return snd_soc_component_read32(comp, amic_mux_sel_reg) & 0x07;
+}
+
+static u16 wcd934x_codec_get_amic_pwlvl_reg(struct snd_soc_component *comp,
+ int amic)
+{
+ u16 pwr_level_reg = 0;
+
+ switch (amic) {
+ case 1:
+ case 2:
+ pwr_level_reg = WCD934X_ANA_AMIC1;
+ break;
+
+ case 3:
+ case 4:
+ pwr_level_reg = WCD934X_ANA_AMIC3;
+ break;
+ default:
+ break;
+ }
+
+ return pwr_level_reg;
+}
+
+static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ unsigned int decimator;
+ char *dec_adc_mux_name = NULL;
+ char *widget_name = NULL;
+ char *wname;
+ int ret = 0, amic_n;
+ u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
+ u16 tx_gain_ctl_reg;
+ char *dec;
+ u8 hpf_coff_freq;
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+
+ wname = widget_name;
+ dec_adc_mux_name = strsep(&widget_name, " ");
+ if (!dec_adc_mux_name) {
+ dev_err(comp->dev, "%s: Invalid decimator = %s\n",
+ __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ dec_adc_mux_name = widget_name;
+
+ dec = strpbrk(dec_adc_mux_name, "012345678");
+ if (!dec) {
+ dev_err(comp->dev, "%s: decimator index not found\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(dec, 10, &decimator);
+ if (ret < 0) {
+ dev_err(comp->dev, "%s: Invalid decimator = %s\n",
+ __func__, wname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator;
+ hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 + 16 * decimator;
+ dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * decimator;
+ tx_gain_ctl_reg = WCD934X_CDC_TX0_TX_VOL_CTL + 16 * decimator;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ amic_n = wcd934x_codec_find_amic_input(comp, decimator);
+ if (amic_n)
+ pwr_level_reg = wcd934x_codec_get_amic_pwlvl_reg(comp,
+ amic_n);
+
+ if (!pwr_level_reg)
+ break;
+
+ switch ((snd_soc_component_read32(comp, pwr_level_reg) &
+ WCD934X_AMIC_PWR_LVL_MASK) >>
+ WCD934X_AMIC_PWR_LVL_SHIFT) {
+ case WCD934X_AMIC_PWR_LEVEL_LP:
+ snd_soc_component_update_bits(comp, dec_cfg_reg,
+ WCD934X_DEC_PWR_LVL_MASK,
+ WCD934X_DEC_PWR_LVL_LP);
+ break;
+ case WCD934X_AMIC_PWR_LEVEL_HP:
+ snd_soc_component_update_bits(comp, dec_cfg_reg,
+ WCD934X_DEC_PWR_LVL_MASK,
+ WCD934X_DEC_PWR_LVL_HP);
+ break;
+ case WCD934X_AMIC_PWR_LEVEL_DEFAULT:
+ case WCD934X_AMIC_PWR_LEVEL_HYBRID:
+ default:
+ snd_soc_component_update_bits(comp, dec_cfg_reg,
+ WCD934X_DEC_PWR_LVL_MASK,
+ WCD934X_DEC_PWR_LVL_DF);
+ break;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) &
+ TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+ if (hpf_coff_freq != CF_MIN_3DB_150HZ) {
+ snd_soc_component_update_bits(comp, dec_cfg_reg,
+ TX_HPF_CUT_OFF_FREQ_MASK,
+ CF_MIN_3DB_150HZ << 5);
+ snd_soc_component_update_bits(comp, hpf_gate_reg,
+ WCD934X_HPH_CUTOFF_FREQ_CHANGE_REQ_MASK,
+ WCD934X_HPH_CUTOFF_FREQ_CHANGE_REQ);
+ /*
+ * Minimum 1 clk cycle delay is required as per
+ * HW spec.
+ */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(comp, hpf_gate_reg,
+ WCD934X_HPH_CUTOFF_FREQ_CHANGE_REQ_MASK,
+ 0);
+ }
+ /* apply gain after decimator is enabled */
+ snd_soc_component_write(comp, tx_gain_ctl_reg,
+ snd_soc_component_read32(comp,
+ tx_gain_ctl_reg));
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) &
+ TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+
+ if (hpf_coff_freq != CF_MIN_3DB_150HZ) {
+ snd_soc_component_update_bits(comp, dec_cfg_reg,
+ TX_HPF_CUT_OFF_FREQ_MASK,
+ hpf_coff_freq << 5);
+ snd_soc_component_update_bits(comp, hpf_gate_reg,
+ WCD934X_HPH_CUTOFF_FREQ_CHANGE_REQ_MASK,
+ WCD934X_HPH_CUTOFF_FREQ_CHANGE_REQ);
+ /*
+ * Minimum 1 clk cycle delay is required as per
+ * HW spec.
+ */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(comp, hpf_gate_reg,
+ WCD934X_HPH_CUTOFF_FREQ_CHANGE_REQ_MASK,
+ 0);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+ 0x10, 0x00);
+ snd_soc_component_update_bits(comp, dec_cfg_reg,
+ WCD934X_DEC_PWR_LVL_MASK,
+ WCD934X_DEC_PWR_LVL_DF);
+ break;
+ };
+out:
+ kfree(wname);
+ return ret;
+}
+
+static void wcd934x_codec_set_tx_hold(struct snd_soc_component *comp,
+ u16 amic_reg, bool set)
+{
+ u8 mask = 0x20;
+ u8 val;
+
+ if (amic_reg == WCD934X_ANA_AMIC1 ||
+ amic_reg == WCD934X_ANA_AMIC3)
+ mask = 0x40;
+
+ val = set ? mask : 0x00;
+
+ switch (amic_reg) {
+ case WCD934X_ANA_AMIC1:
+ case WCD934X_ANA_AMIC2:
+ snd_soc_component_update_bits(comp, WCD934X_ANA_AMIC2,
+ mask, val);
+ break;
+ case WCD934X_ANA_AMIC3:
+ case WCD934X_ANA_AMIC4:
+ snd_soc_component_update_bits(comp, WCD934X_ANA_AMIC4,
+ mask, val);
+ break;
+ default:
+ break;
+ }
+}
+
+static int wcd934x_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd934x_codec_set_tx_hold(comp, w->reg, true);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wcd934x_dapm_widgets[] = {
+ /* Analog Outputs */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+ SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+ SND_SOC_DAPM_OUTPUT("ANC EAR"),
+ SND_SOC_DAPM_OUTPUT("ANC HPHL"),
+ SND_SOC_DAPM_OUTPUT("ANC HPHR"),
+ SND_SOC_DAPM_OUTPUT("WDMA3_OUT"),
+ SND_SOC_DAPM_OUTPUT("MAD_CPE_OUT1"),
+ SND_SOC_DAPM_OUTPUT("MAD_CPE_OUT2"),
+ SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+ AIF1_PB, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+ AIF2_PB, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+ AIF3_PB, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM,
+ AIF4_PB, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, WCD934X_RX0, 0,
+ &slim_rx_mux[WCD934X_RX0]),
+ SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, WCD934X_RX1, 0,
+ &slim_rx_mux[WCD934X_RX1]),
+ SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, WCD934X_RX2, 0,
+ &slim_rx_mux[WCD934X_RX2]),
+ SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, WCD934X_RX3, 0,
+ &slim_rx_mux[WCD934X_RX3]),
+ SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, WCD934X_RX4, 0,
+ &slim_rx_mux[WCD934X_RX4]),
+ SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, WCD934X_RX5, 0,
+ &slim_rx_mux[WCD934X_RX5]),
+ SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, WCD934X_RX6, 0,
+ &slim_rx_mux[WCD934X_RX6]),
+ SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, WCD934X_RX7, 0,
+ &slim_rx_mux[WCD934X_RX7]),
+
+ SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_EAR, 0,
+ &rx_int0_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0,
+ &rx_int1_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0,
+ &rx_int2_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", SND_SOC_NOPM, INTERP_LO1, 0,
+ &rx_int3_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", SND_SOC_NOPM, INTERP_LO2, 0,
+ &rx_int4_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", SND_SOC_NOPM, INTERP_SPKR1, 0,
+ &rx_int7_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", SND_SOC_NOPM, INTERP_SPKR2, 0,
+ &rx_int8_2_mux, wcd934x_codec_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int0_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int0_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int0_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int1_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int1_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int1_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int2_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int2_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int2_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int3_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int3_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int3_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int4_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int4_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int4_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int7_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int7_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int7_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int8_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int8_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int8_1_mix_inp2_mux),
+ SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0,
+ rx_int1_asrc_switch,
+ ARRAY_SIZE(rx_int1_asrc_switch)),
+ SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0,
+ rx_int2_asrc_switch,
+ ARRAY_SIZE(rx_int2_asrc_switch)),
+ SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0,
+ rx_int3_asrc_switch,
+ ARRAY_SIZE(rx_int3_asrc_switch)),
+ SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0,
+ rx_int4_asrc_switch,
+ ARRAY_SIZE(rx_int4_asrc_switch)),
+ SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1 MIX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT2 MIX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 MIX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 MIX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0,
+ NULL, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("RX INT8 CHAIN", SND_SOC_NOPM, 0, 0,
+ NULL, 0, NULL, 0),
+ SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", WCD934X_CDC_RX0_RX_PATH_CFG0, 4,
+ 0, &rx_int0_mix2_inp_mux, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", WCD934X_CDC_RX1_RX_PATH_CFG0, 4,
+ 0, &rx_int1_mix2_inp_mux, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", WCD934X_CDC_RX2_RX_PATH_CFG0, 4,
+ 0, &rx_int2_mix2_inp_mux, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT3 MIX2 INP", WCD934X_CDC_RX3_RX_PATH_CFG0, 4,
+ 0, &rx_int3_mix2_inp_mux, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT4 MIX2 INP", WCD934X_CDC_RX4_RX_PATH_CFG0, 4,
+ 0, &rx_int4_mix2_inp_mux, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT7 MIX2 INP", WCD934X_CDC_RX7_RX_PATH_CFG0, 4,
+ 0, &rx_int7_mix2_inp_mux, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("IIR0 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp0_mux),
+ SND_SOC_DAPM_MUX("IIR0 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp1_mux),
+ SND_SOC_DAPM_MUX("IIR0 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp2_mux),
+ SND_SOC_DAPM_MUX("IIR0 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp3_mux),
+ SND_SOC_DAPM_MUX("IIR1 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp0_mux),
+ SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_MUX("IIR1 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp2_mux),
+ SND_SOC_DAPM_MUX("IIR1 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp3_mux),
+
+ SND_SOC_DAPM_PGA_E("IIR0", WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL,
+ 0, 0, NULL, 0, wcd934x_codec_set_iir_gain,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("IIR1", WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL,
+ 1, 0, NULL, 0, wcd934x_codec_set_iir_gain,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER("SRC0", WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SRC1", WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int0_dem_inp_mux),
+ SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int1_dem_inp_mux),
+ SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int2_dem_inp_mux),
+
+ SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_EAR, 0,
+ &rx_int0_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0,
+ &rx_int1_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0,
+ &rx_int2_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT3_1 INTERP", SND_SOC_NOPM, INTERP_LO1, 0,
+ &rx_int3_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT4_1 INTERP", SND_SOC_NOPM, INTERP_LO2, 0,
+ &rx_int4_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT7_1 INTERP", SND_SOC_NOPM, INTERP_SPKR1, 0,
+ &rx_int7_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT8_1 INTERP", SND_SOC_NOPM, INTERP_SPKR2, 0,
+ &rx_int8_1_interp_mux,
+ wcd934x_codec_enable_main_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("RX INT0_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int0_2_interp_mux),
+ SND_SOC_DAPM_MUX("RX INT1_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int1_2_interp_mux),
+ SND_SOC_DAPM_MUX("RX INT2_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int2_2_interp_mux),
+ SND_SOC_DAPM_MUX("RX INT3_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int3_2_interp_mux),
+ SND_SOC_DAPM_MUX("RX INT4_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int4_2_interp_mux),
+ SND_SOC_DAPM_MUX("RX INT7_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int7_2_interp_mux),
+ SND_SOC_DAPM_MUX("RX INT8_2 INTERP", SND_SOC_NOPM, 0, 0,
+ &rx_int8_2_interp_mux),
+ SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd934x_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD934X_ANA_HPH,
+ 5, 0, wcd934x_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD934X_ANA_HPH,
+ 4, 0, wcd934x_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd934x_codec_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd934x_codec_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("HPHL PA", WCD934X_ANA_HPH, 7, 0, NULL, 0,
+ wcd934x_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PA", WCD934X_ANA_HPH, 6, 0, NULL, 0,
+ wcd934x_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0,
+ NULL, 0),
+ SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX_BIAS", WCD934X_ANA_RX_SUPPLIES, 0, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("SBOOST0", WCD934X_CDC_RX7_RX_PATH_CFG1,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SBOOST0_CLK", WCD934X_CDC_BOOST0_BOOST_PATH_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SBOOST1", WCD934X_CDC_RX8_RX_PATH_CFG1,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SBOOST1_CLK", WCD934X_CDC_BOOST1_BOOST_PATH_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("INT0_CLK", SND_SOC_NOPM, INTERP_EAR, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT1_CLK", SND_SOC_NOPM, INTERP_HPHL, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT2_CLK", SND_SOC_NOPM, INTERP_HPHR, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT3_CLK", SND_SOC_NOPM, INTERP_LO1, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT4_CLK", SND_SOC_NOPM, INTERP_LO2, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT7_CLK", SND_SOC_NOPM, INTERP_SPKR1, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("INT8_CLK", SND_SOC_NOPM, INTERP_SPKR2, 0,
+ wcd934x_codec_enable_interp_clk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("DSMDEM0_CLK", WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DSMDEM1_CLK", WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DSMDEM2_CLK", WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DSMDEM3_CLK", WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DSMDEM4_CLK", WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DSMDEM7_CLK", WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DSMDEM8_CLK", WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_mclk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* TX */
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("AMIC4"),
+ SND_SOC_DAPM_INPUT("AMIC5"),
+ SND_SOC_DAPM_INPUT("DMIC0 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC3 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC4 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC5 Pin"),
+
+ SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+ AIF1_CAP, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
+ AIF2_CAP, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
+ AIF3_CAP, 0, wcd934x_codec_enable_slim,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("SLIM TX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX8", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX9", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX10", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX11", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM TX13", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Mic Inputs */
+ SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+ wcd934x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_dmic_mux0),
+ SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_dmic_mux1),
+ SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_dmic_mux2),
+ SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_dmic_mux3),
+ SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_dmic_mux4),
+ SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_dmic_mux5),
+ SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_dmic_mux6),
+ SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_dmic_mux7),
+ SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0, &tx_dmic_mux8),
+ SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_amic_mux0),
+ SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_amic_mux1),
+ SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_amic_mux2),
+ SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_amic_mux3),
+ SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_amic_mux4),
+ SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_amic_mux5),
+ SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_amic_mux6),
+ SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_amic_mux7),
+ SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0, &tx_amic_mux8),
+ SND_SOC_DAPM_MUX_E("ADC MUX0", WCD934X_CDC_TX0_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux0_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX1", WCD934X_CDC_TX1_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux1_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX2", WCD934X_CDC_TX2_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux2_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX3", WCD934X_CDC_TX3_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux3_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX4", WCD934X_CDC_TX4_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux4_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX5", WCD934X_CDC_TX5_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux5_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX6", WCD934X_CDC_TX6_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux6_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX7", WCD934X_CDC_TX7_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux7_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("ADC MUX8", WCD934X_CDC_TX8_TX_PATH_CTL, 5, 0,
+ &tx_adc_mux8_mux, wcd934x_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD934X_ANA_AMIC1, 7, 0,
+ wcd934x_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD934X_ANA_AMIC2, 7, 0,
+ wcd934x_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD934X_ANA_AMIC3, 7, 0,
+ wcd934x_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD934X_ANA_AMIC4, 7, 0,
+ wcd934x_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS1", WCD934X_ANA_MICB1, 6, 0, NULL,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS2", WCD934X_ANA_MICB2, 6, 0, NULL,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS3", WCD934X_ANA_MICB3, 6, 0, NULL,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS4", WCD934X_ANA_MICB4, 6, 0, NULL,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("AMIC4_5 SEL", SND_SOC_NOPM, 0, 0, &tx_amic4_5),
+ SND_SOC_DAPM_MUX("CDC_IF TX0 MUX", SND_SOC_NOPM, WCD934X_TX0, 0,
+ &cdc_if_tx0_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX1 MUX", SND_SOC_NOPM, WCD934X_TX1, 0,
+ &cdc_if_tx1_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX2 MUX", SND_SOC_NOPM, WCD934X_TX2, 0,
+ &cdc_if_tx2_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX3 MUX", SND_SOC_NOPM, WCD934X_TX3, 0,
+ &cdc_if_tx3_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX4 MUX", SND_SOC_NOPM, WCD934X_TX4, 0,
+ &cdc_if_tx4_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX5 MUX", SND_SOC_NOPM, WCD934X_TX5, 0,
+ &cdc_if_tx5_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX6 MUX", SND_SOC_NOPM, WCD934X_TX6, 0,
+ &cdc_if_tx6_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX7 MUX", SND_SOC_NOPM, WCD934X_TX7, 0,
+ &cdc_if_tx7_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX8 MUX", SND_SOC_NOPM, WCD934X_TX8, 0,
+ &cdc_if_tx8_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX9 MUX", SND_SOC_NOPM, WCD934X_TX9, 0,
+ &cdc_if_tx9_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX10 MUX", SND_SOC_NOPM, WCD934X_TX10, 0,
+ &cdc_if_tx10_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX11 MUX", SND_SOC_NOPM, WCD934X_TX11, 0,
+ &cdc_if_tx11_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX11 INP1 MUX", SND_SOC_NOPM, WCD934X_TX11, 0,
+ &cdc_if_tx11_inp1_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX13 MUX", SND_SOC_NOPM, WCD934X_TX13, 0,
+ &cdc_if_tx13_mux),
+ SND_SOC_DAPM_MUX("CDC_IF TX13 INP1 MUX", SND_SOC_NOPM, WCD934X_TX13, 0,
+ &cdc_if_tx13_inp1_mux),
+ SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+ aif1_slim_cap_mixer,
+ ARRAY_SIZE(aif1_slim_cap_mixer)),
+ SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+ aif2_slim_cap_mixer,
+ ARRAY_SIZE(aif2_slim_cap_mixer)),
+ SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+ aif3_slim_cap_mixer,
+ ARRAY_SIZE(aif3_slim_cap_mixer)),
+};
+
+static const struct snd_soc_dapm_route wcd934x_audio_map[] = {
+ /* RX0-RX7 */
+ WCD934X_SLIM_RX_AIF_PATH(0),
+ WCD934X_SLIM_RX_AIF_PATH(1),
+ WCD934X_SLIM_RX_AIF_PATH(2),
+ WCD934X_SLIM_RX_AIF_PATH(3),
+ WCD934X_SLIM_RX_AIF_PATH(4),
+ WCD934X_SLIM_RX_AIF_PATH(5),
+ WCD934X_SLIM_RX_AIF_PATH(6),
+ WCD934X_SLIM_RX_AIF_PATH(7),
+
+ /* RX0 Ear out */
+ WCD934X_INTERPOLATOR_PATH(0),
+ WCD934X_INTERPOLATOR_MIX2(0),
+ {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"},
+ {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"},
+ {"RX INT0 DAC", NULL, "RX_BIAS"},
+ {"EAR PA", NULL, "RX INT0 DAC"},
+ {"EAR", NULL, "EAR PA"},
+
+ /* RX1 Headphone left */
+ WCD934X_INTERPOLATOR_PATH(1),
+ WCD934X_INTERPOLATOR_MIX2(1),
+ {"RX INT1 MIX3", NULL, "RX INT1 MIX2"},
+ {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX3"},
+ {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"},
+ {"RX INT1 DAC", NULL, "RX_BIAS"},
+ {"HPHL PA", NULL, "RX INT1 DAC"},
+ {"HPHL", NULL, "HPHL PA"},
+
+ /* RX2 Headphone right */
+ WCD934X_INTERPOLATOR_PATH(2),
+ WCD934X_INTERPOLATOR_MIX2(2),
+ {"RX INT2 MIX3", NULL, "RX INT2 MIX2"},
+ {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 MIX3"},
+ {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"},
+ {"RX INT2 DAC", NULL, "RX_BIAS"},
+ {"HPHR PA", NULL, "RX INT2 DAC"},
+ {"HPHR", NULL, "HPHR PA"},
+
+ /* RX3 HIFi LineOut1 */
+ WCD934X_INTERPOLATOR_PATH(3),
+ WCD934X_INTERPOLATOR_MIX2(3),
+ {"RX INT3 MIX3", NULL, "RX INT3 MIX2"},
+ {"RX INT3 DAC", NULL, "RX INT3 MIX3"},
+ {"RX INT3 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT1 PA", NULL, "RX INT3 DAC"},
+ {"LINEOUT1", NULL, "LINEOUT1 PA"},
+
+ /* RX4 HIFi LineOut2 */
+ WCD934X_INTERPOLATOR_PATH(4),
+ WCD934X_INTERPOLATOR_MIX2(4),
+ {"RX INT4 MIX3", NULL, "RX INT4 MIX2"},
+ {"RX INT4 DAC", NULL, "RX INT4 MIX3"},
+ {"RX INT4 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT2 PA", NULL, "RX INT4 DAC"},
+ {"LINEOUT2", NULL, "LINEOUT2 PA"},
+
+ /* RX7 Speaker Left Out PA */
+ WCD934X_INTERPOLATOR_PATH(7),
+ WCD934X_INTERPOLATOR_MIX2(7),
+ {"RX INT7 CHAIN", NULL, "RX INT7 MIX2"},
+ {"RX INT7 CHAIN", NULL, "RX_BIAS"},
+ {"RX INT7 CHAIN", NULL, "SBOOST0"},
+ {"RX INT7 CHAIN", NULL, "SBOOST0_CLK"},
+ {"SPK1 OUT", NULL, "RX INT7 CHAIN"},
+
+ /* RX8 Speaker Right Out PA */
+ WCD934X_INTERPOLATOR_PATH(8),
+ {"RX INT8 CHAIN", NULL, "RX INT8 SEC MIX"},
+ {"RX INT8 CHAIN", NULL, "RX_BIAS"},
+ {"RX INT8 CHAIN", NULL, "SBOOST1"},
+ {"RX INT8 CHAIN", NULL, "SBOOST1_CLK"},
+ {"SPK2 OUT", NULL, "RX INT8 CHAIN"},
+
+ /* Tx */
+ {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+ {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+ {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+
+ WCD934X_SLIM_TX_AIF_PATH(0),
+ WCD934X_SLIM_TX_AIF_PATH(1),
+ WCD934X_SLIM_TX_AIF_PATH(2),
+ WCD934X_SLIM_TX_AIF_PATH(3),
+ WCD934X_SLIM_TX_AIF_PATH(4),
+ WCD934X_SLIM_TX_AIF_PATH(5),
+ WCD934X_SLIM_TX_AIF_PATH(6),
+ WCD934X_SLIM_TX_AIF_PATH(7),
+ WCD934X_SLIM_TX_AIF_PATH(8),
+
+ WCD934X_ADC_MUX(0),
+ WCD934X_ADC_MUX(1),
+ WCD934X_ADC_MUX(2),
+ WCD934X_ADC_MUX(3),
+ WCD934X_ADC_MUX(4),
+ WCD934X_ADC_MUX(5),
+ WCD934X_ADC_MUX(6),
+ WCD934X_ADC_MUX(7),
+ WCD934X_ADC_MUX(8),
+
+ {"CDC_IF TX0 MUX", "DEC0", "ADC MUX0"},
+ {"CDC_IF TX1 MUX", "DEC1", "ADC MUX1"},
+ {"CDC_IF TX2 MUX", "DEC2", "ADC MUX2"},
+ {"CDC_IF TX3 MUX", "DEC3", "ADC MUX3"},
+ {"CDC_IF TX4 MUX", "DEC4", "ADC MUX4"},
+ {"CDC_IF TX5 MUX", "DEC5", "ADC MUX5"},
+ {"CDC_IF TX6 MUX", "DEC6", "ADC MUX6"},
+ {"CDC_IF TX7 MUX", "DEC7", "ADC MUX7"},
+ {"CDC_IF TX8 MUX", "DEC8", "ADC MUX8"},
+
+ {"AMIC4_5 SEL", "AMIC4", "AMIC4"},
+ {"AMIC4_5 SEL", "AMIC5", "AMIC5"},
+
+ { "DMIC0", NULL, "DMIC0 Pin" },
+ { "DMIC1", NULL, "DMIC1 Pin" },
+ { "DMIC2", NULL, "DMIC2 Pin" },
+ { "DMIC3", NULL, "DMIC3 Pin" },
+ { "DMIC4", NULL, "DMIC4 Pin" },
+ { "DMIC5", NULL, "DMIC5 Pin" },
+
+ {"ADC1", NULL, "AMIC1"},
+ {"ADC2", NULL, "AMIC2"},
+ {"ADC3", NULL, "AMIC3"},
+ {"ADC4", NULL, "AMIC4_5 SEL"},
+
+ WCD934X_IIR_INP_MUX(0),
+ WCD934X_IIR_INP_MUX(1),
+
+ {"SRC0", NULL, "IIR0"},
+ {"SRC1", NULL, "IIR1"},
+};
+
+static const struct snd_soc_component_driver wcd934x_component_drv = {
+ .probe = wcd934x_comp_probe,
+ .remove = wcd934x_comp_remove,
+ .set_sysclk = wcd934x_comp_set_sysclk,
+ .controls = wcd934x_snd_controls,
+ .num_controls = ARRAY_SIZE(wcd934x_snd_controls),
+ .dapm_widgets = wcd934x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wcd934x_dapm_widgets),
+ .dapm_routes = wcd934x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wcd934x_audio_map),
+};
+
+static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
+{
+ struct device *dev = &wcd->sdev->dev;
+ struct device_node *ifc_dev_np;
+
+ ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0);
+ if (!ifc_dev_np) {
+ dev_err(dev, "No Interface device found\n");
+ return -EINVAL;
+ }
+
+ wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np);
+ if (!wcd->sidev) {
+ dev_err(dev, "Unable to get SLIM Interface device\n");
+ return -EINVAL;
+ }
+
+ slim_get_logical_addr(wcd->sidev);
+ wcd->if_regmap = regmap_init_slimbus(wcd->sidev,
+ &wcd934x_ifc_regmap_config);
+ if (IS_ERR(wcd->if_regmap)) {
+ dev_err(dev, "Failed to allocate ifc register map\n");
+ return PTR_ERR(wcd->if_regmap);
+ }
+
+ of_property_read_u32(dev->parent->of_node, "qcom,dmic-sample-rate",
+ &wcd->dmic_sample_rate);
+
+ return 0;
+}
+
+static int wcd934x_codec_probe(struct platform_device *pdev)
+{
+ struct wcd934x_ddata *data = dev_get_drvdata(pdev->dev.parent);
+ struct wcd934x_codec *wcd;
+ struct device *dev = &pdev->dev;
+ int ret, irq;
+
+ wcd = devm_kzalloc(&pdev->dev, sizeof(*wcd), GFP_KERNEL);
+ if (!wcd)
+ return -ENOMEM;
+
+ wcd->dev = dev;
+ wcd->regmap = data->regmap;
+ wcd->extclk = data->extclk;
+ wcd->sdev = to_slim_device(data->dev);
+ mutex_init(&wcd->sysclk_mutex);
+
+ ret = wcd934x_codec_parse_data(wcd);
+ if (ret) {
+ dev_err(wcd->dev, "Failed to get SLIM IRQ\n");
+ return ret;
+ }
+
+ /* set default rate 9P6MHz */
+ regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ WCD934X_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+ WCD934X_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ);
+ memcpy(wcd->rx_chs, wcd934x_rx_chs, sizeof(wcd934x_rx_chs));
+ memcpy(wcd->tx_chs, wcd934x_tx_chs, sizeof(wcd934x_tx_chs));
+
+ irq = regmap_irq_get_virq(data->irq_data, WCD934X_IRQ_SLIMBUS);
+ if (irq < 0) {
+ dev_err(wcd->dev, "Failed to get SLIM IRQ\n");
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ wcd934x_slim_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "slim", wcd);
+ if (ret) {
+ dev_err(dev, "Failed to request slimbus irq\n");
+ return ret;
+ }
+
+ wcd934x_register_mclk_output(wcd);
+ platform_set_drvdata(pdev, wcd);
+
+ return devm_snd_soc_register_component(dev, &wcd934x_component_drv,
+ wcd934x_slim_dais,
+ ARRAY_SIZE(wcd934x_slim_dais));
+}
+
+static const struct platform_device_id wcd934x_driver_id[] = {
+ {
+ .name = "wcd934x-codec",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, wcd934x_driver_id);
+
+static struct platform_driver wcd934x_codec_driver = {
+ .probe = &wcd934x_codec_probe,
+ .id_table = wcd934x_driver_id,
+ .driver = {
+ .name = "wcd934x-codec",
+ }
+};
+
+MODULE_ALIAS("platform:wcd934x-codec");
+module_platform_driver(wcd934x_codec_driver);
+MODULE_DESCRIPTION("WCD934x codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 7d7ea15d73e0..5ffbaddd6e49 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1806,6 +1806,12 @@ static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
switch (clk_id) {
case WM8904_CLK_AUTO:
+ /* We don't have any rate constraints, so just ignore the
+ * request to disable constraining.
+ */
+ if (!freq)
+ return 0;
+
mclk_freq = clk_get_rate(priv->mclk);
/* enable FLL if a different sysclk is desired */
if (mclk_freq != freq) {
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 3e5c69fbc33a..d9d59f45833f 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2788,7 +2788,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
if (target % Fref == 0) {
fll_div->theta = 0;
- fll_div->lambda = 0;
+ fll_div->lambda = 1;
} else {
gcd_fll = gcd(target, fratio * Fref);
@@ -2858,7 +2858,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
return -EINVAL;
}
- if (fll_div.theta || fll_div.lambda)
+ if (fll_div.theta)
fll1 |= WM8962_FLL_FRAC;
/* Stop the FLL while we reconfigure */
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
new file mode 100644
index 000000000000..b59f1d0e7f84
--- /dev/null
+++ b/sound/soc/codecs/wsa881x.c
@@ -0,0 +1,1185 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2017, The Linux Foundation.
+// Copyright (c) 2019, Linaro Limited
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define WSA881X_DIGITAL_BASE 0x3000
+#define WSA881X_ANALOG_BASE 0x3100
+
+/* Digital register address space */
+#define WSA881X_CHIP_ID0 (WSA881X_DIGITAL_BASE + 0x0000)
+#define WSA881X_CHIP_ID1 (WSA881X_DIGITAL_BASE + 0x0001)
+#define WSA881X_CHIP_ID2 (WSA881X_DIGITAL_BASE + 0x0002)
+#define WSA881X_CHIP_ID3 (WSA881X_DIGITAL_BASE + 0x0003)
+#define WSA881X_BUS_ID (WSA881X_DIGITAL_BASE + 0x0004)
+#define WSA881X_CDC_RST_CTL (WSA881X_DIGITAL_BASE + 0x0005)
+#define WSA881X_CDC_TOP_CLK_CTL (WSA881X_DIGITAL_BASE + 0x0006)
+#define WSA881X_CDC_ANA_CLK_CTL (WSA881X_DIGITAL_BASE + 0x0007)
+#define WSA881X_CDC_DIG_CLK_CTL (WSA881X_DIGITAL_BASE + 0x0008)
+#define WSA881X_CLOCK_CONFIG (WSA881X_DIGITAL_BASE + 0x0009)
+#define WSA881X_ANA_CTL (WSA881X_DIGITAL_BASE + 0x000A)
+#define WSA881X_SWR_RESET_EN (WSA881X_DIGITAL_BASE + 0x000B)
+#define WSA881X_RESET_CTL (WSA881X_DIGITAL_BASE + 0x000C)
+#define WSA881X_TADC_VALUE_CTL (WSA881X_DIGITAL_BASE + 0x000F)
+#define WSA881X_TEMP_DETECT_CTL (WSA881X_DIGITAL_BASE + 0x0010)
+#define WSA881X_TEMP_MSB (WSA881X_DIGITAL_BASE + 0x0011)
+#define WSA881X_TEMP_LSB (WSA881X_DIGITAL_BASE + 0x0012)
+#define WSA881X_TEMP_CONFIG0 (WSA881X_DIGITAL_BASE + 0x0013)
+#define WSA881X_TEMP_CONFIG1 (WSA881X_DIGITAL_BASE + 0x0014)
+#define WSA881X_CDC_CLIP_CTL (WSA881X_DIGITAL_BASE + 0x0015)
+#define WSA881X_SDM_PDM9_LSB (WSA881X_DIGITAL_BASE + 0x0016)
+#define WSA881X_SDM_PDM9_MSB (WSA881X_DIGITAL_BASE + 0x0017)
+#define WSA881X_CDC_RX_CTL (WSA881X_DIGITAL_BASE + 0x0018)
+#define WSA881X_DEM_BYPASS_DATA0 (WSA881X_DIGITAL_BASE + 0x0019)
+#define WSA881X_DEM_BYPASS_DATA1 (WSA881X_DIGITAL_BASE + 0x001A)
+#define WSA881X_DEM_BYPASS_DATA2 (WSA881X_DIGITAL_BASE + 0x001B)
+#define WSA881X_DEM_BYPASS_DATA3 (WSA881X_DIGITAL_BASE + 0x001C)
+#define WSA881X_OTP_CTRL0 (WSA881X_DIGITAL_BASE + 0x001D)
+#define WSA881X_OTP_CTRL1 (WSA881X_DIGITAL_BASE + 0x001E)
+#define WSA881X_HDRIVE_CTL_GROUP1 (WSA881X_DIGITAL_BASE + 0x001F)
+#define WSA881X_INTR_MODE (WSA881X_DIGITAL_BASE + 0x0020)
+#define WSA881X_INTR_MASK (WSA881X_DIGITAL_BASE + 0x0021)
+#define WSA881X_INTR_STATUS (WSA881X_DIGITAL_BASE + 0x0022)
+#define WSA881X_INTR_CLEAR (WSA881X_DIGITAL_BASE + 0x0023)
+#define WSA881X_INTR_LEVEL (WSA881X_DIGITAL_BASE + 0x0024)
+#define WSA881X_INTR_SET (WSA881X_DIGITAL_BASE + 0x0025)
+#define WSA881X_INTR_TEST (WSA881X_DIGITAL_BASE + 0x0026)
+#define WSA881X_PDM_TEST_MODE (WSA881X_DIGITAL_BASE + 0x0030)
+#define WSA881X_ATE_TEST_MODE (WSA881X_DIGITAL_BASE + 0x0031)
+#define WSA881X_PIN_CTL_MODE (WSA881X_DIGITAL_BASE + 0x0032)
+#define WSA881X_PIN_CTL_OE (WSA881X_DIGITAL_BASE + 0x0033)
+#define WSA881X_PIN_WDATA_IOPAD (WSA881X_DIGITAL_BASE + 0x0034)
+#define WSA881X_PIN_STATUS (WSA881X_DIGITAL_BASE + 0x0035)
+#define WSA881X_DIG_DEBUG_MODE (WSA881X_DIGITAL_BASE + 0x0037)
+#define WSA881X_DIG_DEBUG_SEL (WSA881X_DIGITAL_BASE + 0x0038)
+#define WSA881X_DIG_DEBUG_EN (WSA881X_DIGITAL_BASE + 0x0039)
+#define WSA881X_SWR_HM_TEST1 (WSA881X_DIGITAL_BASE + 0x003B)
+#define WSA881X_SWR_HM_TEST2 (WSA881X_DIGITAL_BASE + 0x003C)
+#define WSA881X_TEMP_DETECT_DBG_CTL (WSA881X_DIGITAL_BASE + 0x003D)
+#define WSA881X_TEMP_DEBUG_MSB (WSA881X_DIGITAL_BASE + 0x003E)
+#define WSA881X_TEMP_DEBUG_LSB (WSA881X_DIGITAL_BASE + 0x003F)
+#define WSA881X_SAMPLE_EDGE_SEL (WSA881X_DIGITAL_BASE + 0x0044)
+#define WSA881X_IOPAD_CTL (WSA881X_DIGITAL_BASE + 0x0045)
+#define WSA881X_SPARE_0 (WSA881X_DIGITAL_BASE + 0x0050)
+#define WSA881X_SPARE_1 (WSA881X_DIGITAL_BASE + 0x0051)
+#define WSA881X_SPARE_2 (WSA881X_DIGITAL_BASE + 0x0052)
+#define WSA881X_OTP_REG_0 (WSA881X_DIGITAL_BASE + 0x0080)
+#define WSA881X_OTP_REG_1 (WSA881X_DIGITAL_BASE + 0x0081)
+#define WSA881X_OTP_REG_2 (WSA881X_DIGITAL_BASE + 0x0082)
+#define WSA881X_OTP_REG_3 (WSA881X_DIGITAL_BASE + 0x0083)
+#define WSA881X_OTP_REG_4 (WSA881X_DIGITAL_BASE + 0x0084)
+#define WSA881X_OTP_REG_5 (WSA881X_DIGITAL_BASE + 0x0085)
+#define WSA881X_OTP_REG_6 (WSA881X_DIGITAL_BASE + 0x0086)
+#define WSA881X_OTP_REG_7 (WSA881X_DIGITAL_BASE + 0x0087)
+#define WSA881X_OTP_REG_8 (WSA881X_DIGITAL_BASE + 0x0088)
+#define WSA881X_OTP_REG_9 (WSA881X_DIGITAL_BASE + 0x0089)
+#define WSA881X_OTP_REG_10 (WSA881X_DIGITAL_BASE + 0x008A)
+#define WSA881X_OTP_REG_11 (WSA881X_DIGITAL_BASE + 0x008B)
+#define WSA881X_OTP_REG_12 (WSA881X_DIGITAL_BASE + 0x008C)
+#define WSA881X_OTP_REG_13 (WSA881X_DIGITAL_BASE + 0x008D)
+#define WSA881X_OTP_REG_14 (WSA881X_DIGITAL_BASE + 0x008E)
+#define WSA881X_OTP_REG_15 (WSA881X_DIGITAL_BASE + 0x008F)
+#define WSA881X_OTP_REG_16 (WSA881X_DIGITAL_BASE + 0x0090)
+#define WSA881X_OTP_REG_17 (WSA881X_DIGITAL_BASE + 0x0091)
+#define WSA881X_OTP_REG_18 (WSA881X_DIGITAL_BASE + 0x0092)
+#define WSA881X_OTP_REG_19 (WSA881X_DIGITAL_BASE + 0x0093)
+#define WSA881X_OTP_REG_20 (WSA881X_DIGITAL_BASE + 0x0094)
+#define WSA881X_OTP_REG_21 (WSA881X_DIGITAL_BASE + 0x0095)
+#define WSA881X_OTP_REG_22 (WSA881X_DIGITAL_BASE + 0x0096)
+#define WSA881X_OTP_REG_23 (WSA881X_DIGITAL_BASE + 0x0097)
+#define WSA881X_OTP_REG_24 (WSA881X_DIGITAL_BASE + 0x0098)
+#define WSA881X_OTP_REG_25 (WSA881X_DIGITAL_BASE + 0x0099)
+#define WSA881X_OTP_REG_26 (WSA881X_DIGITAL_BASE + 0x009A)
+#define WSA881X_OTP_REG_27 (WSA881X_DIGITAL_BASE + 0x009B)
+#define WSA881X_OTP_REG_28 (WSA881X_DIGITAL_BASE + 0x009C)
+#define WSA881X_OTP_REG_29 (WSA881X_DIGITAL_BASE + 0x009D)
+#define WSA881X_OTP_REG_30 (WSA881X_DIGITAL_BASE + 0x009E)
+#define WSA881X_OTP_REG_31 (WSA881X_DIGITAL_BASE + 0x009F)
+#define WSA881X_OTP_REG_63 (WSA881X_DIGITAL_BASE + 0x00BF)
+
+/* Analog Register address space */
+#define WSA881X_BIAS_REF_CTRL (WSA881X_ANALOG_BASE + 0x0000)
+#define WSA881X_BIAS_TEST (WSA881X_ANALOG_BASE + 0x0001)
+#define WSA881X_BIAS_BIAS (WSA881X_ANALOG_BASE + 0x0002)
+#define WSA881X_TEMP_OP (WSA881X_ANALOG_BASE + 0x0003)
+#define WSA881X_TEMP_IREF_CTRL (WSA881X_ANALOG_BASE + 0x0004)
+#define WSA881X_TEMP_ISENS_CTRL (WSA881X_ANALOG_BASE + 0x0005)
+#define WSA881X_TEMP_CLK_CTRL (WSA881X_ANALOG_BASE + 0x0006)
+#define WSA881X_TEMP_TEST (WSA881X_ANALOG_BASE + 0x0007)
+#define WSA881X_TEMP_BIAS (WSA881X_ANALOG_BASE + 0x0008)
+#define WSA881X_TEMP_ADC_CTRL (WSA881X_ANALOG_BASE + 0x0009)
+#define WSA881X_TEMP_DOUT_MSB (WSA881X_ANALOG_BASE + 0x000A)
+#define WSA881X_TEMP_DOUT_LSB (WSA881X_ANALOG_BASE + 0x000B)
+#define WSA881X_ADC_EN_MODU_V (WSA881X_ANALOG_BASE + 0x0010)
+#define WSA881X_ADC_EN_MODU_I (WSA881X_ANALOG_BASE + 0x0011)
+#define WSA881X_ADC_EN_DET_TEST_V (WSA881X_ANALOG_BASE + 0x0012)
+#define WSA881X_ADC_EN_DET_TEST_I (WSA881X_ANALOG_BASE + 0x0013)
+#define WSA881X_ADC_SEL_IBIAS (WSA881X_ANALOG_BASE + 0x0014)
+#define WSA881X_ADC_EN_SEL_IBAIS (WSA881X_ANALOG_BASE + 0x0015)
+#define WSA881X_SPKR_DRV_EN (WSA881X_ANALOG_BASE + 0x001A)
+#define WSA881X_SPKR_DRV_GAIN (WSA881X_ANALOG_BASE + 0x001B)
+#define WSA881X_PA_GAIN_SEL_MASK BIT(3)
+#define WSA881X_PA_GAIN_SEL_REG BIT(3)
+#define WSA881X_PA_GAIN_SEL_DRE 0
+#define WSA881X_SPKR_PAG_GAIN_MASK GENMASK(7, 4)
+#define WSA881X_SPKR_DAC_CTL (WSA881X_ANALOG_BASE + 0x001C)
+#define WSA881X_SPKR_DRV_DBG (WSA881X_ANALOG_BASE + 0x001D)
+#define WSA881X_SPKR_PWRSTG_DBG (WSA881X_ANALOG_BASE + 0x001E)
+#define WSA881X_SPKR_OCP_CTL (WSA881X_ANALOG_BASE + 0x001F)
+#define WSA881X_SPKR_OCP_MASK GENMASK(7, 6)
+#define WSA881X_SPKR_OCP_EN BIT(7)
+#define WSA881X_SPKR_OCP_HOLD BIT(6)
+#define WSA881X_SPKR_CLIP_CTL (WSA881X_ANALOG_BASE + 0x0020)
+#define WSA881X_SPKR_BBM_CTL (WSA881X_ANALOG_BASE + 0x0021)
+#define WSA881X_SPKR_MISC_CTL1 (WSA881X_ANALOG_BASE + 0x0022)
+#define WSA881X_SPKR_MISC_CTL2 (WSA881X_ANALOG_BASE + 0x0023)
+#define WSA881X_SPKR_BIAS_INT (WSA881X_ANALOG_BASE + 0x0024)
+#define WSA881X_SPKR_PA_INT (WSA881X_ANALOG_BASE + 0x0025)
+#define WSA881X_SPKR_BIAS_CAL (WSA881X_ANALOG_BASE + 0x0026)
+#define WSA881X_SPKR_BIAS_PSRR (WSA881X_ANALOG_BASE + 0x0027)
+#define WSA881X_SPKR_STATUS1 (WSA881X_ANALOG_BASE + 0x0028)
+#define WSA881X_SPKR_STATUS2 (WSA881X_ANALOG_BASE + 0x0029)
+#define WSA881X_BOOST_EN_CTL (WSA881X_ANALOG_BASE + 0x002A)
+#define WSA881X_BOOST_EN_MASK BIT(7)
+#define WSA881X_BOOST_EN BIT(7)
+#define WSA881X_BOOST_CURRENT_LIMIT (WSA881X_ANALOG_BASE + 0x002B)
+#define WSA881X_BOOST_PS_CTL (WSA881X_ANALOG_BASE + 0x002C)
+#define WSA881X_BOOST_PRESET_OUT1 (WSA881X_ANALOG_BASE + 0x002D)
+#define WSA881X_BOOST_PRESET_OUT2 (WSA881X_ANALOG_BASE + 0x002E)
+#define WSA881X_BOOST_FORCE_OUT (WSA881X_ANALOG_BASE + 0x002F)
+#define WSA881X_BOOST_LDO_PROG (WSA881X_ANALOG_BASE + 0x0030)
+#define WSA881X_BOOST_SLOPE_COMP_ISENSE_FB (WSA881X_ANALOG_BASE + 0x0031)
+#define WSA881X_BOOST_RON_CTL (WSA881X_ANALOG_BASE + 0x0032)
+#define WSA881X_BOOST_LOOP_STABILITY (WSA881X_ANALOG_BASE + 0x0033)
+#define WSA881X_BOOST_ZX_CTL (WSA881X_ANALOG_BASE + 0x0034)
+#define WSA881X_BOOST_START_CTL (WSA881X_ANALOG_BASE + 0x0035)
+#define WSA881X_BOOST_MISC1_CTL (WSA881X_ANALOG_BASE + 0x0036)
+#define WSA881X_BOOST_MISC2_CTL (WSA881X_ANALOG_BASE + 0x0037)
+#define WSA881X_BOOST_MISC3_CTL (WSA881X_ANALOG_BASE + 0x0038)
+#define WSA881X_BOOST_ATEST_CTL (WSA881X_ANALOG_BASE + 0x0039)
+#define WSA881X_SPKR_PROT_FE_GAIN (WSA881X_ANALOG_BASE + 0x003A)
+#define WSA881X_SPKR_PROT_FE_CM_LDO_SET (WSA881X_ANALOG_BASE + 0x003B)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 (WSA881X_ANALOG_BASE + 0x003C)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 (WSA881X_ANALOG_BASE + 0x003D)
+#define WSA881X_SPKR_PROT_ATEST1 (WSA881X_ANALOG_BASE + 0x003E)
+#define WSA881X_SPKR_PROT_ATEST2 (WSA881X_ANALOG_BASE + 0x003F)
+#define WSA881X_SPKR_PROT_FE_VSENSE_VCM (WSA881X_ANALOG_BASE + 0x0040)
+#define WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 (WSA881X_ANALOG_BASE + 0x0041)
+#define WSA881X_BONGO_RESRV_REG1 (WSA881X_ANALOG_BASE + 0x0042)
+#define WSA881X_BONGO_RESRV_REG2 (WSA881X_ANALOG_BASE + 0x0043)
+#define WSA881X_SPKR_PROT_SAR (WSA881X_ANALOG_BASE + 0x0044)
+#define WSA881X_SPKR_STATUS3 (WSA881X_ANALOG_BASE + 0x0045)
+
+#define SWRS_SCP_FRAME_CTRL_BANK(m) (0x60 + 0x10 * (m))
+#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
+#define SWR_SLV_MAX_REG_ADDR 0x390
+#define SWR_SLV_START_REG_ADDR 0x40
+#define SWR_SLV_MAX_BUF_LEN 20
+#define BYTES_PER_LINE 12
+#define SWR_SLV_RD_BUF_LEN 8
+#define SWR_SLV_WR_BUF_LEN 32
+#define SWR_SLV_MAX_DEVICES 2
+#define WSA881X_MAX_SWR_PORTS 4
+#define WSA881X_VERSION_ENTRY_SIZE 27
+#define WSA881X_OCP_CTL_TIMER_SEC 2
+#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
+#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
+
+#define WSA881X_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+ .put = wsa881x_put_pa_gain, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+
+static struct reg_default wsa881x_defaults[] = {
+ { WSA881X_CHIP_ID0, 0x00 },
+ { WSA881X_CHIP_ID1, 0x00 },
+ { WSA881X_CHIP_ID2, 0x00 },
+ { WSA881X_CHIP_ID3, 0x02 },
+ { WSA881X_BUS_ID, 0x00 },
+ { WSA881X_CDC_RST_CTL, 0x00 },
+ { WSA881X_CDC_TOP_CLK_CTL, 0x03 },
+ { WSA881X_CDC_ANA_CLK_CTL, 0x00 },
+ { WSA881X_CDC_DIG_CLK_CTL, 0x00 },
+ { WSA881X_CLOCK_CONFIG, 0x00 },
+ { WSA881X_ANA_CTL, 0x08 },
+ { WSA881X_SWR_RESET_EN, 0x00 },
+ { WSA881X_TEMP_DETECT_CTL, 0x01 },
+ { WSA881X_TEMP_MSB, 0x00 },
+ { WSA881X_TEMP_LSB, 0x00 },
+ { WSA881X_TEMP_CONFIG0, 0x00 },
+ { WSA881X_TEMP_CONFIG1, 0x00 },
+ { WSA881X_CDC_CLIP_CTL, 0x03 },
+ { WSA881X_SDM_PDM9_LSB, 0x00 },
+ { WSA881X_SDM_PDM9_MSB, 0x00 },
+ { WSA881X_CDC_RX_CTL, 0x7E },
+ { WSA881X_DEM_BYPASS_DATA0, 0x00 },
+ { WSA881X_DEM_BYPASS_DATA1, 0x00 },
+ { WSA881X_DEM_BYPASS_DATA2, 0x00 },
+ { WSA881X_DEM_BYPASS_DATA3, 0x00 },
+ { WSA881X_OTP_CTRL0, 0x00 },
+ { WSA881X_OTP_CTRL1, 0x00 },
+ { WSA881X_HDRIVE_CTL_GROUP1, 0x00 },
+ { WSA881X_INTR_MODE, 0x00 },
+ { WSA881X_INTR_STATUS, 0x00 },
+ { WSA881X_INTR_CLEAR, 0x00 },
+ { WSA881X_INTR_LEVEL, 0x00 },
+ { WSA881X_INTR_SET, 0x00 },
+ { WSA881X_INTR_TEST, 0x00 },
+ { WSA881X_PDM_TEST_MODE, 0x00 },
+ { WSA881X_ATE_TEST_MODE, 0x00 },
+ { WSA881X_PIN_CTL_MODE, 0x00 },
+ { WSA881X_PIN_CTL_OE, 0x00 },
+ { WSA881X_PIN_WDATA_IOPAD, 0x00 },
+ { WSA881X_PIN_STATUS, 0x00 },
+ { WSA881X_DIG_DEBUG_MODE, 0x00 },
+ { WSA881X_DIG_DEBUG_SEL, 0x00 },
+ { WSA881X_DIG_DEBUG_EN, 0x00 },
+ { WSA881X_SWR_HM_TEST1, 0x08 },
+ { WSA881X_SWR_HM_TEST2, 0x00 },
+ { WSA881X_TEMP_DETECT_DBG_CTL, 0x00 },
+ { WSA881X_TEMP_DEBUG_MSB, 0x00 },
+ { WSA881X_TEMP_DEBUG_LSB, 0x00 },
+ { WSA881X_SAMPLE_EDGE_SEL, 0x0C },
+ { WSA881X_SPARE_0, 0x00 },
+ { WSA881X_SPARE_1, 0x00 },
+ { WSA881X_SPARE_2, 0x00 },
+ { WSA881X_OTP_REG_0, 0x01 },
+ { WSA881X_OTP_REG_1, 0xFF },
+ { WSA881X_OTP_REG_2, 0xC0 },
+ { WSA881X_OTP_REG_3, 0xFF },
+ { WSA881X_OTP_REG_4, 0xC0 },
+ { WSA881X_OTP_REG_5, 0xFF },
+ { WSA881X_OTP_REG_6, 0xFF },
+ { WSA881X_OTP_REG_7, 0xFF },
+ { WSA881X_OTP_REG_8, 0xFF },
+ { WSA881X_OTP_REG_9, 0xFF },
+ { WSA881X_OTP_REG_10, 0xFF },
+ { WSA881X_OTP_REG_11, 0xFF },
+ { WSA881X_OTP_REG_12, 0xFF },
+ { WSA881X_OTP_REG_13, 0xFF },
+ { WSA881X_OTP_REG_14, 0xFF },
+ { WSA881X_OTP_REG_15, 0xFF },
+ { WSA881X_OTP_REG_16, 0xFF },
+ { WSA881X_OTP_REG_17, 0xFF },
+ { WSA881X_OTP_REG_18, 0xFF },
+ { WSA881X_OTP_REG_19, 0xFF },
+ { WSA881X_OTP_REG_20, 0xFF },
+ { WSA881X_OTP_REG_21, 0xFF },
+ { WSA881X_OTP_REG_22, 0xFF },
+ { WSA881X_OTP_REG_23, 0xFF },
+ { WSA881X_OTP_REG_24, 0x03 },
+ { WSA881X_OTP_REG_25, 0x01 },
+ { WSA881X_OTP_REG_26, 0x03 },
+ { WSA881X_OTP_REG_27, 0x11 },
+ { WSA881X_OTP_REG_63, 0x40 },
+ /* WSA881x Analog registers */
+ { WSA881X_BIAS_REF_CTRL, 0x6C },
+ { WSA881X_BIAS_TEST, 0x16 },
+ { WSA881X_BIAS_BIAS, 0xF0 },
+ { WSA881X_TEMP_OP, 0x00 },
+ { WSA881X_TEMP_IREF_CTRL, 0x56 },
+ { WSA881X_TEMP_ISENS_CTRL, 0x47 },
+ { WSA881X_TEMP_CLK_CTRL, 0x87 },
+ { WSA881X_TEMP_TEST, 0x00 },
+ { WSA881X_TEMP_BIAS, 0x51 },
+ { WSA881X_TEMP_DOUT_MSB, 0x00 },
+ { WSA881X_TEMP_DOUT_LSB, 0x00 },
+ { WSA881X_ADC_EN_MODU_V, 0x00 },
+ { WSA881X_ADC_EN_MODU_I, 0x00 },
+ { WSA881X_ADC_EN_DET_TEST_V, 0x00 },
+ { WSA881X_ADC_EN_DET_TEST_I, 0x00 },
+ { WSA881X_ADC_EN_SEL_IBAIS, 0x10 },
+ { WSA881X_SPKR_DRV_EN, 0x74 },
+ { WSA881X_SPKR_DRV_DBG, 0x15 },
+ { WSA881X_SPKR_PWRSTG_DBG, 0x00 },
+ { WSA881X_SPKR_OCP_CTL, 0xD4 },
+ { WSA881X_SPKR_CLIP_CTL, 0x90 },
+ { WSA881X_SPKR_PA_INT, 0x54 },
+ { WSA881X_SPKR_BIAS_CAL, 0xAC },
+ { WSA881X_SPKR_STATUS1, 0x00 },
+ { WSA881X_SPKR_STATUS2, 0x00 },
+ { WSA881X_BOOST_EN_CTL, 0x18 },
+ { WSA881X_BOOST_CURRENT_LIMIT, 0x7A },
+ { WSA881X_BOOST_PRESET_OUT2, 0x70 },
+ { WSA881X_BOOST_FORCE_OUT, 0x0E },
+ { WSA881X_BOOST_LDO_PROG, 0x16 },
+ { WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x71 },
+ { WSA881X_BOOST_RON_CTL, 0x0F },
+ { WSA881X_BOOST_ZX_CTL, 0x34 },
+ { WSA881X_BOOST_START_CTL, 0x23 },
+ { WSA881X_BOOST_MISC1_CTL, 0x80 },
+ { WSA881X_BOOST_MISC2_CTL, 0x00 },
+ { WSA881X_BOOST_MISC3_CTL, 0x00 },
+ { WSA881X_BOOST_ATEST_CTL, 0x00 },
+ { WSA881X_SPKR_PROT_FE_GAIN, 0x46 },
+ { WSA881X_SPKR_PROT_FE_CM_LDO_SET, 0x3B },
+ { WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1, 0x8D },
+ { WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2, 0x8D },
+ { WSA881X_SPKR_PROT_ATEST1, 0x01 },
+ { WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x8D },
+ { WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1, 0x4D },
+ { WSA881X_SPKR_PROT_SAR, 0x00 },
+ { WSA881X_SPKR_STATUS3, 0x00 },
+};
+
+static const struct reg_sequence wsa881x_pre_pmu_pa_2_0[] = {
+ { WSA881X_SPKR_DRV_GAIN, 0x41, 0 },
+ { WSA881X_SPKR_MISC_CTL1, 0x87, 0 },
+};
+
+static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = {
+ { WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0 },
+ { WSA881X_SPKR_PROT_ATEST2, 0x0A, 0 },
+ { WSA881X_SPKR_PROT_FE_GAIN, 0x47, 0 },
+};
+
+/* Default register reset values for WSA881x rev 2.0 */
+static struct reg_sequence wsa881x_rev_2_0[] = {
+ { WSA881X_RESET_CTL, 0x00, 0x00 },
+ { WSA881X_TADC_VALUE_CTL, 0x01, 0x00 },
+ { WSA881X_INTR_MASK, 0x1B, 0x00 },
+ { WSA881X_IOPAD_CTL, 0x00, 0x00 },
+ { WSA881X_OTP_REG_28, 0x3F, 0x00 },
+ { WSA881X_OTP_REG_29, 0x3F, 0x00 },
+ { WSA881X_OTP_REG_30, 0x01, 0x00 },
+ { WSA881X_OTP_REG_31, 0x01, 0x00 },
+ { WSA881X_TEMP_ADC_CTRL, 0x03, 0x00 },
+ { WSA881X_ADC_SEL_IBIAS, 0x45, 0x00 },
+ { WSA881X_SPKR_DRV_GAIN, 0xC1, 0x00 },
+ { WSA881X_SPKR_DAC_CTL, 0x42, 0x00 },
+ { WSA881X_SPKR_BBM_CTL, 0x02, 0x00 },
+ { WSA881X_SPKR_MISC_CTL1, 0x40, 0x00 },
+ { WSA881X_SPKR_MISC_CTL2, 0x07, 0x00 },
+ { WSA881X_SPKR_BIAS_INT, 0x5F, 0x00 },
+ { WSA881X_SPKR_BIAS_PSRR, 0x44, 0x00 },
+ { WSA881X_BOOST_PS_CTL, 0xA0, 0x00 },
+ { WSA881X_BOOST_PRESET_OUT1, 0xB7, 0x00 },
+ { WSA881X_BOOST_LOOP_STABILITY, 0x8D, 0x00 },
+ { WSA881X_SPKR_PROT_ATEST2, 0x02, 0x00 },
+ { WSA881X_BONGO_RESRV_REG1, 0x5E, 0x00 },
+ { WSA881X_BONGO_RESRV_REG2, 0x07, 0x00 },
+};
+
+enum wsa_port_ids {
+ WSA881X_PORT_DAC,
+ WSA881X_PORT_COMP,
+ WSA881X_PORT_BOOST,
+ WSA881X_PORT_VISENSE,
+};
+
+/* 4 ports */
+static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
+ {
+ /* DAC */
+ .num = 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ }, {
+ /* COMP */
+ .num = 2,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ }, {
+ /* BOOST */
+ .num = 3,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ }, {
+ /* VISENSE */
+ .num = 4,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ }
+};
+
+static struct sdw_port_config wsa881x_pconfig[WSA881X_MAX_SWR_PORTS] = {
+ {
+ .num = 1,
+ .ch_mask = 0x1,
+ }, {
+ .num = 2,
+ .ch_mask = 0xf,
+ }, {
+ .num = 3,
+ .ch_mask = 0x3,
+ }, { /* IV feedback */
+ .num = 4,
+ .ch_mask = 0x3,
+ },
+};
+
+static bool wsa881x_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA881X_CHIP_ID0:
+ case WSA881X_CHIP_ID1:
+ case WSA881X_CHIP_ID2:
+ case WSA881X_CHIP_ID3:
+ case WSA881X_BUS_ID:
+ case WSA881X_CDC_RST_CTL:
+ case WSA881X_CDC_TOP_CLK_CTL:
+ case WSA881X_CDC_ANA_CLK_CTL:
+ case WSA881X_CDC_DIG_CLK_CTL:
+ case WSA881X_CLOCK_CONFIG:
+ case WSA881X_ANA_CTL:
+ case WSA881X_SWR_RESET_EN:
+ case WSA881X_RESET_CTL:
+ case WSA881X_TADC_VALUE_CTL:
+ case WSA881X_TEMP_DETECT_CTL:
+ case WSA881X_TEMP_MSB:
+ case WSA881X_TEMP_LSB:
+ case WSA881X_TEMP_CONFIG0:
+ case WSA881X_TEMP_CONFIG1:
+ case WSA881X_CDC_CLIP_CTL:
+ case WSA881X_SDM_PDM9_LSB:
+ case WSA881X_SDM_PDM9_MSB:
+ case WSA881X_CDC_RX_CTL:
+ case WSA881X_DEM_BYPASS_DATA0:
+ case WSA881X_DEM_BYPASS_DATA1:
+ case WSA881X_DEM_BYPASS_DATA2:
+ case WSA881X_DEM_BYPASS_DATA3:
+ case WSA881X_OTP_CTRL0:
+ case WSA881X_OTP_CTRL1:
+ case WSA881X_HDRIVE_CTL_GROUP1:
+ case WSA881X_INTR_MODE:
+ case WSA881X_INTR_MASK:
+ case WSA881X_INTR_STATUS:
+ case WSA881X_INTR_CLEAR:
+ case WSA881X_INTR_LEVEL:
+ case WSA881X_INTR_SET:
+ case WSA881X_INTR_TEST:
+ case WSA881X_PDM_TEST_MODE:
+ case WSA881X_ATE_TEST_MODE:
+ case WSA881X_PIN_CTL_MODE:
+ case WSA881X_PIN_CTL_OE:
+ case WSA881X_PIN_WDATA_IOPAD:
+ case WSA881X_PIN_STATUS:
+ case WSA881X_DIG_DEBUG_MODE:
+ case WSA881X_DIG_DEBUG_SEL:
+ case WSA881X_DIG_DEBUG_EN:
+ case WSA881X_SWR_HM_TEST1:
+ case WSA881X_SWR_HM_TEST2:
+ case WSA881X_TEMP_DETECT_DBG_CTL:
+ case WSA881X_TEMP_DEBUG_MSB:
+ case WSA881X_TEMP_DEBUG_LSB:
+ case WSA881X_SAMPLE_EDGE_SEL:
+ case WSA881X_IOPAD_CTL:
+ case WSA881X_SPARE_0:
+ case WSA881X_SPARE_1:
+ case WSA881X_SPARE_2:
+ case WSA881X_OTP_REG_0:
+ case WSA881X_OTP_REG_1:
+ case WSA881X_OTP_REG_2:
+ case WSA881X_OTP_REG_3:
+ case WSA881X_OTP_REG_4:
+ case WSA881X_OTP_REG_5:
+ case WSA881X_OTP_REG_6:
+ case WSA881X_OTP_REG_7:
+ case WSA881X_OTP_REG_8:
+ case WSA881X_OTP_REG_9:
+ case WSA881X_OTP_REG_10:
+ case WSA881X_OTP_REG_11:
+ case WSA881X_OTP_REG_12:
+ case WSA881X_OTP_REG_13:
+ case WSA881X_OTP_REG_14:
+ case WSA881X_OTP_REG_15:
+ case WSA881X_OTP_REG_16:
+ case WSA881X_OTP_REG_17:
+ case WSA881X_OTP_REG_18:
+ case WSA881X_OTP_REG_19:
+ case WSA881X_OTP_REG_20:
+ case WSA881X_OTP_REG_21:
+ case WSA881X_OTP_REG_22:
+ case WSA881X_OTP_REG_23:
+ case WSA881X_OTP_REG_24:
+ case WSA881X_OTP_REG_25:
+ case WSA881X_OTP_REG_26:
+ case WSA881X_OTP_REG_27:
+ case WSA881X_OTP_REG_28:
+ case WSA881X_OTP_REG_29:
+ case WSA881X_OTP_REG_30:
+ case WSA881X_OTP_REG_31:
+ case WSA881X_OTP_REG_63:
+ case WSA881X_BIAS_REF_CTRL:
+ case WSA881X_BIAS_TEST:
+ case WSA881X_BIAS_BIAS:
+ case WSA881X_TEMP_OP:
+ case WSA881X_TEMP_IREF_CTRL:
+ case WSA881X_TEMP_ISENS_CTRL:
+ case WSA881X_TEMP_CLK_CTRL:
+ case WSA881X_TEMP_TEST:
+ case WSA881X_TEMP_BIAS:
+ case WSA881X_TEMP_ADC_CTRL:
+ case WSA881X_TEMP_DOUT_MSB:
+ case WSA881X_TEMP_DOUT_LSB:
+ case WSA881X_ADC_EN_MODU_V:
+ case WSA881X_ADC_EN_MODU_I:
+ case WSA881X_ADC_EN_DET_TEST_V:
+ case WSA881X_ADC_EN_DET_TEST_I:
+ case WSA881X_ADC_SEL_IBIAS:
+ case WSA881X_ADC_EN_SEL_IBAIS:
+ case WSA881X_SPKR_DRV_EN:
+ case WSA881X_SPKR_DRV_GAIN:
+ case WSA881X_SPKR_DAC_CTL:
+ case WSA881X_SPKR_DRV_DBG:
+ case WSA881X_SPKR_PWRSTG_DBG:
+ case WSA881X_SPKR_OCP_CTL:
+ case WSA881X_SPKR_CLIP_CTL:
+ case WSA881X_SPKR_BBM_CTL:
+ case WSA881X_SPKR_MISC_CTL1:
+ case WSA881X_SPKR_MISC_CTL2:
+ case WSA881X_SPKR_BIAS_INT:
+ case WSA881X_SPKR_PA_INT:
+ case WSA881X_SPKR_BIAS_CAL:
+ case WSA881X_SPKR_BIAS_PSRR:
+ case WSA881X_SPKR_STATUS1:
+ case WSA881X_SPKR_STATUS2:
+ case WSA881X_BOOST_EN_CTL:
+ case WSA881X_BOOST_CURRENT_LIMIT:
+ case WSA881X_BOOST_PS_CTL:
+ case WSA881X_BOOST_PRESET_OUT1:
+ case WSA881X_BOOST_PRESET_OUT2:
+ case WSA881X_BOOST_FORCE_OUT:
+ case WSA881X_BOOST_LDO_PROG:
+ case WSA881X_BOOST_SLOPE_COMP_ISENSE_FB:
+ case WSA881X_BOOST_RON_CTL:
+ case WSA881X_BOOST_LOOP_STABILITY:
+ case WSA881X_BOOST_ZX_CTL:
+ case WSA881X_BOOST_START_CTL:
+ case WSA881X_BOOST_MISC1_CTL:
+ case WSA881X_BOOST_MISC2_CTL:
+ case WSA881X_BOOST_MISC3_CTL:
+ case WSA881X_BOOST_ATEST_CTL:
+ case WSA881X_SPKR_PROT_FE_GAIN:
+ case WSA881X_SPKR_PROT_FE_CM_LDO_SET:
+ case WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1:
+ case WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2:
+ case WSA881X_SPKR_PROT_ATEST1:
+ case WSA881X_SPKR_PROT_ATEST2:
+ case WSA881X_SPKR_PROT_FE_VSENSE_VCM:
+ case WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1:
+ case WSA881X_BONGO_RESRV_REG1:
+ case WSA881X_BONGO_RESRV_REG2:
+ case WSA881X_SPKR_PROT_SAR:
+ case WSA881X_SPKR_STATUS3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA881X_CHIP_ID0:
+ case WSA881X_CHIP_ID1:
+ case WSA881X_CHIP_ID2:
+ case WSA881X_CHIP_ID3:
+ case WSA881X_BUS_ID:
+ case WSA881X_TEMP_MSB:
+ case WSA881X_TEMP_LSB:
+ case WSA881X_SDM_PDM9_LSB:
+ case WSA881X_SDM_PDM9_MSB:
+ case WSA881X_OTP_CTRL1:
+ case WSA881X_INTR_STATUS:
+ case WSA881X_ATE_TEST_MODE:
+ case WSA881X_PIN_STATUS:
+ case WSA881X_SWR_HM_TEST2:
+ case WSA881X_SPKR_STATUS1:
+ case WSA881X_SPKR_STATUS2:
+ case WSA881X_SPKR_STATUS3:
+ case WSA881X_OTP_REG_0:
+ case WSA881X_OTP_REG_1:
+ case WSA881X_OTP_REG_2:
+ case WSA881X_OTP_REG_3:
+ case WSA881X_OTP_REG_4:
+ case WSA881X_OTP_REG_5:
+ case WSA881X_OTP_REG_31:
+ case WSA881X_TEMP_DOUT_MSB:
+ case WSA881X_TEMP_DOUT_LSB:
+ case WSA881X_TEMP_OP:
+ case WSA881X_SPKR_PROT_SAR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct regmap_config wsa881x_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = wsa881x_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wsa881x_defaults),
+ .volatile_reg = wsa881x_volatile_register,
+ .readable_reg = wsa881x_readable_register,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .can_multi_write = true,
+};
+
+enum {
+ G_18DB = 0,
+ G_16P5DB,
+ G_15DB,
+ G_13P5DB,
+ G_12DB,
+ G_10P5DB,
+ G_9DB,
+ G_7P5DB,
+ G_6DB,
+ G_4P5DB,
+ G_3DB,
+ G_1P5DB,
+ G_0DB,
+};
+
+/*
+ * Private data Structure for wsa881x. All parameters related to
+ * WSA881X codec needs to be defined here.
+ */
+struct wsa881x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct sdw_slave *slave;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[WSA881X_MAX_SWR_PORTS];
+ struct gpio_desc *sd_n;
+ int version;
+ int active_ports;
+ bool port_prepared[WSA881X_MAX_SWR_PORTS];
+ bool port_enable[WSA881X_MAX_SWR_PORTS];
+ bool stream_prepared;
+};
+
+static void wsa881x_init(struct wsa881x_priv *wsa881x)
+{
+ struct regmap *rm = wsa881x->regmap;
+ unsigned int val = 0;
+
+ regmap_read(rm, WSA881X_CHIP_ID1, &wsa881x->version);
+ regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0,
+ ARRAY_SIZE(wsa881x_rev_2_0));
+
+ /* Enable software reset output from soundwire slave */
+ regmap_update_bits(rm, WSA881X_SWR_RESET_EN, 0x07, 0x07);
+
+ /* Bring out of analog reset */
+ regmap_update_bits(rm, WSA881X_CDC_RST_CTL, 0x02, 0x02);
+
+ /* Bring out of digital reset */
+ regmap_update_bits(rm, WSA881X_CDC_RST_CTL, 0x01, 0x01);
+ regmap_update_bits(rm, WSA881X_CLOCK_CONFIG, 0x10, 0x10);
+ regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x02, 0x02);
+ regmap_update_bits(rm, WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80);
+ regmap_update_bits(rm, WSA881X_SPKR_MISC_CTL1, 0x06, 0x06);
+ regmap_update_bits(rm, WSA881X_SPKR_BIAS_INT, 0xFF, 0x00);
+ regmap_update_bits(rm, WSA881X_SPKR_PA_INT, 0xF0, 0x40);
+ regmap_update_bits(rm, WSA881X_SPKR_PA_INT, 0x0E, 0x0E);
+ regmap_update_bits(rm, WSA881X_BOOST_LOOP_STABILITY, 0x03, 0x03);
+ regmap_update_bits(rm, WSA881X_BOOST_MISC2_CTL, 0xFF, 0x14);
+ regmap_update_bits(rm, WSA881X_BOOST_START_CTL, 0x80, 0x80);
+ regmap_update_bits(rm, WSA881X_BOOST_START_CTL, 0x03, 0x00);
+ regmap_update_bits(rm, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x0C, 0x04);
+ regmap_update_bits(rm, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x03, 0x00);
+
+ regmap_read(rm, WSA881X_OTP_REG_0, &val);
+ if (val)
+ regmap_update_bits(rm, WSA881X_BOOST_PRESET_OUT1, 0xF0, 0x70);
+
+ regmap_update_bits(rm, WSA881X_BOOST_PRESET_OUT2, 0xF0, 0x30);
+ regmap_update_bits(rm, WSA881X_SPKR_DRV_EN, 0x08, 0x08);
+ regmap_update_bits(rm, WSA881X_BOOST_CURRENT_LIMIT, 0x0F, 0x08);
+ regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x30, 0x30);
+ regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x0C, 0x00);
+ regmap_update_bits(rm, WSA881X_OTP_REG_28, 0x3F, 0x3A);
+ regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG1, 0xFF, 0xB2);
+ regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG2, 0xFF, 0x05);
+}
+
+static int wsa881x_component_probe(struct snd_soc_component *comp)
+{
+ struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp);
+
+ snd_soc_component_init_regmap(comp, wsa881x->regmap);
+
+ return 0;
+}
+
+static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kc);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kc->private_value;
+ int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ int val, ret, min_gain, max_gain;
+
+ max_gain = (max - ucontrol->value.integer.value[0]) & mask;
+ /*
+ * Gain has to set incrementally in 4 steps
+ * as per HW sequence
+ */
+ if (max_gain > G_4P5DB)
+ min_gain = G_0DB;
+ else
+ min_gain = max_gain + 3;
+ /*
+ * 1ms delay is needed before change in gain
+ * as per HW requirement.
+ */
+ usleep_range(1000, 1010);
+
+ for (val = min_gain; max_gain <= val; val--) {
+ ret = snd_soc_component_update_bits(comp,
+ WSA881X_SPKR_DRV_GAIN,
+ WSA881X_SPKR_PAG_GAIN_MASK,
+ val << 4);
+ if (ret < 0)
+ dev_err(comp->dev, "Failed to change PA gain");
+
+ usleep_range(1000, 1010);
+ }
+ return 0;
+}
+
+static int wsa881x_get_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_priv *data = snd_soc_component_get_drvdata(comp);
+ struct soc_mixer_control *mixer =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+ ucontrol->value.integer.value[0] = data->port_enable[portidx];
+
+
+ return 0;
+}
+
+static int wsa881x_boost_ctrl(struct snd_soc_component *comp, bool enable)
+{
+ if (enable)
+ snd_soc_component_update_bits(comp, WSA881X_BOOST_EN_CTL,
+ WSA881X_BOOST_EN_MASK,
+ WSA881X_BOOST_EN);
+ else
+ snd_soc_component_update_bits(comp, WSA881X_BOOST_EN_CTL,
+ WSA881X_BOOST_EN_MASK, 0);
+ /*
+ * 1.5ms sleep is needed after boost enable/disable as per
+ * HW requirement
+ */
+ usleep_range(1500, 1510);
+ return 0;
+}
+
+static int wsa881x_set_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_priv *data = snd_soc_component_get_drvdata(comp);
+ struct soc_mixer_control *mixer =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+ if (ucontrol->value.integer.value[0])
+ data->port_enable[portidx] = true;
+ else
+ data->port_enable[portidx] = false;
+
+ if (portidx == WSA881X_PORT_BOOST) /* Boost Switch */
+ wsa881x_boost_ctrl(comp, data->port_enable[portidx]);
+
+ return 0;
+}
+
+static const char * const smart_boost_lvl_text[] = {
+ "6.625 V", "6.750 V", "6.875 V", "7.000 V",
+ "7.125 V", "7.250 V", "7.375 V", "7.500 V",
+ "7.625 V", "7.750 V", "7.875 V", "8.000 V",
+ "8.125 V", "8.250 V", "8.375 V", "8.500 V"
+};
+
+static const struct soc_enum smart_boost_lvl_enum =
+ SOC_ENUM_SINGLE(WSA881X_BOOST_PRESET_OUT1, 0,
+ ARRAY_SIZE(smart_boost_lvl_text),
+ smart_boost_lvl_text);
+
+static const DECLARE_TLV_DB_SCALE(pa_gain, 0, 150, 0);
+
+static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
+ SOC_ENUM("Smart Boost Level", smart_boost_lvl_enum),
+ WSA881X_PA_GAIN_TLV("PA Volume", WSA881X_SPKR_DRV_GAIN,
+ 4, 0xC, 1, pa_gain),
+ SOC_SINGLE_EXT("DAC Switch", WSA881X_PORT_DAC, 0, 1, 0,
+ wsa881x_get_port, wsa881x_set_port),
+ SOC_SINGLE_EXT("COMP Switch", WSA881X_PORT_COMP, 0, 1, 0,
+ wsa881x_get_port, wsa881x_set_port),
+ SOC_SINGLE_EXT("BOOST Switch", WSA881X_PORT_BOOST, 0, 1, 0,
+ wsa881x_get_port, wsa881x_set_port),
+ SOC_SINGLE_EXT("VISENSE Switch", WSA881X_PORT_VISENSE, 0, 1, 0,
+ wsa881x_get_port, wsa881x_set_port),
+};
+
+static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
+ { "RDAC", NULL, "IN" },
+ { "RDAC", NULL, "DCLK" },
+ { "RDAC", NULL, "ACLK" },
+ { "RDAC", NULL, "Bandgap" },
+ { "SPKR PGA", NULL, "RDAC" },
+ { "SPKR", NULL, "SPKR PGA" },
+};
+
+static int wsa881x_visense_txfe_ctrl(struct snd_soc_component *comp,
+ bool enable)
+{
+ struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp);
+
+ if (enable) {
+ regmap_multi_reg_write(wsa881x->regmap, wsa881x_vi_txfe_en_2_0,
+ ARRAY_SIZE(wsa881x_vi_txfe_en_2_0));
+ } else {
+ snd_soc_component_update_bits(comp,
+ WSA881X_SPKR_PROT_FE_VSENSE_VCM,
+ 0x08, 0x08);
+ /*
+ * 200us sleep is needed after visense txfe disable as per
+ * HW requirement.
+ */
+ usleep_range(200, 210);
+ snd_soc_component_update_bits(comp, WSA881X_SPKR_PROT_FE_GAIN,
+ 0x01, 0x00);
+ }
+ return 0;
+}
+
+static int wsa881x_visense_adc_ctrl(struct snd_soc_component *comp,
+ bool enable)
+{
+ snd_soc_component_update_bits(comp, WSA881X_ADC_EN_MODU_V, BIT(7),
+ (enable << 7));
+ snd_soc_component_update_bits(comp, WSA881X_ADC_EN_MODU_I, BIT(7),
+ (enable << 7));
+ return 0;
+}
+
+static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(comp, WSA881X_SPKR_OCP_CTL,
+ WSA881X_SPKR_OCP_MASK,
+ WSA881X_SPKR_OCP_EN);
+ regmap_multi_reg_write(wsa881x->regmap, wsa881x_pre_pmu_pa_2_0,
+ ARRAY_SIZE(wsa881x_pre_pmu_pa_2_0));
+
+ snd_soc_component_update_bits(comp, WSA881X_SPKR_DRV_GAIN,
+ WSA881X_PA_GAIN_SEL_MASK,
+ WSA881X_PA_GAIN_SEL_REG);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (wsa881x->port_prepared[WSA881X_PORT_VISENSE]) {
+ wsa881x_visense_txfe_ctrl(comp, true);
+ snd_soc_component_update_bits(comp,
+ WSA881X_ADC_EN_SEL_IBAIS,
+ 0x07, 0x01);
+ wsa881x_visense_adc_ctrl(comp, true);
+ }
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (wsa881x->port_prepared[WSA881X_PORT_VISENSE]) {
+ wsa881x_visense_adc_ctrl(comp, false);
+ wsa881x_visense_txfe_ctrl(comp, false);
+ }
+
+ snd_soc_component_update_bits(comp, WSA881X_SPKR_OCP_CTL,
+ WSA881X_SPKR_OCP_MASK,
+ WSA881X_SPKR_OCP_EN |
+ WSA881X_SPKR_OCP_HOLD);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("IN"),
+ SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA881X_SPKR_DAC_CTL, 7, 0,
+ NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("DCLK", WSA881X_CDC_DIG_CLK_CTL, 0, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("ACLK", WSA881X_CDC_ANA_CLK_CTL, 0, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("Bandgap", WSA881X_TEMP_OP, 3, 0,
+ NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+};
+
+static int wsa881x_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev);
+ int ret;
+
+ if (wsa881x->stream_prepared) {
+ sdw_disable_stream(wsa881x->sruntime);
+ sdw_deprepare_stream(wsa881x->sruntime);
+ wsa881x->stream_prepared = false;
+ }
+
+
+ ret = sdw_prepare_stream(wsa881x->sruntime);
+ if (ret)
+ return ret;
+
+ /**
+ * NOTE: there is a strict hw requirement about the ordering of port
+ * enables and actual PA enable. PA enable should only happen after
+ * soundwire ports are enabled if not DC on the line is accumulated
+ * resulting in Click/Pop Noise
+ * PA enable/mute are handled as part of DAPM and digital mute.
+ */
+
+ ret = sdw_enable_stream(wsa881x->sruntime);
+ if (ret) {
+ sdw_deprepare_stream(wsa881x->sruntime);
+ return ret;
+ }
+ wsa881x->stream_prepared = true;
+
+ return ret;
+}
+
+static int wsa881x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev);
+ int i;
+
+ wsa881x->active_ports = 0;
+ for (i = 0; i < WSA881X_MAX_SWR_PORTS; i++) {
+ if (!wsa881x->port_enable[i])
+ continue;
+
+ wsa881x->port_config[wsa881x->active_ports] =
+ wsa881x_pconfig[i];
+ wsa881x->active_ports++;
+ }
+
+ return sdw_stream_add_slave(wsa881x->slave, &wsa881x->sconfig,
+ wsa881x->port_config, wsa881x->active_ports,
+ wsa881x->sruntime);
+}
+
+static int wsa881x_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev);
+
+ if (wsa881x->stream_prepared) {
+ sdw_disable_stream(wsa881x->sruntime);
+ sdw_deprepare_stream(wsa881x->sruntime);
+ sdw_stream_remove_slave(wsa881x->slave, wsa881x->sruntime);
+ wsa881x->stream_prepared = false;
+ }
+
+ return 0;
+}
+
+static int wsa881x_set_sdw_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev);
+
+ wsa881x->sruntime = stream;
+
+ return 0;
+}
+
+static int wsa881x_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev);
+
+ if (mute)
+ regmap_update_bits(wsa881x->regmap, WSA881X_SPKR_DRV_EN, 0x80,
+ 0x00);
+ else
+ regmap_update_bits(wsa881x->regmap, WSA881X_SPKR_DRV_EN, 0x80,
+ 0x80);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops wsa881x_dai_ops = {
+ .hw_params = wsa881x_hw_params,
+ .prepare = wsa881x_prepare,
+ .hw_free = wsa881x_hw_free,
+ .mute_stream = wsa881x_digital_mute,
+ .set_sdw_stream = wsa881x_set_sdw_stream,
+};
+
+static struct snd_soc_dai_driver wsa881x_dais[] = {
+ {
+ .name = "SPKR",
+ .id = 0,
+ .playback = {
+ .stream_name = "SPKR Playback",
+ .rate_max = 48000,
+ .rate_min = 48000,
+ .channels_min = 1,
+ .channels_max = 1,
+ },
+ .ops = &wsa881x_dai_ops,
+ },
+};
+
+static const struct snd_soc_component_driver wsa881x_component_drv = {
+ .name = "WSA881x",
+ .probe = wsa881x_component_probe,
+ .controls = wsa881x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa881x_snd_controls),
+ .dapm_widgets = wsa881x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
+ .dapm_routes = wsa881x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
+};
+
+static int wsa881x_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0)
+ wsa881x_init(wsa881x);
+
+ return 0;
+}
+
+static int wsa881x_port_prep(struct sdw_slave *slave,
+ struct sdw_prepare_ch *prepare_ch,
+ enum sdw_port_prep_ops state)
+{
+ struct wsa881x_priv *wsa881x = dev_get_drvdata(&slave->dev);
+
+ if (state == SDW_OPS_PORT_POST_PREP)
+ wsa881x->port_prepared[prepare_ch->num - 1] = true;
+ else
+ wsa881x->port_prepared[prepare_ch->num - 1] = false;
+
+ return 0;
+}
+
+static int wsa881x_bus_config(struct sdw_slave *slave,
+ struct sdw_bus_params *params)
+{
+ sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank),
+ 0x01);
+
+ return 0;
+}
+
+static struct sdw_slave_ops wsa881x_slave_ops = {
+ .update_status = wsa881x_update_status,
+ .bus_config = wsa881x_bus_config,
+ .port_prep = wsa881x_port_prep,
+};
+
+static int wsa881x_probe(struct sdw_slave *pdev,
+ const struct sdw_device_id *id)
+{
+ struct wsa881x_priv *wsa881x;
+
+ wsa881x = devm_kzalloc(&pdev->dev, sizeof(*wsa881x), GFP_KERNEL);
+ if (!wsa881x)
+ return -ENOMEM;
+
+ wsa881x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ if (IS_ERR(wsa881x->sd_n)) {
+ dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
+ return PTR_ERR(wsa881x->sd_n);
+ }
+
+ dev_set_drvdata(&pdev->dev, wsa881x);
+ wsa881x->slave = pdev;
+ wsa881x->dev = &pdev->dev;
+ wsa881x->sconfig.ch_count = 1;
+ wsa881x->sconfig.bps = 1;
+ wsa881x->sconfig.frame_rate = 48000;
+ wsa881x->sconfig.direction = SDW_DATA_DIR_RX;
+ wsa881x->sconfig.type = SDW_STREAM_PDM;
+ pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0);
+ pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
+ gpiod_set_value(wsa881x->sd_n, 1);
+
+ wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
+ if (IS_ERR(wsa881x->regmap)) {
+ dev_err(&pdev->dev, "regmap_init failed\n");
+ return PTR_ERR(wsa881x->regmap);
+ }
+
+ return devm_snd_soc_register_component(&pdev->dev,
+ &wsa881x_component_drv,
+ wsa881x_dais,
+ ARRAY_SIZE(wsa881x_dais));
+}
+
+static const struct sdw_device_id wsa881x_slave_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x2010, 0),
+ SDW_SLAVE_ENTRY(0x0217, 0x2110, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, wsa881x_slave_id);
+
+static struct sdw_driver wsa881x_codec_driver = {
+ .probe = wsa881x_probe,
+ .ops = &wsa881x_slave_ops,
+ .id_table = wsa881x_slave_id,
+ .driver = {
+ .name = "wsa881x-codec",
+ }
+};
+module_sdw_driver(wsa881x_codec_driver);
+
+MODULE_DESCRIPTION("WSA881x codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c
index 4771eb5fbe2a..4b25aca3804f 100644
--- a/sound/soc/dwc/dwc-pcm.c
+++ b/sound/soc/dwc/dwc-pcm.c
@@ -162,7 +162,6 @@ static int dw_pcm_hw_params(struct snd_soc_component *component,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct dw_i2s_dev *dev = runtime->private_data;
- int ret;
switch (params_channels(hw_params)) {
case 2:
@@ -187,18 +186,7 @@ static int dw_pcm_hw_params(struct snd_soc_component *component,
return -EINVAL;
}
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0)
- return ret;
- else
- return 0;
-}
-
-static int dw_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}
static int dw_pcm_trigger(struct snd_soc_component *component,
@@ -256,28 +244,19 @@ static int dw_pcm_new(struct snd_soc_component *component,
{
size_t size = dw_pcm_hardware.buffer_bytes_max;
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+ snd_pcm_set_managed_buffer_all(rtd->pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
NULL, size, size);
return 0;
}
-static void dw_pcm_free(struct snd_soc_component *component,
- struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static const struct snd_soc_component_driver dw_pcm_component = {
.open = dw_pcm_open,
.close = dw_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = dw_pcm_hw_params,
- .hw_free = dw_pcm_hw_free,
.trigger = dw_pcm_trigger,
.pointer = dw_pcm_pointer,
.pcm_construct = dw_pcm_new,
- .pcm_destruct = dw_pcm_free,
};
int dw_pcm_register(struct platform_device *pdev)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 39ea9bda1394..9ce55feaac22 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -256,7 +256,7 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
unsigned int pll_out;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
return 0;
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index d6146de9acd2..79d66224c0a8 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -428,7 +428,6 @@ static void fsl_asrc_dma_pcm_free(struct snd_soc_component *component,
struct snd_soc_component_driver fsl_asrc_component = {
.name = DRV_NAME,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = fsl_asrc_dma_hw_params,
.hw_free = fsl_asrc_dma_hw_free,
.trigger = fsl_asrc_dma_trigger,
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index a1db1bce330f..5faecbeb5497 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -505,15 +505,20 @@ static int fsl_audmix_probe(struct platform_device *pdev)
ARRAY_SIZE(fsl_audmix_dai));
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
- return ret;
+ goto err_disable_pm;
}
priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0);
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret);
+ goto err_disable_pm;
}
+ return 0;
+
+err_disable_pm:
+ pm_runtime_disable(dev);
return ret;
}
@@ -521,6 +526,8 @@ static int fsl_audmix_remove(struct platform_device *pdev)
{
struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
if (priv->pdev)
platform_device_unregister(priv->pdev);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 2868c4f97cb2..13ae089c1911 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -903,7 +903,6 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
dma->dai.name = DRV_NAME;
dma->dai.open = fsl_dma_open;
dma->dai.close = fsl_dma_close;
- dma->dai.ioctl = snd_soc_pcm_lib_ioctl;
dma->dai.hw_params = fsl_dma_hw_params;
dma->dai.hw_free = fsl_dma_hw_free;
dma->dai.pointer = fsl_dma_pointer;
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index b517e4bc1b87..8c3ea7300972 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -958,7 +958,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+ ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED,
+ np->name, sai);
if (ret) {
dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
return ret;
diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
index 71590ca6394b..5ef6881395e0 100644
--- a/sound/soc/fsl/imx-audmix.c
+++ b/sound/soc/fsl/imx-audmix.c
@@ -289,7 +289,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
priv->dai[num_dai + i].ignore_pmdown_time = 1;
priv->dai[num_dai + i].ops = &imx_audmix_be_ops;
- priv->dai_conf[i].of_node = args.np;
+ priv->dai_conf[i].dlc.of_node = args.np;
priv->dai_conf[i].name_prefix = dai_name;
priv->dapm_routes[i].source =
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 08131d147983..f20d5b1c3848 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -338,7 +338,6 @@ static void snd_imx_pcm_free(struct snd_soc_component *component,
static const struct snd_soc_component_driver imx_soc_component_fiq = {
.open = snd_imx_open,
.close = snd_imx_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = snd_imx_pcm_hw_params,
.prepare = snd_imx_pcm_prepare,
.trigger = snd_imx_pcm_trigger,
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 5237ac96b756..ed7211d744b3 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -360,7 +360,6 @@ static const struct snd_soc_component_driver mpc5200_audio_dma_component = {
.open = psc_dma_open,
.close = psc_dma_close,
.hw_free = psc_dma_hw_free,
- .ioctl = snd_soc_pcm_lib_ioctl,
.pointer = psc_dma_pointer,
.trigger = psc_dma_trigger,
.hw_params = psc_dma_hw_params,
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 10b82bf043d1..55e9f8800b3e 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -371,6 +371,7 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
do {
struct asoc_simple_data adata;
struct device_node *codec;
+ struct device_node *plat;
struct device_node *np;
int num = of_get_child_count(node);
@@ -381,6 +382,9 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
ret = -ENODEV;
goto error;
}
+ /* get platform */
+ plat = of_get_child_by_name(node, is_top ?
+ PREFIX "plat" : "plat");
/* get convert-xxx property */
memset(&adata, 0, sizeof(adata));
@@ -389,6 +393,8 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
/* loop for all CPU/Codec node */
for_each_child_of_node(node, np) {
+ if (plat == np)
+ continue;
/*
* It is DPCM
* if it has many CPUs,
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 47e3d1943d7e..340bd2be39a7 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -387,27 +387,6 @@ static int sst_media_prepare(struct snd_pcm_substream *substream,
return ret_val;
}
-static int sst_media_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- int ret;
-
- ret =
- snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(params));
- if (ret)
- return ret;
- memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
- return 0;
-}
-
-static int sst_media_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static int sst_enable_ssp(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -473,8 +452,6 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = {
.startup = sst_media_open,
.shutdown = sst_media_close,
.prepare = sst_media_prepare,
- .hw_params = sst_media_hw_params,
- .hw_free = sst_media_hw_free,
.mute_stream = sst_media_digital_mute,
};
@@ -677,7 +654,7 @@ static int sst_soc_pcm_new(struct snd_soc_component *component,
if (dai->driver->playback.channels_min ||
dai->driver->capture.channels_min) {
- snd_pcm_lib_preallocate_pages_for_all(pcm,
+ snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_DMA),
SST_MIN_BUFFER, SST_MAX_BUFFER);
@@ -705,7 +682,6 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = {
.probe = sst_soc_probe,
.remove = sst_soc_remove,
.open = sst_soc_open,
- .ioctl = snd_soc_pcm_lib_ioctl,
.trigger = sst_soc_trigger,
.pointer = sst_soc_pointer,
.compr_ops = &sst_platform_compr_ops,
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
index fbecbb74350b..68bcec5241f7 100644
--- a/sound/soc/intel/atom/sst/sst.c
+++ b/sound/soc/intel/atom/sst/sst.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/firmware.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
index 1d780fcc448c..53383055c8dc 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
@@ -102,8 +102,6 @@ static int sst_byt_pcm_hw_params(struct snd_soc_component *component,
return ret;
}
- snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-
ret = sst_byt_stream_buffer(byt, pcm_data->stream,
substream->dma_buffer.addr,
params_buffer_bytes(params));
@@ -121,17 +119,6 @@ static int sst_byt_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
-static int sst_byt_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
- dev_dbg(rtd->dev, "PCM: hw_free\n");
- snd_pcm_lib_free_pages(substream);
-
- return 0;
-}
-
static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -315,9 +302,8 @@ static int sst_byt_pcm_new(struct snd_soc_component *component,
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
size = sst_byt_pcm_hardware.buffer_bytes_max;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- pdata->dma_dev,
- size, size);
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+ pdata->dma_dev, size, size);
}
return 0;
@@ -373,9 +359,7 @@ static const struct snd_soc_component_driver byt_dai_component = {
.probe = sst_byt_pcm_probe,
.open = sst_byt_pcm_open,
.close = sst_byt_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = sst_byt_pcm_hw_params,
- .hw_free = sst_byt_pcm_hw_free,
.trigger = sst_byt_pcm_trigger,
.pointer = sst_byt_pcm_pointer,
.mmap = sst_byt_pcm_mmap,
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index ef20316e83d1..bddf04715f15 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -13,6 +13,19 @@ menuconfig SND_SOC_INTEL_MACH
if SND_SOC_INTEL_MACH
+config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES
+ bool "Use more user friendly long card names"
+ help
+ Some drivers report the I/O configuration to userspace through the
+ soundcard's long card name in the control user space AP. An unfortunate
+ side effect is that this long name may also be used by the GUI,
+ confusing users with information they don't need.
+ This option prevents the long name from being modified, and the I/O
+ configuration will be provided through a different component interface.
+ Select Y if userspace like UCM (Use Case Manager) uses the component
+ interface.
+ If unsure select N.
+
if SND_SOC_INTEL_HASWELL
config SND_SOC_INTEL_HASWELL_MACH
@@ -31,6 +44,18 @@ endif ## SND_SOC_INTEL_HASWELL
if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL
+config SND_SOC_INTEL_BDW_RT5650_MACH
+ tristate "Broadwell with RT5650 codec"
+ depends on I2C
+ depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
+ depends on X86_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5645
+ help
+ This adds the ASoC machine driver for Intel Broadwell platforms with
+ the RT5650 codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
config SND_SOC_INTEL_BDW_RT5677_MACH
tristate "Broadwell with RT5677 codec"
depends on I2C
@@ -261,6 +286,7 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
select SND_SOC_DA7219
select SND_SOC_MAX98357A
select SND_SOC_DMIC
+ select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_HDAC_HDMI
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
@@ -387,6 +413,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
select SND_SOC_RT5682
select SND_SOC_MAX98357A
select SND_SOC_DMIC
+ select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC machine driver for Geminilake platforms
@@ -400,6 +427,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
tristate "SKL/KBL/BXT/APL with HDA Codecs"
+ select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_HDAC_HDMI
select SND_SOC_DMIC
# SND_SOC_HDAC_HDA is already selected
@@ -419,6 +447,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
(SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST))
select SND_SOC_RT5682
select SND_SOC_DMIC
+ select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC machine driver for SOF platforms
@@ -448,6 +477,7 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH
select SND_SOC_RT5682
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
+ select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC
help
This adds support for ASoC machine driver for SOF platform with
RT1011 + RT5682 I2S codec.
@@ -456,4 +486,22 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH
endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK
+if SND_SOC_SOF_JASPERLAKE
+
+config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH
+ tristate "SOF with DA7219 and MAX98373 in I2S Mode"
+ depends on I2C && ACPI
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_DA7219
+ select SND_SOC_MAX98373
+ select SND_SOC_DMIC
+ select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC
+ help
+ This adds support for ASoC machine driver for SOF platforms
+ with DA7219 + MAX98373 I2S audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+endif ## SND_SOC_SOF_JASPERLAKE
+
endif ## SND_SOC_INTEL_MACH
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index ba1aa89db09d..b74ddd49bd39 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -2,6 +2,7 @@
snd-soc-sst-haswell-objs := haswell.o
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
+snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o
snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
snd-soc-sst-broadwell-objs := broadwell.o
snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o
@@ -28,6 +29,7 @@ snd-soc-skl_rt286-objs := skl_rt286.o
snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
+snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
@@ -37,6 +39,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da721
obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
+obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
@@ -58,3 +61,5 @@ 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
obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o
+obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o
+
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
new file mode 100644
index 000000000000..ba3fc1ef900a
--- /dev/null
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ASoC machine driver for Intel Broadwell platforms with RT5650 codec
+ *
+ * Copyright 2019, The Chromium OS Authors. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+#include "../common/sst-dsp.h"
+#include "../haswell/sst-haswell-ipc.h"
+
+#include "../../codecs/rt5645.h"
+
+struct bdw_rt5650_priv {
+ struct gpio_desc *gpio_hp_en;
+ struct snd_soc_component *component;
+};
+
+static const struct snd_soc_dapm_widget bdw_rt5650_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("DMIC Pair1", NULL),
+ SND_SOC_DAPM_MIC("DMIC Pair2", NULL),
+};
+
+static const struct snd_soc_dapm_route bdw_rt5650_map[] = {
+ /* Speakers */
+ {"Speaker", NULL, "SPOL"},
+ {"Speaker", NULL, "SPOR"},
+
+ /* Headset jack connectors */
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN1N", NULL, "Headset Mic"},
+
+ /* Digital MICs
+ * DMIC Pair1 are the two DMICs connected on the DMICN1 connector.
+ * DMIC Pair2 are the two DMICs connected on the DMICN2 connector.
+ * Facing the camera, DMIC Pair1 are on the left side, DMIC Pair2
+ * are on the right side.
+ */
+ {"DMIC L1", NULL, "DMIC Pair1"},
+ {"DMIC R1", NULL, "DMIC Pair1"},
+ {"DMIC L2", NULL, "DMIC Pair2"},
+ {"DMIC R2", NULL, "DMIC Pair2"},
+
+ /* CODEC BE connections */
+ {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+ {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static const struct snd_kcontrol_new bdw_rt5650_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("DMIC Pair1"),
+ SOC_DAPM_PIN_SWITCH("DMIC Pair2"),
+};
+
+
+static struct snd_soc_jack headphone_jack;
+static struct snd_soc_jack mic_jack;
+
+static struct snd_soc_jack_pin headphone_jack_pin = {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+};
+
+static struct snd_soc_jack_pin mic_jack_pin = {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+};
+
+static int broadwell_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);
+
+ /* The ADSP will covert the FE rate to 48k, max 4-channels */
+ rate->min = rate->max = 48000;
+ channels->min = 2;
+ channels->max = 4;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_set_format(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int bdw_rt5650_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;
+
+ /* Workaround: set codec PLL to 19.2MHz that PLL source is
+ * from MCLK(24MHz) to conform 2.4MHz DMIC clock.
+ */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
+ 24000000, 19200000);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ /* The actual MCLK freq is 24MHz. The codec is told that MCLK is
+ * 24.576MHz to satisfy the requirement of rl6231_get_clk_info.
+ * ASRC is enabled on AD and DA filters to ensure good audio quality.
+ */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1, 24576000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static struct snd_soc_ops bdw_rt5650_ops = {
+ .hw_params = bdw_rt5650_hw_params,
+};
+
+#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
+static int bdw_rt5650_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct sst_pdata *pdata = dev_get_platdata(component->dev);
+ struct sst_hsw *broadwell = pdata->dsp;
+ int ret;
+
+ /* Set ADSP SSP port settings
+ * clock_divider = 4 means BCLK = MCLK/5 = 24MHz/5 = 4.8MHz
+ */
+ ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
+ SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+ SST_HSW_DEVICE_TDM_CLOCK_MASTER, 4);
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: failed to set device config\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static int bdw_rt5650_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct bdw_rt5650_priv *bdw_rt5650 =
+ snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1.
+ * The ASRC clock source is clk_i2s1_asrc.
+ */
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_DA_STEREO_FILTER |
+ RT5645_DA_MONO_L_FILTER |
+ RT5645_DA_MONO_R_FILTER |
+ RT5645_AD_STEREO_FILTER |
+ RT5645_AD_MONO_L_FILTER |
+ RT5645_AD_MONO_R_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+
+ /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
+ return ret;
+ }
+
+ /* Create and initialize headphone jack */
+ if (snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+ SND_JACK_HEADPHONE, &headphone_jack,
+ &headphone_jack_pin, 1)) {
+ dev_err(component->dev, "Can't create headphone jack\n");
+ }
+
+ /* Create and initialize mic jack */
+ if (snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
+ &mic_jack, &mic_jack_pin, 1)) {
+ dev_err(component->dev, "Can't create mic jack\n");
+ }
+
+ rt5645_set_jack_detect(component, &headphone_jack, &mic_jack, NULL);
+
+ bdw_rt5650->component = component;
+
+ return 0;
+}
+
+/* broadwell digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEF(dummy,
+ DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+SND_SOC_DAILINK_DEF(fe,
+ DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
+
+SND_SOC_DAILINK_DEF(platform,
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
+
+SND_SOC_DAILINK_DEF(be,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1")));
+
+static struct snd_soc_dai_link bdw_rt5650_dais[] = {
+ /* Front End DAI links */
+ {
+ .name = "System PCM",
+ .stream_name = "System Playback",
+ .dynamic = 1,
+#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
+ .init = bdw_rt5650_rtd_init,
+#endif
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(fe, dummy, platform),
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "Codec",
+ .id = 0,
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = broadwell_ssp0_fixup,
+ .ops = &bdw_rt5650_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .init = bdw_rt5650_init,
+ SND_SOC_DAILINK_REG(dummy, be, dummy),
+ },
+};
+
+/* ASoC machine driver for Broadwell DSP + RT5650 */
+static struct snd_soc_card bdw_rt5650_card = {
+ .name = "bdw-rt5650",
+ .owner = THIS_MODULE,
+ .dai_link = bdw_rt5650_dais,
+ .num_links = ARRAY_SIZE(bdw_rt5650_dais),
+ .dapm_widgets = bdw_rt5650_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(bdw_rt5650_widgets),
+ .dapm_routes = bdw_rt5650_map,
+ .num_dapm_routes = ARRAY_SIZE(bdw_rt5650_map),
+ .controls = bdw_rt5650_controls,
+ .num_controls = ARRAY_SIZE(bdw_rt5650_controls),
+ .fully_routed = true,
+};
+
+static int bdw_rt5650_probe(struct platform_device *pdev)
+{
+ struct bdw_rt5650_priv *bdw_rt5650;
+ struct snd_soc_acpi_mach *mach;
+ int ret;
+
+ bdw_rt5650_card.dev = &pdev->dev;
+
+ /* Allocate driver private struct */
+ bdw_rt5650 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5650_priv),
+ GFP_KERNEL);
+ if (!bdw_rt5650)
+ return -ENOMEM;
+
+ /* override plaform name, if required */
+ mach = (&pdev->dev)->platform_data;
+ ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5650_card,
+ mach->mach_params.platform);
+
+ if (ret)
+ return ret;
+
+ snd_soc_card_set_drvdata(&bdw_rt5650_card, bdw_rt5650);
+
+ return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5650_card);
+}
+
+static struct platform_driver bdw_rt5650_audio = {
+ .probe = bdw_rt5650_probe,
+ .driver = {
+ .name = "bdw-rt5650",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(bdw_rt5650_audio)
+
+/* Module information */
+MODULE_AUTHOR("Ben Zhang <[email protected]>");
+MODULE_DESCRIPTION("Intel Broadwell RT5650 machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bdw-rt5650");
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 46612331f5ea..12a1c5255484 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -360,7 +360,10 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
/* SoC card */
static char codec_name[SND_ACPI_I2C_ID_LEN];
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */
+#endif
+static char components_string[32]; /* = "cfg-spk:* cfg-mic:* */
static int byt_cht_es8316_suspend(struct snd_soc_card *card)
{
@@ -572,11 +575,19 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
}
}
- /* register the soc card */
+ snprintf(components_string, sizeof(components_string),
+ "cfg-spk:%s cfg-mic:%s",
+ (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "1" : "2",
+ mic_name[BYT_CHT_ES8316_MAP(quirk)]);
+ byt_cht_es8316_card.components = components_string;
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic",
(quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo",
mic_name[BYT_CHT_ES8316_MAP(quirk)]);
byt_cht_es8316_card.long_name = long_name;
+#endif
+
+ /* register the soc card */
snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card);
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index dd2b5ad08659..ab586a486839 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -707,13 +707,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_MCLK_EN),
},
{
+ /* Teclast X89 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
},
.driver_data = (void *)(BYT_RT5640_IN3_MAP |
- BYT_RT5640_MCLK_EN |
- BYT_RT5640_SSP0_AIF1),
+ BYT_RT5640_JD_SRC_JD1_IN4P |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_1P0 |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
},
{ /* Toshiba Satellite Click Mini L9W-B */
.matches = {
@@ -1082,7 +1086,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
+#endif
+static char byt_rt5640_components[32]; /* = "cfg-spk:* cfg-mic:*" */
static int byt_rt5640_suspend(struct snd_soc_card *card)
{
@@ -1305,12 +1312,19 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
}
+ snprintf(byt_rt5640_components, sizeof(byt_rt5640_components),
+ "cfg-spk:%s cfg-mic:%s",
+ (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "1" : "2",
+ map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
+ byt_rt5640_card.components = byt_rt5640_components;
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
"bytcr-rt5640-%s-spk-%s-mic",
(byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ?
"mono" : "stereo",
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
byt_rt5640_card.long_name = byt_rt5640_long_name;
+#endif
/* override plaform name, if required */
platform_name = mach->mach_params.platform;
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 4606f6f582d6..c0d322a859f7 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -797,7 +797,10 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */
static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
static char byt_rt5651_long_name[50]; /* = "bytcr-rt5651-*-spk-*-mic[-swapped-hp]" */
+#endif
+static char byt_rt5651_components[50]; /* = "cfg-spk:* cfg-mic:*" */
static int byt_rt5651_suspend(struct snd_soc_card *card)
{
@@ -876,7 +879,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
const char *platform_name;
struct acpi_device *adev;
struct device *codec_dev;
- const char *hp_swapped;
bool is_bytcr = false;
int ret_val = 0;
int dai_index = 0;
@@ -1080,17 +1082,23 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
}
}
- if (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED)
- hp_swapped = "-hp-swapped";
- else
- hp_swapped = "";
-
+ snprintf(byt_rt5651_components, sizeof(byt_rt5651_components),
+ "cfg-spk:%s cfg-mic:%s%s",
+ (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ? "1" : "2",
+ mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
+ (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ?
+ " cfg-hp:lrswap" : "");
+ byt_rt5651_card.components = byt_rt5651_components;
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name),
"bytcr-rt5651-%s-spk-%s-mic%s",
(byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ?
"mono" : "stereo",
- mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped);
+ mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
+ (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ?
+ "-hp-swapped" : "");
byt_rt5651_card.long_name = byt_rt5651_long_name;
+#endif
/* override plaform name, if required */
platform_name = mach->mach_params.platform;
diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c
index a22f97234201..ab1196108d23 100644
--- a/sound/soc/intel/boards/cml_rt1011_rt5682.c
+++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c
@@ -406,19 +406,19 @@ static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = {
static struct snd_soc_codec_conf rt1011_conf[] = {
{
- .dev_name = "i2c-10EC1011:00",
+ .dlc = COMP_CODEC_CONF("i2c-10EC1011:00"),
.name_prefix = "WL",
},
{
- .dev_name = "i2c-10EC1011:01",
+ .dlc = COMP_CODEC_CONF("i2c-10EC1011:01"),
.name_prefix = "WR",
},
{
- .dev_name = "i2c-10EC1011:02",
+ .dlc = COMP_CODEC_CONF("i2c-10EC1011:02"),
.name_prefix = "TL",
},
{
- .dev_name = "i2c-10EC1011:03",
+ .dlc = COMP_CODEC_CONF("i2c-10EC1011:03"),
.name_prefix = "TR",
},
};
diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c
index ed36b68d6705..9179f07f9ee4 100644
--- a/sound/soc/intel/boards/hda_dsp_common.c
+++ b/sound/soc/intel/boards/hda_dsp_common.c
@@ -63,7 +63,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card,
"%s: mapping HDMI converter %d to PCM %d (%p)\n",
__func__, i, hpcm->device, spcm);
} else {
- hpcm->pcm = 0;
+ hpcm->pcm = NULL;
hpcm->device = SNDRV_PCM_INVALID_DEVICE;
dev_warn(card->dev,
"%s: no PCM in topology for HDMI converter %d\n\n",
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 537a88932bb6..0d55319a0773 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -336,19 +336,6 @@ static struct snd_soc_ops kabylake_dmic_ops = {
.startup = kabylake_dmic_startup,
};
-static const unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-
SND_SOC_DAILINK_DEF(dummy,
DAILINK_COMP_ARRAY(COMP_DUMMY()));
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 829f95fc4179..34e734adac19 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -571,12 +571,12 @@ static struct snd_soc_ops skylake_refcap_ops = {
static struct snd_soc_codec_conf max98927_codec_conf[] = {
{
- .dev_name = MAX98927_DEV0_NAME,
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME),
.name_prefix = "Right",
},
{
- .dev_name = MAX98927_DEV1_NAME,
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME),
.name_prefix = "Left",
},
};
@@ -584,12 +584,12 @@ static struct snd_soc_codec_conf max98927_codec_conf[] = {
static struct snd_soc_codec_conf max98373_codec_conf[] = {
{
- .dev_name = MAX98373_DEV0_NAME,
+ .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME),
.name_prefix = "Right",
},
{
- .dev_name = MAX98373_DEV1_NAME,
+ .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME),
.name_prefix = "Left",
},
};
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 7cefda341fbf..cd748d6f4af3 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -229,11 +229,11 @@ static const struct snd_soc_dapm_route kabylake_5663_map[] = {
static struct snd_soc_codec_conf max98927_codec_conf[] = {
{
- .dev_name = MAXIM_DEV0_NAME,
+ .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
.name_prefix = "Right",
},
{
- .dev_name = MAXIM_DEV1_NAME,
+ .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
.name_prefix = "Left",
},
};
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 3e5f6bead229..e2b0a027f5a1 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -193,11 +193,11 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
static struct snd_soc_codec_conf max98927_codec_conf[] = {
{
- .dev_name = MAXIM_DEV0_NAME,
+ .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
.name_prefix = "Right",
},
{
- .dev_name = MAXIM_DEV1_NAME,
+ .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
.name_prefix = "Left",
},
};
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index 4e45901e3a2f..11eaee9ae41f 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -100,6 +100,8 @@ static struct snd_soc_card hda_soc_card = {
.late_probe = skl_hda_card_late_probe,
};
+static char hda_soc_components[30];
+
#define IDISP_DAI_COUNT 3
#define HDAC_DAI_COUNT 2
#define DMIC_DAI_COUNT 2
@@ -183,6 +185,12 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
hda_soc_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&hda_soc_card, ctx);
+ if (mach->mach_params.dmic_num > 0) {
+ snprintf(hda_soc_components, sizeof(hda_soc_components),
+ "cfg-dmics:%d", mach->mach_params.dmic_num);
+ hda_soc_card.components = hda_soc_components;
+ }
+
return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
}
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 1a7ac8bdf543..b96b014e8c9e 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -147,11 +147,11 @@ static const struct snd_soc_dapm_route skylake_map[] = {
static struct snd_soc_codec_conf ssm4567_codec_conf[] = {
{
- .dev_name = "i2c-INT343B:00",
+ .dlc = COMP_CODEC_CONF("i2c-INT343B:00"),
.name_prefix = "Left",
},
{
- .dev_name = "i2c-INT343B:01",
+ .dlc = COMP_CODEC_CONF("i2c-INT343B:01"),
.name_prefix = "Right",
},
};
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
new file mode 100644
index 000000000000..8f44f13d2848
--- /dev/null
+++ b/sound/soc/intel/boards/sof_da7219_max98373.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2019 Intel Corporation.
+
+/*
+ * Intel SOF Machine driver for DA7219 + MAX98373 codec
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/da7219.h"
+#include "../../codecs/da7219-aad.h"
+#include "hda_dsp_common.h"
+
+#define DIALOG_CODEC_DAI "da7219-hifi"
+#define MAX98373_CODEC_DAI "max98373-aif1"
+#define MAXIM_DEV0_NAME "i2c-MX98373:00"
+#define MAXIM_DEV1_NAME "i2c-MX98373:01"
+
+struct hdmi_pcm {
+ struct list_head head;
+ struct snd_soc_dai *codec_dai;
+ int device;
+};
+
+struct card_private {
+ struct snd_soc_jack headset;
+ struct list_head hdmi_pcm_list;
+ struct snd_soc_jack hdmi[3];
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
+ 0, 0);
+ if (ret)
+ dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+ 0, DA7219_PLL_FREQ_OUT_98304);
+ if (ret)
+ dev_err(card->dev, "failed to start PLL: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget 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_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ { "Headphone Jack", NULL, "HPL" },
+ { "Headphone Jack", NULL, "HPR" },
+
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+
+ { "MIC", NULL, "Headset Mic" },
+
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_jack headset;
+
+static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_jack *jack;
+ int ret;
+
+ /* Configure sysclk for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+ return ret;
+ }
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+ &headset, NULL, 0);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ jack = &headset;
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+ da7219_aad_jack_det(component, jack);
+
+ return ret;
+}
+
+static int ssp1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = substream->private_data;
+ int ret, j;
+
+ for (j = 0; j < runtime->num_codecs; j++) {
+ struct snd_soc_dai *codec_dai = runtime->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
+ /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16);
+ if (ret < 0) {
+ dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
+ /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16);
+ if (ret < 0) {
+ dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops ssp1_ops = {
+ .hw_params = ssp1_hw_params,
+};
+
+static struct snd_soc_codec_conf max98373_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
+ .name_prefix = "Left",
+ },
+};
+
+static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai = rtd->codec_dai;
+ struct hdmi_pcm *pcm;
+
+ pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ pcm->device = dai->id;
+ pcm->codec_dai = dai;
+
+ list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+ return 0;
+}
+
+static int card_late_probe(struct snd_soc_card *card)
+{
+ struct card_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_acpi_mach *mach = (card->dev)->platform_data;
+ struct hdmi_pcm *pcm;
+
+ if (mach->mach_params.common_hdmi_codec_drv) {
+ pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
+ head);
+ return hda_dsp_hdmi_build_controls(card,
+ pcm->codec_dai->component);
+ }
+
+ return -EINVAL;
+}
+
+SND_SOC_DAILINK_DEF(ssp0_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
+SND_SOC_DAILINK_DEF(ssp0_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI)));
+
+SND_SOC_DAILINK_DEF(ssp1_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
+SND_SOC_DAILINK_DEF(ssp1_amps,
+ DAILINK_COMP_ARRAY(
+ /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI),
+ /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI)));
+
+SND_SOC_DAILINK_DEF(dmic_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
+SND_SOC_DAILINK_DEF(dmic_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+
+SND_SOC_DAILINK_DEF(idisp1_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
+SND_SOC_DAILINK_DEF(idisp1_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
+
+SND_SOC_DAILINK_DEF(idisp2_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
+SND_SOC_DAILINK_DEF(idisp2_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
+
+SND_SOC_DAILINK_DEF(idisp3_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
+SND_SOC_DAILINK_DEF(idisp3_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
+
+SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
+
+static struct snd_soc_dai_link dais[] = {
+ /* Back End DAI links */
+ {
+ .name = "SSP1-Codec",
+ .id = 0,
+ .ignore_pmdown_time = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1, /* IV feedback */
+ .ops = &ssp1_ops,
+ SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform),
+ },
+ {
+ .name = "SSP0-Codec",
+ .id = 1,
+ .no_pcm = 1,
+ .init = da7219_codec_init,
+ .ignore_pmdown_time = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
+ },
+ {
+ .name = "dmic01",
+ .id = 2,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
+ },
+ {
+ .name = "iDisp1",
+ .id = 3,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
+ },
+ {
+ .name = "iDisp2",
+ .id = 4,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
+ },
+ {
+ .name = "iDisp3",
+ .id = 5,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
+ },
+};
+
+static struct snd_soc_card card_da7219_m98373 = {
+ .name = "da7219max",
+ .owner = THIS_MODULE,
+ .dai_link = dais,
+ .num_links = ARRAY_SIZE(dais),
+ .controls = controls,
+ .num_controls = ARRAY_SIZE(controls),
+ .dapm_widgets = widgets,
+ .num_dapm_widgets = ARRAY_SIZE(widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+ .codec_conf = max98373_codec_conf,
+ .num_configs = ARRAY_SIZE(max98373_codec_conf),
+ .fully_routed = true,
+ .late_probe = card_late_probe,
+};
+
+static int audio_probe(struct platform_device *pdev)
+{
+ static struct snd_soc_card *card;
+ struct snd_soc_acpi_mach *mach;
+ struct card_private *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ card = (struct snd_soc_card *)pdev->id_entry->driver_data;
+ card->dev = &pdev->dev;
+
+ mach = (&pdev->dev)->platform_data;
+ ret = snd_soc_fixup_dai_links_platform_name(card,
+ mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ snd_soc_card_set_drvdata(card, ctx);
+
+ return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+static const struct platform_device_id board_ids[] = {
+ {
+ .name = "sof_da7219_max98373",
+ .driver_data = (kernel_ulong_t)&card_da7219_m98373,
+ },
+ { }
+};
+
+static struct platform_driver audio = {
+ .probe = audio_probe,
+ .driver = {
+ .name = "sof_da7219_max98373",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = board_ids,
+};
+module_platform_driver(audio)
+
+/* Module information */
+MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver");
+MODULE_AUTHOR("Yong Zhi <[email protected]>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sof_da7219_max98373");
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 751b8ea6ae1f..8a13231dee15 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -35,6 +35,10 @@
#define SOF_RT5682_SSP_AMP(quirk) \
(((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9)
+#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10
+#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10))
+#define SOF_RT5682_NUM_HDMIDEV(quirk) \
+ ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK)
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
@@ -594,6 +598,19 @@ static int sof_audio_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
+ if (pdev->id_entry && pdev->id_entry->driver_data)
+ sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+ dmi_check_system(sof_rt5682_quirk_table);
+
+ mach = (&pdev->dev)->platform_data;
+
+ /* A speaker amp might not be present when the quirk claims one is.
+ * Detect this via whether the machine driver match includes quirk_data.
+ */
+ if ((sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data)
+ sof_rt5682_quirk &= ~SOF_SPEAKER_AMP_PRESENT;
+
if (soc_intel_is_byt() || soc_intel_is_cht()) {
is_legacy_cpu = 1;
dmic_be_num = 0;
@@ -604,11 +621,13 @@ static int sof_audio_probe(struct platform_device *pdev)
SOF_RT5682_SSP_CODEC(2);
} else {
dmic_be_num = 2;
- hdmi_num = 3;
+ hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >>
+ SOF_RT5682_NUM_HDMIDEV_SHIFT;
+ /* default number of HDMI DAI's */
+ if (!hdmi_num)
+ hdmi_num = 3;
}
- dmi_check_system(sof_rt5682_quirk_table);
-
/* need to get main clock from pmc */
if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
@@ -652,7 +671,6 @@ static int sof_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
sof_audio_card_rt5682.dev = &pdev->dev;
- mach = (&pdev->dev)->platform_data;
/* set platform name for each dailink */
ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682,
@@ -683,6 +701,21 @@ static int sof_rt5682_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id board_ids[] = {
+ {
+ .name = "sof_rt5682",
+ },
+ {
+ .name = "tgl_max98357a_rt5682",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_RT5682_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_RT5682_SSP_AMP(1) |
+ SOF_RT5682_NUM_HDMIDEV(4)),
+ },
+ { }
+};
+
static struct platform_driver sof_audio = {
.probe = sof_audio_probe,
.remove = sof_rt5682_remove,
@@ -690,6 +723,7 @@ static struct platform_driver sof_audio = {
.name = "sof_rt5682",
.pm = &snd_soc_pm_ops,
},
+ .id_table = board_ids,
};
module_platform_driver(sof_audio)
@@ -699,3 +733,4 @@ MODULE_AUTHOR("Bard Liao <[email protected]>");
MODULE_AUTHOR("Sathya Prakash M R <[email protected]>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sof_rt5682");
+MODULE_ALIAS("platform:tgl_max98357a_rt5682");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
index 5d08ae066738..fb9ba8819706 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -9,45 +9,52 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-static struct snd_soc_acpi_codecs cml_codecs = {
+static struct snd_soc_acpi_codecs rt1011_spk_codecs = {
.num_codecs = 1,
- .codecs = {"10EC5682"}
+ .codecs = {"10EC1011"}
};
-static struct snd_soc_acpi_codecs cml_spk_codecs = {
+static struct snd_soc_acpi_codecs max98357a_spk_codecs = {
.num_codecs = 1,
.codecs = {"MX98357A"}
};
+/*
+ * The order of the three entries with .id = "10EC5682" matters
+ * here, because DSDT tables expose an ACPI HID for the MAX98357A
+ * speaker amplifier which is not populated on the board.
+ */
struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
{
- .id = "DLGS7219",
- .drv_name = "cml_da7219_max98357a",
- .quirk_data = &cml_spk_codecs,
+ .id = "10EC5682",
+ .drv_name = "cml_rt1011_rt5682",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rt1011_spk_codecs,
.sof_fw_filename = "sof-cml.ri",
- .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg",
+ .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
},
{
- .id = "MX98357A",
+ .id = "10EC5682",
.drv_name = "sof_rt5682",
- .quirk_data = &cml_codecs,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &max98357a_spk_codecs,
.sof_fw_filename = "sof-cml.ri",
.sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg",
},
{
- .id = "10EC1011",
- .drv_name = "cml_rt1011_rt5682",
- .quirk_data = &cml_codecs,
- .sof_fw_filename = "sof-cml.ri",
- .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
- },
- {
.id = "10EC5682",
.drv_name = "sof_rt5682",
.sof_fw_filename = "sof-cml.ri",
.sof_tplg_filename = "sof-cml-rt5682.tplg",
},
-
+ {
+ .id = "DLGS7219",
+ .drv_name = "cml_da7219_max98357a",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &max98357a_spk_codecs,
+ .sof_fw_filename = "sof-cml.ri",
+ .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
index 34eb0baaa951..35958553652e 100644
--- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
@@ -30,6 +30,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
.sof_tplg_filename = "sof-bdw-rt286.tplg",
},
{
+ .id = "10EC5650",
+ .drv_name = "bdw-rt5650",
+ .fw_filename = "intel/IntcSST2.bin",
+ .sof_fw_filename = "sof-bdw.ri",
+ .sof_tplg_filename = "sof-bdw-rt5650.tplg",
+ },
+ {
.id = "RT5677CE",
.drv_name = "bdw-rt5677",
.fw_filename = "intel/IntcSST2.bin",
diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
index 1c68a04f0c6e..ed2b125f6a11 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -10,6 +10,13 @@
#include <sound/soc-acpi-intel-match.h>
struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
+ {
+ .id = "DLGS7219",
+ .drv_name = "sof_da7219_max98373",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .sof_fw_filename = "sof-jsl.ri",
+ .sof_tplg_filename = "sof-jsl-da7219.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
index 57a6298d6dca..b4687a5d1962 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -9,6 +9,11 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+static struct snd_soc_acpi_codecs tgl_codecs = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
{
.id = "10EC1308",
@@ -16,6 +21,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
.sof_fw_filename = "sof-tgl.ri",
.sof_tplg_filename = "sof-tgl-rt1308.tplg",
},
+ {
+ .id = "10EC5682",
+ .drv_name = "tgl_max98357a_rt5682",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &tgl_codecs,
+ .sof_fw_filename = "sof-tgl.ri",
+ .sof_tplg_filename = "sof-tgl-max98357a-rt5682.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines);
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c
index a3a5bba2fbd9..033d7c05d7fb 100644
--- a/sound/soc/intel/haswell/sst-haswell-pcm.c
+++ b/sound/soc/intel/haswell/sst-haswell-pcm.c
@@ -592,13 +592,6 @@ static int hsw_pcm_hw_params(struct snd_soc_component *component,
return ret;
}
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (ret < 0) {
- dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
- params_buffer_bytes(params), ret);
- return ret;
- }
-
dmab = snd_pcm_get_dma_buf(substream);
ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
@@ -656,13 +649,6 @@ static int hsw_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
-static int hsw_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- snd_pcm_lib_free_pages(substream);
- return 0;
-}
-
static int hsw_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
@@ -930,7 +916,7 @@ static int hsw_pcm_new(struct snd_soc_component *component,
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
- snd_pcm_lib_preallocate_pages_for_all(pcm,
+ snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_DEV_SG,
dev,
hsw_pcm_hardware.buffer_bytes_max,
@@ -1114,10 +1100,8 @@ static const struct snd_soc_component_driver hsw_dai_component = {
.open = hsw_pcm_open,
.close = hsw_pcm_close,
.hw_params = hsw_pcm_hw_params,
- .hw_free = hsw_pcm_hw_free,
.trigger = hsw_pcm_trigger,
.pointer = hsw_pcm_pointer,
- .ioctl = snd_soc_pcm_lib_ioctl,
.pcm_construct = hsw_pcm_new,
.controls = hsw_volume_controls,
.num_controls = ARRAY_SIZE(hsw_volume_controls),
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 8b9abb79a69e..355165fd6b6a 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -77,13 +77,7 @@ static int skl_substream_alloc_pages(struct hdac_bus *bus,
hdac_stream(stream)->period_bytes = 0;
hdac_stream(stream)->format_val = 0;
- return snd_pcm_lib_malloc_pages(substream, size);
-}
-
-static int skl_substream_free_pages(struct hdac_bus *bus,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}
static void skl_set_pcm_constrains(struct hdac_bus *bus,
@@ -385,7 +379,6 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct skl_dev *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig;
@@ -405,7 +398,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
snd_hdac_stream_cleanup(hdac_stream(stream));
hdac_stream(stream)->prepared = 0;
- return skl_substream_free_pages(bus, substream);
+ return 0;
}
static int skl_be_hw_params(struct snd_pcm_substream *substream,
@@ -1289,12 +1282,6 @@ static int skl_platform_soc_get_time_info(
return 0;
}
-static void skl_platform_soc_free(struct snd_soc_component *component,
- struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
static int skl_platform_soc_new(struct snd_soc_component *component,
@@ -1312,10 +1299,10 @@ static int skl_platform_soc_new(struct snd_soc_component *component,
size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
if (size > MAX_PREALLOC_SIZE)
size = MAX_PREALLOC_SIZE;
- snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_DEV_SG,
- &skl->pci->dev,
- size, MAX_PREALLOC_SIZE);
+ snd_pcm_set_managed_buffer_all(pcm,
+ SNDRV_DMA_TYPE_DEV_SG,
+ &skl->pci->dev,
+ size, MAX_PREALLOC_SIZE);
}
return 0;
@@ -1477,13 +1464,11 @@ static const struct snd_soc_component_driver skl_component = {
.probe = skl_platform_soc_probe,
.remove = skl_platform_soc_remove,
.open = skl_platform_soc_open,
- .ioctl = snd_soc_pcm_lib_ioctl,
.trigger = skl_platform_soc_trigger,
.pointer = skl_platform_soc_pointer,
.get_time_info = skl_platform_soc_get_time_info,
.mmap = skl_platform_soc_mmap,
.pcm_construct = skl_platform_soc_new,
- .pcm_destruct = skl_platform_soc_free,
.module_get_upon_open = 1, /* increment refcount when a pcm is opened */
};
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 58ba3e9469ba..f755ca2484cf 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -773,11 +773,6 @@ static void skl_codec_create(struct hdac_bus *bus)
}
}
-static const struct hdac_bus_ops bus_core_ops = {
- .command = snd_hdac_bus_send_cmd,
- .get_response = snd_hdac_bus_get_response,
-};
-
static int skl_i915_init(struct hdac_bus *bus)
{
int err;
@@ -888,7 +883,7 @@ static int skl_create(struct pci_dev *pci,
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
ext_ops = snd_soc_hdac_hda_get_ops();
#endif
- snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, ext_ops);
+ snd_hdac_ext_bus_init(bus, &pci->dev, NULL, ext_ops);
bus->use_posbuf = 1;
skl->pci = pci;
INIT_WORK(&skl->probe_work, skl_probe_work);
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index e28fb3449f1d..f882b4003edf 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -316,7 +316,6 @@ const struct snd_soc_component_driver kirkwood_soc_component = {
.name = DRV_NAME,
.open = kirkwood_dma_open,
.close = kirkwood_dma_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = kirkwood_dma_hw_params,
.hw_free = kirkwood_dma_hw_free,
.prepare = kirkwood_dma_prepare,
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index 10ea4fdbeb1e..8f314e15ce73 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -6,11 +6,13 @@
* Author: Garlic Tseng <[email protected]>
*/
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "mtk-afe-platform-driver.h"
+#include <sound/pcm_params.h>
#include "mtk-afe-fe-dai.h"
#include "mtk-base-afe.h"
@@ -120,50 +122,60 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
- int msb_at_bit33 = 0;
- int ret, fs = 0;
-
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (ret < 0)
+ int id = rtd->cpu_dai->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int ret;
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+ snd_pcm_format_t format = params_format(params);
+
+ if (afe->request_dram_resource)
+ afe->request_dram_resource(afe->dev);
+
+ dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n",
+ __func__, memif->data->name,
+ channels, rate, format,
+ &substream->runtime->dma_addr,
+ substream->runtime->dma_area,
+ substream->runtime->dma_bytes);
+
+ memset_io(substream->runtime->dma_area, 0,
+ substream->runtime->dma_bytes);
+
+ /* set addr */
+ ret = mtk_memif_set_addr(afe, id,
+ substream->runtime->dma_area,
+ substream->runtime->dma_addr,
+ substream->runtime->dma_bytes);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n",
+ __func__, id, ret);
return ret;
-
- msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0;
- memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
- memif->buffer_size = substream->runtime->dma_bytes;
-
- /* start */
- mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
- memif->phys_buf_addr);
- /* end */
- mtk_regmap_write(afe->regmap,
- memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
- memif->phys_buf_addr + memif->buffer_size - 1);
-
- /* set MSB to 33-bit */
- mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
- 1, msb_at_bit33, memif->data->msb_shift);
+ }
/* set channel */
- if (memif->data->mono_shift >= 0) {
- unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
-
- mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
- 1, mono, memif->data->mono_shift);
+ ret = mtk_memif_set_channel(afe, id, channels);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n",
+ __func__, id, channels, ret);
+ return ret;
}
/* set rate */
- if (memif->data->fs_shift < 0)
- return 0;
-
- fs = afe->memif_fs(substream, params_rate(params));
-
- if (fs < 0)
- return -EINVAL;
+ ret = mtk_memif_set_rate_substream(substream, id, rate);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n",
+ __func__, id, rate, ret);
+ return ret;
+ }
- mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
- memif->data->fs_maskbit, fs,
- memif->data->fs_shift);
+ /* set format */
+ ret = mtk_memif_set_format(afe, id, format);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n",
+ __func__, id, format, ret);
+ return ret;
+ }
return 0;
}
@@ -172,7 +184,12 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);
int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- return snd_pcm_lib_free_pages(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (afe->release_dram_resource)
+ afe->release_dram_resource(afe->dev);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
@@ -182,20 +199,25 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+ int id = rtd->cpu_dai->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
const struct mtk_base_irq_data *irq_data = irqs->irq_data;
unsigned int counter = runtime->period_size;
int fs;
+ int ret;
dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
- mtk_regmap_update_bits(afe->regmap,
- memif->data->enable_reg,
- 1, 1, memif->data->enable_shift);
+ ret = mtk_memif_set_enable(afe, id);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+ __func__, id, ret);
+ return ret;
+ }
/* set irq counter */
mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
@@ -219,15 +241,19 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
- 1, 0, memif->data->enable_shift);
+ ret = mtk_memif_set_disable(afe, id);
+ if (ret) {
+ dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+ __func__, id, ret);
+ }
+
/* disable interrupt */
mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
1, 0, irq_data->irq_en_shift);
/* and clear pending IRQ */
mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
1 << irq_data->irq_clr_shift);
- return 0;
+ return ret;
default:
return -EINVAL;
}
@@ -239,34 +265,15 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
- int hd_audio = 0;
- int hd_align = 0;
+ int id = rtd->cpu_dai->id;
+ int pbuf_size;
- /* set hd mode */
- switch (substream->runtime->format) {
- case SNDRV_PCM_FORMAT_S16_LE:
- hd_audio = 0;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- hd_audio = 1;
- hd_align = 1;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- hd_audio = 1;
- break;
- default:
- dev_err(afe->dev, "%s() error: unsupported format %d\n",
- __func__, substream->runtime->format);
- break;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (afe->get_memif_pbuf_size) {
+ pbuf_size = afe->get_memif_pbuf_size(substream);
+ mtk_memif_set_pbuf_size(afe, id, pbuf_size);
+ }
}
-
- mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
- 1, hd_audio, memif->data->hd_shift);
-
- mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
- 1, hd_align, memif->data->hd_align_mshift);
-
return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
@@ -361,6 +368,222 @@ int mtk_afe_dai_resume(struct snd_soc_dai *dai)
}
EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
+int mtk_memif_set_enable(struct mtk_base_afe *afe, int id)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+
+ if (memif->data->enable_shift < 0) {
+ dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",
+ __func__, id);
+ return 0;
+ }
+ return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
+ 1, 1, memif->data->enable_shift);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_enable);
+
+int mtk_memif_set_disable(struct mtk_base_afe *afe, int id)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+
+ if (memif->data->enable_shift < 0) {
+ dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",
+ __func__, id);
+ return 0;
+ }
+ return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
+ 1, 0, memif->data->enable_shift);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_disable);
+
+int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
+ unsigned char *dma_area,
+ dma_addr_t dma_addr,
+ size_t dma_bytes)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0;
+ unsigned int phys_buf_addr = lower_32_bits(dma_addr);
+ unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr);
+
+ memif->dma_area = dma_area;
+ memif->dma_addr = dma_addr;
+ memif->dma_bytes = dma_bytes;
+
+ /* start */
+ mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
+ phys_buf_addr);
+ /* end */
+ if (memif->data->reg_ofs_end)
+ mtk_regmap_write(afe->regmap,
+ memif->data->reg_ofs_end,
+ phys_buf_addr + dma_bytes - 1);
+ else
+ mtk_regmap_write(afe->regmap,
+ memif->data->reg_ofs_base +
+ AFE_BASE_END_OFFSET,
+ phys_buf_addr + dma_bytes - 1);
+
+ /* set start, end, upper 32 bits */
+ if (memif->data->reg_ofs_base_msb) {
+ mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb,
+ phys_buf_addr_upper_32);
+ mtk_regmap_write(afe->regmap,
+ memif->data->reg_ofs_end_msb,
+ phys_buf_addr_upper_32);
+ }
+
+ /* set MSB to 33-bit */
+ if (memif->data->msb_reg >= 0)
+ mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
+ 1, msb_at_bit33, memif->data->msb_shift);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_addr);
+
+int mtk_memif_set_channel(struct mtk_base_afe *afe,
+ int id, unsigned int channel)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ unsigned int mono;
+
+ if (memif->data->mono_shift < 0)
+ return 0;
+
+ if (memif->data->quad_ch_mask) {
+ unsigned int quad_ch = (channel == 4) ? 1 : 0;
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg,
+ memif->data->quad_ch_mask,
+ quad_ch, memif->data->quad_ch_shift);
+ }
+
+ if (memif->data->mono_invert)
+ mono = (channel == 1) ? 0 : 1;
+ else
+ mono = (channel == 1) ? 1 : 0;
+
+ return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
+ 1, mono, memif->data->mono_shift);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_channel);
+
+static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe,
+ int id, int fs)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+
+ if (memif->data->fs_shift >= 0)
+ mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
+ memif->data->fs_maskbit,
+ fs, memif->data->fs_shift);
+
+ return 0;
+}
+
+int mtk_memif_set_rate(struct mtk_base_afe *afe,
+ int id, unsigned int rate)
+{
+ int fs = 0;
+
+ if (!afe->get_dai_fs) {
+ dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ fs = afe->get_dai_fs(afe, id, rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ return mtk_memif_set_rate_fs(afe, id, fs);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_rate);
+
+int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
+ int id, unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ int fs = 0;
+
+ if (!afe->memif_fs) {
+ dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ fs = afe->memif_fs(substream, rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ return mtk_memif_set_rate_fs(afe, id, fs);
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream);
+
+int mtk_memif_set_format(struct mtk_base_afe *afe,
+ int id, snd_pcm_format_t format)
+{
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int hd_audio = 0;
+ int hd_align = 0;
+
+ /* set hd mode */
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_U16_LE:
+ hd_audio = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_U32_LE:
+ hd_audio = 1;
+ hd_align = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ hd_audio = 1;
+ break;
+ default:
+ dev_err(afe->dev, "%s() error: unsupported format %d\n",
+ __func__, format);
+ break;
+ }
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 1, hd_audio, memif->data->hd_shift);
+
+ mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
+ 1, hd_align, memif->data->hd_align_mshift);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_format);
+
+int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,
+ int id, int pbuf_size)
+{
+ const struct mtk_base_memif_data *memif_data = afe->memif[id].data;
+
+ if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0)
+ return 0;
+
+ mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg,
+ memif_data->pbuf_mask,
+ pbuf_size, memif_data->pbuf_shift);
+
+ mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg,
+ memif_data->minlen_mask,
+ pbuf_size, memif_data->minlen_shift);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size);
+
MODULE_DESCRIPTION("Mediatek simple fe dai operator");
MODULE_AUTHOR("Garlic Tseng <[email protected]>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
index 55074fb9861a..507e3e7c3c7d 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
@@ -34,4 +34,20 @@ int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id);
int mtk_afe_dai_suspend(struct snd_soc_dai *dai);
int mtk_afe_dai_resume(struct snd_soc_dai *dai);
+int mtk_memif_set_enable(struct mtk_base_afe *afe, int id);
+int mtk_memif_set_disable(struct mtk_base_afe *afe, int id);
+int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
+ unsigned char *dma_area,
+ dma_addr_t dma_addr,
+ size_t dma_bytes);
+int mtk_memif_set_channel(struct mtk_base_afe *afe,
+ int id, unsigned int channel);
+int mtk_memif_set_rate(struct mtk_base_afe *afe,
+ int id, unsigned int rate);
+int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
+ int id, unsigned int rate);
+int mtk_memif_set_format(struct mtk_base_afe *afe,
+ int id, snd_pcm_format_t format);
+int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,
+ int id, int pbuf_size);
#endif
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index b6624d8d084b..44dfef713905 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -120,25 +120,16 @@ int mtk_afe_pcm_new(struct snd_soc_component *component,
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
size = afe->mtk_afe_hardware->buffer_bytes_max;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- afe->dev, size, size);
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+ afe->dev, size, size);
return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
-void mtk_afe_pcm_free(struct snd_soc_component *component,
- struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
-
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
.name = AFE_PCM_NAME,
- .ioctl = snd_soc_pcm_lib_ioctl,
.pointer = mtk_afe_pcm_pointer,
.pcm_construct = mtk_afe_pcm_new,
- .pcm_destruct = mtk_afe_pcm_free,
};
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
index e550d11568c3..fcc923b88f12 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -21,8 +21,6 @@ snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
int mtk_afe_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd);
-void mtk_afe_pcm_free(struct snd_soc_component *component,
- struct snd_pcm *pcm);
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe);
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component);
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index 60cb609a9790..a8cf44d98244 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -16,21 +16,38 @@ struct mtk_base_memif_data {
const char *name;
int reg_ofs_base;
int reg_ofs_cur;
+ int reg_ofs_end;
+ int reg_ofs_base_msb;
+ int reg_ofs_cur_msb;
+ int reg_ofs_end_msb;
int fs_reg;
int fs_shift;
int fs_maskbit;
int mono_reg;
int mono_shift;
+ int mono_invert;
+ int quad_ch_reg;
+ int quad_ch_mask;
+ int quad_ch_shift;
int enable_reg;
int enable_shift;
int hd_reg;
- int hd_align_reg;
int hd_shift;
+ int hd_align_reg;
int hd_align_mshift;
int msb_reg;
int msb_shift;
+ int msb2_reg;
+ int msb2_shift;
int agent_disable_reg;
int agent_disable_shift;
+ /* playback memif only */
+ int pbuf_reg;
+ int pbuf_mask;
+ int pbuf_shift;
+ int minlen_reg;
+ int minlen_mask;
+ int minlen_shift;
};
struct mtk_base_irq_data {
@@ -84,6 +101,12 @@ struct mtk_base_afe {
unsigned int rate);
int (*irq_fs)(struct snd_pcm_substream *substream,
unsigned int rate);
+ int (*get_dai_fs)(struct mtk_base_afe *afe,
+ int dai_id, unsigned int rate);
+ int (*get_memif_pbuf_size)(struct snd_pcm_substream *substream);
+
+ int (*request_dram_resource)(struct device *dev);
+ int (*release_dram_resource)(struct device *dev);
void *platform_priv;
};
@@ -95,6 +118,9 @@ struct mtk_base_afe_memif {
const struct mtk_base_memif_data *data;
int irq_usage;
int const_irq;
+ unsigned char *dma_area;
+ dma_addr_t dma_addr;
+ size_t dma_bytes;
};
struct mtk_base_afe_irq {
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
index 2b490ae2e642..668fef3e319a 100644
--- a/sound/soc/mediatek/common/mtk-btcvsd.c
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -1271,7 +1271,6 @@ static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = {
.probe = mtk_btcvsd_snd_component_probe,
.open = mtk_pcm_btcvsd_open,
.close = mtk_pcm_btcvsd_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = mtk_pcm_btcvsd_hw_params,
.hw_free = mtk_pcm_btcvsd_hw_free,
.prepare = mtk_pcm_btcvsd_prepare,
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 033c07fb599c..378bfc16ef52 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -712,10 +712,8 @@ static int mt6797_afe_component_probe(struct snd_soc_component *component)
static const struct snd_soc_component_driver mt6797_afe_component = {
.name = AFE_PCM_NAME,
.probe = mt6797_afe_component_probe,
- .ioctl = snd_soc_pcm_lib_ioctl,
.pointer = mtk_afe_pcm_pointer,
.pcm_construct = mtk_afe_pcm_new,
- .pcm_destruct = mtk_afe_pcm_free,
};
static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 8717e87bfe26..2e1e61d8f127 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -209,7 +209,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
"Property 'audio-codec' missing or invalid\n");
return -EINVAL;
}
- mt8173_rt5650_rt5514_codec_conf[0].of_node =
+ mt8173_rt5650_rt5514_codec_conf[0].dlc.of_node =
mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
card->dev = &pdev->dev;
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index 9d4dd9721154..ebcc0b86286b 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -265,7 +265,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
"Property 'audio-codec' missing or invalid\n");
return -EINVAL;
}
- mt8173_rt5650_rt5676_codec_conf[0].of_node =
+ mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codecs->of_node =
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
index 76af09d8f1af..6e2270bbb10e 100644
--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
@@ -1050,10 +1050,8 @@ static int mt8183_afe_component_probe(struct snd_soc_component *component)
static const struct snd_soc_component_driver mt8183_afe_component = {
.name = AFE_PCM_NAME,
.probe = mt8183_afe_component_probe,
- .ioctl = snd_soc_pcm_lib_ioctl,
.pointer = mtk_afe_pcm_pointer,
.pcm_construct = mtk_afe_pcm_new,
- .pcm_destruct = mtk_afe_pcm_free,
};
static int mt8183_dai_memif_register(struct mtk_base_afe *afe)
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 43f99e59a078..c65493721e90 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -367,7 +367,7 @@ static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = {
static struct snd_soc_codec_conf mt6358_codec_conf[] = {
{
- .dev_name = "mt6358-sound",
+ .dlc = COMP_CODEC_CONF("mt6358-sound"),
.name_prefix = "Mt6358",
},
};
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
index d6f3eefb8f09..c12b0d5e8ebf 100644
--- a/sound/soc/meson/axg-fifo.c
+++ b/sound/soc/meson/axg-fifo.c
@@ -34,7 +34,7 @@ static struct snd_pcm_hardware axg_fifo_hw = {
.rate_max = 192000,
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
- .period_bytes_min = AXG_FIFO_MIN_DEPTH,
+ .period_bytes_min = AXG_FIFO_BURST,
.period_bytes_max = UINT_MAX,
.periods_min = 2,
.periods_max = UINT_MAX,
@@ -113,13 +113,10 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
{
struct snd_pcm_runtime *runtime = ss->runtime;
struct axg_fifo *fifo = axg_fifo_data(ss);
+ unsigned int burst_num, period, threshold;
dma_addr_t end_ptr;
- unsigned int burst_num;
- int ret;
- ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(params));
- if (ret < 0)
- return ret;
+ period = params_period_bytes(params);
/* Setup dma memory pointers */
end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
@@ -127,9 +124,24 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
/* Setup interrupt periodicity */
- burst_num = params_period_bytes(params) / AXG_FIFO_BURST;
+ burst_num = period / AXG_FIFO_BURST;
regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
+ /*
+ * Start the fifo request on the smallest of the following:
+ * - Half the fifo size
+ * - Half the period size
+ */
+ threshold = min(period / 2, fifo->depth / 2);
+
+ /*
+ * With the threshold in bytes, register value is:
+ * V = (threshold / burst) - 1
+ */
+ threshold /= AXG_FIFO_BURST;
+ regmap_field_write(fifo->field_threshold,
+ threshold ? threshold - 1 : 0);
+
/* Enable block count irq */
regmap_update_bits(fifo->map, FIFO_CTRL0,
CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
@@ -167,7 +179,7 @@ int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
regmap_update_bits(fifo->map, FIFO_CTRL0,
CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
- return snd_pcm_lib_free_pages(ss);
+ return 0;
}
EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
@@ -215,17 +227,17 @@ int axg_fifo_pcm_open(struct snd_soc_component *component,
/*
* Make sure the buffer and period size are multiple of the FIFO
- * minimum depth size
+ * burst
*/
ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- AXG_FIFO_MIN_DEPTH);
+ AXG_FIFO_BURST);
if (ret)
return ret;
ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- AXG_FIFO_MIN_DEPTH);
+ AXG_FIFO_BURST);
if (ret)
return ret;
@@ -287,9 +299,9 @@ int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
struct snd_card *card = rtd->card->snd_card;
size_t size = axg_fifo_hw.buffer_bytes_max;
- snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream,
- SNDRV_DMA_TYPE_DEV, card->dev,
- size, size);
+ snd_pcm_set_managed_buffer(rtd->pcm->streams[type].substream,
+ SNDRV_DMA_TYPE_DEV, card->dev,
+ size, size);
return 0;
}
EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
@@ -307,6 +319,7 @@ int axg_fifo_probe(struct platform_device *pdev)
const struct axg_fifo_match_data *data;
struct axg_fifo *fifo;
void __iomem *regs;
+ int ret;
data = of_device_get_match_data(dev);
if (!data) {
@@ -352,6 +365,26 @@ int axg_fifo_probe(struct platform_device *pdev)
return fifo->irq;
}
+ fifo->field_threshold =
+ devm_regmap_field_alloc(dev, fifo->map, data->field_threshold);
+ if (IS_ERR(fifo->field_threshold))
+ return PTR_ERR(fifo->field_threshold);
+
+ ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth",
+ &fifo->depth);
+ if (ret) {
+ /* Error out for anything but a missing property */
+ if (ret != -EINVAL)
+ return ret;
+ /*
+ * If the property is missing, it might be because of an old
+ * DT. In such case, assume the smallest known fifo depth
+ */
+ fifo->depth = 256;
+ dev_warn(dev, "fifo depth not found, assume %u bytes\n",
+ fifo->depth);
+ }
+
return devm_snd_soc_register_component(dev, data->component_drv,
data->dai_drv, 1);
}
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
index cf928d43b558..b63acd723c87 100644
--- a/sound/soc/meson/axg-fifo.h
+++ b/sound/soc/meson/axg-fifo.h
@@ -9,7 +9,9 @@
struct clk;
struct platform_device;
+struct reg_field;
struct regmap;
+struct regmap_field;
struct reset_control;
struct snd_soc_component_driver;
@@ -29,8 +31,6 @@ struct snd_soc_pcm_runtime;
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
#define AXG_FIFO_BURST 8
-#define AXG_FIFO_MIN_CNT 64
-#define AXG_FIFO_MIN_DEPTH (AXG_FIFO_BURST * AXG_FIFO_MIN_CNT)
#define FIFO_INT_ADDR_FINISH BIT(0)
#define FIFO_INT_ADDR_INT BIT(1)
@@ -50,8 +50,6 @@ struct snd_soc_pcm_runtime;
#define CTRL1_STATUS2_SEL_MASK GENMASK(11, 8)
#define CTRL1_STATUS2_SEL(x) ((x) << 8)
#define STATUS2_SEL_DDR_READ 0
-#define CTRL1_THRESHOLD_MASK GENMASK(23, 16)
-#define CTRL1_THRESHOLD(x) ((x) << 16)
#define CTRL1_FRDDR_DEPTH_MASK GENMASK(31, 24)
#define CTRL1_FRDDR_DEPTH(x) ((x) << 24)
#define FIFO_START_ADDR 0x08
@@ -67,12 +65,15 @@ struct axg_fifo {
struct regmap *map;
struct clk *pclk;
struct reset_control *arb;
+ struct regmap_field *field_threshold;
+ unsigned int depth;
int irq;
};
struct axg_fifo_match_data {
const struct snd_soc_component_driver *component_drv;
struct snd_soc_dai_driver *dai_drv;
+ struct reg_field field_threshold;
};
int axg_fifo_pcm_open(struct snd_soc_component *component,
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
index 665d75d49d7b..c3ae8ac30745 100644
--- a/sound/soc/meson/axg-frddr.c
+++ b/sound/soc/meson/axg-frddr.c
@@ -50,7 +50,7 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
- unsigned int fifo_depth, fifo_threshold;
+ unsigned int val;
int ret;
/* Enable pclk to access registers and clock the fifo ip */
@@ -61,18 +61,10 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
/* Apply single buffer mode to the interface */
regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
- /*
- * TODO: We could adapt the fifo depth and the fifo threshold
- * depending on the expected memory throughput and lantencies
- * For now, we'll just use the same values as the vendor kernel
- * Depth and threshold are zero based.
- */
- fifo_depth = AXG_FIFO_MIN_CNT - 1;
- fifo_threshold = (AXG_FIFO_MIN_CNT / 2) - 1;
- regmap_update_bits(fifo->map, FIFO_CTRL1,
- CTRL1_FRDDR_DEPTH_MASK | CTRL1_THRESHOLD_MASK,
- CTRL1_FRDDR_DEPTH(fifo_depth) |
- CTRL1_THRESHOLD(fifo_threshold));
+ /* Use all fifo depth */
+ val = (fifo->depth / AXG_FIFO_BURST) - 1;
+ regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
+ CTRL1_FRDDR_DEPTH(val));
return 0;
}
@@ -151,7 +143,6 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = {
.num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes),
.open = axg_fifo_pcm_open,
.close = axg_fifo_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = axg_fifo_pcm_hw_params,
.hw_free = axg_fifo_pcm_hw_free,
.pointer = axg_fifo_pcm_pointer,
@@ -159,8 +150,9 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = {
};
static const struct axg_fifo_match_data axg_frddr_match_data = {
- .component_drv = &axg_frddr_component_drv,
- .dai_drv = &axg_frddr_dai_drv
+ .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
+ .component_drv = &axg_frddr_component_drv,
+ .dai_drv = &axg_frddr_dai_drv
};
static const struct snd_soc_dai_ops g12a_frddr_ops = {
@@ -275,7 +267,6 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = {
.num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
.open = axg_fifo_pcm_open,
.close = axg_fifo_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = g12a_fifo_pcm_hw_params,
.hw_free = axg_fifo_pcm_hw_free,
.pointer = axg_fifo_pcm_pointer,
@@ -283,8 +274,9 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = {
};
static const struct axg_fifo_match_data g12a_frddr_match_data = {
- .component_drv = &g12a_frddr_component_drv,
- .dai_drv = &g12a_frddr_dai_drv
+ .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
+ .component_drv = &g12a_frddr_component_drv,
+ .dai_drv = &g12a_frddr_dai_drv
};
/* On SM1, the output selection in on CTRL2 */
@@ -345,7 +337,6 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = {
.num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
.open = axg_fifo_pcm_open,
.close = axg_fifo_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = g12a_fifo_pcm_hw_params,
.hw_free = axg_fifo_pcm_hw_free,
.pointer = axg_fifo_pcm_pointer,
@@ -353,8 +344,9 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = {
};
static const struct axg_fifo_match_data sm1_frddr_match_data = {
- .component_drv = &sm1_frddr_component_drv,
- .dai_drv = &g12a_frddr_dai_drv
+ .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
+ .component_drv = &sm1_frddr_component_drv,
+ .dai_drv = &g12a_frddr_dai_drv
};
static const struct of_device_id axg_frddr_of_match[] = {
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
index 7fef0b961496..e711abcf8c12 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -89,7 +89,6 @@ static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
- unsigned int fifo_threshold;
int ret;
/* Enable pclk to access registers and clock the fifo ip */
@@ -107,11 +106,6 @@ static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
/* Apply single buffer mode to the interface */
regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_PP_MODE, 0);
- /* TODDR does not have a configurable fifo depth */
- fifo_threshold = AXG_FIFO_MIN_CNT - 1;
- regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_THRESHOLD_MASK,
- CTRL1_THRESHOLD(fifo_threshold));
-
return 0;
}
@@ -183,7 +177,6 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = {
.num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
.open = axg_fifo_pcm_open,
.close = axg_fifo_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = axg_fifo_pcm_hw_params,
.hw_free = axg_fifo_pcm_hw_free,
.pointer = axg_fifo_pcm_pointer,
@@ -191,8 +184,9 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = {
};
static const struct axg_fifo_match_data axg_toddr_match_data = {
- .component_drv = &axg_toddr_component_drv,
- .dai_drv = &axg_toddr_dai_drv
+ .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
+ .component_drv = &axg_toddr_component_drv,
+ .dai_drv = &axg_toddr_dai_drv
};
static const struct snd_soc_dai_ops g12a_toddr_ops = {
@@ -222,7 +216,6 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = {
.num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
.open = axg_fifo_pcm_open,
.close = axg_fifo_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = g12a_fifo_pcm_hw_params,
.hw_free = axg_fifo_pcm_hw_free,
.pointer = axg_fifo_pcm_pointer,
@@ -230,8 +223,9 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = {
};
static const struct axg_fifo_match_data g12a_toddr_match_data = {
- .component_drv = &g12a_toddr_component_drv,
- .dai_drv = &g12a_toddr_dai_drv
+ .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
+ .component_drv = &g12a_toddr_component_drv,
+ .dai_drv = &g12a_toddr_dai_drv
};
static const char * const sm1_toddr_sel_texts[] = {
@@ -292,7 +286,6 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = {
.num_dapm_routes = ARRAY_SIZE(sm1_toddr_dapm_routes),
.open = axg_fifo_pcm_open,
.close = axg_fifo_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = g12a_fifo_pcm_hw_params,
.hw_free = axg_fifo_pcm_hw_free,
.pointer = axg_fifo_pcm_pointer,
@@ -300,8 +293,9 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = {
};
static const struct axg_fifo_match_data sm1_toddr_match_data = {
- .component_drv = &sm1_toddr_component_drv,
- .dai_drv = &g12a_toddr_dai_drv
+ .field_threshold = REG_FIELD(FIFO_CTRL1, 12, 23),
+ .component_drv = &sm1_toddr_component_drv,
+ .dai_drv = &g12a_toddr_dai_drv
};
static const struct of_device_id axg_toddr_of_match[] = {
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 129eb5251a5f..76e054d514a8 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -72,7 +72,7 @@ static int rear_amp_event(struct snd_soc_dapm_widget *widget,
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *component;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
component = rtd->codec_dai->component;
return rear_amp_power(component, SND_SOC_DAPM_EVENT_ON(event));
}
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 54a4c9213e83..287b5da739e5 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -225,7 +225,6 @@ static const struct snd_soc_component_driver mmp_soc_component = {
.name = DRV_NAME,
.open = mmp_pcm_open,
.close = mmp_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = mmp_pcm_hw_params,
.trigger = mmp_pcm_trigger,
.pointer = mmp_pcm_pointer,
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 76fdce54f007..f37ea0fb4f3f 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -873,7 +873,6 @@ static const struct snd_soc_component_driver pxa_ssp_component = {
.pcm_destruct = pxa2xx_soc_pcm_free,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = pxa2xx_soc_pcm_hw_params,
.hw_free = pxa2xx_soc_pcm_hw_free,
.prepare = pxa2xx_soc_pcm_prepare,
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 31e81a6f616f..22fe77955c2c 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -208,7 +208,6 @@ static const struct snd_soc_component_driver pxa_ac97_component = {
.pcm_destruct = pxa2xx_soc_pcm_free,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = pxa2xx_soc_pcm_hw_params,
.hw_free = pxa2xx_soc_pcm_hw_free,
.prepare = pxa2xx_soc_pcm_prepare,
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index e77d707efde7..d9d366a8df11 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -364,7 +364,6 @@ static const struct snd_soc_component_driver pxa_i2s_component = {
.pcm_destruct = pxa2xx_soc_pcm_free,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = pxa2xx_soc_pcm_hw_params,
.hw_free = pxa2xx_soc_pcm_hw_free,
.prepare = pxa2xx_soc_pcm_prepare,
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 07b3455a6f23..2b7839715dd5 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -22,7 +22,6 @@ static const struct snd_soc_component_driver pxa2xx_soc_platform = {
.pcm_destruct = pxa2xx_soc_pcm_free,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = pxa2xx_soc_pcm_hw_params,
.hw_free = pxa2xx_soc_pcm_hw_free,
.prepare = pxa2xx_soc_pcm_prepare,
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 2e8892316423..b05091c283b7 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -543,7 +543,6 @@ static const struct snd_soc_component_driver lpass_component_driver = {
.name = DRV_NAME,
.open = lpass_platform_pcmops_open,
.close = lpass_platform_pcmops_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = lpass_platform_pcmops_hw_params,
.hw_free = lpass_platform_pcmops_hw_free,
.prepare = lpass_platform_pcmops_prepare,
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 8150c10f081e..c0d422d0ab94 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -72,7 +72,7 @@ struct q6asm_dai_data {
long long int sid;
};
-static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
+static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -880,7 +880,6 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.open = q6asm_dai_open,
.hw_params = q6asm_dai_hw_params,
.close = q6asm_dai_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.prepare = q6asm_dai_prepare,
.trigger = q6asm_dai_trigger,
.pointer = q6asm_dai_pointer,
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 28f3cef696e6..3b5547a27aad 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -24,6 +24,9 @@
#define RIGHT_SPK_TDM_TX_MASK 0xC0
#define SPK_TDM_RX_MASK 0x03
#define NUM_TDM_SLOTS 8
+#define SLIM_MAX_TX_PORTS 16
+#define SLIM_MAX_RX_PORTS 16
+#define WCD934X_DEFAULT_MCLK_RATE 9600000
struct sdm845_snd_data {
struct snd_soc_jack jack;
@@ -36,6 +39,39 @@ struct sdm845_snd_data {
static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret = 0, i;
+
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ ret = snd_soc_dai_get_channel_map(rtd->codec_dais[i],
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+
+ if (ret != 0 && ret != -ENOTSUPP) {
+ pr_err("failed to get codec chan map, err:%d\n", ret);
+ return ret;
+ } else if (ret == -ENOTSUPP) {
+ /* Ignore unsupported */
+ continue;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ rx_ch_cnt, rx_ch);
+ else
+ ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
+ tx_ch, 0, NULL);
+ }
+
+ return 0;
+}
+
static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -151,6 +187,11 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
case QUATERNARY_TDM_TX_0:
ret = sdm845_tdm_snd_hw_params(substream, params);
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ ret = sdm845_slim_snd_hw_params(substream, params);
+ break;
+ case QUATERNARY_MI2S_RX:
+ break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
break;
@@ -173,7 +214,20 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
struct snd_jack *jack;
- int rval;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ /*
+ * Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+ int rval, i;
+
if (!pdata->jack_setup) {
rval = snd_soc_card_jack_new(card, "Headset Jack",
@@ -211,6 +265,21 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
return rval;
}
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ rval = snd_soc_dai_set_channel_map(rtd->codec_dais[i],
+ ARRAY_SIZE(tx_ch),
+ tx_ch,
+ ARRAY_SIZE(rx_ch),
+ rx_ch);
+ if (rval != 0 && rval != -ENOTSUPP)
+ return rval;
+
+ snd_soc_dai_set_sysclk(rtd->codec_dais[i], 0,
+ WCD934X_DEFAULT_MCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ break;
default:
break;
}
@@ -257,6 +326,14 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
snd_soc_dai_set_fmt(cpu_dai, fmt);
snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
break;
+ case QUATERNARY_MI2S_RX:
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+
+
+ break;
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
@@ -294,6 +371,8 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
}
}
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
@@ -338,6 +417,9 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
0, SNDRV_PCM_STREAM_PLAYBACK);
}
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ case QUATERNARY_MI2S_RX:
+ break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
@@ -451,6 +533,8 @@ static int sdm845_snd_platform_remove(struct platform_device *pdev)
static const struct of_device_id sdm845_snd_device_id[] = {
{ .compatible = "qcom,sdm845-sndcard" },
+ { .compatible = "qcom,db845c-sndcard" },
+ { .compatible = "lenovo,yoga-c630-sndcard" },
{},
};
MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index b60b2268b608..5de633497f83 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -59,7 +59,7 @@ static int bells_set_bias_level(struct snd_soc_card *card,
struct bells_drvdata *bells = card->drvdata;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]);
codec_dai = rtd->codec_dai;
component = codec_dai->component;
@@ -105,7 +105,7 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
struct bells_drvdata *bells = card->drvdata;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]);
codec_dai = rtd->codec_dai;
component = codec_dai->component;
@@ -151,10 +151,10 @@ static int bells_late_probe(struct snd_soc_card *card)
struct snd_soc_dai *wm9081_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_AP_DSP]);
wm0010 = rtd->codec_dai->component;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]);
component = rtd->codec_dai->component;
aif1_dai = rtd->codec_dai;
@@ -194,7 +194,7 @@ static int bells_late_probe(struct snd_soc_card *card)
return ret;
}
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_CODEC_CP]);
aif2_dai = rtd->cpu_dai;
ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
@@ -206,7 +206,7 @@ static int bells_late_probe(struct snd_soc_card *card)
if (card->num_rtd == DAI_CODEC_SUB)
return 0;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_CODEC_SUB]);
aif3_dai = rtd->cpu_dai;
wm9081_dai = rtd->codec_dai;
@@ -381,7 +381,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = {
static struct snd_soc_codec_conf bells_codec_conf[] = {
{
- .dev_name = "wm9081.1-006c",
+ .dlc = COMP_CODEC_CONF("wm9081.1-006c"),
.name_prefix = "Sub",
},
};
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index 294dce111b05..66bcc2f97544 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -394,7 +394,6 @@ EXPORT_SYMBOL_GPL(idma_reg_addr_init);
static const struct snd_soc_component_driver asoc_idma_platform = {
.open = idma_open,
.close = idma_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.trigger = idma_trigger,
.pointer = idma_pointer,
.mmap = idma_mmap,
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 6132cee8550b..59904f44118b 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -22,7 +22,7 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dai *aif1_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
aif1_dai = rtd->codec_dai;
if (dapm->dev != aif1_dai->dev)
@@ -69,7 +69,7 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dai *aif1_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
aif1_dai = rtd->codec_dai;
if (dapm->dev != aif1_dai->dev)
@@ -180,7 +180,7 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
struct snd_soc_dai *aif2_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
aif2_dai = rtd->cpu_dai;
switch (event) {
@@ -263,11 +263,11 @@ static int littlemill_late_probe(struct snd_soc_card *card)
struct snd_soc_dai *aif2_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
component = rtd->codec_dai->component;
aif1_dai = rtd->codec_dai;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
aif2_dai = rtd->cpu_dai;
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 973f22bcc747..098eefc764db 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -126,7 +126,7 @@ static struct snd_soc_dai_link lowland_dai[] = {
static struct snd_soc_codec_conf lowland_codec_conf[] = {
{
- .dev_name = "wm9081.1-006c",
+ .dlc = COMP_CODEC_CONF("wm9081.1-006c"),
.name_prefix = "Sub",
},
};
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 38f536bafa09..1339e41e9860 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -303,7 +303,7 @@ static struct snd_soc_aux_dev neo1973_aux_devs[] = {
static struct snd_soc_codec_conf neo1973_codec_conf[] = {
{
- .dev_name = "lm4857.0-007c",
+ .dlc = COMP_CODEC_CONF("lm4857.0-007c"),
.name_prefix = "Amp",
},
};
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 8ea7799df028..f075aae9561a 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -106,7 +106,7 @@ static int snow_late_probe(struct snd_soc_card *card)
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *codec_dai;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
/* In the multi-codec case codec_dais 0 is MAX98095 and 1 is HDMI. */
if (rtd->num_codecs > 1)
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 9e58cbed942a..ea0d1ec67f01 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -24,7 +24,7 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
@@ -60,7 +60,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
@@ -247,7 +247,7 @@ static struct snd_soc_aux_dev speyside_aux_dev[] = {
static struct snd_soc_codec_conf speyside_codec_conf[] = {
{
- .dev_name = "wm9081.1-006c",
+ .dlc = COMP_CODEC_CONF("wm9081.1-006c"),
.name_prefix = "Sub",
},
};
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index bb9910d4cbe2..10ff14b856f2 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -282,7 +282,7 @@ static int tm2_set_bias_level(struct snd_soc_card *card,
{
struct snd_soc_pcm_runtime *rtd;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
if (dapm->dev != rtd->codec_dai->dev)
return 0;
@@ -314,7 +314,7 @@ static int tm2_late_probe(struct snd_soc_card *card)
struct snd_soc_dai *aif2_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF1]);
aif1_dai = rtd->codec_dai;
priv->component = rtd->codec_dai->component;
@@ -324,7 +324,7 @@ static int tm2_late_probe(struct snd_soc_card *card)
return ret;
}
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF2]);
aif2_dai = rtd->codec_dai;
ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index ef51f289fbc7..fdce28cc26c4 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -22,7 +22,7 @@ static int tobermory_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
@@ -65,7 +65,7 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
@@ -180,7 +180,7 @@ static int tobermory_late_probe(struct snd_soc_card *card)
struct snd_soc_dai *codec_dai;
int ret;
- rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
component = rtd->codec_dai->component;
codec_dai = rtd->codec_dai;
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 2b0eca02a8b9..eee1a1e994cb 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -179,11 +179,6 @@ static int camelot_hw_params(struct snd_soc_component *component,
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int ret;
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0)
- return ret;
-
if (recv) {
cam->rx_period_size = params_period_bytes(hw_params);
cam->rx_period = 0;
@@ -194,12 +189,6 @@ static int camelot_hw_params(struct snd_soc_component *component,
return 0;
}
-static int camelot_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static int camelot_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -307,7 +296,7 @@ static int camelot_pcm_new(struct snd_soc_component *component,
/* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
* in MMAP mode (i.e. aplay -M)
*/
- snd_pcm_lib_preallocate_pages_for_all(pcm,
+ snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
NULL,
DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
@@ -318,9 +307,7 @@ static int camelot_pcm_new(struct snd_soc_component *component,
static const struct snd_soc_component_driver sh7760_soc_component = {
.open = camelot_pcm_open,
.close = camelot_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = camelot_hw_params,
- .hw_free = camelot_hw_free,
.prepare = camelot_prepare,
.trigger = camelot_trigger,
.pointer = camelot_pos,
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index e384fdc8d60e..89119acfa911 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1732,20 +1732,6 @@ static int fsi_pcm_open(struct snd_soc_component *component,
return ret;
}
-static int fsi_hw_params(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- return snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
-}
-
-static int fsi_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -1765,7 +1751,7 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component,
static int fsi_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- snd_pcm_lib_preallocate_pages_for_all(
+ snd_pcm_set_managed_buffer_all(
rtd->pcm,
SNDRV_DMA_TYPE_DEV,
rtd->card->snd_card->dev,
@@ -1815,9 +1801,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
static const struct snd_soc_component_driver fsi_soc_component = {
.name = "fsi",
.open = fsi_pcm_open,
- .ioctl = snd_soc_pcm_lib_ioctl,
- .hw_params = fsi_hw_params,
- .hw_free = fsi_hw_free,
.pointer = fsi_pointer,
.pcm_construct = fsi_pcm_new,
};
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 399dc6e9bde5..0bfcb77e5f65 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -376,20 +376,15 @@ 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)
{
- static const u32 dalign_values[8][2] = {
- {0x76543210, 0x67452301},
- {0x00000032, 0x00000023},
- {0x00007654, 0x00006745},
- {0x00000076, 0x00000067},
- {0xfedcba98, 0xefcdab89},
- {0x000000ba, 0x000000ab},
- {0x0000fedc, 0x0000efcd},
- {0x000000fe, 0x000000ef},
+ static const u32 dalign_values[8] = {
+ 0x76543210, 0x00000032, 0x00007654, 0x00000076,
+ 0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe,
};
- int id = 0, inv;
+ int id = 0;
struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
struct rsnd_mod *target;
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ u32 dalign;
/*
* *Hardware* L/R and *Software* L/R are inverted for 16bit data.
@@ -425,15 +420,15 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
if (mod == ssiu)
id = rsnd_mod_id_sub(mod);
- /* Non target mod or non 16bit needs normal DALIGN */
- if ((snd_pcm_format_width(runtime->format) != 16) ||
- (mod != target))
- inv = 0;
- /* Target mod needs inverted DALIGN when 16bit */
- else
- inv = 1;
+ dalign = dalign_values[id];
+
+ if (mod == target && snd_pcm_format_width(runtime->format) == 16) {
+ /* Target mod needs inverted DALIGN when 16bit */
+ dalign = (dalign & 0xf0f0f0f0) >> 4 |
+ (dalign & 0x0f0f0f0f) << 4;
+ }
- return dalign_values[id][inv];
+ return dalign;
}
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
@@ -1223,10 +1218,10 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
for (substream = rtd->pcm->streams[stream].substream;
substream;
substream = substream->next) {
- snd_pcm_lib_preallocate_pages(substream,
- SNDRV_DMA_TYPE_DEV,
- dev,
- PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+ snd_pcm_set_managed_buffer(substream,
+ SNDRV_DMA_TYPE_DEV,
+ dev,
+ PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
}
return 0;
@@ -1405,7 +1400,6 @@ static int rsnd_hw_params(struct snd_soc_component *component,
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
@@ -1438,12 +1432,7 @@ static int rsnd_hw_params(struct snd_soc_component *component,
dev_dbg(dev, "convert rate = %d\n", io->converted_rate);
}
- ret = rsnd_dai_call(hw_params, io, substream, hw_params);
- if (ret)
- return ret;
-
- return snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
+ return rsnd_dai_call(hw_params, io, substream, hw_params);
}
static int rsnd_hw_free(struct snd_soc_component *component,
@@ -1452,13 +1441,8 @@ static int rsnd_hw_free(struct snd_soc_component *component,
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);
- int ret;
-
- ret = rsnd_dai_call(hw_free, io, substream);
- if (ret)
- return ret;
- return snd_pcm_lib_free_pages(substream);
+ return rsnd_dai_call(hw_free, io, substream);
}
static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component,
@@ -1668,7 +1652,6 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
*/
static const struct snd_soc_component_driver rsnd_soc_component = {
.name = "rsnd",
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = rsnd_hw_params,
.hw_free = rsnd_hw_free,
.pointer = rsnd_pointer,
@@ -1824,8 +1807,6 @@ static int rsnd_remove(struct platform_device *pdev)
};
int ret = 0, i;
- snd_soc_disconnect_sync(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) {
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index a5e21e554da2..6a6ffd6d3192 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -281,41 +281,6 @@ static int siu_pcm_stmread_stop(struct siu_port *port_info)
return 0;
}
-static int siu_pcm_hw_params(struct snd_soc_component *component,
- struct snd_pcm_substream *ss,
- struct snd_pcm_hw_params *hw_params)
-{
- struct siu_info *info = siu_i2s_data;
- struct device *dev = ss->pcm->card->dev;
- int ret;
-
- dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
-
- ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
- if (ret < 0)
- dev_err(dev, "snd_pcm_lib_malloc_pages() failed\n");
-
- return ret;
-}
-
-static int siu_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *ss)
-{
- struct siu_info *info = siu_i2s_data;
- struct siu_port *port_info = siu_port_info(ss);
- struct device *dev = ss->pcm->card->dev;
- struct siu_stream *siu_stream;
-
- if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
- siu_stream = &port_info->playback;
- else
- siu_stream = &port_info->capture;
-
- dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
-
- return snd_pcm_lib_free_pages(ss);
-}
-
static bool filter(struct dma_chan *chan, void *slave)
{
struct sh_dmae_slave *param = slave;
@@ -548,7 +513,7 @@ static int siu_pcm_new(struct snd_soc_component *component,
if (ret < 0)
return ret;
- snd_pcm_lib_preallocate_pages_for_all(pcm,
+ snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_DEV, card->dev,
SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
@@ -583,9 +548,6 @@ struct const snd_soc_component_driver siu_component = {
.name = DRV_NAME,
.open = siu_pcm_open,
.close = siu_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
- .hw_params = siu_pcm_hw_params,
- .hw_free = siu_pcm_hw_free,
.prepare = siu_pcm_prepare,
.trigger = siu_pcm_trigger,
.pointer = siu_pcm_pointer_dma,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 61f230324164..b2a5351b1a11 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -19,6 +19,7 @@
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/soc-dpcm.h>
+#include <linux/pm_runtime.h>
static int soc_compr_components_open(struct snd_compr_stream *cstream,
struct snd_soc_component **last)
@@ -72,10 +73,20 @@ static int soc_compr_components_free(struct snd_compr_stream *cstream,
static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component;
+ struct snd_soc_component *component, *save = NULL;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
+ for_each_rtd_components(rtd, rtdcom, component) {
+ ret = pm_runtime_get_sync(component->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(component->dev);
+ save = component;
+ goto pm_err;
+ }
+ }
+
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
@@ -115,6 +126,14 @@ machine_err:
cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
out:
mutex_unlock(&rtd->card->pcm_mutex);
+pm_err:
+ for_each_rtd_components(rtd, rtdcom, component) {
+ if (component == save)
+ break;
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+ }
+
return ret;
}
@@ -214,10 +233,8 @@ be_err:
* This is to ensure there are no pops or clicks in between any music tracks
* due to DAPM power cycling.
*/
-static void close_delayed_work(struct work_struct *work)
+static void close_delayed_work(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_pcm_runtime *rtd =
- container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -241,6 +258,8 @@ static void close_delayed_work(struct work_struct *work)
static int soc_compr_free(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int stream;
@@ -289,6 +308,12 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
}
mutex_unlock(&rtd->card->pcm_mutex);
+
+ for_each_rtd_components(rtd, rtdcom, component) {
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+ }
+
return 0;
}
@@ -929,7 +954,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
}
/* DAPM dai link stream work */
- INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+ rtd->close_delayed_work_func = close_delayed_work;
rtd->compr = compr;
compr->private_data = rtd;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 062653ab03a3..55b98e82a978 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -45,11 +45,6 @@
#define NAME_SIZE 32
-#ifdef CONFIG_DEBUG_FS
-struct dentry *snd_soc_debugfs_root;
-EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
-#endif
-
static DEFINE_MUTEX(client_mutex);
static LIST_HEAD(component_list);
static LIST_HEAD(unbind_card_list);
@@ -73,23 +68,6 @@ static int pmdown_time = 5000;
module_param(pmdown_time, int, 0);
MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
-#ifdef CONFIG_DMI
-/*
- * If a DMI filed contain strings in this blacklist (e.g.
- * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken
- * as invalid and dropped when setting the card long name from DMI info.
- */
-static const char * const dmi_blacklist[] = {
- "To be filled by OEM",
- "TBD by OEM",
- "Default String",
- "Board Manufacturer",
- "Board Vendor Name",
- "Board Product Name",
- NULL, /* terminator */
-};
-#endif
-
static ssize_t pmdown_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -150,6 +128,9 @@ static const struct attribute_group *soc_dev_attr_groups[] = {
};
#ifdef CONFIG_DEBUG_FS
+struct dentry *snd_soc_debugfs_root;
+EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
+
static void soc_init_component_debugfs(struct snd_soc_component *component)
{
if (!component->card->debugfs_card_root)
@@ -277,18 +258,6 @@ static inline void snd_soc_debugfs_exit(void)
#endif
-/*
- * This is glue code between snd_pcm_lib_ioctl() and
- * snd_soc_component_driver :: ioctl
- */
-int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-EXPORT_SYMBOL_GPL(snd_soc_pcm_lib_ioctl);
-
static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_component *component)
{
@@ -389,22 +358,22 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
}
EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
-struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
- const char *dai_link, int stream)
+static const struct snd_soc_ops null_snd_soc_ops;
+
+struct snd_soc_pcm_runtime
+*snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
{
struct snd_soc_pcm_runtime *rtd;
for_each_card_rtds(card, rtd) {
- if (rtd->dai_link->no_pcm &&
- !strcmp(rtd->dai_link->name, dai_link))
- return rtd->pcm->streams[stream].substream;
+ if (rtd->dai_link == dai_link)
+ return rtd;
}
- dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link);
+ dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link->name);
return NULL;
}
-EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
-
-static const struct snd_soc_ops null_snd_soc_ops;
+EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
static void soc_release_rtd_dev(struct device *dev)
{
@@ -419,7 +388,8 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
list_del(&rtd->list);
- flush_delayed_work(&rtd->delayed_work);
+ if (delayed_work_pending(&rtd->delayed_work))
+ flush_delayed_work(&rtd->delayed_work);
snd_soc_pcm_component_free(rtd);
/*
@@ -435,6 +405,15 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
device_unregister(rtd->dev);
}
+static void close_delayed_work(struct work_struct *work) {
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(work, struct snd_soc_pcm_runtime,
+ delayed_work.work);
+
+ if (rtd->close_delayed_work_func)
+ rtd->close_delayed_work_func(rtd);
+}
+
static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
@@ -469,7 +448,14 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
goto free_rtd;
rtd->dev = dev;
+ INIT_LIST_HEAD(&rtd->list);
+ INIT_LIST_HEAD(&rtd->component_list);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
dev_set_drvdata(dev, rtd);
+ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
/*
* for rtd->codec_dais
@@ -483,12 +469,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
/*
* rtd remaining settings
*/
- INIT_LIST_HEAD(&rtd->component_list);
- INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
- INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
- INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
- INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
-
rtd->card = card;
rtd->dai_link = dai_link;
if (!rtd->dai_link->ops)
@@ -506,20 +486,6 @@ free_rtd:
return NULL;
}
-struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
- const char *dai_link)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- for_each_card_rtds(card, rtd) {
- if (!strcmp(rtd->dai_link->name, dai_link))
- return rtd;
- }
- dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
-
static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
@@ -915,47 +881,6 @@ struct snd_soc_dai *snd_soc_find_dai(
}
EXPORT_SYMBOL_GPL(snd_soc_find_dai);
-/**
- * snd_soc_find_dai_link - Find a DAI link
- *
- * @card: soc card
- * @id: DAI link ID to match
- * @name: DAI link name to match, optional
- * @stream_name: DAI link stream name to match, optional
- *
- * This function will search all existing DAI links of the soc card to
- * find the link of the same ID. Since DAI links may not have their
- * unique ID, so name and stream name should also match if being
- * specified.
- *
- * Return: pointer of DAI link, or NULL if not found.
- */
-struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card,
- int id, const char *name,
- const char *stream_name)
-{
- struct snd_soc_dai_link *link;
-
- lockdep_assert_held(&client_mutex);
-
- for_each_card_links(card, link) {
- if (link->id != id)
- continue;
-
- if (name && (!link->name || strcmp(name, link->name)))
- continue;
-
- if (stream_name && (!link->stream_name
- || strcmp(stream_name, link->stream_name)))
- continue;
-
- return link;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(snd_soc_find_dai_link);
-
static int soc_dai_link_sanity_check(struct snd_soc_card *card,
struct snd_soc_dai_link *link)
{
@@ -1053,49 +978,40 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
}
/**
- * snd_soc_remove_dai_link - Remove a DAI link from the list
- * @card: The ASoC card that owns the link
- * @dai_link: The DAI link to remove
- *
- * This function removes a DAI link from the ASoC card's link list.
+ * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card
+ * @card: The ASoC card to which the pcm_runtime has
+ * @rtd: The pcm_runtime to remove
*
- * For DAI links previously added by topology, topology should
- * remove them by using the dobj embedded in the link.
+ * This function removes a pcm_runtime from the ASoC card.
*/
-void snd_soc_remove_dai_link(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
+void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_pcm_runtime *rtd;
-
lockdep_assert_held(&client_mutex);
/*
* Notify the machine driver for extra destruction
*/
if (card->remove_dai_link)
- card->remove_dai_link(card, dai_link);
+ card->remove_dai_link(card, rtd->dai_link);
- list_del(&dai_link->list);
-
- rtd = snd_soc_get_pcm_runtime(card, dai_link->name);
- if (rtd)
- soc_free_pcm_runtime(rtd);
+ soc_free_pcm_runtime(rtd);
}
-EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
+EXPORT_SYMBOL_GPL(snd_soc_remove_pcm_runtime);
/**
- * snd_soc_add_dai_link - Add a DAI link dynamically
- * @card: The ASoC card to which the DAI link is added
- * @dai_link: The new DAI link to add
+ * snd_soc_add_pcm_runtime - Add a pcm_runtime dynamically via dai_link
+ * @card: The ASoC card to which the pcm_runtime is added
+ * @dai_link: The DAI link to find pcm_runtime
*
- * This function adds a DAI link to the ASoC card's link list.
+ * This function adds a pcm_runtime ASoC card by using dai_link.
*
- * Note: Topology can use this API to add DAI links when probing the
+ * Note: Topology can use this API to add pcm_runtime when probing the
* topology component. And machine drivers can still define static
* DAI links in dai_link array.
*/
-int snd_soc_add_dai_link(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
+int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
{
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai_link_component *codec, *platform;
@@ -1158,50 +1074,132 @@ int snd_soc_add_dai_link(struct snd_soc_card *card,
}
}
- /* see for_each_card_links */
- list_add_tail(&dai_link->list, &card->dai_link_list);
-
return 0;
_err_defer:
- soc_free_pcm_runtime(rtd);
+ snd_soc_remove_pcm_runtime(card, rtd);
return -EPROBE_DEFER;
}
-EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
+EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime);
-static void soc_set_of_name_prefix(struct snd_soc_component *component)
+static int soc_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
+ struct snd_soc_pcm_runtime *rtd)
{
- struct device_node *of_node = soc_component_to_node(component);
- const char *str;
- int ret;
+ int i, ret = 0;
- ret = of_property_read_string(of_node, "sound-name-prefix", &str);
- if (!ret)
- component->name_prefix = str;
+ for (i = 0; i < num_dais; ++i) {
+ struct snd_soc_dai_driver *drv = dais[i]->driver;
+
+ if (drv->pcm_new)
+ ret = drv->pcm_new(rtd, dais[i]);
+ if (ret < 0) {
+ dev_err(dais[i]->dev,
+ "ASoC: Failed to bind %s with pcm device\n",
+ dais[i]->name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int soc_init_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+ int ret, num;
+
+ /* set default power off timeout */
+ rtd->pmdown_time = pmdown_time;
+
+ /* do machine specific initialization */
+ if (dai_link->init) {
+ ret = dai_link->init(rtd);
+ if (ret < 0) {
+ dev_err(card->dev, "ASoC: failed to init %s: %d\n",
+ dai_link->name, ret);
+ return ret;
+ }
+ }
+
+ if (dai_link->dai_fmt) {
+ ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
+ if (ret)
+ return ret;
+ }
+
+ /* add DPCM sysfs entries */
+ soc_dpcm_debugfs_add(rtd);
+
+ num = rtd->num;
+
+ /*
+ * most drivers will register their PCMs using DAI link ordering but
+ * topology based drivers can use the DAI link id field to set PCM
+ * device number and then use rtd + a base offset of the BEs.
+ */
+ for_each_rtd_components(rtd, rtdcom, component) {
+ if (!component->driver->use_dai_pcm_id)
+ continue;
+
+ if (rtd->dai_link->no_pcm)
+ num += component->driver->be_pcm_base;
+ else
+ num = rtd->dai_link->id;
+ }
+
+ /* create compress_device if possible */
+ ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
+ if (ret != -ENOTSUPP) {
+ if (ret < 0)
+ dev_err(card->dev, "ASoC: can't create compress %s\n",
+ dai_link->stream_name);
+ return ret;
+ }
+
+ /* create the pcm */
+ ret = soc_new_pcm(rtd, num);
+ if (ret < 0) {
+ dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
+ dai_link->stream_name, ret);
+ return ret;
+ }
+ ret = soc_dai_pcm_new(&cpu_dai, 1, rtd);
+ if (ret < 0)
+ return ret;
+ ret = soc_dai_pcm_new(rtd->codec_dais,
+ rtd->num_codecs, rtd);
+ return ret;
}
static void soc_set_name_prefix(struct snd_soc_card *card,
struct snd_soc_component *component)
{
- int i;
+ struct device_node *of_node = soc_component_to_node(component);
+ const char *str;
+ int ret, i;
- for (i = 0; i < card->num_configs && card->codec_conf; i++) {
+ for (i = 0; i < card->num_configs; i++) {
struct snd_soc_codec_conf *map = &card->codec_conf[i];
- struct device_node *of_node = soc_component_to_node(component);
- if (map->of_node && of_node != map->of_node)
- continue;
- if (map->dev_name && strcmp(component->name, map->dev_name))
- continue;
- component->name_prefix = map->name_prefix;
- return;
+ if (snd_soc_is_matching_component(&map->dlc, component)) {
+ component->name_prefix = map->name_prefix;
+ return;
+ }
}
/*
* If there is no configuration table or no match in the table,
* check if a prefix is provided in the node
*/
- soc_set_of_name_prefix(component);
+ ret = of_property_read_string(of_node, "sound-name-prefix", &str);
+ if (ret < 0)
+ return;
+
+ component->name_prefix = str;
}
static void soc_remove_component(struct snd_soc_component *component,
@@ -1446,111 +1444,6 @@ static int soc_probe_link_components(struct snd_soc_card *card)
return 0;
}
-void snd_soc_disconnect_sync(struct device *dev)
-{
- struct snd_soc_component *component =
- snd_soc_lookup_component(dev, NULL);
-
- if (!component || !component->card)
- return;
-
- snd_card_disconnect_sync(component->card->snd_card);
-}
-EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync);
-
-static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
- struct snd_soc_pcm_runtime *rtd)
-{
- int i, ret = 0;
-
- for (i = 0; i < num_dais; ++i) {
- struct snd_soc_dai_driver *drv = dais[i]->driver;
-
- if (drv->pcm_new)
- ret = drv->pcm_new(rtd, dais[i]);
- if (ret < 0) {
- dev_err(dais[i]->dev,
- "ASoC: Failed to bind %s with pcm device\n",
- dais[i]->name);
- return ret;
- }
- }
-
- return 0;
-}
-
-static int soc_link_init(struct snd_soc_card *card,
- struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai_link *dai_link = rtd->dai_link;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_rtdcom_list *rtdcom;
- struct snd_soc_component *component;
- int ret, num;
-
- /* set default power off timeout */
- rtd->pmdown_time = pmdown_time;
-
- /* do machine specific initialization */
- if (dai_link->init) {
- ret = dai_link->init(rtd);
- if (ret < 0) {
- dev_err(card->dev, "ASoC: failed to init %s: %d\n",
- dai_link->name, ret);
- return ret;
- }
- }
-
- if (dai_link->dai_fmt) {
- ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
- if (ret)
- return ret;
- }
-
- /* add DPCM sysfs entries */
- soc_dpcm_debugfs_add(rtd);
-
- num = rtd->num;
-
- /*
- * most drivers will register their PCMs using DAI link ordering but
- * topology based drivers can use the DAI link id field to set PCM
- * device number and then use rtd + a base offset of the BEs.
- */
- for_each_rtd_components(rtd, rtdcom, component) {
- if (!component->driver->use_dai_pcm_id)
- continue;
-
- if (rtd->dai_link->no_pcm)
- num += component->driver->be_pcm_base;
- else
- num = rtd->dai_link->id;
- }
-
- /* create compress_device if possible */
- ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
- if (ret != -ENOTSUPP) {
- if (ret < 0)
- dev_err(card->dev, "ASoC: can't create compress %s\n",
- dai_link->stream_name);
- return ret;
- }
-
- /* create the pcm */
- ret = soc_new_pcm(rtd, num);
- if (ret < 0) {
- dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
- dai_link->stream_name, ret);
- return ret;
- }
- ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd);
- if (ret < 0)
- return ret;
- ret = soc_link_dai_pcm_new(rtd->codec_dais,
- rtd->num_codecs, rtd);
- return ret;
-}
-
static void soc_unbind_aux_dev(struct snd_soc_card *card)
{
struct snd_soc_component *component, *_component;
@@ -1682,6 +1575,21 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
#ifdef CONFIG_DMI
/*
+ * If a DMI filed contain strings in this blacklist (e.g.
+ * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken
+ * as invalid and dropped when setting the card long name from DMI info.
+ */
+static const char * const dmi_blacklist[] = {
+ "To be filled by OEM",
+ "TBD by OEM",
+ "Default String",
+ "Board Manufacturer",
+ "Board Vendor Name",
+ "Board Product Name",
+ NULL, /* terminator */
+};
+
+/*
* Trim special characters, and replace '-' with '_' since '-' is used to
* separate different DMI fields in the card long name. Only number and
* alphabet characters and a few separator characters are kept.
@@ -1860,6 +1768,8 @@ match:
/* convert non BE into BE */
dai_link->no_pcm = 1;
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
/* override any BE fixups */
dai_link->be_hw_params_fixup =
@@ -1931,7 +1841,7 @@ static void __soc_setup_card_name(char *name, int len,
static void soc_cleanup_card_resources(struct snd_soc_card *card,
int card_probed)
{
- struct snd_soc_dai_link *link, *_link;
+ struct snd_soc_pcm_runtime *rtd, *n;
if (card->snd_card)
snd_card_disconnect_sync(card->snd_card);
@@ -1942,8 +1852,8 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card,
soc_remove_link_dais(card);
soc_remove_link_components(card);
- for_each_card_links_safe(card, link, _link)
- snd_soc_remove_dai_link(card, link);
+ for_each_card_rtds_safe(card, rtd, n)
+ snd_soc_remove_pcm_runtime(card, rtd);
/* remove auxiliary devices */
soc_remove_aux_devices(card);
@@ -2001,7 +1911,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
/* add predefined DAI links to the list */
card->num_rtd = 0;
for_each_card_prelinks(card, i, dai_link) {
- ret = snd_soc_add_dai_link(card, dai_link);
+ ret = snd_soc_add_pcm_runtime(card, dai_link);
if (ret < 0)
goto probe_end;
}
@@ -2062,8 +1972,11 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
goto probe_end;
}
- for_each_card_rtds(card, rtd)
- soc_link_init(card, rtd);
+ for_each_card_rtds(card, rtd) {
+ ret = soc_init_pcm_runtime(card, rtd);
+ if (ret < 0)
+ goto probe_end;
+ }
snd_soc_dapm_link_dai_widgets(card);
snd_soc_dapm_connect_dai_link_widgets(card);
@@ -2393,7 +2306,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->aux_comp_list);
INIT_LIST_HEAD(&card->component_dev_list);
INIT_LIST_HEAD(&card->list);
- INIT_LIST_HEAD(&card->dai_link_list);
INIT_LIST_HEAD(&card->rtd_list);
INIT_LIST_HEAD(&card->dapm_dirty);
INIT_LIST_HEAD(&card->dobj_list);
@@ -2498,6 +2410,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
*
* @component: The component the DAIs are registered for
* @dai_drv: DAI driver to use for the DAI
+ * @legacy_dai_naming: if %true, use legacy single-name format;
+ * if %false, use multiple-name format;
*
* Topology can use this API to register DAIs when probing a component.
* These DAIs's widgets will be freed in the card cleanup and the DAIs
@@ -3001,7 +2915,7 @@ void snd_soc_of_parse_node_prefix(struct device_node *np,
return;
}
- codec_conf->of_node = of_node;
+ codec_conf->dlc.of_node = of_node;
codec_conf->name_prefix = str;
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix);
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index a428ff393ea2..df57ec47ad60 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -104,7 +104,7 @@ static int dmaengine_pcm_hw_params(struct snd_soc_component *component,
return ret;
}
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ return 0;
}
static int
@@ -168,12 +168,6 @@ static int dmaengine_pcm_close(struct snd_soc_component *component,
return snd_dmaengine_pcm_close(substream);
}
-static int dmaengine_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static int dmaengine_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
@@ -261,7 +255,7 @@ static int dmaengine_pcm_new(struct snd_soc_component *component,
return -EINVAL;
}
- snd_pcm_lib_preallocate_pages(substream,
+ snd_pcm_set_managed_buffer(substream,
SNDRV_DMA_TYPE_DEV_IRAM,
dmaengine_dma_dev(pcm, substream),
prealloc_buffer_size,
@@ -329,9 +323,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component = {
.probe_order = SND_SOC_COMP_ORDER_LATE,
.open = dmaengine_pcm_open,
.close = dmaengine_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = dmaengine_pcm_hw_params,
- .hw_free = dmaengine_pcm_hw_free,
.trigger = dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
.pcm_construct = dmaengine_pcm_new,
@@ -342,9 +334,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component_process = {
.probe_order = SND_SOC_COMP_ORDER_LATE,
.open = dmaengine_pcm_open,
.close = dmaengine_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = dmaengine_pcm_hw_params,
- .hw_free = dmaengine_pcm_hw_free,
.trigger = dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
.copy_user = dmaengine_copy_user,
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 76b7ee637e86..01e7bc03d92f 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -637,10 +637,8 @@ out:
* This is to ensure there are no pops or clicks in between any music tracks
* due to DAPM power cycling.
*/
-static void close_delayed_work(struct work_struct *work)
+static void close_delayed_work(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_pcm_runtime *rtd =
- container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -660,7 +658,7 @@ static void close_delayed_work(struct work_struct *work)
mutex_unlock(&rtd->card->pcm_mutex);
}
-static void codec2codec_close_delayed_work(struct work_struct *work)
+static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
{
/*
* Currently nothing to do for c2c links
@@ -2974,10 +2972,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
/* DAPM dai link stream work */
if (rtd->dai_link->params)
- INIT_DELAYED_WORK(&rtd->delayed_work,
- codec2codec_close_delayed_work);
+ rtd->close_delayed_work_func = codec2codec_close_delayed_work;
else
- INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+ rtd->close_delayed_work_func = close_delayed_work;
pcm->nonatomic = rtd->dai_link->nonatomic;
rtd->pcm = pcm;
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 81d2af000a5c..107ba3ed5440 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -548,12 +548,13 @@ static void remove_link(struct snd_soc_component *comp,
if (dobj->ops && dobj->ops->link_unload)
dobj->ops->link_unload(comp, dobj);
+ list_del(&dobj->list);
+ snd_soc_remove_pcm_runtime(comp->card,
+ snd_soc_get_pcm_runtime(comp->card, link));
+
kfree(link->name);
kfree(link->stream_name);
kfree(link->cpus->dai_name);
-
- list_del(&dobj->list);
- snd_soc_remove_dai_link(comp->card, link);
kfree(link);
}
@@ -604,9 +605,11 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
ext_ops = tplg->bytes_ext_ops;
num_ops = tplg->bytes_ext_ops_count;
for (i = 0; i < num_ops; i++) {
- if (!sbe->put && ext_ops[i].id == be->ext_ops.put)
+ if (!sbe->put &&
+ ext_ops[i].id == le32_to_cpu(be->ext_ops.put))
sbe->put = ext_ops[i].put;
- if (!sbe->get && ext_ops[i].id == be->ext_ops.get)
+ if (!sbe->get &&
+ ext_ops[i].id == le32_to_cpu(be->ext_ops.get))
sbe->get = ext_ops[i].get;
}
@@ -621,11 +624,11 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
num_ops = tplg->io_ops_count;
for (i = 0; i < num_ops; i++) {
- if (k->put == NULL && ops[i].id == hdr->ops.put)
+ if (k->put == NULL && ops[i].id == le32_to_cpu(hdr->ops.put))
k->put = ops[i].put;
- if (k->get == NULL && ops[i].id == hdr->ops.get)
+ if (k->get == NULL && ops[i].id == le32_to_cpu(hdr->ops.get))
k->get = ops[i].get;
- if (k->info == NULL && ops[i].id == hdr->ops.info)
+ if (k->info == NULL && ops[i].id == le32_to_cpu(hdr->ops.info))
k->info = ops[i].info;
}
@@ -638,11 +641,11 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
num_ops = ARRAY_SIZE(io_ops);
for (i = 0; i < num_ops; i++) {
- if (k->put == NULL && ops[i].id == hdr->ops.put)
+ if (k->put == NULL && ops[i].id == le32_to_cpu(hdr->ops.put))
k->put = ops[i].put;
- if (k->get == NULL && ops[i].id == hdr->ops.get)
+ if (k->get == NULL && ops[i].id == le32_to_cpu(hdr->ops.get))
k->get = ops[i].get;
- if (k->info == NULL && ops[i].id == hdr->ops.info)
+ if (k->info == NULL && ops[i].id == le32_to_cpu(hdr->ops.info))
k->info = ops[i].info;
}
@@ -931,7 +934,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
if (se->dobj.control.dtexts == NULL)
return -ENOMEM;
- for (i = 0; i < ec->items; i++) {
+ for (i = 0; i < le32_to_cpu(ec->items); i++) {
if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
@@ -1325,7 +1328,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
if (kc[i].name == NULL)
goto err_sm;
kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc[i].access = mc->hdr.access;
+ kc[i].access = le32_to_cpu(mc->hdr.access);
/* we only support FL/FR channel mapping atm */
sm->reg = tplc_chan_get_reg(tplg, mc->channel,
@@ -1337,10 +1340,10 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
SNDRV_CHMAP_FR);
- sm->max = mc->max;
- sm->min = mc->min;
- sm->invert = mc->invert;
- sm->platform_max = mc->platform_max;
+ sm->max = le32_to_cpu(mc->max);
+ sm->min = le32_to_cpu(mc->min);
+ sm->invert = le32_to_cpu(mc->invert);
+ sm->platform_max = le32_to_cpu(mc->platform_max);
sm->dobj.index = tplg->index;
INIT_LIST_HEAD(&sm->dobj.list);
@@ -1401,7 +1404,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
goto err_se;
tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
- ec->priv.size);
+ le32_to_cpu(ec->priv.size));
dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
ec->hdr.name);
@@ -1411,7 +1414,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
if (kc[i].name == NULL)
goto err_se;
kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc[i].access = ec->hdr.access;
+ kc[i].access = le32_to_cpu(ec->hdr.access);
/* we only support FL/FR channel mapping atm */
se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
@@ -1420,8 +1423,8 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
SNDRV_CHMAP_FR);
- se->items = ec->items;
- se->mask = ec->mask;
+ se->items = le32_to_cpu(ec->items);
+ se->mask = le32_to_cpu(ec->mask);
se->dobj.index = tplg->index;
switch (le32_to_cpu(ec->hdr.ops.info)) {
@@ -1523,9 +1526,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
if (kc[i].name == NULL)
goto err_sbe;
kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc[i].access = be->hdr.access;
+ kc[i].access = le32_to_cpu(be->hdr.access);
- sbe->max = be->max;
+ sbe->max = le32_to_cpu(be->max);
INIT_LIST_HEAD(&sbe->dobj.list);
/* map standard io handlers and check for external handlers */
@@ -1933,11 +1936,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
ret = soc_tplg_dai_link_load(tplg, link, NULL);
if (ret < 0) {
dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
- kfree(link->name);
- kfree(link->stream_name);
- kfree(link->cpus->dai_name);
- kfree(link);
- return ret;
+ goto err;
+ }
+
+ ret = snd_soc_add_pcm_runtime(tplg->comp->card, link);
+ if (ret < 0) {
+ dev_err(tplg->comp->dev, "ASoC: adding FE link failed\n");
+ goto err;
}
link->dobj.index = tplg->index;
@@ -1945,8 +1950,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
link->dobj.type = SND_SOC_DOBJ_DAI_LINK;
list_add(&link->dobj.list, &tplg->comp->dobj_list);
- snd_soc_add_dai_link(tplg->comp->card, link);
return 0;
+err:
+ kfree(link->name);
+ kfree(link->stream_name);
+ kfree(link->cpus->dai_name);
+ kfree(link);
+ return ret;
}
/* create a FE DAI and DAI link from the PCM object */
@@ -2039,6 +2049,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
int size;
int i;
bool abi_match;
+ int ret;
count = le32_to_cpu(hdr->count);
@@ -2080,7 +2091,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
}
/* create the FE DAIs and DAI links */
- soc_tplg_pcm_create(tplg, _pcm);
+ ret = soc_tplg_pcm_create(tplg, _pcm);
+ if (ret < 0) {
+ if (!abi_match)
+ kfree(_pcm);
+ return ret;
+ }
/* offset by version-specific struct size and
* real priv data size
@@ -2207,6 +2223,47 @@ static int link_new_ver(struct soc_tplg *tplg,
return 0;
}
+/**
+ * snd_soc_find_dai_link - Find a DAI link
+ *
+ * @card: soc card
+ * @id: DAI link ID to match
+ * @name: DAI link name to match, optional
+ * @stream_name: DAI link stream name to match, optional
+ *
+ * This function will search all existing DAI links of the soc card to
+ * find the link of the same ID. Since DAI links may not have their
+ * unique ID, so name and stream name should also match if being
+ * specified.
+ *
+ * Return: pointer of DAI link, or NULL if not found.
+ */
+static struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card,
+ int id, const char *name,
+ const char *stream_name)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai_link *link;
+
+ for_each_card_rtds(card, rtd) {
+ link = rtd->dai_link;
+
+ if (link->id != id)
+ continue;
+
+ if (name && (!link->name || strcmp(name, link->name)))
+ continue;
+
+ if (stream_name && (!link->stream_name
+ || strcmp(stream_name, link->stream_name)))
+ continue;
+
+ return link;
+ }
+
+ return NULL;
+}
+
/* Find and configure an existing physical DAI link */
static int soc_tplg_link_config(struct soc_tplg *tplg,
struct snd_soc_tplg_link_config *cfg)
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 2fd4562f5e63..922eac930df9 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -77,7 +77,6 @@ static int dummy_dma_open(struct snd_soc_component *component,
static const struct snd_soc_component_driver dummy_platform = {
.open = dummy_dma_open,
- .ioctl = snd_soc_pcm_lib_ioctl,
};
static const struct snd_soc_component_driver dummy_codec = {
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 71a0fc075a63..827b0ec92522 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -28,7 +28,7 @@ config SND_SOC_SOF_ACPI
select IOSF_MBI if X86 && PCI
help
This adds support for ACPI enumeration. This option is required
- to enable Intel Haswell/Broadwell/Baytrail/Cherrytrail devices
+ to enable Intel Broadwell/Baytrail/Cherrytrail devices
Say Y if you need this option
If unsure select "N".
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index b0a6f01bdc44..0a8bc72c28a5 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
- control.o trace.o utils.o
+ control.o trace.o utils.o sof-audio.o
snd-sof-pci-objs := sof-pci-dev.o
snd-sof-acpi-objs := sof-acpi-dev.o
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 7baf7f1507c3..dfc412e2d956 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -13,6 +13,7 @@
#include <linux/pm_runtime.h>
#include <linux/leds.h>
#include "sof-priv.h"
+#include "sof-audio.h"
static void update_mute_led(struct snd_sof_control *scontrol,
struct snd_kcontrol *kcontrol,
@@ -88,7 +89,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
@@ -104,8 +105,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
}
/* notify DSP of mixer updates */
- if (pm_runtime_active(sdev->dev))
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ if (pm_runtime_active(scomp->dev))
+ snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_VOLUME,
@@ -135,7 +136,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
@@ -153,8 +154,8 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
update_mute_led(scontrol, kcontrol, ucontrol);
/* notify DSP of mixer updates */
- if (pm_runtime_active(sdev->dev))
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ if (pm_runtime_active(scomp->dev))
+ snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_SWITCH,
@@ -185,7 +186,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct soc_enum *se =
(struct soc_enum *)kcontrol->private_value;
struct snd_sof_control *scontrol = se->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
@@ -200,8 +201,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
}
/* notify DSP of enum updates */
- if (pm_runtime_active(sdev->dev))
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ if (pm_runtime_active(scomp->dev))
+ snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_ENUM,
@@ -216,14 +217,14 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size;
int ret = 0;
if (be->max > sizeof(ucontrol->value.bytes.data)) {
- dev_err_ratelimited(sdev->dev,
+ dev_err_ratelimited(scomp->dev,
"error: data max %d exceeds ucontrol data array size\n",
be->max);
return -EINVAL;
@@ -231,7 +232,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
size = data->size + sizeof(*data);
if (size > be->max) {
- dev_err_ratelimited(sdev->dev,
+ dev_err_ratelimited(scomp->dev,
"error: DSP sent %zu bytes max is %d\n",
size, be->max);
ret = -EINVAL;
@@ -251,20 +252,20 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size = data->size + sizeof(*data);
if (be->max > sizeof(ucontrol->value.bytes.data)) {
- dev_err_ratelimited(sdev->dev,
+ dev_err_ratelimited(scomp->dev,
"error: data max %d exceeds ucontrol data array size\n",
be->max);
return -EINVAL;
}
if (size > be->max) {
- dev_err_ratelimited(sdev->dev,
+ dev_err_ratelimited(scomp->dev,
"error: size too big %zu bytes max is %d\n",
size, be->max);
return -EINVAL;
@@ -274,8 +275,8 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */
- if (pm_runtime_active(sdev->dev))
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ if (pm_runtime_active(scomp->dev))
+ snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd,
@@ -291,7 +292,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct snd_ctl_tlv header;
const struct snd_ctl_tlv __user *tlvd =
@@ -307,14 +308,14 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
/* be->max is coming from topology */
if (header.length > be->max) {
- dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n",
+ dev_err_ratelimited(scomp->dev, "error: Bytes data size %d exceeds max %d.\n",
header.length, be->max);
return -EINVAL;
}
/* Check that header id matches the command */
if (header.numid != scontrol->cmd) {
- dev_err_ratelimited(sdev->dev,
+ dev_err_ratelimited(scomp->dev,
"error: incorrect numid %d\n",
header.numid);
return -EINVAL;
@@ -324,26 +325,26 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
return -EFAULT;
if (cdata->data->magic != SOF_ABI_MAGIC) {
- dev_err_ratelimited(sdev->dev,
+ dev_err_ratelimited(scomp->dev,
"error: Wrong ABI magic 0x%08x.\n",
cdata->data->magic);
return -EINVAL;
}
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
- dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n",
+ dev_err_ratelimited(scomp->dev, "error: Incompatible ABI version 0x%08x.\n",
cdata->data->abi);
return -EINVAL;
}
if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) {
- dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n");
+ dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n");
return -EINVAL;
}
/* notify DSP of byte control updates */
- if (pm_runtime_active(sdev->dev))
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ if (pm_runtime_active(scomp->dev))
+ snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd,
@@ -359,7 +360,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct snd_ctl_tlv header;
struct snd_ctl_tlv __user *tlvd =
@@ -382,7 +383,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
/* check data size doesn't exceed max coming from topology */
if (data_size > be->max) {
- dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n",
+ dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %d.\n",
data_size, be->max);
ret = -EINVAL;
goto out;
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 805918d3bcc0..44f9c04d54aa 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -10,7 +10,6 @@
#include <linux/firmware.h>
#include <linux/module.h>
-#include <asm/unaligned.h>
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
@@ -26,126 +25,6 @@ MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)");
#define TIMEOUT_DEFAULT_BOOT_MS 2000
/*
- * Generic object lookup APIs.
- */
-
-struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
- const char *name)
-{
- struct snd_sof_pcm *spcm;
-
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- /* match with PCM dai name */
- if (strcmp(spcm->pcm.dai_name, name) == 0)
- return spcm;
-
- /* match with playback caps name if set */
- if (*spcm->pcm.caps[0].name &&
- !strcmp(spcm->pcm.caps[0].name, name))
- return spcm;
-
- /* match with capture caps name if set */
- if (*spcm->pcm.caps[1].name &&
- !strcmp(spcm->pcm.caps[1].name, name))
- return spcm;
- }
-
- return NULL;
-}
-
-struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
- unsigned int comp_id,
- int *direction)
-{
- struct snd_sof_pcm *spcm;
-
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) {
- *direction = SNDRV_PCM_STREAM_PLAYBACK;
- return spcm;
- }
- if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) {
- *direction = SNDRV_PCM_STREAM_CAPTURE;
- return spcm;
- }
- }
-
- return NULL;
-}
-
-struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
- unsigned int pcm_id)
-{
- struct snd_sof_pcm *spcm;
-
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
- return spcm;
- }
-
- return NULL;
-}
-
-struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
- const char *name)
-{
- struct snd_sof_widget *swidget;
-
- list_for_each_entry(swidget, &sdev->widget_list, list) {
- if (strcmp(name, swidget->widget->name) == 0)
- return swidget;
- }
-
- return NULL;
-}
-
-/* find widget by stream name and direction */
-struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
- const char *pcm_name, int dir)
-{
- struct snd_sof_widget *swidget;
- enum snd_soc_dapm_type type;
-
- if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- type = snd_soc_dapm_aif_in;
- else
- type = snd_soc_dapm_aif_out;
-
- list_for_each_entry(swidget, &sdev->widget_list, list) {
- if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type)
- return swidget;
- }
-
- return NULL;
-}
-
-struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
- const char *name)
-{
- struct snd_sof_dai *dai;
-
- list_for_each_entry(dai, &sdev->dai_list, list) {
- if (dai->name && (strcmp(name, dai->name) == 0))
- return dai;
- }
-
- return NULL;
-}
-
-bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev)
-{
- struct snd_sof_pcm *spcm;
-
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
- spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
- return true;
- }
-
- return false;
-}
-
-/*
* FW Panic/fault handling.
*/
@@ -214,104 +93,48 @@ out:
EXPORT_SYMBOL(snd_sof_get_status);
/*
- * Generic buffer page table creation.
- * Take the each physical page address and drop the least significant unused
- * bits from each (based on PAGE_SIZE). Then pack valid page address bits
- * into compressed page table.
- */
-
-int snd_sof_create_page_table(struct snd_sof_dev *sdev,
- struct snd_dma_buffer *dmab,
- unsigned char *page_table, size_t size)
-{
- int i, pages;
-
- pages = snd_sgbuf_aligned_pages(size);
-
- dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n",
- dmab->area, size, pages);
-
- for (i = 0; i < pages; i++) {
- /*
- * The number of valid address bits for each page is 20.
- * idx determines the byte position within page_table
- * where the current page's address is stored
- * in the compressed page_table.
- * This can be calculated by multiplying the page number by 2.5.
- */
- u32 idx = (5 * i) >> 1;
- u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
- u8 *pg_table;
-
- dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
-
- pg_table = (u8 *)(page_table + idx);
-
- /*
- * pagetable compression:
- * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
- * ___________pfn 0__________ __________pfn 1___________ _pfn 2...
- * .... .... .... .... .... .... .... .... .... .... ....
- * It is created by:
- * 1. set current location to 0, PFN index i to 0
- * 2. put pfn[i] at current location in Little Endian byte order
- * 3. calculate an intermediate value as
- * x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
- * 4. put x at offset (current location + 2) in LE byte order
- * 5. increment current location by 5 bytes, increment i by 2
- * 6. continue to (2)
- */
- if (i & 1)
- put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4,
- pg_table);
- else
- put_unaligned_le32(pfn, pg_table);
- }
-
- return pages;
-}
-
-/*
- * SOF Driver enumeration.
+ * FW Boot State Transition Diagram
+ *
+ * +-----------------------------------------------------------------------+
+ * | |
+ * ------------------ ------------------ |
+ * | | | | |
+ * | BOOT_FAILED | | READY_FAILED |-------------------------+ |
+ * | | | | | |
+ * ------------------ ------------------ | |
+ * ^ ^ | |
+ * | | | |
+ * (FW Boot Timeout) (FW_READY FAIL) | |
+ * | | | |
+ * | | | |
+ * ------------------ | ------------------ | |
+ * | | | | | | |
+ * | IN_PROGRESS |---------------+------------->| COMPLETE | | |
+ * | | (FW Boot OK) (FW_READY OK) | | | |
+ * ------------------ ------------------ | |
+ * ^ | | |
+ * | | | |
+ * (FW Loading OK) (System Suspend/Runtime Suspend)
+ * | | | |
+ * | | | |
+ * ------------------ ------------------ | | |
+ * | | | |<-----+ | |
+ * | PREPARE | | NOT_STARTED |<---------------------+ |
+ * | | | |<---------------------------+
+ * ------------------ ------------------
+ * | ^ | ^
+ * | | | |
+ * | +-----------------------+ |
+ * | (DSP Probe OK) |
+ * | |
+ * | |
+ * +------------------------------------+
+ * (System Suspend/Runtime Suspend)
*/
-static int sof_machine_check(struct snd_sof_dev *sdev)
-{
- struct snd_sof_pdata *plat_data = sdev->pdata;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
- struct snd_soc_acpi_mach *machine;
- int ret;
-#endif
-
- if (plat_data->machine)
- return 0;
-
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
- dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
- return -ENODEV;
-#else
- /* fallback to nocodec mode */
- dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n");
- machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL);
- if (!machine)
- return -ENOMEM;
-
- ret = sof_nocodec_setup(sdev->dev, plat_data, machine,
- plat_data->desc, plat_data->desc->ops);
- if (ret < 0)
- return ret;
-
- plat_data->machine = machine;
-
- return 0;
-#endif
-}
static int sof_probe_continue(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *plat_data = sdev->pdata;
- const char *drv_name;
- const void *mach;
- int size;
int ret;
/* probe the DSP hardware */
@@ -321,6 +144,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
return ret;
}
+ sdev->fw_state = SOF_FW_BOOT_PREPARE;
+
/* check machine info */
ret = sof_machine_check(sdev);
if (ret < 0) {
@@ -360,7 +185,12 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
goto fw_load_err;
}
- /* boot the firmware */
+ sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS;
+
+ /*
+ * Boot the firmware. The FW boot status will be modified
+ * in snd_sof_run_firmware() depending on the outcome.
+ */
ret = snd_sof_run_firmware(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n",
@@ -397,22 +227,17 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
goto fw_run_err;
}
- drv_name = plat_data->machine->drv_name;
- mach = (const void *)plat_data->machine;
- size = sizeof(*plat_data->machine);
-
- /* register machine driver, pass machine info as pdata */
- plat_data->pdev_mach =
- platform_device_register_data(sdev->dev, drv_name,
- PLATFORM_DEVID_NONE, mach, size);
-
- if (IS_ERR(plat_data->pdev_mach)) {
- ret = PTR_ERR(plat_data->pdev_mach);
+ ret = snd_sof_machine_register(sdev, plat_data);
+ if (ret < 0)
goto fw_run_err;
- }
- dev_dbg(sdev->dev, "created machine %s\n",
- dev_name(&plat_data->pdev_mach->dev));
+ /*
+ * Some platforms in SOF, ex: BYT, may not have their platform PM
+ * callbacks set. Increment the usage count so as to
+ * prevent the device from entering runtime suspend.
+ */
+ if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
+ pm_runtime_get_noresume(sdev->dev);
if (plat_data->sof_probe_complete)
plat_data->sof_probe_complete(sdev->dev);
@@ -476,6 +301,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
sdev->pdata = plat_data;
sdev->first_boot = true;
+ sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
dev_set_drvdata(dev, sdev);
/* check all mandatory ops */
@@ -534,9 +360,7 @@ int snd_sof_device_remove(struct device *dev)
* will remove the component driver and unload the topology
* before freeing the snd_card.
*/
- if (!IS_ERR_OR_NULL(pdata->pdev_mach))
- platform_device_unregister(pdata->pdev_mach);
-
+ snd_sof_machine_unregister(sdev, pdata);
/*
* Unregistering the machine driver results in unloading the topology.
* Some widgets, ex: scheduler, attempt to power down the core they are
diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c
index cfefcfd92798..b2556f5e2871 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -209,7 +209,7 @@ static int imx8_probe(struct snd_sof_dev *sdev)
priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains,
sizeof(*priv->pd_dev), GFP_KERNEL);
- if (!priv)
+ if (!priv->pd_dev)
return -ENOMEM;
priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains,
@@ -294,8 +294,7 @@ static int imx8_probe(struct snd_sof_dev *sdev)
}
sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- res.end - res.start +
- 1);
+ resource_size(&res));
if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
base, size);
@@ -304,6 +303,9 @@ static int imx8_probe(struct snd_sof_dev *sdev)
}
sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
+ /* set default mailbox offset for FW ready message */
+ sdev->dsp_box.offset = MBOX_OFFSET;
+
return 0;
exit_pdev_unregister:
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index cc09bb606f7d..56a837d2cb95 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -319,6 +319,7 @@ config SND_SOC_SOF_HDA_COMMON_HDMI_CODEC
bool "SOF common HDA HDMI codec driver"
depends on SND_SOC_SOF_HDA_LINK
depends on SND_HDA_CODEC_HDMI
+ default SND_HDA_CODEC_HDMI
help
This adds support for HDMI audio by using the common HDA
HDMI/DisplayPort codec driver.
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 7daa8eb456c8..2483b15699e7 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -17,6 +17,7 @@
#include "../sof-priv.h"
#include "hda.h"
+#include "../sof-audio.h"
static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = {
{"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
@@ -41,7 +42,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
.block_write = sof_block_write,
/* doorbell */
- .irq_handler = hda_dsp_ipc_irq_handler,
.irq_thread = hda_dsp_ipc_irq_thread,
/* ipc */
@@ -53,6 +53,12 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
+ /* machine driver */
+ .machine_select = hda_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = hda_set_mach_params,
+
/* debug */
.debug_map = apl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs),
@@ -105,8 +111,10 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+
+ .arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL(sof_apl_ops);
+EXPORT_SYMBOL_NS(sof_apl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc apl_chip_info = {
/* Apollolake */
@@ -122,4 +130,4 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.ssp_count = APL_SSP_COUNT,
.ssp_base_offset = APL_SSP_BASE_OFFSET,
};
-EXPORT_SYMBOL(apl_chip_info);
+EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index 141dad554764..6c23c5769330 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -17,6 +17,7 @@
#include <sound/sof/xtensa.h>
#include "../ops.h"
#include "shim.h"
+#include "../sof-audio.h"
/* BARs */
#define BDW_DSP_BAR 0
@@ -536,6 +537,32 @@ static int bdw_probe(struct snd_sof_dev *sdev)
return ret;
}
+static void bdw_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_soc_acpi_mach *mach;
+
+ mach = snd_soc_acpi_find_machine(desc->machines);
+ if (!mach) {
+ dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
+ return;
+ }
+
+ sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc;
+ sof_pdata->machine = mach;
+}
+
+static void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach,
+ struct device *dev)
+{
+ struct snd_soc_acpi_mach_params *mach_params;
+
+ mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params;
+ mach_params->platform = dev_name(dev);
+}
+
/* Broadwell DAIs */
static struct snd_soc_dai_driver bdw_dai[] = {
{
@@ -574,6 +601,12 @@ const struct snd_sof_dsp_ops sof_bdw_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_select = bdw_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = bdw_set_mach_params,
+
/* debug */
.debug_map = bdw_debugfs,
.debug_map_count = ARRAY_SIZE(bdw_debugfs),
@@ -599,13 +632,17 @@ const struct snd_sof_dsp_ops sof_bdw_ops = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_BATCH,
+
+ .arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL(sof_bdw_ops);
+EXPORT_SYMBOL_NS(sof_bdw_ops, SND_SOC_SOF_BROADWELL);
const struct sof_intel_dsp_desc bdw_chip_info = {
.cores_num = 1,
.cores_mask = 1,
};
-EXPORT_SYMBOL(bdw_chip_info);
+EXPORT_SYMBOL_NS(bdw_chip_info, SND_SOC_SOF_BROADWELL);
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC);
+MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 2abf80b3eb52..f84391294f12 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -17,6 +17,8 @@
#include <sound/sof/xtensa.h>
#include "../ops.h"
#include "shim.h"
+#include "../sof-audio.h"
+#include "../../intel/common/soc-intel-quirks.h"
/* DSP memories */
#define IRAM_OFFSET 0x0C0000
@@ -24,7 +26,8 @@
#define DRAM_OFFSET 0x100000
#define DRAM_SIZE (160 * 1024)
#define SHIM_OFFSET 0x140000
-#define SHIM_SIZE 0x100
+#define SHIM_SIZE_BYT 0x100
+#define SHIM_SIZE_CHT 0x118
#define MBOX_OFFSET 0x144000
#define MBOX_SIZE 0x1000
#define EXCEPT_OFFSET 0x800
@@ -75,7 +78,7 @@ static const struct snd_sof_debugfs_map byt_debugfs[] = {
SOF_DEBUGFS_ACCESS_D0_ONLY},
{"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
SOF_DEBUGFS_ACCESS_D0_ONLY},
- {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE,
+ {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_BYT,
SOF_DEBUGFS_ACCESS_ALWAYS},
};
@@ -102,7 +105,7 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = {
SOF_DEBUGFS_ACCESS_D0_ONLY},
{"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
SOF_DEBUGFS_ACCESS_D0_ONLY},
- {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE,
+ {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_CHT,
SOF_DEBUGFS_ACCESS_ALWAYS},
};
@@ -145,33 +148,33 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags)
struct sof_ipc_dsp_oops_xtensa xoops;
struct sof_ipc_panic_info panic_info;
u32 stack[BYT_STACK_DUMP_SIZE];
- u32 status, panic, imrd, imrx;
+ u64 status, panic, imrd, imrx;
/* now try generic SOF status messages */
- status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD);
- panic = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCX);
+ status = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD);
+ panic = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX);
byt_get_registers(sdev, &xoops, &panic_info, stack,
BYT_STACK_DUMP_SIZE);
snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack,
BYT_STACK_DUMP_SIZE);
/* provide some context for firmware debug */
- imrx = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRX);
- imrd = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRD);
+ imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX);
+ imrd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRD);
dev_err(sdev->dev,
- "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n",
+ "error: ipc host -> DSP: pending %s complete %s raw 0x%llx\n",
(panic & SHIM_IPCX_BUSY) ? "yes" : "no",
(panic & SHIM_IPCX_DONE) ? "yes" : "no", panic);
dev_err(sdev->dev,
- "error: mask host: pending %s complete %s raw 0x%8.8x\n",
+ "error: mask host: pending %s complete %s raw 0x%llx\n",
(imrx & SHIM_IMRX_BUSY) ? "yes" : "no",
(imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx);
dev_err(sdev->dev,
- "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n",
+ "error: ipc DSP -> host: pending %s complete %s raw 0x%llx\n",
(status & SHIM_IPCD_BUSY) ? "yes" : "no",
(status & SHIM_IPCD_DONE) ? "yes" : "no", status);
dev_err(sdev->dev,
- "error: mask DSP: pending %s complete %s raw 0x%8.8x\n",
+ "error: mask DSP: pending %s complete %s raw 0x%llx\n",
(imrd & SHIM_IMRD_BUSY) ? "yes" : "no",
(imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd);
@@ -382,6 +385,76 @@ static int byt_reset(struct snd_sof_dev *sdev)
return 0;
}
+static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
+ const char *sof_tplg_filename,
+ const char *ssp_str)
+{
+ const char *tplg_filename = NULL;
+ char *filename;
+ char *split_ext;
+
+ filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
+ if (!filename)
+ return NULL;
+
+ /* this assumes a .tplg extension */
+ split_ext = strsep(&filename, ".");
+ if (split_ext) {
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-%s.tplg",
+ split_ext, ssp_str);
+ if (!tplg_filename)
+ return NULL;
+ }
+ return tplg_filename;
+}
+
+static void byt_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_soc_acpi_mach *mach;
+ struct platform_device *pdev;
+ const char *tplg_filename;
+
+ mach = snd_soc_acpi_find_machine(desc->machines);
+ if (!mach) {
+ dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
+ return;
+ }
+
+ pdev = to_platform_device(sdev->dev);
+ if (soc_intel_is_byt_cr(pdev)) {
+ dev_dbg(sdev->dev,
+ "BYT-CR detected, SSP0 used instead of SSP2\n");
+
+ tplg_filename = fixup_tplg_name(sdev,
+ mach->sof_tplg_filename,
+ "ssp0");
+ } else {
+ tplg_filename = mach->sof_tplg_filename;
+ }
+
+ if (!tplg_filename) {
+ dev_dbg(sdev->dev,
+ "error: no topology filename\n");
+ return;
+ }
+
+ sof_pdata->tplg_filename = tplg_filename;
+ mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc;
+ sof_pdata->machine = mach;
+}
+
+static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach,
+ struct device *dev)
+{
+ struct snd_soc_acpi_mach_params *mach_params;
+
+ mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params;
+ mach_params->platform = dev_name(dev);
+}
+
/* Baytrail DAIs */
static struct snd_soc_dai_driver byt_dai[] = {
{
@@ -514,6 +587,12 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_select = byt_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = byt_set_mach_params,
+
/* debug */
.debug_map = byt_debugfs,
.debug_map_count = ARRAY_SIZE(byt_debugfs),
@@ -539,14 +618,16 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_BATCH,
+
+ .arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL(sof_tng_ops);
+EXPORT_SYMBOL_NS(sof_tng_ops, SND_SOC_SOF_MERRIFIELD);
const struct sof_intel_dsp_desc tng_chip_info = {
.cores_num = 1,
.cores_mask = 1,
};
-EXPORT_SYMBOL(tng_chip_info);
+EXPORT_SYMBOL_NS(tng_chip_info, SND_SOC_SOF_MERRIFIELD);
#endif /* CONFIG_SND_SOC_SOF_MERRIFIELD */
@@ -682,6 +763,12 @@ const struct snd_sof_dsp_ops sof_byt_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_select = byt_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = byt_set_mach_params,
+
/* debug */
.debug_map = byt_debugfs,
.debug_map_count = ARRAY_SIZE(byt_debugfs),
@@ -707,14 +794,16 @@ const struct snd_sof_dsp_ops sof_byt_ops = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_BATCH,
+
+ .arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL(sof_byt_ops);
+EXPORT_SYMBOL_NS(sof_byt_ops, SND_SOC_SOF_BAYTRAIL);
const struct sof_intel_dsp_desc byt_chip_info = {
.cores_num = 1,
.cores_mask = 1,
};
-EXPORT_SYMBOL(byt_chip_info);
+EXPORT_SYMBOL_NS(byt_chip_info, SND_SOC_SOF_BAYTRAIL);
/* cherrytrail and braswell ops */
const struct snd_sof_dsp_ops sof_cht_ops = {
@@ -748,6 +837,12 @@ const struct snd_sof_dsp_ops sof_cht_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_select = byt_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = byt_set_mach_params,
+
/* debug */
.debug_map = cht_debugfs,
.debug_map_count = ARRAY_SIZE(cht_debugfs),
@@ -774,15 +869,19 @@ const struct snd_sof_dsp_ops sof_cht_ops = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_BATCH,
+
+ .arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL(sof_cht_ops);
+EXPORT_SYMBOL_NS(sof_cht_ops, SND_SOC_SOF_BAYTRAIL);
const struct sof_intel_dsp_desc cht_chip_info = {
.cores_num = 1,
.cores_mask = 1,
};
-EXPORT_SYMBOL(cht_chip_info);
+EXPORT_SYMBOL_NS(cht_chip_info, SND_SOC_SOF_BAYTRAIL);
#endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC);
+MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 0e1e265f3f3b..9e2d8afe0535 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -18,6 +18,7 @@
#include "../ops.h"
#include "hda.h"
#include "hda-ipc.h"
+#include "../sof-audio.h"
static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = {
{"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
@@ -106,10 +107,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
"nothing to do in IPC IRQ thread\n");
}
- /* re-enable IPC interrupt */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
- HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
-
return IRQ_HANDLED;
}
@@ -231,7 +228,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
.block_write = sof_block_write,
/* doorbell */
- .irq_handler = hda_dsp_ipc_irq_handler,
.irq_thread = cnl_ipc_irq_thread,
/* ipc */
@@ -243,6 +239,12 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
+ /* machine driver */
+ .machine_select = hda_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = hda_set_mach_params,
+
/* debug */
.debug_map = cnl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs),
@@ -295,8 +297,10 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+
+ .arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL(sof_cnl_ops);
+EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc cnl_chip_info = {
/* Cannonlake */
@@ -315,7 +319,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.ssp_count = CNL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
-EXPORT_SYMBOL(cnl_chip_info);
+EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc icl_chip_info = {
/* Icelake */
@@ -334,7 +338,7 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
-EXPORT_SYMBOL(icl_chip_info);
+EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc tgl_chip_info = {
/* Tigerlake */
@@ -350,7 +354,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
-EXPORT_SYMBOL(tgl_chip_info);
+EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc ehl_chip_info = {
/* Elkhartlake */
@@ -366,7 +370,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
-EXPORT_SYMBOL(ehl_chip_info);
+EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc jsl_chip_info = {
/* Jasperlake */
@@ -383,4 +387,4 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
-EXPORT_SYMBOL(jsl_chip_info);
+EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index 827f84a0722e..5514e6191ba4 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -76,16 +76,15 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {}
void hda_codec_jack_check(struct snd_sof_dev *sdev) {}
#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
-EXPORT_SYMBOL(hda_codec_jack_wake_enable);
-EXPORT_SYMBOL(hda_codec_jack_check);
+EXPORT_SYMBOL_NS(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
/* probe individual codec */
-static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
+static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
+ bool hda_codec_use_common_hdmi)
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
struct hdac_hda_priv *hda_priv;
- struct snd_soc_acpi_mach_params *mach_params = NULL;
- struct snd_sof_pdata *pdata = sdev->pdata;
#endif
struct hda_bus *hbus = sof_to_hbus(sdev);
struct hdac_device *hdev;
@@ -115,10 +114,6 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
if (ret < 0)
return ret;
- if (pdata->machine)
- mach_params = (struct snd_soc_acpi_mach_params *)
- &pdata->machine->mach_params;
-
if ((resp & 0xFFFF0000) == IDISP_VID_INTEL)
hda_priv->need_display_power = true;
@@ -126,7 +121,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
* if common HDMI codec driver is not used, codec load
* is skipped here and hdac_hdmi is used instead
*/
- if ((mach_params && mach_params->common_hdmi_codec_drv) ||
+ if (hda_codec_use_common_hdmi ||
(resp & 0xFFFF0000) != IDISP_VID_INTEL) {
hdev->type = HDA_DEV_LEGACY;
hda_codec_load_module(&hda_priv->codec);
@@ -145,7 +140,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
}
/* Codec initialization */
-int hda_codec_probe_bus(struct snd_sof_dev *sdev)
+void hda_codec_probe_bus(struct snd_sof_dev *sdev,
+ bool hda_codec_use_common_hdmi)
{
struct hdac_bus *bus = sof_to_bus(sdev);
int i, ret;
@@ -156,17 +152,15 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev)
if (!(bus->codec_mask & (1 << i)))
continue;
- ret = hda_codec_probe(sdev, i);
+ ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi);
if (ret < 0) {
- dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n",
- i, ret);
- return ret;
+ dev_warn(bus->dev, "codec #%d probe error, ret: %d\n",
+ i, ret);
+ bus->codec_mask &= ~BIT(i);
}
}
-
- return 0;
}
-EXPORT_SYMBOL(hda_codec_probe_bus);
+EXPORT_SYMBOL_NS(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \
IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)
@@ -178,7 +172,7 @@ void hda_codec_i915_get(struct snd_sof_dev *sdev)
dev_dbg(bus->dev, "Turning i915 HDAC power on\n");
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
}
-EXPORT_SYMBOL(hda_codec_i915_get);
+EXPORT_SYMBOL_NS(hda_codec_i915_get, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
void hda_codec_i915_put(struct snd_sof_dev *sdev)
{
@@ -187,7 +181,7 @@ void hda_codec_i915_put(struct snd_sof_dev *sdev)
dev_dbg(bus->dev, "Turning i915 HDAC power off\n");
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
}
-EXPORT_SYMBOL(hda_codec_i915_put);
+EXPORT_SYMBOL_NS(hda_codec_i915_put, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
int hda_codec_i915_init(struct snd_sof_dev *sdev)
{
@@ -203,7 +197,7 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL(hda_codec_i915_init);
+EXPORT_SYMBOL_NS(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
int hda_codec_i915_exit(struct snd_sof_dev *sdev)
{
@@ -216,7 +210,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL(hda_codec_i915_exit);
+EXPORT_SYMBOL_NS(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
#endif
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index df1909e1d950..871b71a15a63 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -15,11 +15,18 @@
* Hardware interface for generic Intel audio DSP HDA IP
*/
+#include <linux/module.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include "../ops.h"
#include "hda.h"
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+static int hda_codec_mask = -1;
+module_param_named(codec_mask, hda_codec_mask, int, 0444);
+MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
+#endif
+
/*
* HDA Operations.
*/
@@ -206,6 +213,12 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
}
+
+ if (hda_codec_mask != -1) {
+ bus->codec_mask &= hda_codec_mask;
+ dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
+ bus->codec_mask);
+ }
#endif
/* clear stream status */
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 8796f385be76..313611dcb5e4 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -11,6 +11,7 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
#include "../sof-priv.h"
+#include "../sof-audio.h"
#include "hda.h"
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
@@ -216,6 +217,8 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
link_dev = hda_link_stream_assign(bus, substream);
if (!link_dev)
return -EBUSY;
+
+ snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
}
stream_tag = hdac_stream(link_dev)->stream_tag;
@@ -228,8 +231,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
-
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -361,6 +362,13 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
bus = hstream->bus;
rtd = snd_pcm_substream_chip(substream);
link_dev = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!link_dev) {
+ dev_dbg(dai->dev,
+ "%s: link_dev is not assigned\n", __func__);
+ return -EINVAL;
+ }
+
hda_stream = hstream_to_sof_hda_stream(link_dev);
/* free the link DMA channel in the FW */
@@ -440,6 +448,10 @@ struct snd_soc_dai_driver skl_dai[] = {
.ops = &hda_link_dai_ops,
},
{
+ .name = "iDisp4 Pin",
+ .ops = &hda_link_dai_ops,
+},
+{
.name = "Analog CPU DAI",
.ops = &hda_link_dai_ops,
},
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index 0fd2153c1769..1837f66e361f 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -230,22 +230,15 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
"nothing to do in IPC IRQ thread\n");
}
- /* re-enable IPC interrupt */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
- HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
-
return IRQ_HANDLED;
}
-/* is this IRQ for ADSP ? - we only care about IPC here */
-irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
+/* Check if an IPC IRQ occurred */
+bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
{
- struct snd_sof_dev *sdev = context;
- int ret = IRQ_NONE;
+ bool ret = false;
u32 irq_status;
- spin_lock(&sdev->hw_lock);
-
/* store status */
irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status);
@@ -255,16 +248,10 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
goto out;
/* IPC message ? */
- if (irq_status & HDA_DSP_ADSPIS_IPC) {
- /* disable IPC interrupt */
- snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
- HDA_DSP_REG_ADSPIC,
- HDA_DSP_ADSPIC_IPC, 0);
- ret = IRQ_WAKE_THREAD;
- }
+ if (irq_status & HDA_DSP_ADSPIS_IPC)
+ ret = true;
out:
- spin_unlock(&sdev->hw_lock);
return ret;
}
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index b1783360fe10..1782f5092639 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -295,7 +295,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
/* init for booting wait */
init_waitqueue_head(&sdev->boot_wait);
- sdev->boot_complete = false;
/* prepare DMA for code loader stream */
tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size,
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 575f5f5877d8..23872f6e708d 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -17,6 +17,7 @@
#include <sound/hda_register.h>
#include <sound/pcm_params.h>
+#include "../sof-audio.h"
#include "../ops.h"
#include "hda.h"
@@ -147,12 +148,13 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *scomp = sdev->component;
struct hdac_stream *hstream = substream->runtime->private_data;
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct snd_sof_pcm *spcm;
snd_pcm_uframes_t pos;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(scomp, rtd);
if (!spcm) {
dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
rtd->dai_link->id);
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 29ab43281670..c0ab9bb2a797 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -20,6 +20,7 @@
#include <sound/hda_register.h>
#include <sound/sof.h>
#include "../ops.h"
+#include "../sof-audio.h"
#include "hda.h"
/*
@@ -549,22 +550,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
return 0;
}
-irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
+bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
{
- struct hdac_bus *bus = context;
- int ret = IRQ_WAKE_THREAD;
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ bool ret = false;
u32 status;
- spin_lock(&bus->reg_lock);
+ /* The function can be called at irq thread, so use spin_lock_irq */
+ spin_lock_irq(&bus->reg_lock);
status = snd_hdac_chip_readl(bus, INTSTS);
dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status);
- /* Register inaccessible, ignore it.*/
- if (status == 0xffffffff)
- ret = IRQ_NONE;
+ /* if Register inaccessible, ignore it.*/
+ if (status != 0xffffffff)
+ ret = true;
- spin_unlock(&bus->reg_lock);
+ spin_unlock_irq(&bus->reg_lock);
return ret;
}
@@ -602,7 +604,8 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
{
- struct hdac_bus *bus = context;
+ struct snd_sof_dev *sdev = context;
+ struct hdac_bus *bus = sof_to_bus(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
u32 rirb_status;
#endif
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 91bd88fddac7..d08462f481de 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -168,7 +168,7 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_ADSP_ERROR_CODE_SKL + 0x4);
- if (sdev->boot_complete) {
+ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
HDA_DSP_STACK_DUMP_SIZE);
snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
@@ -195,7 +195,7 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
HDA_DSP_SRAM_REG_FW_STATUS);
panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP);
- if (sdev->boot_complete) {
+ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
HDA_DSP_STACK_DUMP_SIZE);
snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
@@ -344,16 +344,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
struct hdac_bus *bus = sof_to_bus(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_ext_link *hlink;
- struct snd_soc_acpi_mach_params *mach_params;
- struct snd_soc_acpi_mach *hda_mach;
- struct snd_sof_pdata *pdata = sdev->pdata;
- struct snd_soc_acpi_mach *mach;
- const char *tplg_filename;
- const char *idisp_str;
- const char *dmic_str;
- int dmic_num;
- int codec_num = 0;
- int i;
#endif
int ret = 0;
@@ -387,95 +377,8 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
- /* codec detection */
- if (!bus->codec_mask) {
- dev_info(bus->dev, "no hda codecs found!\n");
- } else {
- dev_info(bus->dev, "hda codecs found, mask %lx\n",
- bus->codec_mask);
-
- for (i = 0; i < HDA_MAX_CODECS; i++) {
- if (bus->codec_mask & (1 << i))
- codec_num++;
- }
-
- /*
- * If no machine driver is found, then:
- *
- * hda machine driver is used if :
- * 1. there is one HDMI codec and one external HDAudio codec
- * 2. only HDMI codec
- */
- if (!pdata->machine && codec_num <= 2 &&
- HDA_IDISP_CODEC(bus->codec_mask)) {
- hda_mach = snd_soc_acpi_intel_hda_machines;
- pdata->machine = hda_mach;
-
- /* topology: use the info from hda_machines */
- pdata->tplg_filename =
- hda_mach->sof_tplg_filename;
-
- /*
- * firmware: pick the first in machine list,
- * or use nocodec firmware name if list is empty
- */
- mach = pdata->desc->machines;
- if (mach->id[0])
- pdata->fw_filename = mach->sof_fw_filename;
- else
- pdata->fw_filename =
- pdata->desc->nocodec_fw_filename;
-
- dev_info(bus->dev, "using HDA machine driver %s now\n",
- hda_mach->drv_name);
-
- if (codec_num == 1)
- idisp_str = "-idisp";
- else
- idisp_str = "";
-
- /* first check NHLT for DMICs */
- dmic_num = check_nhlt_dmic(sdev);
-
- /* allow for module parameter override */
- if (hda_dmic_num != -1)
- dmic_num = hda_dmic_num;
-
- switch (dmic_num) {
- case 2:
- dmic_str = "-2ch";
- break;
- case 4:
- dmic_str = "-4ch";
- break;
- default:
- dmic_num = 0;
- dmic_str = "";
- break;
- }
-
- tplg_filename = pdata->tplg_filename;
- tplg_filename = fixup_tplg_name(sdev, tplg_filename,
- idisp_str, dmic_str);
- if (!tplg_filename) {
- hda_codec_i915_exit(sdev);
- return ret;
- }
- pdata->tplg_filename = tplg_filename;
- }
- }
-
- /* used by hda machine driver to create dai links */
- if (pdata->machine) {
- mach_params = (struct snd_soc_acpi_mach_params *)
- &pdata->machine->mach_params;
- mach_params->codec_mask = bus->codec_mask;
- mach_params->platform = dev_name(sdev->dev);
- mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
- }
-
/* create codec instances */
- hda_codec_probe_bus(sdev);
+ hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi);
hda_codec_i915_put(sdev);
@@ -499,6 +402,49 @@ static const struct sof_intel_dsp_desc
return chip_info;
}
+static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
+{
+ struct snd_sof_dev *sdev = context;
+
+ /*
+ * Get global interrupt status. It includes all hardware interrupt
+ * sources in the Intel HD Audio controller.
+ */
+ if (snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS) &
+ SOF_HDA_INTSTS_GIS) {
+
+ /* disable GIE interrupt */
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+ SOF_HDA_INTCTL,
+ SOF_HDA_INT_GLOBAL_EN,
+ 0);
+
+ return IRQ_WAKE_THREAD;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
+{
+ struct snd_sof_dev *sdev = context;
+
+ /* deal with streams and controller first */
+ if (hda_dsp_check_stream_irq(sdev))
+ hda_dsp_stream_threaded_handler(irq, sdev);
+
+ if (hda_dsp_check_ipc_irq(sdev))
+ sof_ops(sdev)->irq_thread(irq, sdev);
+
+ /* enable GIE interrupt */
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+ SOF_HDA_INTCTL,
+ SOF_HDA_INT_GLOBAL_EN,
+ SOF_HDA_INT_GLOBAL_EN);
+
+ return IRQ_HANDLED;
+}
+
int hda_dsp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
@@ -603,9 +549,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
*/
if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) {
dev_info(sdev->dev, "use msi interrupt mode\n");
- hdev->irq = pci_irq_vector(pci, 0);
- /* ipc irq number is the same of hda irq */
- sdev->ipc_irq = hdev->irq;
+ sdev->ipc_irq = pci_irq_vector(pci, 0);
/* initialised to "false" by kzalloc() */
sdev->msi_enabled = true;
}
@@ -616,28 +560,17 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
* in IO-APIC mode, hda->irq and ipc_irq are using the same
* irq number of pci->irq
*/
- hdev->irq = pci->irq;
sdev->ipc_irq = pci->irq;
}
- dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq);
- ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt,
- hda_dsp_stream_threaded_handler,
- IRQF_SHARED, "AudioHDA", bus);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n",
- hdev->irq);
- goto free_irq_vector;
- }
-
dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq);
- ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler,
- sof_ops(sdev)->irq_thread, IRQF_SHARED,
- "AudioDSP", sdev);
+ ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_interrupt_handler,
+ hda_dsp_interrupt_thread,
+ IRQF_SHARED, "AudioDSP", sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n",
sdev->ipc_irq);
- goto free_hda_irq;
+ goto free_irq_vector;
}
pci_set_master(pci);
@@ -668,8 +601,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
free_ipc_irq:
free_irq(sdev->ipc_irq, sdev);
-free_hda_irq:
- free_irq(hdev->irq, bus);
free_irq_vector:
if (sdev->msi_enabled)
pci_free_irq_vectors(pci);
@@ -715,7 +646,6 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
SOF_HDA_PPCTL_GPROCEN, 0);
free_irq(sdev->ipc_irq, sdev);
- free_irq(hda->irq, bus);
if (sdev->msi_enabled)
pci_free_irq_vectors(pci);
@@ -735,4 +665,136 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
return 0;
}
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+static int hda_generic_machine_select(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct snd_soc_acpi_mach_params *mach_params;
+ struct snd_soc_acpi_mach *hda_mach;
+ struct snd_sof_pdata *pdata = sdev->pdata;
+ const char *tplg_filename;
+ const char *idisp_str;
+ const char *dmic_str;
+ int dmic_num = 0;
+ int codec_num = 0;
+ int i;
+
+ /* codec detection */
+ if (!bus->codec_mask) {
+ dev_info(bus->dev, "no hda codecs found!\n");
+ } else {
+ dev_info(bus->dev, "hda codecs found, mask %lx\n",
+ bus->codec_mask);
+
+ for (i = 0; i < HDA_MAX_CODECS; i++) {
+ if (bus->codec_mask & (1 << i))
+ codec_num++;
+ }
+
+ /*
+ * If no machine driver is found, then:
+ *
+ * hda machine driver is used if :
+ * 1. there is one HDMI codec and one external HDAudio codec
+ * 2. only HDMI codec
+ */
+ if (!pdata->machine && codec_num <= 2 &&
+ HDA_IDISP_CODEC(bus->codec_mask)) {
+ hda_mach = snd_soc_acpi_intel_hda_machines;
+
+ /* topology: use the info from hda_machines */
+ pdata->tplg_filename =
+ hda_mach->sof_tplg_filename;
+
+ dev_info(bus->dev, "using HDA machine driver %s now\n",
+ hda_mach->drv_name);
+
+ if (codec_num == 1)
+ idisp_str = "-idisp";
+ else
+ idisp_str = "";
+
+ /* first check NHLT for DMICs */
+ dmic_num = check_nhlt_dmic(sdev);
+
+ /* allow for module parameter override */
+ if (hda_dmic_num != -1)
+ dmic_num = hda_dmic_num;
+
+ switch (dmic_num) {
+ case 2:
+ dmic_str = "-2ch";
+ break;
+ case 4:
+ dmic_str = "-4ch";
+ break;
+ default:
+ dmic_num = 0;
+ dmic_str = "";
+ break;
+ }
+
+ tplg_filename = pdata->tplg_filename;
+ tplg_filename = fixup_tplg_name(sdev, tplg_filename,
+ idisp_str, dmic_str);
+ if (!tplg_filename)
+ return -EINVAL;
+
+ pdata->machine = hda_mach;
+ pdata->tplg_filename = tplg_filename;
+ }
+ }
+
+ /* used by hda machine driver to create dai links */
+ if (pdata->machine) {
+ mach_params = (struct snd_soc_acpi_mach_params *)
+ &pdata->machine->mach_params;
+ mach_params->codec_mask = bus->codec_mask;
+ mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
+ mach_params->dmic_num = dmic_num;
+ }
+
+ return 0;
+}
+#else
+static int hda_generic_machine_select(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+#endif
+
+void hda_set_mach_params(const struct snd_soc_acpi_mach *mach,
+ struct device *dev)
+{
+ struct snd_soc_acpi_mach_params *mach_params;
+
+ mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params;
+ mach_params->platform = dev_name(dev);
+}
+
+void hda_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_soc_acpi_mach *mach;
+
+ mach = snd_soc_acpi_find_machine(desc->machines);
+ if (mach) {
+ sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ sof_pdata->machine = mach;
+ }
+
+ /*
+ * Choose HDA generic machine driver if mach is NULL.
+ * Otherwise, set certain mach params.
+ */
+ hda_generic_machine_select(sdev);
+
+ if (!sof_pdata->machine)
+ dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
+}
+
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC);
+MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 18d7e72bf9b7..47408ec0de40 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -43,11 +43,14 @@
/* SOF_HDA_GCTL register bist */
#define SOF_HDA_GCTL_RESET BIT(0)
-/* SOF_HDA_INCTL and SOF_HDA_INTSTS regs */
+/* SOF_HDA_INCTL regs */
#define SOF_HDA_INT_GLOBAL_EN BIT(31)
#define SOF_HDA_INT_CTRL_EN BIT(30)
#define SOF_HDA_INT_ALL_STREAM 0xff
+/* SOF_HDA_INTSTS regs */
+#define SOF_HDA_INTSTS_GIS BIT(31)
+
#define SOF_HDA_MAX_CAPS 10
#define SOF_HDA_CAP_ID_OFF 16
#define SOF_HDA_CAP_ID_MASK GENMASK(SOF_HDA_CAP_ID_OFF + 11,\
@@ -406,8 +409,6 @@ struct sof_intel_hda_dev {
/* the maximum number of streams (playback + capture) supported */
u32 stream_max;
- int irq;
-
/* PM related */
bool l1_support_changed;/* during suspend, is L1SEN changed or not */
@@ -511,11 +512,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
struct snd_pcm_hw_params *params);
int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
struct hdac_ext_stream *stream, int cmd);
-irqreturn_t hda_dsp_stream_interrupt(int irq, void *context);
irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context);
int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmab,
struct hdac_stream *stream);
+bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
+bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
struct hdac_ext_stream *
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);
@@ -540,7 +542,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev);
int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
-irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context);
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context);
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
@@ -574,7 +575,8 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev);
/*
* HDA Codec operations.
*/
-int hda_codec_probe_bus(struct snd_sof_dev *sdev);
+void hda_codec_probe_bus(struct snd_sof_dev *sdev,
+ bool hda_codec_use_common_hdmi);
void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev);
void hda_codec_jack_check(struct snd_sof_dev *sdev);
@@ -622,4 +624,9 @@ extern const struct sof_intel_dsp_desc tgl_chip_info;
extern const struct sof_intel_dsp_desc ehl_chip_info;
extern const struct sof_intel_dsp_desc jsl_chip_info;
+/* machine driver select */
+void hda_machine_select(struct snd_sof_dev *sdev);
+void hda_set_mach_params(const struct snd_soc_acpi_mach *mach,
+ struct device *dev);
+
#endif
diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c
index 4edd92151fd5..e935f70d611b 100644
--- a/sound/soc/sof/intel/intel-ipc.c
+++ b/sound/soc/sof/intel/intel-ipc.c
@@ -39,7 +39,7 @@ void intel_ipc_msg_data(struct snd_sof_dev *sdev,
sof_mailbox_read(sdev, stream->posn_offset, p, sz);
}
}
-EXPORT_SYMBOL(intel_ipc_msg_data);
+EXPORT_SYMBOL_NS(intel_ipc_msg_data, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
int intel_ipc_pcm_params(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
@@ -60,7 +60,7 @@ int intel_ipc_pcm_params(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL(intel_ipc_pcm_params);
+EXPORT_SYMBOL_NS(intel_ipc_pcm_params, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
int intel_pcm_open(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
@@ -75,7 +75,7 @@ int intel_pcm_open(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL(intel_pcm_open);
+EXPORT_SYMBOL_NS(intel_pcm_open, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
int intel_pcm_close(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
@@ -87,6 +87,6 @@ int intel_pcm_close(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL(intel_pcm_close);
+EXPORT_SYMBOL_NS(intel_pcm_close, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index f7a3f62e45d4..daaf3364c177 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -12,7 +12,7 @@
#define __SOF_INTEL_SHIM_H
/*
- * SHIM registers for BYT, BSW, CHT, HSW, BDW
+ * SHIM registers for BYT, BSW, CHT, BDW
*/
#define SHIM_CSR (SHIM_OFFSET + 0x00)
@@ -38,7 +38,7 @@
#define SHIM_PWMCTRL 0x1000
/*
- * SST SHIM register bits for BYT, BSW, CHT HSW, BDW
+ * SST SHIM register bits for BYT, BSW, CHT, BDW
* Register bit naming and functionaility can differ between devices.
*/
@@ -169,13 +169,11 @@ struct sof_intel_dsp_desc {
extern const struct snd_sof_dsp_ops sof_tng_ops;
extern const struct snd_sof_dsp_ops sof_byt_ops;
extern const struct snd_sof_dsp_ops sof_cht_ops;
-extern const struct snd_sof_dsp_ops sof_hsw_ops;
extern const struct snd_sof_dsp_ops sof_bdw_ops;
extern const struct sof_intel_dsp_desc byt_chip_info;
extern const struct sof_intel_dsp_desc cht_chip_info;
extern const struct sof_intel_dsp_desc bdw_chip_info;
-extern const struct sof_intel_dsp_desc hsw_chip_info;
extern const struct sof_intel_dsp_desc tng_chip_info;
struct sof_intel_stream {
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index 5994e1073364..b63fc529b456 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include "sof-priv.h"
+#include "sof-audio.h"
#include "ops.h"
static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id);
@@ -346,19 +347,12 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
break;
case SOF_IPC_FW_READY:
/* check for FW boot completion */
- if (!sdev->boot_complete) {
+ if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
err = sof_ops(sdev)->fw_ready(sdev, cmd);
- if (err < 0) {
- /*
- * this indicates a mismatch in ABI
- * between the driver and fw
- */
- dev_err(sdev->dev, "error: ABI mismatch %d\n",
- err);
- } else {
- /* firmware boot completed OK */
- sdev->boot_complete = true;
- }
+ if (err < 0)
+ sdev->fw_state = SOF_FW_BOOT_READY_FAILED;
+ else
+ sdev->fw_state = SOF_FW_BOOT_COMPLETE;
/* wake up firmware loader */
wake_up(&sdev->boot_wait);
@@ -412,12 +406,13 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
{
+ struct snd_soc_component *scomp = sdev->component;
struct snd_sof_pcm_stream *stream;
struct sof_ipc_stream_posn posn;
struct snd_sof_pcm *spcm;
int direction;
- spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
+ spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
if (!spcm) {
dev_err(sdev->dev,
"error: period elapsed for unknown stream, msg_id %d\n",
@@ -441,12 +436,13 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
/* DSP notifies host of an XRUN within FW */
static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
{
+ struct snd_soc_component *scomp = sdev->component;
struct snd_sof_pcm_stream *stream;
struct sof_ipc_stream_posn posn;
struct snd_sof_pcm *spcm;
int direction;
- spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
+ spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
if (!spcm) {
dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n",
msg_id);
@@ -488,10 +484,11 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
}
/* get stream position IPC - use faster MMIO method if available on platform */
-int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
+int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
struct snd_sof_pcm *spcm, int direction,
struct sof_ipc_stream_posn *posn)
{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc_stream stream;
int err;
@@ -620,15 +617,15 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
/*
* IPC get()/set() for kcontrols.
*/
-int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
- struct snd_sof_control *scontrol,
+int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
u32 ipc_cmd,
enum sof_ipc_ctrl_type ctrl_type,
enum sof_ipc_ctrl_cmd ctrl_cmd,
bool send)
{
+ struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
- struct snd_sof_dev *sdev = ipc->sdev;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
struct sof_ipc_ctrl_data_params sparams;
@@ -826,6 +823,9 @@ void snd_sof_ipc_free(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc *ipc = sdev->ipc;
+ if (!ipc)
+ return;
+
/* disable sending of ipc's */
mutex_lock(&ipc->tx_mutex);
ipc->disable_ipc_tx = true;
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index 9a9a381a908d..fc4ab51bacf4 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -32,6 +32,42 @@ static int get_ext_windows(struct snd_sof_dev *sdev,
return 0;
}
+static int get_cc_info(struct snd_sof_dev *sdev,
+ struct sof_ipc_ext_data_hdr *ext_hdr)
+{
+ int ret;
+
+ struct sof_ipc_cc_version *cc =
+ container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
+
+ dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
+ cc->name, cc->major, cc->minor, cc->micro, cc->desc,
+ cc->optim);
+
+ /* create read-only cc_version debugfs to store compiler version info */
+ /* use local copy of the cc_version to prevent data corruption */
+ if (sdev->first_boot) {
+ sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
+ GFP_KERNEL);
+
+ if (!sdev->cc_version)
+ return -ENOMEM;
+
+ memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
+ ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
+ cc->ext_hdr.hdr.size,
+ "cc_version", 0444);
+
+ /* errors are only due to memory allocation, not debugfs */
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
/* parse the extended FW boot data structures from FW boot message */
int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
{
@@ -50,8 +86,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
/* read in ext structure */
- offset += sizeof(*ext_hdr);
- snd_sof_dsp_block_read(sdev, bar, offset,
+ snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr),
(void *)((u8 *)ext_data + sizeof(*ext_hdr)),
ext_hdr->hdr.size - sizeof(*ext_hdr));
@@ -61,11 +96,18 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
/* process structure data */
switch (ext_hdr->type) {
case SOF_IPC_EXT_DMA_BUFFER:
+ ret = 0;
break;
case SOF_IPC_EXT_WINDOW:
ret = get_ext_windows(sdev, ext_hdr);
break;
+ case SOF_IPC_EXT_CC_INFO:
+ ret = get_cc_info(sdev, ext_hdr);
+ break;
default:
+ dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
+ ext_hdr->type, ext_hdr->hdr.size);
+ ret = 0;
break;
}
@@ -445,6 +487,9 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
if (ret < 0) {
dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
fw_filename, ret);
+ } else {
+ dev_dbg(sdev->dev, "request_firmware %s successful\n",
+ fw_filename);
}
kfree(fw_filename);
@@ -509,7 +554,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
int init_core_mask;
init_waitqueue_head(&sdev->boot_wait);
- sdev->boot_complete = false;
/* create read-only fw_version debugfs to store boot version info */
if (sdev->first_boot) {
@@ -541,19 +585,27 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
init_core_mask = ret;
- /* now wait for the DSP to boot */
- ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete,
+ /*
+ * now wait for the DSP to boot. There are 3 possible outcomes:
+ * 1. Boot wait times out indicating FW boot failure.
+ * 2. FW boots successfully and fw_ready op succeeds.
+ * 3. FW boots but fw_ready op fails.
+ */
+ ret = wait_event_timeout(sdev->boot_wait,
+ sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
msecs_to_jiffies(sdev->boot_timeout));
if (ret == 0) {
dev_err(sdev->dev, "error: firmware boot failure\n");
snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
SOF_DBG_TEXT | SOF_DBG_PCI);
- /* after this point FW_READY msg should be ignored */
- sdev->boot_complete = true;
+ sdev->fw_state = SOF_FW_BOOT_FAILED;
return -EIO;
}
- dev_info(sdev->dev, "firmware boot complete\n");
+ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
+ dev_info(sdev->dev, "firmware boot complete\n");
+ else
+ return -EIO; /* FW boots but fw_ready op failed */
/* perform post fw run operations */
ret = snd_sof_dsp_post_fw_run(sdev);
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 3d128e5a132c..2233146386cc 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -63,23 +63,11 @@ static int sof_nocodec_bes_setup(struct device *dev,
}
int sof_nocodec_setup(struct device *dev,
- struct snd_sof_pdata *sof_pdata,
- struct snd_soc_acpi_mach *mach,
- const struct sof_dev_desc *desc,
const struct snd_sof_dsp_ops *ops)
{
struct snd_soc_dai_link *links;
int ret;
- if (!mach)
- return -EINVAL;
-
- sof_pdata->drv_name = "sof-nocodec";
-
- mach->drv_name = "sof-nocodec";
- sof_pdata->fw_filename = desc->nocodec_fw_filename;
- sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
-
/* create dummy BE dai_links */
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
ops->num_drv, GFP_KERNEL);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index 93512dcbaacd..e929a6e0058f 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -391,6 +391,40 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev,
return 0;
}
+/* machine driver */
+static inline int
+snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
+{
+ if (sof_ops(sdev) && sof_ops(sdev)->machine_register)
+ return sof_ops(sdev)->machine_register(sdev, pdata);
+
+ return 0;
+}
+
+static inline void
+snd_sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
+{
+ if (sof_ops(sdev) && sof_ops(sdev)->machine_unregister)
+ sof_ops(sdev)->machine_unregister(sdev, pdata);
+}
+
+static inline void
+snd_sof_machine_select(struct snd_sof_dev *sdev)
+{
+ if (sof_ops(sdev) && sof_ops(sdev)->machine_select)
+ sof_ops(sdev)->machine_select(sdev);
+}
+
+static inline void
+snd_sof_set_mach_params(const struct snd_soc_acpi_mach *mach,
+ struct device *dev)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+
+ if (sof_ops(sdev) && sof_ops(sdev)->set_mach_params)
+ sof_ops(sdev)->set_mach_params(mach, dev);
+}
+
static inline const struct snd_sof_dsp_ops
*sof_get_ops(const struct sof_dev_desc *d,
const struct sof_ops_table mach_ops[], int asize)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 549238a98b2a..9bb6388742e1 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -14,38 +14,38 @@
#include <sound/pcm_params.h>
#include <sound/sof.h>
#include "sof-priv.h"
+#include "sof-audio.h"
#include "ops.h"
-#define DRV_NAME "sof-audio-component"
-
/* Create DMA buffer page table for DSP */
static int create_page_table(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
unsigned char *dma_area, size_t size)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm;
struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
int stream = substream->stream;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
- return snd_sof_create_page_table(sdev, dmab,
+ return snd_sof_create_page_table(component->dev, dmab,
spcm->stream[stream].page_table.area, size);
}
static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream,
const struct sof_ipc_pcm_params_reply *reply)
{
- struct snd_sof_dev *sdev = spcm->sdev;
+ struct snd_soc_component *scomp = spcm->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+
/* validate offset */
int ret = snd_sof_ipc_pcm_params(sdev, substream, reply);
if (ret < 0)
- dev_err(sdev->dev, "error: got wrong reply for PCM %d\n",
+ dev_err(scomp->dev, "error: got wrong reply for PCM %d\n",
spcm->pcm.pcm_id);
return ret;
@@ -70,13 +70,12 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_pcm *spcm;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm) {
- dev_err(sdev->dev,
+ dev_err(component->dev,
"error: period elapsed for unknown stream!\n");
return;
}
@@ -110,29 +109,17 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
- dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n",
+ dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
memset(&pcm, 0, sizeof(pcm));
- /* allocate audio buffer pages */
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (ret < 0) {
- dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n",
- params_buffer_bytes(params), spcm->pcm.pcm_id);
- return ret;
- }
- if (ret) {
- /*
- * ret == 1 means the buffer is changed
- * create compressed page table for audio firmware
- * ret == 0 means the buffer is not changed
- * so no need to regenerate the page table
- */
+ /* create compressed page table for audio firmware */
+ if (runtime->buffer_changed) {
ret = create_page_table(component, substream, runtime->dma_area,
runtime->dma_bytes);
if (ret < 0)
@@ -187,17 +174,17 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
params,
&pcm.params);
if (ret < 0) {
- dev_err(sdev->dev, "error: platform hw params failed\n");
+ dev_err(component->dev, "error: platform hw params failed\n");
return ret;
}
- dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag);
+ dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
/* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
- dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n",
+ dev_err(component->dev, "error: hw params ipc failed for stream %d\n",
pcm.params.stream_tag);
return ret;
}
@@ -247,12 +234,12 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
- dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
- substream->stream);
+ dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
+ spcm->pcm.pcm_id, substream->stream);
if (spcm->prepared[substream->stream]) {
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
@@ -260,13 +247,11 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
err = ret;
}
- snd_pcm_lib_free_pages(substream);
-
cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0) {
- dev_err(sdev->dev, "error: platform hw free failed\n");
+ dev_err(component->dev, "error: platform hw free failed\n");
err = ret;
}
@@ -277,7 +262,6 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm;
int ret;
@@ -285,21 +269,22 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
if (spcm->prepared[substream->stream])
return 0;
- dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id,
- substream->stream);
+ dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
+ spcm->pcm.pcm_id, substream->stream);
/* set hw_params */
ret = sof_pcm_hw_params(component,
substream, &spcm->params[substream->stream]);
if (ret < 0) {
- dev_err(sdev->dev, "error: set pcm hw_params after resume\n");
+ dev_err(component->dev,
+ "error: set pcm hw_params after resume\n");
return ret;
}
@@ -326,11 +311,11 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
- dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n",
+ dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n",
spcm->pcm.pcm_id, substream->stream, cmd);
stream.hdr.size = sizeof(stream);
@@ -359,7 +344,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
/* set up hw_params */
ret = sof_pcm_prepare(component, substream);
if (ret < 0) {
- dev_err(sdev->dev,
+ dev_err(component->dev,
"error: failed to set up hw_params upon resume\n");
return ret;
}
@@ -396,7 +381,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
reset_hw_params = true;
break;
default:
- dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd);
+ dev_err(component->dev, "error: unhandled trigger cmd %d\n",
+ cmd);
return -EINVAL;
}
@@ -438,7 +424,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component,
if (sof_ops(sdev)->pcm_pointer)
return sof_ops(sdev)->pcm_pointer(sdev, substream);
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
@@ -448,7 +434,8 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component,
dai = bytes_to_frames(substream->runtime,
spcm->stream[substream->stream].posn.dai_posn);
- dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
+ dev_dbg(component->dev,
+ "PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
spcm->pcm.pcm_id, substream->stream, host, dai);
return host;
@@ -469,12 +456,12 @@ static int sof_pcm_open(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
- dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
- substream->stream);
+ dev_dbg(component->dev, "pcm: open stream %d dir %d\n",
+ spcm->pcm.pcm_id, substream->stream);
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
sof_pcm_period_elapsed_work);
@@ -504,13 +491,13 @@ static int sof_pcm_open(struct snd_soc_component *component,
*/
runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
- dev_dbg(sdev->dev, "period min %zd max %zd bytes\n",
+ dev_dbg(component->dev, "period min %zd max %zd bytes\n",
runtime->hw.period_bytes_min,
runtime->hw.period_bytes_max);
- dev_dbg(sdev->dev, "period count %d max %d\n",
+ dev_dbg(component->dev, "period count %d max %d\n",
runtime->hw.periods_min,
runtime->hw.periods_max);
- dev_dbg(sdev->dev, "buffer max %zd bytes\n",
+ dev_dbg(component->dev, "buffer max %zd bytes\n",
runtime->hw.buffer_bytes_max);
/* set wait time - TODO: come from topology */
@@ -523,7 +510,7 @@ static int sof_pcm_open(struct snd_soc_component *component,
ret = snd_sof_pcm_platform_open(sdev, substream);
if (ret < 0)
- dev_err(sdev->dev, "error: pcm open failed %d\n", ret);
+ dev_err(component->dev, "error: pcm open failed %d\n", ret);
return ret;
}
@@ -540,16 +527,16 @@ static int sof_pcm_close(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
- dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id,
- substream->stream);
+ dev_dbg(component->dev, "pcm: close stream %d dir %d\n",
+ spcm->pcm.pcm_id, substream->stream);
err = snd_sof_pcm_platform_close(sdev, substream);
if (err < 0) {
- dev_err(sdev->dev, "error: pcm close failed %d\n",
+ dev_err(component->dev, "error: pcm close failed %d\n",
err);
/*
* keep going, no point in preventing the close
@@ -575,14 +562,14 @@ static int sof_pcm_new(struct snd_soc_component *component,
int stream = SNDRV_PCM_STREAM_PLAYBACK;
/* find SOF PCM for this RTD */
- spcm = snd_sof_find_spcm_dai(sdev, rtd);
+ spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm) {
- dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
+ dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n",
rtd->dai_link->id);
return 0;
}
- dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
+ dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
/* do we need to pre-allocate playback audio buffer pages */
if (!spcm->pcm.playback)
@@ -591,13 +578,14 @@ static int sof_pcm_new(struct snd_soc_component *component,
caps = &spcm->pcm.caps[stream];
/* pre-allocate playback audio buffer pages */
- dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
+ dev_dbg(component->dev,
+ "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
caps->name, caps->buffer_size_min, caps->buffer_size_max);
- snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
- SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
- le32_to_cpu(caps->buffer_size_min),
- le32_to_cpu(caps->buffer_size_max));
+ snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
+ SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
+ le32_to_cpu(caps->buffer_size_min),
+ le32_to_cpu(caps->buffer_size_max));
capture:
stream = SNDRV_PCM_STREAM_CAPTURE;
@@ -608,13 +596,14 @@ capture:
caps = &spcm->pcm.caps[stream];
/* pre-allocate capture audio buffer pages */
- dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
+ dev_dbg(component->dev,
+ "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
caps->name, caps->buffer_size_min, caps->buffer_size_max);
- snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
- SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
- le32_to_cpu(caps->buffer_size_min),
- le32_to_cpu(caps->buffer_size_max));
+ snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
+ SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
+ le32_to_cpu(caps->buffer_size_min),
+ le32_to_cpu(caps->buffer_size_max));
return 0;
}
@@ -629,14 +618,14 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_dai *dai =
- snd_sof_find_dai(sdev, (char *)rtd->dai_link->name);
+ snd_sof_find_dai(component, (char *)rtd->dai_link->name);
/* no topology exists for this BE, try a common configuration */
if (!dai) {
- dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n",
+ dev_warn(component->dev,
+ "warning: no topology found for BE DAI %s config\n",
rtd->dai_link->name);
/* set 48k, stereo, 16bits by default */
@@ -666,7 +655,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
break;
default:
- dev_err(sdev->dev, "error: No available DAI format!\n");
+ dev_err(component->dev, "error: No available DAI format!\n");
return -EINVAL;
}
@@ -678,9 +667,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = dai->dai_config->ssp.tdm_slots;
channels->max = dai->dai_config->ssp.tdm_slots;
- dev_dbg(sdev->dev,
+ dev_dbg(component->dev,
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(sdev->dev,
+ dev_dbg(component->dev,
"channels_min: %d channels_max: %d\n",
channels->min, channels->max);
@@ -688,7 +677,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
case SOF_DAI_INTEL_DMIC:
/* DMIC only supports 16 or 32 bit formats */
if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
- dev_err(sdev->dev,
+ dev_err(component->dev,
"error: invalid fmt %d for DAI type %d\n",
dai->comp_dai.config.frame_fmt,
dai->dai_config->type);
@@ -704,12 +693,20 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = dai->dai_config->esai.tdm_slots;
channels->max = dai->dai_config->esai.tdm_slots;
- dev_dbg(sdev->dev,
+ dev_dbg(component->dev,
+ "channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_IMX_SAI:
+ channels->min = dai->dai_config->sai.tdm_slots;
+ channels->max = dai->dai_config->sai.tdm_slots;
+
+ dev_dbg(component->dev,
"channels_min: %d channels_max: %d\n",
channels->min, channels->max);
break;
default:
- dev_err(sdev->dev, "error: invalid DAI type %d\n",
+ dev_err(component->dev, "error: invalid DAI type %d\n",
dai->dai_config->type);
break;
}
@@ -734,21 +731,13 @@ static int sof_pcm_probe(struct snd_soc_component *component)
if (!tplg_filename)
return -ENOMEM;
- ret = snd_sof_load_topology(sdev, tplg_filename);
+ ret = snd_sof_load_topology(component, tplg_filename);
if (ret < 0) {
- dev_err(sdev->dev, "error: failed to load DSP topology %d\n",
+ dev_err(component->dev, "error: failed to load DSP topology %d\n",
ret);
return ret;
}
- /*
- * Some platforms in SOF, ex: BYT, may not have their platform PM
- * callbacks set. Increment the usage count so as to
- * prevent the device from entering runtime suspend.
- */
- if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
- pm_runtime_get_noresume(sdev->dev);
-
return ret;
}
@@ -771,7 +760,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
pd->remove = sof_pcm_remove;
pd->open = sof_pcm_open;
pd->close = sof_pcm_close;
- pd->ioctl = snd_soc_pcm_lib_ioctl;
pd->hw_params = sof_pcm_hw_params;
pd->prepare = sof_pcm_prepare;
pd->hw_free = sof_pcm_hw_free;
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
index 0fd5567237a8..84290bbeebdd 100644
--- a/sound/soc/sof/pm.c
+++ b/sound/soc/sof/pm.c
@@ -10,192 +10,7 @@
#include "ops.h"
#include "sof-priv.h"
-
-static int sof_restore_kcontrols(struct snd_sof_dev *sdev)
-{
- struct snd_sof_control *scontrol;
- int ipc_cmd, ctrl_type;
- int ret = 0;
-
- /* restore kcontrol values */
- list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
- /* reset readback offset for scontrol after resuming */
- scontrol->readback_offset = 0;
-
- /* notify DSP of kcontrol values */
- switch (scontrol->cmd) {
- case SOF_CTRL_CMD_VOLUME:
- case SOF_CTRL_CMD_ENUM:
- case SOF_CTRL_CMD_SWITCH:
- ipc_cmd = SOF_IPC_COMP_SET_VALUE;
- ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
- ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- ipc_cmd, ctrl_type,
- scontrol->cmd,
- true);
- break;
- case SOF_CTRL_CMD_BINARY:
- ipc_cmd = SOF_IPC_COMP_SET_DATA;
- ctrl_type = SOF_CTRL_TYPE_DATA_SET;
- ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- ipc_cmd, ctrl_type,
- scontrol->cmd,
- true);
- break;
-
- default:
- break;
- }
-
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed kcontrol value set for widget: %d\n",
- scontrol->comp_id);
-
- return ret;
- }
- }
-
- return 0;
-}
-
-static int sof_restore_pipelines(struct snd_sof_dev *sdev)
-{
- struct snd_sof_widget *swidget;
- struct snd_sof_route *sroute;
- struct sof_ipc_pipe_new *pipeline;
- struct snd_sof_dai *dai;
- struct sof_ipc_comp_dai *comp_dai;
- struct sof_ipc_cmd_hdr *hdr;
- int ret;
-
- /* restore pipeline components */
- list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
- struct sof_ipc_comp_reply r;
-
- /* skip if there is no private data */
- if (!swidget->private)
- continue;
-
- switch (swidget->id) {
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_dai_out:
- dai = swidget->private;
- comp_dai = &dai->comp_dai;
- ret = sof_ipc_tx_message(sdev->ipc,
- comp_dai->comp.hdr.cmd,
- comp_dai, sizeof(*comp_dai),
- &r, sizeof(r));
- break;
- case snd_soc_dapm_scheduler:
-
- /*
- * During suspend, all DSP cores are powered off.
- * Therefore upon resume, create the pipeline comp
- * and power up the core that the pipeline is
- * scheduled on.
- */
- pipeline = swidget->private;
- ret = sof_load_pipeline_ipc(sdev, pipeline, &r);
- break;
- default:
- hdr = swidget->private;
- ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd,
- swidget->private, hdr->size,
- &r, sizeof(r));
- break;
- }
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to load widget type %d with ID: %d\n",
- swidget->widget->id, swidget->comp_id);
-
- return ret;
- }
- }
-
- /* restore pipeline connections */
- list_for_each_entry_reverse(sroute, &sdev->route_list, list) {
- struct sof_ipc_pipe_comp_connect *connect;
- struct sof_ipc_reply reply;
-
- /* skip if there's no private data */
- if (!sroute->private)
- continue;
-
- connect = sroute->private;
-
- /* send ipc */
- ret = sof_ipc_tx_message(sdev->ipc,
- connect->hdr.cmd,
- connect, sizeof(*connect),
- &reply, sizeof(reply));
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to load route sink %s control %s source %s\n",
- sroute->route->sink,
- sroute->route->control ? sroute->route->control
- : "none",
- sroute->route->source);
-
- return ret;
- }
- }
-
- /* restore dai links */
- list_for_each_entry_reverse(dai, &sdev->dai_list, list) {
- struct sof_ipc_reply reply;
- struct sof_ipc_dai_config *config = dai->dai_config;
-
- if (!config) {
- dev_err(sdev->dev, "error: no config for DAI %s\n",
- dai->name);
- continue;
- }
-
- /*
- * The link DMA channel would be invalidated for running
- * streams but not for streams that were in the PAUSED
- * state during suspend. So invalidate it here before setting
- * the dai config in the DSP.
- */
- if (config->type == SOF_DAI_INTEL_HDA)
- config->hda.link_dma_ch = DMA_CHAN_INVALID;
-
- ret = sof_ipc_tx_message(sdev->ipc,
- config->hdr.cmd, config,
- config->hdr.size,
- &reply, sizeof(reply));
-
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to set dai config for %s\n",
- dai->name);
-
- return ret;
- }
- }
-
- /* complete pipeline */
- list_for_each_entry(swidget, &sdev->widget_list, list) {
- switch (swidget->id) {
- case snd_soc_dapm_scheduler:
- swidget->complete =
- snd_sof_complete_pipeline(sdev, swidget);
- break;
- default:
- break;
- }
- }
-
- /* restore pipeline kcontrols */
- ret = sof_restore_kcontrols(sdev);
- if (ret < 0)
- dev_err(sdev->dev,
- "error: restoring kcontrols after resume\n");
-
- return ret;
-}
+#include "sof-audio.h"
static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
{
@@ -213,34 +28,6 @@ static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
sizeof(pm_ctx), &reply, sizeof(reply));
}
-static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
-{
- struct snd_pcm_substream *substream;
- struct snd_sof_pcm *spcm;
- snd_pcm_state_t state;
- int dir;
-
- /*
- * SOF requires hw_params to be set-up internally upon resume.
- * So, set the flag to indicate this for those streams that
- * have been suspended.
- */
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
- substream = spcm->stream[dir].substream;
- if (!substream || !substream->runtime)
- continue;
-
- state = substream->runtime->status->state;
- if (state == SNDRV_PCM_STATE_SUSPENDED)
- spcm->prepared[dir] = false;
- }
- }
-
- /* set internal flag for BE */
- return snd_sof_dsp_hw_params_upon_resume(sdev);
-}
-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
static void sof_cache_debugfs(struct snd_sof_dev *sdev)
{
@@ -283,6 +70,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
return ret;
}
+ sdev->fw_state = SOF_FW_BOOT_PREPARE;
+
/* load the firmware */
ret = snd_sof_load_firmware(sdev);
if (ret < 0) {
@@ -292,7 +81,12 @@ static int sof_resume(struct device *dev, bool runtime_resume)
return ret;
}
- /* boot the firmware */
+ sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS;
+
+ /*
+ * Boot the firmware. The FW boot status will be modified
+ * in snd_sof_run_firmware() depending on the outcome.
+ */
ret = snd_sof_run_firmware(sdev);
if (ret < 0) {
dev_err(sdev->dev,
@@ -311,7 +105,7 @@ static int sof_resume(struct device *dev, bool runtime_resume)
}
/* restore pipelines */
- ret = sof_restore_pipelines(sdev);
+ ret = sof_restore_pipelines(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to restore pipeline after resume %d\n",
@@ -341,12 +135,15 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
if (!sof_ops(sdev)->suspend)
return 0;
+ if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
+ goto power_down;
+
/* release trace */
snd_sof_release_trace(sdev);
/* set restore_stream for all streams during system suspend */
if (!runtime_suspend) {
- ret = sof_set_hw_params_upon_resume(sdev);
+ ret = sof_set_hw_params_upon_resume(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev,
"error: setting hw_params flag during suspend %d\n",
@@ -378,6 +175,12 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
ret);
}
+power_down:
+
+ /* return if the DSP was not probed successfully */
+ if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED)
+ return 0;
+
/* power down all DSP cores */
if (runtime_suspend)
ret = snd_sof_dsp_runtime_suspend(sdev);
@@ -388,6 +191,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
"error: failed to power down DSP during suspend %d\n",
ret);
+ /* reset FW state */
+ sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
+
return ret;
}
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index df318f50dd0b..1278aa95effa 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -35,23 +35,6 @@ MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)");
#define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0)
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL)
-static const struct sof_dev_desc sof_acpi_haswell_desc = {
- .machines = snd_soc_acpi_intel_haswell_machines,
- .resindex_lpe_base = 0,
- .resindex_pcicfg_base = 1,
- .resindex_imr_base = -1,
- .irqindex_host_ipc = 0,
- .chip_info = &hsw_chip_info,
- .default_fw_path = "intel/sof",
- .default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-hsw.ri",
- .nocodec_tplg_filename = "sof-hsw-nocodec.tplg",
- .ops = &sof_hsw_ops,
- .arch_ops = &sof_xtensa_arch_ops
-};
-#endif
-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
static const struct sof_dev_desc sof_acpi_broadwell_desc = {
.machines = snd_soc_acpi_intel_broadwell_machines,
@@ -62,10 +45,9 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = {
.chip_info = &bdw_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-bdw.ri",
+ .default_fw_filename = "sof-bdw.ri",
.nocodec_tplg_filename = "sof-bdw-nocodec.tplg",
.ops = &sof_bdw_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -81,10 +63,9 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = {
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-byt.ri",
+ .default_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
static const struct sof_dev_desc sof_acpi_baytrail_desc = {
@@ -96,10 +77,9 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = {
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-byt.ri",
+ .default_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
@@ -111,10 +91,9 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
.chip_info = &cht_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-cht.ri",
+ .default_fw_filename = "sof-cht.ri",
.nocodec_tplg_filename = "sof-cht-nocodec.tplg",
.ops = &sof_cht_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -140,7 +119,6 @@ static int sof_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct sof_dev_desc *desc;
- struct snd_soc_acpi_mach *mach;
struct snd_sof_pdata *sof_pdata;
const struct snd_sof_dsp_ops *ops;
int ret;
@@ -167,35 +145,9 @@ static int sof_acpi_probe(struct platform_device *pdev)
return -ENODEV;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
- /* force nocodec mode */
- dev_warn(dev, "Force to use nocodec mode\n");
- mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
- if (!mach)
- return -ENOMEM;
- ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
- if (ret < 0)
- return ret;
-#else
- /* find machine */
- mach = snd_soc_acpi_find_machine(desc->machines);
- if (!mach) {
- dev_warn(dev, "warning: No matching ASoC machine driver found\n");
- } else {
- sof_pdata->fw_filename = mach->sof_fw_filename;
- sof_pdata->tplg_filename = mach->sof_tplg_filename;
- }
-#endif
-
- if (mach) {
- mach->mach_params.platform = dev_name(dev);
- mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc;
- }
-
- sof_pdata->machine = mach;
sof_pdata->desc = desc;
sof_pdata->dev = &pdev->dev;
- sof_pdata->platform = dev_name(dev);
+ sof_pdata->fw_filename = desc->default_fw_filename;
/* alternate fw and tplg filenames ? */
if (fw_path)
@@ -240,9 +192,6 @@ static int sof_acpi_remove(struct platform_device *pdev)
}
static const struct acpi_device_id sof_acpi_match[] = {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL)
- { "INT33C8", (unsigned long)&sof_acpi_haswell_desc },
-#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
{ "INT3438", (unsigned long)&sof_acpi_broadwell_desc },
#endif
@@ -267,3 +216,5 @@ static struct platform_driver snd_sof_acpi_driver = {
module_platform_driver(snd_sof_acpi_driver);
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_BAYTRAIL);
+MODULE_IMPORT_NS(SND_SOC_SOF_BROADWELL);
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
new file mode 100644
index 000000000000..0d8f65b9ae25
--- /dev/null
+++ b/sound/soc/sof/sof-audio.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2019 Intel Corporation. All rights reserved.
+//
+// Author: Ranjani Sridharan <[email protected]>
+//
+
+#include "sof-audio.h"
+#include "ops.h"
+
+bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pcm *spcm;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
+ spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
+ return true;
+ }
+
+ return false;
+}
+
+int sof_set_hw_params_upon_resume(struct device *dev)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct snd_pcm_substream *substream;
+ struct snd_sof_pcm *spcm;
+ snd_pcm_state_t state;
+ int dir;
+
+ /*
+ * SOF requires hw_params to be set-up internally upon resume.
+ * So, set the flag to indicate this for those streams that
+ * have been suspended.
+ */
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
+ substream = spcm->stream[dir].substream;
+ if (!substream || !substream->runtime)
+ continue;
+
+ state = substream->runtime->status->state;
+ if (state == SNDRV_PCM_STATE_SUSPENDED)
+ spcm->prepared[dir] = false;
+ }
+ }
+
+ /* set internal flag for BE */
+ return snd_sof_dsp_hw_params_upon_resume(sdev);
+}
+
+static int sof_restore_kcontrols(struct device *dev)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct snd_sof_control *scontrol;
+ int ipc_cmd, ctrl_type;
+ int ret = 0;
+
+ /* restore kcontrol values */
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
+ /* reset readback offset for scontrol after resuming */
+ scontrol->readback_offset = 0;
+
+ /* notify DSP of kcontrol values */
+ switch (scontrol->cmd) {
+ case SOF_CTRL_CMD_VOLUME:
+ case SOF_CTRL_CMD_ENUM:
+ case SOF_CTRL_CMD_SWITCH:
+ ipc_cmd = SOF_IPC_COMP_SET_VALUE;
+ ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
+ ret = snd_sof_ipc_set_get_comp_data(scontrol,
+ ipc_cmd, ctrl_type,
+ scontrol->cmd,
+ true);
+ break;
+ case SOF_CTRL_CMD_BINARY:
+ ipc_cmd = SOF_IPC_COMP_SET_DATA;
+ ctrl_type = SOF_CTRL_TYPE_DATA_SET;
+ ret = snd_sof_ipc_set_get_comp_data(scontrol,
+ ipc_cmd, ctrl_type,
+ scontrol->cmd,
+ true);
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret < 0) {
+ dev_err(dev,
+ "error: failed kcontrol value set for widget: %d\n",
+ scontrol->comp_id);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int sof_restore_pipelines(struct device *dev)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct snd_sof_widget *swidget;
+ struct snd_sof_route *sroute;
+ struct sof_ipc_pipe_new *pipeline;
+ struct snd_sof_dai *dai;
+ struct sof_ipc_comp_dai *comp_dai;
+ struct sof_ipc_cmd_hdr *hdr;
+ int ret;
+
+ /* restore pipeline components */
+ list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
+ struct sof_ipc_comp_reply r;
+
+ /* skip if there is no private data */
+ if (!swidget->private)
+ continue;
+
+ switch (swidget->id) {
+ case snd_soc_dapm_dai_in:
+ case snd_soc_dapm_dai_out:
+ dai = swidget->private;
+ comp_dai = &dai->comp_dai;
+ ret = sof_ipc_tx_message(sdev->ipc,
+ comp_dai->comp.hdr.cmd,
+ comp_dai, sizeof(*comp_dai),
+ &r, sizeof(r));
+ break;
+ case snd_soc_dapm_scheduler:
+
+ /*
+ * During suspend, all DSP cores are powered off.
+ * Therefore upon resume, create the pipeline comp
+ * and power up the core that the pipeline is
+ * scheduled on.
+ */
+ pipeline = swidget->private;
+ ret = sof_load_pipeline_ipc(dev, pipeline, &r);
+ break;
+ default:
+ hdr = swidget->private;
+ ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd,
+ swidget->private, hdr->size,
+ &r, sizeof(r));
+ break;
+ }
+ if (ret < 0) {
+ dev_err(dev,
+ "error: failed to load widget type %d with ID: %d\n",
+ swidget->widget->id, swidget->comp_id);
+
+ return ret;
+ }
+ }
+
+ /* restore pipeline connections */
+ list_for_each_entry_reverse(sroute, &sdev->route_list, list) {
+ struct sof_ipc_pipe_comp_connect *connect;
+ struct sof_ipc_reply reply;
+
+ /* skip if there's no private data */
+ if (!sroute->private)
+ continue;
+
+ connect = sroute->private;
+
+ /* send ipc */
+ ret = sof_ipc_tx_message(sdev->ipc,
+ connect->hdr.cmd,
+ connect, sizeof(*connect),
+ &reply, sizeof(reply));
+ if (ret < 0) {
+ dev_err(dev,
+ "error: failed to load route sink %s control %s source %s\n",
+ sroute->route->sink,
+ sroute->route->control ? sroute->route->control
+ : "none",
+ sroute->route->source);
+
+ return ret;
+ }
+ }
+
+ /* restore dai links */
+ list_for_each_entry_reverse(dai, &sdev->dai_list, list) {
+ struct sof_ipc_reply reply;
+ struct sof_ipc_dai_config *config = dai->dai_config;
+
+ if (!config) {
+ dev_err(dev, "error: no config for DAI %s\n",
+ dai->name);
+ continue;
+ }
+
+ /*
+ * The link DMA channel would be invalidated for running
+ * streams but not for streams that were in the PAUSED
+ * state during suspend. So invalidate it here before setting
+ * the dai config in the DSP.
+ */
+ if (config->type == SOF_DAI_INTEL_HDA)
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
+ ret = sof_ipc_tx_message(sdev->ipc,
+ config->hdr.cmd, config,
+ config->hdr.size,
+ &reply, sizeof(reply));
+
+ if (ret < 0) {
+ dev_err(dev,
+ "error: failed to set dai config for %s\n",
+ dai->name);
+
+ return ret;
+ }
+ }
+
+ /* complete pipeline */
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ switch (swidget->id) {
+ case snd_soc_dapm_scheduler:
+ swidget->complete =
+ snd_sof_complete_pipeline(dev, swidget);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* restore pipeline kcontrols */
+ ret = sof_restore_kcontrols(dev);
+ if (ret < 0)
+ dev_err(dev,
+ "error: restoring kcontrols after resume\n");
+
+ return ret;
+}
+
+/*
+ * Generic object lookup APIs.
+ */
+
+struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
+ const char *name)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_pcm *spcm;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ /* match with PCM dai name */
+ if (strcmp(spcm->pcm.dai_name, name) == 0)
+ return spcm;
+
+ /* match with playback caps name if set */
+ if (*spcm->pcm.caps[0].name &&
+ !strcmp(spcm->pcm.caps[0].name, name))
+ return spcm;
+
+ /* match with capture caps name if set */
+ if (*spcm->pcm.caps[1].name &&
+ !strcmp(spcm->pcm.caps[1].name, name))
+ return spcm;
+ }
+
+ return NULL;
+}
+
+struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
+ unsigned int comp_id,
+ int *direction)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_pcm *spcm;
+ int dir;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ if (spcm->stream[dir].comp_id == comp_id) {
+ *direction = dir;
+ return spcm;
+ }
+
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ if (spcm->stream[dir].comp_id == comp_id) {
+ *direction = dir;
+ return spcm;
+ }
+ }
+
+ return NULL;
+}
+
+struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
+ unsigned int pcm_id)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_pcm *spcm;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
+ return spcm;
+ }
+
+ return NULL;
+}
+
+struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
+ const char *name)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_widget *swidget;
+
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (strcmp(name, swidget->widget->name) == 0)
+ return swidget;
+ }
+
+ return NULL;
+}
+
+/* find widget by stream name and direction */
+struct snd_sof_widget *
+snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
+ const char *pcm_name, int dir)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_widget *swidget;
+ enum snd_soc_dapm_type type;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ type = snd_soc_dapm_aif_in;
+ else
+ type = snd_soc_dapm_aif_out;
+
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (!strcmp(pcm_name, swidget->widget->sname) &&
+ swidget->id == type)
+ return swidget;
+ }
+
+ return NULL;
+}
+
+struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
+ const char *name)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_dai *dai;
+
+ list_for_each_entry(dai, &sdev->dai_list, list) {
+ if (dai->name && (strcmp(name, dai->name) == 0))
+ return dai;
+ }
+
+ return NULL;
+}
+
+/*
+ * SOF Driver enumeration.
+ */
+int sof_machine_check(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_soc_acpi_mach *mach;
+ int ret;
+
+ /* force nocodec mode */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
+ dev_warn(sdev->dev, "Force to use nocodec mode\n");
+ goto nocodec;
+#endif
+
+ /* find machine */
+ snd_sof_machine_select(sdev);
+ if (sof_pdata->machine) {
+ snd_sof_set_mach_params(sof_pdata->machine, sdev->dev);
+ return 0;
+ }
+
+#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
+ dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
+ return -ENODEV;
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
+nocodec:
+#endif
+ /* select nocodec mode */
+ dev_warn(sdev->dev, "Using nocodec machine driver\n");
+ mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
+ if (!mach)
+ return -ENOMEM;
+
+ mach->drv_name = "sof-nocodec";
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+
+ ret = sof_nocodec_setup(sdev->dev, desc->ops);
+ if (ret < 0)
+ return ret;
+
+ sof_pdata->machine = mach;
+ snd_sof_set_mach_params(sof_pdata->machine, sdev->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(sof_machine_check);
+
+int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata;
+ const char *drv_name;
+ const void *mach;
+ int size;
+
+ drv_name = plat_data->machine->drv_name;
+ mach = (const void *)plat_data->machine;
+ size = sizeof(*plat_data->machine);
+
+ /* register machine driver, pass machine info as pdata */
+ plat_data->pdev_mach =
+ platform_device_register_data(sdev->dev, drv_name,
+ PLATFORM_DEVID_NONE, mach, size);
+ if (IS_ERR(plat_data->pdev_mach))
+ return PTR_ERR(plat_data->pdev_mach);
+
+ dev_dbg(sdev->dev, "created machine %s\n",
+ dev_name(&plat_data->pdev_mach->dev));
+
+ return 0;
+}
+EXPORT_SYMBOL(sof_machine_register);
+
+void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata;
+
+ if (!IS_ERR_OR_NULL(plat_data->pdev_mach))
+ platform_device_unregister(plat_data->pdev_mach);
+}
+EXPORT_SYMBOL(sof_machine_unregister);
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
new file mode 100644
index 000000000000..a62fb2da6a6e
--- /dev/null
+++ b/sound/soc/sof/sof-audio.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2019 Intel Corporation. All rights reserved.
+ *
+ * Author: Ranjani Sridharan <[email protected]>
+ */
+
+#ifndef __SOUND_SOC_SOF_AUDIO_H
+#define __SOUND_SOC_SOF_AUDIO_H
+
+#include <sound/soc.h>
+#include <sound/control.h>
+#include <sound/sof/stream.h> /* needs to be included before control.h */
+#include <sound/sof/control.h>
+#include <sound/sof/dai.h>
+#include <sound/sof/topology.h>
+#include "sof-priv.h"
+
+#define SOF_AUDIO_PCM_DRV_NAME "sof-audio-component"
+
+/* max number of FE PCMs before BEs */
+#define SOF_BE_PCM_BASE 16
+
+#define DMA_CHAN_INVALID 0xFFFFFFFF
+
+/* PCM stream, mapped to FW component */
+struct snd_sof_pcm_stream {
+ u32 comp_id;
+ struct snd_dma_buffer page_table;
+ struct sof_ipc_stream_posn posn;
+ struct snd_pcm_substream *substream;
+ struct work_struct period_elapsed_work;
+ bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
+ /*
+ * flag to indicate that the DSP pipelines should be kept
+ * active or not while suspending the stream
+ */
+ bool suspend_ignored;
+};
+
+/* ALSA SOF PCM device */
+struct snd_sof_pcm {
+ struct snd_soc_component *scomp;
+ struct snd_soc_tplg_pcm pcm;
+ struct snd_sof_pcm_stream stream[2];
+ struct list_head list; /* list in sdev pcm list */
+ struct snd_pcm_hw_params params[2];
+ bool prepared[2]; /* PCM_PARAMS set successfully */
+};
+
+struct snd_sof_led_control {
+ unsigned int use_led;
+ unsigned int direction;
+ unsigned int led_value;
+};
+
+/* ALSA SOF Kcontrol device */
+struct snd_sof_control {
+ struct snd_soc_component *scomp;
+ int comp_id;
+ int min_volume_step; /* min volume step for volume_table */
+ int max_volume_step; /* max volume step for volume_table */
+ int num_channels;
+ u32 readback_offset; /* offset to mmapped data if used */
+ struct sof_ipc_ctrl_data *control_data;
+ u32 size; /* cdata size */
+ enum sof_ipc_ctrl_cmd cmd;
+ u32 *volume_table; /* volume table computed from tlv data*/
+
+ struct list_head list; /* list in sdev control list */
+
+ struct snd_sof_led_control led_ctl;
+};
+
+/* ASoC SOF DAPM widget */
+struct snd_sof_widget {
+ struct snd_soc_component *scomp;
+ int comp_id;
+ int pipeline_id;
+ int complete;
+ int id;
+
+ struct snd_soc_dapm_widget *widget;
+ struct list_head list; /* list in sdev widget list */
+
+ void *private; /* core does not touch this */
+};
+
+/* ASoC SOF DAPM route */
+struct snd_sof_route {
+ struct snd_soc_component *scomp;
+
+ struct snd_soc_dapm_route *route;
+ struct list_head list; /* list in sdev route list */
+
+ void *private;
+};
+
+/* ASoC DAI device */
+struct snd_sof_dai {
+ struct snd_soc_component *scomp;
+ const char *name;
+ const char *cpu_dai_name;
+
+ struct sof_ipc_comp_dai comp_dai;
+ struct sof_ipc_dai_config *dai_config;
+ struct list_head list; /* list in sdev dai list */
+};
+
+/*
+ * Kcontrols.
+ */
+
+int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
+ const unsigned int __user *binary_data,
+ unsigned int size);
+int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
+ unsigned int __user *binary_data,
+ unsigned int size);
+
+/*
+ * Topology.
+ * There is no snd_sof_free_topology since topology components will
+ * be freed by snd_soc_unregister_component,
+ */
+int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file);
+int snd_sof_complete_pipeline(struct device *dev,
+ struct snd_sof_widget *swidget);
+
+int sof_load_pipeline_ipc(struct device *dev,
+ struct sof_ipc_pipe_new *pipeline,
+ struct sof_ipc_comp_reply *r);
+
+/*
+ * Stream IPC
+ */
+int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
+ struct snd_sof_pcm *spcm, int direction,
+ struct sof_ipc_stream_posn *posn);
+
+struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
+ const char *name);
+struct snd_sof_widget *
+snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
+ const char *pcm_name, int dir);
+struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
+ const char *name);
+
+static inline
+struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_soc_component *scomp,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+
+ struct snd_sof_pcm *spcm = NULL;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id)
+ return spcm;
+ }
+
+ return NULL;
+}
+
+struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
+ const char *name);
+struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
+ unsigned int comp_id,
+ int *direction);
+struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
+ unsigned int pcm_id);
+void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
+
+/*
+ * Mixer IPC
+ */
+int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
+ u32 ipc_cmd,
+ enum sof_ipc_ctrl_type ctrl_type,
+ enum sof_ipc_ctrl_cmd ctrl_cmd,
+ bool send);
+
+/* PM */
+int sof_restore_pipelines(struct device *dev);
+int sof_set_hw_params_upon_resume(struct device *dev);
+bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev);
+
+/* Machine driver enumeration */
+int sof_machine_register(struct snd_sof_dev *sdev, void *pdata);
+void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata);
+
+#endif
diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c
index 28a9692974e5..39ea8af6213f 100644
--- a/sound/soc/sof/sof-of-dev.c
+++ b/sound/soc/sof/sof-of-dev.c
@@ -19,7 +19,7 @@ extern struct snd_sof_dsp_ops sof_imx8_ops;
static struct sof_dev_desc sof_of_imx8qxp_desc = {
.default_fw_path = "imx/sof",
.default_tplg_path = "imx/sof-tplg",
- .nocodec_fw_filename = "sof-imx8.ri",
+ .default_fw_filename = "sof-imx8.ri",
.nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8_ops,
};
@@ -43,8 +43,6 @@ static int sof_of_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct sof_dev_desc *desc;
- /*TODO: create a generic snd_soc_xxx_mach */
- struct snd_soc_acpi_mach *mach;
struct snd_sof_pdata *sof_pdata;
const struct snd_sof_dsp_ops *ops;
int ret;
@@ -66,27 +64,9 @@ static int sof_of_probe(struct platform_device *pdev)
return -ENODEV;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
- /* force nocodec mode */
- dev_warn(dev, "Force to use nocodec mode\n");
- mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
- if (!mach)
- return -ENOMEM;
- ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
- if (ret < 0)
- return ret;
-#else
- /* TODO: implement case where we actually have a codec */
- return -ENODEV;
-#endif
-
- if (mach)
- mach->mach_params.platform = dev_name(dev);
-
- sof_pdata->machine = mach;
sof_pdata->desc = desc;
sof_pdata->dev = &pdev->dev;
- sof_pdata->platform = dev_name(dev);
+ sof_pdata->fw_filename = desc->default_fw_filename;
/* TODO: read alternate fw and tplg filenames from DT */
sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path;
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index bbeffd932de7..9993be36d105 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -9,6 +9,7 @@
//
#include <linux/firmware.h>
+#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
@@ -36,6 +37,23 @@ MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)");
#define SOF_PCI_DISABLE_PM_RUNTIME BIT(0)
+static const struct dmi_system_id community_key_platforms[] = {
+ {
+ .ident = "Up Squared",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
+ DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
+ }
+ },
+ {
+ .ident = "Google Chromebooks",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ }
+ },
+ {},
+};
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
static const struct sof_dev_desc bxt_desc = {
.machines = snd_soc_acpi_intel_bxt_machines,
@@ -47,10 +65,9 @@ static const struct sof_dev_desc bxt_desc = {
.chip_info = &apl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-apl.ri",
+ .default_fw_filename = "sof-apl.ri",
.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
.ops = &sof_apl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -65,10 +82,9 @@ static const struct sof_dev_desc glk_desc = {
.chip_info = &apl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-glk.ri",
+ .default_fw_filename = "sof-glk.ri",
.nocodec_tplg_filename = "sof-glk-nocodec.tplg",
.ops = &sof_apl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -93,10 +109,9 @@ static const struct sof_dev_desc tng_desc = {
.chip_info = &tng_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-byt.ri",
+ .default_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt.tplg",
.ops = &sof_tng_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -111,10 +126,9 @@ static const struct sof_dev_desc cnl_desc = {
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-cnl.ri",
+ .default_fw_filename = "sof-cnl.ri",
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -129,10 +143,9 @@ static const struct sof_dev_desc cfl_desc = {
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-cfl.ri",
+ .default_fw_filename = "sof-cfl.ri",
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -149,10 +162,9 @@ static const struct sof_dev_desc cml_desc = {
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-cml.ri",
+ .default_fw_filename = "sof-cml.ri",
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -167,10 +179,9 @@ static const struct sof_dev_desc icl_desc = {
.chip_info = &icl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-icl.ri",
+ .default_fw_filename = "sof-icl.ri",
.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -185,10 +196,9 @@ static const struct sof_dev_desc tgl_desc = {
.chip_info = &tgl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-tgl.ri",
+ .default_fw_filename = "sof-tgl.ri",
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -203,10 +213,9 @@ static const struct sof_dev_desc ehl_desc = {
.chip_info = &ehl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-ehl.ri",
+ .default_fw_filename = "sof-ehl.ri",
.nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -221,10 +230,8 @@ static const struct sof_dev_desc jsl_desc = {
.chip_info = &jsl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-jsl.ri",
.nocodec_tplg_filename = "sof-jsl-nocodec.tplg",
.ops = &sof_cnl_ops,
- .arch_ops = &sof_xtensa_arch_ops
};
#endif
@@ -266,7 +273,6 @@ static int sof_pci_probe(struct pci_dev *pci,
struct device *dev = &pci->dev;
const struct sof_dev_desc *desc =
(const struct sof_dev_desc *)pci_id->driver_data;
- struct snd_soc_acpi_mach *mach;
struct snd_sof_pdata *sof_pdata;
const struct snd_sof_dsp_ops *ops;
int ret;
@@ -297,42 +303,39 @@ static int sof_pci_probe(struct pci_dev *pci,
if (ret < 0)
return ret;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
- /* force nocodec mode */
- dev_warn(dev, "Force to use nocodec mode\n");
- mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
- if (!mach) {
- ret = -ENOMEM;
- goto release_regions;
- }
- ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
- if (ret < 0)
- goto release_regions;
-
-#else
- /* find machine */
- mach = snd_soc_acpi_find_machine(desc->machines);
- if (!mach) {
- dev_warn(dev, "warning: No matching ASoC machine driver found\n");
- } else {
- mach->mach_params.platform = dev_name(dev);
- sof_pdata->fw_filename = mach->sof_fw_filename;
- sof_pdata->tplg_filename = mach->sof_tplg_filename;
- }
-#endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */
-
sof_pdata->name = pci_name(pci);
- sof_pdata->machine = mach;
sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data;
sof_pdata->dev = dev;
- sof_pdata->platform = dev_name(dev);
+ sof_pdata->fw_filename = desc->default_fw_filename;
+
+ /*
+ * for platforms using the SOF community key, change the
+ * default path automatically to pick the right files from the
+ * linux-firmware tree. This can be overridden with the
+ * fw_path kernel parameter, e.g. for developers.
+ */
/* alternate fw and tplg filenames ? */
- if (fw_path)
+ if (fw_path) {
sof_pdata->fw_filename_prefix = fw_path;
- else
+
+ dev_dbg(dev,
+ "Module parameter used, changed fw path to %s\n",
+ sof_pdata->fw_filename_prefix);
+
+ } else if (dmi_check_system(community_key_platforms)) {
+ sof_pdata->fw_filename_prefix =
+ devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
+ sof_pdata->desc->default_fw_path,
+ "community");
+
+ dev_dbg(dev,
+ "Platform uses community key, changed fw path to %s\n",
+ sof_pdata->fw_filename_prefix);
+ } else {
sof_pdata->fw_filename_prefix =
sof_pdata->desc->default_fw_path;
+ }
if (tplg_path)
sof_pdata->tplg_filename_prefix = tplg_path;
@@ -442,3 +445,5 @@ static struct pci_driver snd_sof_pci_driver = {
module_pci_driver(snd_sof_pci_driver);
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD);
+MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index c7c2c70ee4d0..bc2337cf1142 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -12,20 +12,11 @@
#define __SOUND_SOC_SOF_PRIV_H
#include <linux/device.h>
-
#include <sound/hdaudio.h>
-#include <sound/soc.h>
-#include <sound/control.h>
-
#include <sound/sof.h>
-#include <sound/sof/stream.h> /* needs to be included before control.h */
-#include <sound/sof/control.h>
-#include <sound/sof/dai.h>
#include <sound/sof/info.h>
#include <sound/sof/pm.h>
-#include <sound/sof/topology.h>
#include <sound/sof/trace.h>
-
#include <uapi/sound/sof/fw.h>
/* debug flags */
@@ -48,9 +39,6 @@ extern int sof_core_debug;
/* DMA buffer size for trace */
#define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16)
-/* max number of FE PCMs before BEs */
-#define SOF_BE_PCM_BASE 16
-
#define SOF_IPC_DSP_REPLY 0
#define SOF_IPC_HOST_REPLY 1
@@ -66,8 +54,6 @@ extern int sof_core_debug;
(IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \
IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST))
-#define DMA_CHAN_INVALID 0xFFFFFFFF
-
/* DSP D0ix sub-state */
enum sof_d0_substate {
SOF_DSP_D0I0 = 0, /* DSP default D0 substate */
@@ -216,12 +202,23 @@ struct snd_sof_dsp_ops {
int (*get_window_offset)(struct snd_sof_dev *sdev,
u32 id);/* mandatory for common loader code */
+ /* machine driver ops */
+ int (*machine_register)(struct snd_sof_dev *sdev,
+ void *pdata); /* optional */
+ void (*machine_unregister)(struct snd_sof_dev *sdev,
+ void *pdata); /* optional */
+ void (*machine_select)(struct snd_sof_dev *sdev); /* optional */
+ void (*set_mach_params)(const struct snd_soc_acpi_mach *mach,
+ struct device *dev); /* optional */
+
/* DAI ops */
struct snd_soc_dai_driver *drv;
int num_drv;
/* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */
u32 hw_info;
+
+ const struct sof_arch_ops *arch_ops;
};
/* DSP architecture specific callbacks for oops and stack dumps */
@@ -231,7 +228,7 @@ struct sof_arch_ops {
u32 *stack, u32 stack_words);
};
-#define sof_arch_ops(sdev) ((sdev)->pdata->desc->arch_ops)
+#define sof_arch_ops(sdev) ((sdev)->pdata->desc->ops->arch_ops)
/* DSP device HW descriptor mapping between bus ID and ops */
struct sof_ops_table {
@@ -303,88 +300,13 @@ struct snd_sof_ipc_msg {
bool ipc_complete;
};
-/* PCM stream, mapped to FW component */
-struct snd_sof_pcm_stream {
- u32 comp_id;
- struct snd_dma_buffer page_table;
- struct sof_ipc_stream_posn posn;
- struct snd_pcm_substream *substream;
- struct work_struct period_elapsed_work;
- bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
- /*
- * flag to indicate that the DSP pipelines should be kept
- * active or not while suspending the stream
- */
- bool suspend_ignored;
-};
-
-/* ALSA SOF PCM device */
-struct snd_sof_pcm {
- struct snd_sof_dev *sdev;
- struct snd_soc_tplg_pcm pcm;
- struct snd_sof_pcm_stream stream[2];
- struct list_head list; /* list in sdev pcm list */
- struct snd_pcm_hw_params params[2];
- bool prepared[2]; /* PCM_PARAMS set successfully */
-};
-
-struct snd_sof_led_control {
- unsigned int use_led;
- unsigned int direction;
- unsigned int led_value;
-};
-
-/* ALSA SOF Kcontrol device */
-struct snd_sof_control {
- struct snd_sof_dev *sdev;
- int comp_id;
- int min_volume_step; /* min volume step for volume_table */
- int max_volume_step; /* max volume step for volume_table */
- int num_channels;
- u32 readback_offset; /* offset to mmaped data if used */
- struct sof_ipc_ctrl_data *control_data;
- u32 size; /* cdata size */
- enum sof_ipc_ctrl_cmd cmd;
- u32 *volume_table; /* volume table computed from tlv data*/
-
- struct list_head list; /* list in sdev control list */
-
- struct snd_sof_led_control led_ctl;
-};
-
-/* ASoC SOF DAPM widget */
-struct snd_sof_widget {
- struct snd_sof_dev *sdev;
- int comp_id;
- int pipeline_id;
- int complete;
- int id;
-
- struct snd_soc_dapm_widget *widget;
- struct list_head list; /* list in sdev widget list */
-
- void *private; /* core does not touch this */
-};
-
-/* ASoC SOF DAPM route */
-struct snd_sof_route {
- struct snd_sof_dev *sdev;
-
- struct snd_soc_dapm_route *route;
- struct list_head list; /* list in sdev route list */
-
- void *private;
-};
-
-/* ASoC DAI device */
-struct snd_sof_dai {
- struct snd_sof_dev *sdev;
- const char *name;
- const char *cpu_dai_name;
-
- struct sof_ipc_comp_dai comp_dai;
- struct sof_ipc_dai_config *dai_config;
- struct list_head list; /* list in sdev dai list */
+enum snd_sof_fw_state {
+ SOF_FW_BOOT_NOT_STARTED = 0,
+ SOF_FW_BOOT_PREPARE,
+ SOF_FW_BOOT_IN_PROGRESS,
+ SOF_FW_BOOT_FAILED,
+ SOF_FW_BOOT_READY_FAILED, /* firmware booted but fw_ready op failed */
+ SOF_FW_BOOT_COMPLETE,
};
/*
@@ -408,7 +330,7 @@ struct snd_sof_dev {
/* DSP firmware boot */
wait_queue_head_t boot_wait;
- u32 boot_complete;
+ enum snd_sof_fw_state fw_state;
u32 first_boot;
/* work queue in case the probe is implemented in two steps */
@@ -441,6 +363,7 @@ struct snd_sof_dev {
struct snd_dma_buffer dmab_bdl;
struct sof_ipc_fw_ready fw_ready;
struct sof_ipc_fw_version fw_version;
+ struct sof_ipc_cc_version *cc_version;
/* topology */
struct snd_soc_tplg_ops *tplg_ops;
@@ -499,7 +422,7 @@ int snd_sof_set_d0_substate(struct snd_sof_dev *sdev,
void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
-int snd_sof_create_page_table(struct snd_sof_dev *sdev,
+int snd_sof_create_page_table(struct device *dev,
struct snd_dma_buffer *dmab,
unsigned char *page_table, size_t size);
@@ -531,69 +454,6 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev);
int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
void *msg_data, size_t msg_bytes, void *reply_data,
size_t reply_bytes);
-struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
- const char *name);
-struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
- const char *pcm_name,
- int dir);
-struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
- const char *name);
-
-static inline
-struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev,
- struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_sof_pcm *spcm = NULL;
-
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id)
- return spcm;
- }
-
- return NULL;
-}
-
-bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev);
-
-struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
- const char *name);
-struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
- unsigned int comp_id,
- int *direction);
-struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
- unsigned int pcm_id);
-void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
-
-/*
- * Stream IPC
- */
-int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
- struct snd_sof_pcm *spcm, int direction,
- struct sof_ipc_stream_posn *posn);
-
-/*
- * Mixer IPC
- */
-int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
- struct snd_sof_control *scontrol, u32 ipc_cmd,
- enum sof_ipc_ctrl_type ctrl_type,
- enum sof_ipc_ctrl_cmd ctrl_cmd,
- bool send);
-
-/*
- * Topology.
- * There is no snd_sof_free_topology since topology components will
- * be freed by snd_soc_unregister_component,
- */
-int snd_sof_init_topology(struct snd_sof_dev *sdev,
- struct snd_soc_tplg_ops *ops);
-int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file);
-int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget);
-
-int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
- struct sof_ipc_pipe_new *pipeline,
- struct sof_ipc_comp_reply *r);
/*
* Trace/debug
@@ -626,39 +486,11 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
extern struct snd_compr_ops sof_compressed_ops;
/*
- * Kcontrols.
- */
-
-int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
- const unsigned int __user *binary_data,
- unsigned int size);
-int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
- unsigned int __user *binary_data,
- unsigned int size);
-
-/*
* DSP Architectures.
*/
static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
u32 stack_words)
{
- if (sof_arch_ops(sdev)->dsp_stack)
sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words);
}
@@ -700,4 +532,6 @@ int intel_pcm_open(struct snd_sof_dev *sdev,
int intel_pcm_close(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream);
+int sof_machine_check(struct snd_sof_dev *sdev);
+
#endif
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index d82ab981e840..9f4f8868b386 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -13,6 +13,7 @@
#include <sound/pcm_params.h>
#include <uapi/sound/sof/tokens.h>
#include "sof-priv.h"
+#include "sof-audio.h"
#include "ops.h"
#define COMP_ID_UNASSIGNED 0xffffffff
@@ -53,7 +54,8 @@ struct sof_widget_data {
static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
{
struct sof_ipc_pcm_params_reply ipc_params_reply;
- struct snd_sof_dev *sdev = swidget->sdev;
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc_pcm_params pcm;
struct snd_pcm_hw_params *params;
struct snd_sof_pcm *spcm;
@@ -62,9 +64,9 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
memset(&pcm, 0, sizeof(pcm));
/* get runtime PCM params using widget's stream name */
- spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname);
+ spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
if (!spcm) {
- dev_err(sdev->dev, "error: cannot find PCM for %s\n",
+ dev_err(scomp->dev, "error: cannot find PCM for %s\n",
swidget->widget->name);
return -EINVAL;
}
@@ -102,7 +104,7 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0)
- dev_err(sdev->dev, "error: pcm params failed for %s\n",
+ dev_err(scomp->dev, "error: pcm params failed for %s\n",
swidget->widget->name);
return ret;
@@ -111,7 +113,8 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
/* send stream trigger ipc */
static int ipc_trigger(struct snd_sof_widget *swidget, int cmd)
{
- struct snd_sof_dev *sdev = swidget->sdev;
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc_stream stream;
struct sof_ipc_reply reply;
int ret = 0;
@@ -125,7 +128,7 @@ static int ipc_trigger(struct snd_sof_widget *swidget, int cmd)
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
sizeof(stream), &reply, sizeof(reply));
if (ret < 0)
- dev_err(sdev->dev, "error: failed to trigger %s\n",
+ dev_err(scomp->dev, "error: failed to trigger %s\n",
swidget->widget->name);
return ret;
@@ -135,23 +138,23 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_soc_component *scomp;
int stream = SNDRV_PCM_STREAM_CAPTURE;
- struct snd_sof_dev *sdev;
struct snd_sof_pcm *spcm;
int ret = 0;
if (!swidget)
return 0;
- sdev = swidget->sdev;
+ scomp = swidget->scomp;
- dev_dbg(sdev->dev, "received event %d for widget %s\n",
+ dev_dbg(scomp->dev, "received event %d for widget %s\n",
event, w->name);
/* get runtime PCM params using widget's stream name */
- spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname);
+ spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
if (!spcm) {
- dev_err(sdev->dev, "error: cannot find PCM for %s\n",
+ dev_err(scomp->dev, "error: cannot find PCM for %s\n",
swidget->widget->name);
return -EINVAL;
}
@@ -160,14 +163,14 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (spcm->stream[stream].suspend_ignored) {
- dev_dbg(sdev->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
+ dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
return 0;
}
/* set pcm params */
ret = ipc_pcm_params(swidget, stream);
if (ret < 0) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: failed to set pcm params for widget %s\n",
swidget->widget->name);
break;
@@ -176,27 +179,27 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
/* start trigger */
ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
if (ret < 0)
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: failed to trigger widget %s\n",
swidget->widget->name);
break;
case SND_SOC_DAPM_POST_PMD:
if (spcm->stream[stream].suspend_ignored) {
- dev_dbg(sdev->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
+ dev_dbg(scomp->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
return 0;
}
/* stop trigger */
ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
if (ret < 0)
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: failed to trigger widget %s\n",
swidget->widget->name);
/* pcm free */
ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
if (ret < 0)
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: failed to trigger widget %s\n",
swidget->widget->name);
break;
@@ -570,6 +573,20 @@ static const struct sof_topology_token src_tokens[] = {
offsetof(struct sof_ipc_comp_src, sink_rate), 0},
};
+/* ASRC */
+static const struct sof_topology_token asrc_tokens[] = {
+ {SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_comp_asrc, source_rate), 0},
+ {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_comp_asrc, sink_rate), 0},
+ {SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32,
+ offsetof(struct sof_ipc_comp_asrc, asynchronous_mode), 0},
+ {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32,
+ offsetof(struct sof_ipc_comp_asrc, operation_mode), 0},
+};
+
/* Tone */
static const struct sof_topology_token tone_tokens[] = {
};
@@ -678,6 +695,13 @@ static const struct sof_topology_token esai_tokens[] = {
offsetof(struct sof_ipc_dai_esai_params, mclk_id), 0},
};
+/* SAI */
+static const struct sof_topology_token sai_tokens[] = {
+ {SOF_TKN_IMX_SAI_MCLK_ID,
+ SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
+ offsetof(struct sof_ipc_dai_sai_params, mclk_id), 0},
+};
+
/*
* DMIC PDM Tokens
* SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
@@ -838,7 +862,7 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
/* check if array index is valid */
if (!index || *index == 0) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: invalid array offset\n");
continue;
} else {
@@ -866,7 +890,6 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
struct snd_soc_tplg_vendor_array *array,
int priv_size)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
int asize;
while (priv_size > 0) {
@@ -874,7 +897,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
/* validate asize */
if (asize < 0) { /* FIXME: A zero-size array makes no sense */
- dev_err(sdev->dev, "error: invalid array size 0x%x\n",
+ dev_err(scomp->dev, "error: invalid array size 0x%x\n",
asize);
return -EINVAL;
}
@@ -882,7 +905,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
/* make sure there is enough data before parsing */
priv_size -= asize;
if (priv_size < 0) {
- dev_err(sdev->dev, "error: invalid array size 0x%x\n",
+ dev_err(scomp->dev, "error: invalid array size 0x%x\n",
asize);
return -EINVAL;
}
@@ -905,7 +928,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
array);
break;
default:
- dev_err(sdev->dev, "error: unknown token type %d\n",
+ dev_err(scomp->dev, "error: unknown token type %d\n",
array->type);
return -EINVAL;
}
@@ -920,9 +943,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
static void sof_dbg_comp_config(struct snd_soc_component *scomp,
struct sof_ipc_comp_config *config)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
-
- dev_dbg(sdev->dev, " config: periods snk %d src %d fmt %d\n",
+ dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
config->periods_sink, config->periods_source,
config->frame_fmt);
}
@@ -974,7 +995,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
/* extract tlv data */
if (get_tlv_data(kc->tlv.p, tlv) < 0) {
- dev_err(sdev->dev, "error: invalid TLV data\n");
+ dev_err(scomp->dev, "error: invalid TLV data\n");
ret = -EINVAL;
goto out_free;
}
@@ -982,7 +1003,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
/* set up volume table */
ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1);
if (ret < 0) {
- dev_err(sdev->dev, "error: setting up volume table\n");
+ dev_err(scomp->dev, "error: setting up volume table\n");
goto out_free;
}
@@ -999,12 +1020,12 @@ skip:
ARRAY_SIZE(led_tokens), mc->priv.array,
le32_to_cpu(mc->priv.size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse led tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse led tokens failed %d\n",
le32_to_cpu(mc->priv.size));
goto out_free_table;
}
- dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n",
+ dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n",
scontrol->comp_id, scontrol->num_channels);
return ret;
@@ -1043,7 +1064,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp,
scontrol->cmd = SOF_CTRL_CMD_ENUM;
- dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n",
+ dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n",
scontrol->comp_id, scontrol->num_channels, scontrol->comp_id);
return 0;
@@ -1067,7 +1088,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
le32_to_cpu(control->priv.size);
if (scontrol->size > max_size) {
- dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n",
+ dev_err(scomp->dev, "err: bytes data size %d exceeds max %d.\n",
scontrol->size, max_size);
ret = -EINVAL;
goto out;
@@ -1083,7 +1104,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
scontrol->comp_id = sdev->next_comp_id;
scontrol->cmd = SOF_CTRL_CMD_BINARY;
- dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n",
+ dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n",
scontrol->comp_id, scontrol->num_channels);
if (le32_to_cpu(control->priv.size) > 0) {
@@ -1091,14 +1112,14 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
le32_to_cpu(control->priv.size));
if (cdata->data->magic != SOF_ABI_MAGIC) {
- dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n",
+ dev_err(scomp->dev, "error: Wrong ABI magic 0x%08x.\n",
cdata->data->magic);
ret = -EINVAL;
goto out_free;
}
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION,
cdata->data->abi)) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: Incompatible ABI version 0x%08x.\n",
cdata->data->abi);
ret = -EINVAL;
@@ -1106,7 +1127,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
}
if (cdata->data->size + sizeof(const struct sof_abi_hdr) !=
le32_to_cpu(control->priv.size)) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: Conflict in bytes vs. priv size.\n");
ret = -EINVAL;
goto out_free;
@@ -1134,14 +1155,14 @@ static int sof_control_load(struct snd_soc_component *scomp, int index,
struct snd_sof_control *scontrol;
int ret = -EINVAL;
- dev_dbg(sdev->dev, "tplg: load control type %d name : %s\n",
+ dev_dbg(scomp->dev, "tplg: load control type %d name : %s\n",
hdr->type, hdr->name);
scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
if (!scontrol)
return -ENOMEM;
- scontrol->sdev = sdev;
+ scontrol->scomp = scomp;
switch (le32_to_cpu(hdr->ops.info)) {
case SND_SOC_TPLG_CTL_VOLSW:
@@ -1170,7 +1191,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index,
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
case SND_SOC_TPLG_DAPM_CTL_PIN:
default:
- dev_warn(sdev->dev, "control type not supported %d:%d:%d\n",
+ dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
hdr->ops.get, hdr->ops.put, hdr->ops.info);
kfree(scontrol);
return 0;
@@ -1193,7 +1214,7 @@ static int sof_control_unload(struct snd_soc_component *scomp,
struct sof_ipc_free fcomp;
struct snd_sof_control *scontrol = dobj->private;
- dev_dbg(sdev->dev, "tplg: unload control name : %s\n", scomp->name);
+ dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scomp->name);
fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
fcomp.hdr.size = sizeof(fcomp);
@@ -1217,12 +1238,11 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
struct snd_soc_tplg_dapm_widget *tw,
struct snd_sof_dai *dai)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_card *card = scomp->card;
struct snd_soc_pcm_runtime *rtd;
list_for_each_entry(rtd, &card->rtd_list, list) {
- dev_vdbg(sdev->dev, "tplg: check widget: %s stream: %s dai stream: %s\n",
+ dev_vdbg(scomp->dev, "tplg: check widget: %s stream: %s dai stream: %s\n",
w->name, w->sname, rtd->dai_link->stream_name);
if (!w->sname || !rtd->dai_link->stream_name)
@@ -1236,13 +1256,13 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
case snd_soc_dapm_dai_out:
rtd->cpu_dai->capture_widget = w;
dai->name = rtd->dai_link->name;
- dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n",
+ dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n",
w->name, rtd->dai_link->name);
break;
case snd_soc_dapm_dai_in:
rtd->cpu_dai->playback_widget = w;
dai->name = rtd->dai_link->name;
- dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n",
+ dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n",
w->name, rtd->dai_link->name);
break;
default:
@@ -1252,7 +1272,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
/* check we have a connection */
if (!dai->name) {
- dev_err(sdev->dev, "error: can't connect DAI %s stream %s\n",
+ dev_err(scomp->dev, "error: can't connect DAI %s stream %s\n",
w->name, w->sname);
return -EINVAL;
}
@@ -1284,7 +1304,7 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(dai_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse dai tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse dai tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -1293,12 +1313,12 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse dai.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n",
private->size);
return ret;
}
- dev_dbg(sdev->dev, "dai %s: type %d index %d\n",
+ dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
swidget->widget->name, comp_dai.type, comp_dai.dai_index);
sof_dbg_comp_config(scomp, &comp_dai.config);
@@ -1306,7 +1326,7 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index,
&comp_dai, sizeof(comp_dai), r, sizeof(*r));
if (ret == 0 && dai) {
- dai->sdev = sdev;
+ dai->scomp = scomp;
memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai));
}
@@ -1342,13 +1362,13 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(buffer_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse buffer tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse buffer tokens failed %d\n",
private->size);
kfree(buffer);
return ret;
}
- dev_dbg(sdev->dev, "buffer %s: size %d caps 0x%x\n",
+ dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
swidget->widget->name, buffer->size, buffer->caps);
swidget->private = buffer;
@@ -1356,7 +1376,7 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index,
ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer,
sizeof(*buffer), r, sizeof(*r));
if (ret < 0) {
- dev_err(sdev->dev, "error: buffer %s load failed\n",
+ dev_err(scomp->dev, "error: buffer %s load failed\n",
swidget->widget->name);
kfree(buffer);
}
@@ -1365,16 +1385,16 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index,
}
/* bind PCM ID to host component ID */
-static int spcm_bind(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
+static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
int dir)
{
struct snd_sof_widget *host_widget;
- host_widget = snd_sof_find_swidget_sname(sdev,
+ host_widget = snd_sof_find_swidget_sname(scomp,
spcm->pcm.caps[dir].name,
dir);
if (!host_widget) {
- dev_err(sdev->dev, "can't find host comp to bind pcm\n");
+ dev_err(scomp->dev, "can't find host comp to bind pcm\n");
return -EINVAL;
}
@@ -1415,7 +1435,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(pcm_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse host tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse host tokens failed %d\n",
private->size);
goto err;
}
@@ -1424,12 +1444,12 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse host.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse host.cfg tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
- dev_dbg(sdev->dev, "loaded host %s\n", swidget->widget->name);
+ dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
sof_dbg_comp_config(scomp, &host->config);
swidget->private = host;
@@ -1446,24 +1466,25 @@ err:
/*
* Pipeline Topology
*/
-int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
+int sof_load_pipeline_ipc(struct device *dev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r)
{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct sof_ipc_pm_core_config pm_core_config;
int ret;
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), r, sizeof(*r));
if (ret < 0) {
- dev_err(sdev->dev, "error: load pipeline ipc failure\n");
+ dev_err(dev, "error: load pipeline ipc failure\n");
return ret;
}
/* power up the core that this pipeline is scheduled on */
ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core);
if (ret < 0) {
- dev_err(sdev->dev, "error: powering up pipeline schedule core %d\n",
+ dev_err(dev, "error: powering up pipeline schedule core %d\n",
pipeline->core);
return ret;
}
@@ -1487,7 +1508,7 @@ int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
if (ret < 0)
- dev_err(sdev->dev, "error: core enable ipc failure\n");
+ dev_err(dev, "error: core enable ipc failure\n");
return ret;
}
@@ -1497,7 +1518,6 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp,
struct snd_soc_tplg_dapm_widget *tw,
struct sof_ipc_comp_reply *r)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &tw->priv;
struct sof_ipc_pipe_new *pipeline;
struct snd_sof_widget *comp_swidget;
@@ -1514,9 +1534,9 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp,
pipeline->comp_id = swidget->comp_id;
/* component at start of pipeline is our stream id */
- comp_swidget = snd_sof_find_swidget(sdev, tw->sname);
+ comp_swidget = snd_sof_find_swidget(scomp, tw->sname);
if (!comp_swidget) {
- dev_err(sdev->dev, "error: widget %s refers to non existent widget %s\n",
+ dev_err(scomp->dev, "error: widget %s refers to non existent widget %s\n",
tw->name, tw->sname);
ret = -EINVAL;
goto err;
@@ -1524,26 +1544,26 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp,
pipeline->sched_id = comp_swidget->comp_id;
- dev_dbg(sdev->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n",
+ dev_dbg(scomp->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n",
pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id);
ret = sof_parse_tokens(scomp, pipeline, sched_tokens,
ARRAY_SIZE(sched_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse pipeline tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse pipeline tokens failed %d\n",
private->size);
goto err;
}
- dev_dbg(sdev->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n",
+ dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n",
swidget->widget->name, pipeline->period, pipeline->priority,
pipeline->period_mips, pipeline->core, pipeline->frames_per_sched);
swidget->private = pipeline;
/* send ipc's to create pipeline comp and power up schedule core */
- ret = sof_load_pipeline_ipc(sdev, pipeline, r);
+ ret = sof_load_pipeline_ipc(scomp->dev, pipeline, r);
if (ret >= 0)
return ret;
err:
@@ -1581,7 +1601,7 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse mixer.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse mixer.cfg tokens failed %d\n",
private->size);
kfree(mixer);
return ret;
@@ -1628,7 +1648,7 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse mux.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse mux.cfg tokens failed %d\n",
private->size);
kfree(mux);
return ret;
@@ -1668,7 +1688,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
return -ENOMEM;
if (!le32_to_cpu(tw->num_kcontrols)) {
- dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n",
+ dev_err(scomp->dev, "error: invalid kcontrol count %d for volume\n",
tw->num_kcontrols);
ret = -EINVAL;
goto err;
@@ -1686,7 +1706,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(volume_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse volume tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse volume tokens failed %d\n",
private->size);
goto err;
}
@@ -1694,7 +1714,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse volume.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse volume.cfg tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
@@ -1754,7 +1774,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(src_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse src tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse src tokens failed %d\n",
private->size);
goto err;
}
@@ -1763,12 +1783,12 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse src.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse src.cfg tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
- dev_dbg(sdev->dev, "src %s: source rate %d sink rate %d\n",
+ dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n",
swidget->widget->name, src->source_rate, src->sink_rate);
sof_dbg_comp_config(scomp, &src->config);
@@ -1784,6 +1804,67 @@ err:
}
/*
+ * ASRC Topology
+ */
+
+static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index,
+ struct snd_sof_widget *swidget,
+ struct snd_soc_tplg_dapm_widget *tw,
+ struct sof_ipc_comp_reply *r)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_soc_tplg_private *private = &tw->priv;
+ struct sof_ipc_comp_asrc *asrc;
+ int ret;
+
+ asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
+ if (!asrc)
+ return -ENOMEM;
+
+ /* configure ASRC IPC message */
+ asrc->comp.hdr.size = sizeof(*asrc);
+ asrc->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
+ asrc->comp.id = swidget->comp_id;
+ asrc->comp.type = SOF_COMP_ASRC;
+ asrc->comp.pipeline_id = index;
+ asrc->config.hdr.size = sizeof(asrc->config);
+
+ ret = sof_parse_tokens(scomp, asrc, asrc_tokens,
+ ARRAY_SIZE(asrc_tokens), private->array,
+ le32_to_cpu(private->size));
+ if (ret != 0) {
+ dev_err(scomp->dev, "error: parse asrc tokens failed %d\n",
+ private->size);
+ goto err;
+ }
+
+ ret = sof_parse_tokens(scomp, &asrc->config, comp_tokens,
+ ARRAY_SIZE(comp_tokens), private->array,
+ le32_to_cpu(private->size));
+ if (ret != 0) {
+ dev_err(scomp->dev, "error: parse asrc.cfg tokens failed %d\n",
+ le32_to_cpu(private->size));
+ goto err;
+ }
+
+ dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d "
+ "asynch %d operation %d\n",
+ swidget->widget->name, asrc->source_rate, asrc->sink_rate,
+ asrc->asynchronous_mode, asrc->operation_mode);
+ sof_dbg_comp_config(scomp, &asrc->config);
+
+ swidget->private = asrc;
+
+ ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc,
+ sizeof(*asrc), r, sizeof(*r));
+ if (ret >= 0)
+ return ret;
+err:
+ kfree(asrc);
+ return ret;
+}
+
+/*
* Signal Generator Topology
*/
@@ -1813,7 +1894,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(tone_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse tone tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse tone tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
@@ -1822,12 +1903,12 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse tone.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse tone.cfg tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
- dev_dbg(sdev->dev, "tone %s: frequency %d amplitude %d\n",
+ dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n",
swidget->widget->name, tone->frequency, tone->amplitude);
sof_dbg_comp_config(scomp, &tone->config);
@@ -1842,7 +1923,7 @@ err:
return ret;
}
-static int sof_get_control_data(struct snd_sof_dev *sdev,
+static int sof_get_control_data(struct snd_soc_component *scomp,
struct snd_soc_dapm_widget *widget,
struct sof_widget_data *wdata,
size_t *size)
@@ -1872,14 +1953,14 @@ static int sof_get_control_data(struct snd_sof_dev *sdev,
wdata[i].control = se->dobj.private;
break;
default:
- dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n",
+ dev_err(scomp->dev, "error: unknown kcontrol type %d in widget %s\n",
widget->dobj.widget.kcontrol_type,
widget->name);
return -EINVAL;
}
if (!wdata[i].control) {
- dev_err(sdev->dev, "error: no scontrol for widget %s\n",
+ dev_err(scomp->dev, "error: no scontrol for widget %s\n",
widget->name);
return -EINVAL;
}
@@ -1932,7 +2013,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index,
int i;
if (type == SOF_COMP_NONE) {
- dev_err(sdev->dev, "error: invalid process comp type %d\n",
+ dev_err(scomp->dev, "error: invalid process comp type %d\n",
type);
return -EINVAL;
}
@@ -1947,7 +2028,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index,
return -ENOMEM;
/* get possible component controls and get size of all pdata */
- ret = sof_get_control_data(sdev, widget, wdata,
+ ret = sof_get_control_data(scomp, widget, wdata,
&ipc_data_size);
if (ret < 0)
@@ -1982,7 +2063,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(comp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse process.cfg tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
@@ -2010,7 +2091,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index,
ipc_size, r, sizeof(*r));
if (ret < 0) {
- dev_err(sdev->dev, "error: create process failed\n");
+ dev_err(scomp->dev, "error: create process failed\n");
goto err;
}
@@ -2021,13 +2102,13 @@ static int sof_process_load(struct snd_soc_component *scomp, int index,
/* send control data with large message supported method */
for (i = 0; i < widget->num_kcontrols; i++) {
wdata[i].control->readback_offset = 0;
- ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, wdata[i].control,
+ ret = snd_sof_ipc_set_get_comp_data(wdata[i].control,
wdata[i].ipc_cmd,
wdata[i].ctrl_type,
wdata[i].control->cmd,
true);
if (ret != 0) {
- dev_err(sdev->dev, "error: send control failed\n");
+ dev_err(scomp->dev, "error: send control failed\n");
break;
}
}
@@ -2050,14 +2131,13 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_dapm_widget *tw,
struct sof_ipc_comp_reply *r)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &tw->priv;
struct sof_ipc_comp_process config;
int ret;
/* check we have some tokens - we need at least process type */
if (le32_to_cpu(private->size) == 0) {
- dev_err(sdev->dev, "error: process tokens not found\n");
+ dev_err(scomp->dev, "error: process tokens not found\n");
return -EINVAL;
}
@@ -2068,7 +2148,7 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(process_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse process tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse process tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -2077,14 +2157,14 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index,
ret = sof_process_load(scomp, index, swidget, tw, r,
find_process_comp_type(config.type));
if (ret < 0) {
- dev_err(sdev->dev, "error: process loading failed\n");
+ dev_err(scomp->dev, "error: process loading failed\n");
return ret;
}
return 0;
}
-static int sof_widget_bind_event(struct snd_sof_dev *sdev,
+static int sof_widget_bind_event(struct snd_soc_component *scomp,
struct snd_sof_widget *swidget,
u16 event_type)
{
@@ -2110,7 +2190,7 @@ static int sof_widget_bind_event(struct snd_sof_dev *sdev,
break;
}
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: invalid event type %d for widget %s\n",
event_type, swidget->widget->name);
return -EINVAL;
@@ -2132,7 +2212,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
if (!swidget)
return -ENOMEM;
- swidget->sdev = sdev;
+ swidget->scomp = scomp;
swidget->widget = w;
swidget->comp_id = sdev->next_comp_id++;
swidget->complete = 0;
@@ -2141,7 +2221,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
swidget->private = NULL;
memset(&reply, 0, sizeof(reply));
- dev_dbg(sdev->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
+ dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
swidget->comp_id, index, swidget->id, tw->name,
strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
? tw->sname : "none");
@@ -2197,6 +2277,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
case snd_soc_dapm_src:
ret = sof_widget_load_src(scomp, index, swidget, tw, &reply);
break;
+ case snd_soc_dapm_asrc:
+ ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply);
+ break;
case snd_soc_dapm_siggen:
ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply);
break;
@@ -2212,14 +2295,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
case snd_soc_dapm_dai_link:
case snd_soc_dapm_kcontrol:
default:
- dev_warn(sdev->dev, "warning: widget type %d name %s not handled\n",
+ dev_warn(scomp->dev, "warning: widget type %d name %s not handled\n",
swidget->id, tw->name);
break;
}
/* check IPC reply */
if (ret < 0 || reply.rhdr.error < 0) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n",
tw->shift, swidget->id, tw->name,
strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
@@ -2230,10 +2313,10 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
/* bind widget to external event */
if (tw->event_type) {
- ret = sof_widget_bind_event(sdev, swidget,
+ ret = sof_widget_bind_event(scomp, swidget,
le16_to_cpu(tw->event_type));
if (ret) {
- dev_err(sdev->dev, "error: widget event binding failed\n");
+ dev_err(scomp->dev, "error: widget event binding failed\n");
kfree(swidget->private);
kfree(swidget);
return ret;
@@ -2301,7 +2384,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
pipeline = swidget->private;
ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
if (ret < 0)
- dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n",
+ dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
pipeline->core);
/* update enabled cores mask */
@@ -2329,7 +2412,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
scontrol = sbe->dobj.private;
break;
default:
- dev_warn(sdev->dev, "unsupported kcontrol_type\n");
+ dev_warn(scomp->dev, "unsupported kcontrol_type\n");
goto out;
}
kfree(scontrol->control_data);
@@ -2372,12 +2455,12 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
if (!spcm)
return -ENOMEM;
- spcm->sdev = sdev;
+ spcm->scomp = scomp;
spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED;
spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED;
spcm->pcm = *pcm;
- dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name);
+ dev_dbg(scomp->dev, "tplg: load pcm %s\n", pcm->dai_name);
dai_drv->dobj.private = spcm;
list_add(&spcm->list, &sdev->pcm_list);
@@ -2386,7 +2469,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(stream_tokens), private->array,
le32_to_cpu(private->size));
if (ret) {
- dev_err(sdev->dev, "error: parse stream tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse stream tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -2395,7 +2478,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
if (!spcm->pcm.playback)
goto capture;
- dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n",
+ dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n",
spcm->pcm.pcm_name, spcm->stream[0].d0i3_compatible);
caps = &spcm->pcm.caps[stream];
@@ -2404,16 +2487,16 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
PAGE_SIZE, &spcm->stream[stream].page_table);
if (ret < 0) {
- dev_err(sdev->dev, "error: can't alloc page table for %s %d\n",
+ dev_err(scomp->dev, "error: can't alloc page table for %s %d\n",
caps->name, ret);
return ret;
}
/* bind pcm to host comp */
- ret = spcm_bind(sdev, spcm, stream);
+ ret = spcm_bind(scomp, spcm, stream);
if (ret) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: can't bind pcm to host\n");
goto free_playback_tables;
}
@@ -2425,7 +2508,7 @@ capture:
if (!spcm->pcm.capture)
return ret;
- dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n",
+ dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n",
spcm->pcm.pcm_name, spcm->stream[1].d0i3_compatible);
caps = &spcm->pcm.caps[stream];
@@ -2434,15 +2517,15 @@ capture:
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
PAGE_SIZE, &spcm->stream[stream].page_table);
if (ret < 0) {
- dev_err(sdev->dev, "error: can't alloc page table for %s %d\n",
+ dev_err(scomp->dev, "error: can't alloc page table for %s %d\n",
caps->name, ret);
goto free_playback_tables;
}
/* bind pcm to host comp */
- ret = spcm_bind(sdev, spcm, stream);
+ ret = spcm_bind(scomp, spcm, stream);
if (ret) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: can't bind pcm to host\n");
snd_dma_free_pages(&spcm->stream[stream].page_table);
goto free_playback_tables;
@@ -2568,7 +2651,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(ssp_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse ssp tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse ssp tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -2582,7 +2665,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots);
config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots);
- dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n",
+ dev_dbg(scomp->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n",
config->dai_index, config->format,
config->ssp.mclk_rate, config->ssp.bclk_rate,
config->ssp.fsync_rate, config->ssp.sample_valid_bits,
@@ -2591,13 +2674,13 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
/* validate SSP fsync rate and channel count */
if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) {
- dev_err(sdev->dev, "error: invalid fsync rate for SSP%d\n",
+ dev_err(scomp->dev, "error: invalid fsync rate for SSP%d\n",
config->dai_index);
return -EINVAL;
}
if (config->ssp.tdm_slots < 1 || config->ssp.tdm_slots > 8) {
- dev_err(sdev->dev, "error: invalid channel count for SSP%d\n",
+ dev_err(scomp->dev, "error: invalid channel count for SSP%d\n",
config->dai_index);
return -EINVAL;
}
@@ -2608,7 +2691,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
sizeof(reply));
if (ret < 0) {
- dev_err(sdev->dev, "error: failed to set DAI config for SSP%d\n",
+ dev_err(scomp->dev, "error: failed to set DAI config for SSP%d\n",
config->dai_index);
return ret;
}
@@ -2616,7 +2699,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
- dev_err(sdev->dev, "error: failed to save DAI config for SSP%d\n",
+ dev_err(scomp->dev, "error: failed to save DAI config for SSP%d\n",
config->dai_index);
return ret;
@@ -2628,8 +2711,66 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_hw_config *hw_config,
struct sof_ipc_dai_config *config)
{
- /*TODO: Add implementation */
- return 0;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_soc_tplg_private *private = &cfg->priv;
+ struct sof_ipc_reply reply;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ /* init IPC */
+ memset(&config->sai, 0, sizeof(struct sof_ipc_dai_sai_params));
+ config->hdr.size = size;
+
+ ret = sof_parse_tokens(scomp, &config->sai, sai_tokens,
+ ARRAY_SIZE(sai_tokens), private->array,
+ le32_to_cpu(private->size));
+ if (ret != 0) {
+ dev_err(scomp->dev, "error: parse sai tokens failed %d\n",
+ le32_to_cpu(private->size));
+ return ret;
+ }
+
+ config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
+ config->sai.mclk_direction = hw_config->mclk_direction;
+
+ config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
+ config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
+ config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
+
+ dev_info(scomp->dev,
+ "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
+ config->dai_index, config->format,
+ config->sai.mclk_rate, config->sai.tdm_slot_width,
+ config->sai.tdm_slots, config->sai.mclk_id);
+
+ if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
+ dev_err(scomp->dev, "error: invalid channel count for SAI%d\n",
+ config->dai_index);
+ return -EINVAL;
+ }
+
+ /* send message to DSP */
+ ret = sof_ipc_tx_message(sdev->ipc,
+ config->hdr.cmd, config, size, &reply,
+ sizeof(reply));
+
+ if (ret < 0) {
+ dev_err(scomp->dev, "error: failed to set DAI config for SAI%d\n",
+ config->dai_index);
+ return ret;
+ }
+
+ /* set config for all DAI's with name matching the link name */
+ ret = sof_set_dai_config(sdev, size, link, config);
+ if (ret < 0)
+ dev_err(scomp->dev, "error: failed to save DAI config for SAI%d\n",
+ config->dai_index);
+
+ return ret;
}
static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
@@ -2655,7 +2796,7 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(esai_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse esai tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse esai tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -2669,14 +2810,14 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
- dev_info(sdev->dev,
+ dev_info(scomp->dev,
"tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
config->dai_index, config->format,
config->esai.mclk_rate, config->esai.tdm_slot_width,
config->esai.tdm_slots, config->esai.mclk_id);
if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
- dev_err(sdev->dev, "error: invalid channel count for ESAI%d\n",
+ dev_err(scomp->dev, "error: invalid channel count for ESAI%d\n",
config->dai_index);
return -EINVAL;
}
@@ -2686,7 +2827,7 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
config->hdr.cmd, config, size, &reply,
sizeof(reply));
if (ret < 0) {
- dev_err(sdev->dev, "error: failed to set DAI config for ESAI%d\n",
+ dev_err(scomp->dev, "error: failed to set DAI config for ESAI%d\n",
config->dai_index);
return ret;
}
@@ -2694,7 +2835,7 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
- dev_err(sdev->dev, "error: failed to save DAI config for ESAI%d\n",
+ dev_err(scomp->dev, "error: failed to save DAI config for ESAI%d\n",
config->dai_index);
return ret;
@@ -2727,7 +2868,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(dmic_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse dmic tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse dmic tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -2762,7 +2903,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(dmic_pdm_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n",
le32_to_cpu(private->size));
goto err;
}
@@ -2771,27 +2912,27 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
ipc_config->hdr.size = size;
/* debug messages */
- dev_dbg(sdev->dev, "tplg: config DMIC%d driver version %d\n",
+ dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
ipc_config->dai_index, ipc_config->dmic.driver_ipc_version);
- dev_dbg(sdev->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
+ dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max,
ipc_config->dmic.duty_min);
- dev_dbg(sdev->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n",
+ dev_dbg(scomp->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n",
ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs,
ipc_config->dmic.num_pdm_active);
- dev_dbg(sdev->dev, "fifo word length %hd\n",
+ dev_dbg(scomp->dev, "fifo word length %hd\n",
ipc_config->dmic.fifo_bits);
for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) {
- dev_dbg(sdev->dev, "pdm %hd mic a %hd mic b %hd\n",
+ dev_dbg(scomp->dev, "pdm %hd mic a %hd mic b %hd\n",
ipc_config->dmic.pdm[j].id,
ipc_config->dmic.pdm[j].enable_mic_a,
ipc_config->dmic.pdm[j].enable_mic_b);
- dev_dbg(sdev->dev, "pdm %hd polarity a %hd polarity b %hd\n",
+ dev_dbg(scomp->dev, "pdm %hd polarity a %hd polarity b %hd\n",
ipc_config->dmic.pdm[j].id,
ipc_config->dmic.pdm[j].polarity_mic_a,
ipc_config->dmic.pdm[j].polarity_mic_b);
- dev_dbg(sdev->dev, "pdm %hd clk_edge %hd skew %hd\n",
+ dev_dbg(scomp->dev, "pdm %hd clk_edge %hd skew %hd\n",
ipc_config->dmic.pdm[j].id,
ipc_config->dmic.pdm[j].clk_edge,
ipc_config->dmic.pdm[j].skew);
@@ -2808,7 +2949,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
sizeof(reply));
if (ret < 0) {
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: failed to set DAI config for DMIC%d\n",
config->dai_index);
goto err;
@@ -2817,7 +2958,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, ipc_config);
if (ret < 0)
- dev_err(sdev->dev, "error: failed to save DAI config for DMIC%d\n",
+ dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n",
config->dai_index);
err:
@@ -2908,21 +3049,21 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(hda_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse hda tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse hda tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
dai = snd_soc_find_dai(link->cpus);
if (!dai) {
- dev_err(sdev->dev, "error: failed to find dai %s in %s",
+ dev_err(scomp->dev, "error: failed to find dai %s in %s",
link->cpus->dai_name, __func__);
return -EINVAL;
}
ret = sof_link_hda_process(sdev, link, config);
if (ret < 0)
- dev_err(sdev->dev, "error: failed to process hda dai link %s",
+ dev_err(scomp->dev, "error: failed to process hda dai link %s",
link->name);
return ret;
@@ -2948,7 +3089,7 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index,
sizeof(reply));
if (ret < 0) {
- dev_err(sdev->dev, "error: failed to set DAI config for ALH %d\n",
+ dev_err(scomp->dev, "error: failed to set DAI config for ALH %d\n",
config->dai_index);
return ret;
}
@@ -2956,7 +3097,7 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index,
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
- dev_err(sdev->dev, "error: failed to save DAI config for ALH %d\n",
+ dev_err(scomp->dev, "error: failed to save DAI config for ALH %d\n",
config->dai_index);
return ret;
@@ -2967,7 +3108,6 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &cfg->priv;
struct sof_ipc_dai_config config;
struct snd_soc_tplg_hw_config *hw_config;
@@ -2976,10 +3116,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
int i = 0;
if (!link->platforms) {
- dev_err(sdev->dev, "error: no platforms\n");
+ dev_err(scomp->dev, "error: no platforms\n");
return -EINVAL;
}
- link->platforms->name = dev_name(sdev->dev);
+ link->platforms->name = dev_name(scomp->dev);
/*
* Set nonatomic property for FE dai links as their trigger action
@@ -2998,7 +3138,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
/* check we have some tokens - we need at least DAI type */
if (le32_to_cpu(private->size) == 0) {
- dev_err(sdev->dev, "error: expected tokens for DAI, none found\n");
+ dev_err(scomp->dev, "error: expected tokens for DAI, none found\n");
return -EINVAL;
}
@@ -3010,7 +3150,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(dai_link_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
- dev_err(sdev->dev, "error: parse link tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse link tokens failed %d\n",
le32_to_cpu(private->size));
return ret;
}
@@ -3022,12 +3162,12 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
num_hw_configs = le32_to_cpu(cfg->num_hw_configs);
if (!num_hw_configs) {
if (config.type != SOF_DAI_INTEL_HDA) {
- dev_err(sdev->dev, "error: unexpected DAI config count %d!\n",
+ dev_err(scomp->dev, "error: unexpected DAI config count %d!\n",
le32_to_cpu(cfg->num_hw_configs));
return -EINVAL;
}
} else {
- dev_dbg(sdev->dev, "tplg: %d hw_configs found, default id: %d!\n",
+ dev_dbg(scomp->dev, "tplg: %d hw_configs found, default id: %d!\n",
cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id));
for (i = 0; i < num_hw_configs; i++) {
@@ -3036,7 +3176,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
}
if (i == num_hw_configs) {
- dev_err(sdev->dev, "error: default hw_config id: %d not found!\n",
+ dev_err(scomp->dev, "error: default hw_config id: %d not found!\n",
le32_to_cpu(cfg->default_hw_config_id));
return -EINVAL;
}
@@ -3075,7 +3215,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
&config);
break;
default:
- dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type);
+ dev_err(scomp->dev, "error: invalid DAI type %d\n",
+ config.type);
ret = -EINVAL;
break;
}
@@ -3123,7 +3264,7 @@ static int sof_link_unload(struct snd_soc_component *scomp,
goto found;
}
- dev_err(sdev->dev, "error: failed to find dai %s in %s",
+ dev_err(scomp->dev, "error: failed to find dai %s in %s",
link->name, __func__);
return -EINVAL;
found:
@@ -3132,13 +3273,15 @@ found:
case SOF_DAI_INTEL_SSP:
case SOF_DAI_INTEL_DMIC:
case SOF_DAI_INTEL_ALH:
- /* no resource needs to be released for SSP, DMIC and ALH */
+ case SOF_DAI_IMX_SAI:
+ case SOF_DAI_IMX_ESAI:
+ /* no resource needs to be released for all cases above */
break;
case SOF_DAI_INTEL_HDA:
ret = sof_link_hda_unload(sdev, link);
break;
default:
- dev_err(sdev->dev, "error: invalid DAI type %d\n",
+ dev_err(scomp->dev, "error: invalid DAI type %d\n",
sof_dai->dai_config->type);
ret = -EINVAL;
break;
@@ -3164,7 +3307,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
if (!sroute)
return -ENOMEM;
- sroute->sdev = sdev;
+ sroute->scomp = scomp;
connect = kzalloc(sizeof(*connect), GFP_KERNEL);
if (!connect) {
@@ -3175,14 +3318,14 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
connect->hdr.size = sizeof(*connect);
connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
- dev_dbg(sdev->dev, "sink %s control %s source %s\n",
+ dev_dbg(scomp->dev, "sink %s control %s source %s\n",
route->sink, route->control ? route->control : "none",
route->source);
/* source component */
- source_swidget = snd_sof_find_swidget(sdev, (char *)route->source);
+ source_swidget = snd_sof_find_swidget(scomp, (char *)route->source);
if (!source_swidget) {
- dev_err(sdev->dev, "error: source %s not found\n",
+ dev_err(scomp->dev, "error: source %s not found\n",
route->source);
ret = -EINVAL;
goto err;
@@ -3201,9 +3344,9 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
connect->source_id = source_swidget->comp_id;
/* sink component */
- sink_swidget = snd_sof_find_swidget(sdev, (char *)route->sink);
+ sink_swidget = snd_sof_find_swidget(scomp, (char *)route->sink);
if (!sink_swidget) {
- dev_err(sdev->dev, "error: sink %s not found\n",
+ dev_err(scomp->dev, "error: sink %s not found\n",
route->sink);
ret = -EINVAL;
goto err;
@@ -3227,7 +3370,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
*/
if (source_swidget->id != snd_soc_dapm_buffer &&
sink_swidget->id != snd_soc_dapm_buffer) {
- dev_dbg(sdev->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n",
+ dev_dbg(scomp->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n",
route->source, route->sink);
ret = 0;
goto err;
@@ -3239,7 +3382,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
/* check IPC return value */
if (ret < 0) {
- dev_err(sdev->dev, "error: failed to add route sink %s control %s source %s\n",
+ dev_err(scomp->dev, "error: failed to add route sink %s control %s source %s\n",
route->sink,
route->control ? route->control : "none",
route->source);
@@ -3248,7 +3391,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
/* check IPC reply */
if (reply.error < 0) {
- dev_err(sdev->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n",
+ dev_err(scomp->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n",
route->sink,
route->control ? route->control : "none",
route->source, reply.error);
@@ -3275,8 +3418,9 @@ err:
/* Function to set the initial value of SOF kcontrols.
* The value will be stored in scontrol->control_data
*/
-static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev)
+static int snd_sof_cache_kcontrol_val(struct snd_soc_component *scomp)
{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_control *scontrol = NULL;
int ipc_cmd, ctrl_type;
int ret = 0;
@@ -3296,33 +3440,34 @@ static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev)
ctrl_type = SOF_CTRL_TYPE_DATA_GET;
break;
default:
- dev_err(sdev->dev,
+ dev_err(scomp->dev,
"error: Invalid scontrol->cmd: %d\n",
scontrol->cmd);
return -EINVAL;
}
- ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ ret = snd_sof_ipc_set_get_comp_data(scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd,
false);
if (ret < 0) {
- dev_warn(sdev->dev,
- "error: kcontrol value get for widget: %d\n",
- scontrol->comp_id);
+ dev_warn(scomp->dev,
+ "error: kcontrol value get for widget: %d\n",
+ scontrol->comp_id);
}
}
return ret;
}
-int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
+int snd_sof_complete_pipeline(struct device *dev,
struct snd_sof_widget *swidget)
{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct sof_ipc_pipe_ready ready;
struct sof_ipc_reply reply;
int ret;
- dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
+ dev_dbg(dev, "tplg: complete pipeline %s id %d\n",
swidget->widget->name, swidget->comp_id);
memset(&ready, 0, sizeof(ready));
@@ -3352,7 +3497,7 @@ static void sof_complete(struct snd_soc_component *scomp)
switch (swidget->id) {
case snd_soc_dapm_scheduler:
swidget->complete =
- snd_sof_complete_pipeline(sdev, swidget);
+ snd_sof_complete_pipeline(scomp->dev, swidget);
break;
default:
break;
@@ -3362,14 +3507,13 @@ static void sof_complete(struct snd_soc_component *scomp)
* cache initial values of SOF kcontrols by reading DSP value over
* IPC. It may be overwritten by alsa-mixer after booting up
*/
- snd_sof_cache_kcontrol_val(sdev);
+ snd_sof_cache_kcontrol_val(scomp);
}
/* manifest - optional to inform component of manifest */
static int sof_manifest(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_manifest *man)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
u32 size;
u32 abi_version;
@@ -3377,16 +3521,16 @@ static int sof_manifest(struct snd_soc_component *scomp, int index,
/* backward compatible with tplg without ABI info */
if (!size) {
- dev_dbg(sdev->dev, "No topology ABI info\n");
+ dev_dbg(scomp->dev, "No topology ABI info\n");
return 0;
}
if (size != SOF_TPLG_ABI_SIZE) {
- dev_err(sdev->dev, "error: invalid topology ABI size\n");
+ dev_err(scomp->dev, "error: invalid topology ABI size\n");
return -EINVAL;
}
- dev_info(sdev->dev,
+ dev_info(scomp->dev,
"Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
man->priv.data[0], man->priv.data[1],
man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
@@ -3397,15 +3541,15 @@ static int sof_manifest(struct snd_soc_component *scomp, int index,
man->priv.data[2]);
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
- dev_err(sdev->dev, "error: incompatible topology ABI version\n");
+ dev_err(scomp->dev, "error: incompatible topology ABI version\n");
return -EINVAL;
}
if (abi_version > SOF_ABI_VERSION) {
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
- dev_warn(sdev->dev, "warn: topology ABI is more recent than kernel\n");
+ dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
} else {
- dev_err(sdev->dev, "error: topology ABI is more recent than kernel\n");
+ dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
return -EINVAL;
}
}
@@ -3463,34 +3607,25 @@ static struct snd_soc_tplg_ops sof_tplg_ops = {
.bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops),
};
-int snd_sof_init_topology(struct snd_sof_dev *sdev,
- struct snd_soc_tplg_ops *ops)
-{
- /* TODO: support linked list of topologies */
- sdev->tplg_ops = ops;
- return 0;
-}
-EXPORT_SYMBOL(snd_sof_init_topology);
-
-int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file)
+int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
{
const struct firmware *fw;
int ret;
- dev_dbg(sdev->dev, "loading topology:%s\n", file);
+ dev_dbg(scomp->dev, "loading topology:%s\n", file);
- ret = request_firmware(&fw, file, sdev->dev);
+ ret = request_firmware(&fw, file, scomp->dev);
if (ret < 0) {
- dev_err(sdev->dev, "error: tplg request firmware %s failed err: %d\n",
+ dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n",
file, ret);
return ret;
}
- ret = snd_soc_tplg_component_load(sdev->component,
+ ret = snd_soc_tplg_component_load(scomp,
&sof_tplg_ops, fw,
SND_SOC_TPLG_INDEX_ALL);
if (ret < 0) {
- dev_err(sdev->dev, "error: tplg component load failed %d\n",
+ dev_err(scomp->dev, "error: tplg component load failed %d\n",
ret);
ret = -EINVAL;
}
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index b0e4556c8536..4bb65030819d 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -250,8 +250,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev)
}
/* create compressed page table for audio firmware */
- ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area,
- sdev->dmatb.bytes);
+ ret = snd_sof_create_page_table(sdev->dev, &sdev->dmatb,
+ sdev->dmatp.area, sdev->dmatb.bytes);
if (ret < 0)
goto table_err;
diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c
index 2ac4c3da0320..9831eb57df6c 100644
--- a/sound/soc/sof/utils.c
+++ b/sound/soc/sof/utils.c
@@ -10,6 +10,7 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/platform_device.h>
+#include <asm/unaligned.h>
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
@@ -110,3 +111,62 @@ void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest,
memcpy_fromio(dest, src, size);
}
EXPORT_SYMBOL(sof_block_read);
+
+/*
+ * Generic buffer page table creation.
+ * Take the each physical page address and drop the least significant unused
+ * bits from each (based on PAGE_SIZE). Then pack valid page address bits
+ * into compressed page table.
+ */
+
+int snd_sof_create_page_table(struct device *dev,
+ struct snd_dma_buffer *dmab,
+ unsigned char *page_table, size_t size)
+{
+ int i, pages;
+
+ pages = snd_sgbuf_aligned_pages(size);
+
+ dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n",
+ dmab->area, size, pages);
+
+ for (i = 0; i < pages; i++) {
+ /*
+ * The number of valid address bits for each page is 20.
+ * idx determines the byte position within page_table
+ * where the current page's address is stored
+ * in the compressed page_table.
+ * This can be calculated by multiplying the page number by 2.5.
+ */
+ u32 idx = (5 * i) >> 1;
+ u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
+ u8 *pg_table;
+
+ dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
+
+ pg_table = (u8 *)(page_table + idx);
+
+ /*
+ * pagetable compression:
+ * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
+ * ___________pfn 0__________ __________pfn 1___________ _pfn 2...
+ * .... .... .... .... .... .... .... .... .... .... ....
+ * It is created by:
+ * 1. set current location to 0, PFN index i to 0
+ * 2. put pfn[i] at current location in Little Endian byte order
+ * 3. calculate an intermediate value as
+ * x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
+ * 4. put x at offset (current location + 2) in LE byte order
+ * 5. increment current location by 5 bytes, increment i by 2
+ * 6. continue to (2)
+ */
+ if (i & 1)
+ put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4,
+ pg_table);
+ else
+ put_unaligned_le32(pfn, pg_table);
+ }
+
+ return pages;
+}
+EXPORT_SYMBOL(snd_sof_create_page_table);
diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c
index 46a4905a9dce..ea08651f0bb3 100644
--- a/sound/soc/sof/xtensa/core.c
+++ b/sound/soc/sof/xtensa/core.c
@@ -132,7 +132,7 @@ const struct sof_arch_ops sof_xtensa_arch_ops = {
.dsp_oops = xtensa_dsp_oops,
.dsp_stack = xtensa_stack,
};
-EXPORT_SYMBOL(sof_xtensa_arch_ops);
+EXPORT_SYMBOL_NS(sof_xtensa_arch_ops, SND_SOC_SOF_XTENSA);
MODULE_DESCRIPTION("SOF Xtensa DSP support");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index da4b8f5f192b..2284558684bc 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -508,7 +508,6 @@ static const struct snd_soc_component_driver sprd_soc_component = {
.name = DRV_NAME,
.open = sprd_pcm_open,
.close = sprd_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = sprd_pcm_hw_params,
.hw_free = sprd_pcm_hw_free,
.trigger = sprd_pcm_trigger,
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 81c407da15c5..807fee1eac66 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -252,7 +252,6 @@ static int stm32_adfsdm_pcm_close(struct snd_soc_component *component,
struct stm32_adfsdm_priv *priv =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
- snd_pcm_lib_free_pages(substream);
priv->substream = NULL;
return 0;
@@ -276,25 +275,13 @@ static int stm32_adfsdm_pcm_hw_params(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct stm32_adfsdm_priv *priv =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
- int ret;
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (ret < 0)
- return ret;
priv->pcm_buff = substream->runtime->dma_area;
return iio_channel_cb_set_buffer_watermark(priv->iio_cb,
params_period_size(params));
}
-static int stm32_adfsdm_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- snd_pcm_lib_free_pages(substream);
-
- return 0;
-}
-
static int stm32_adfsdm_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
@@ -303,30 +290,18 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_component *component,
snd_soc_dai_get_drvdata(rtd->cpu_dai);
unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- priv->dev, size, size);
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+ priv->dev, size, size);
return 0;
}
-static void stm32_adfsdm_pcm_free(struct snd_soc_component *component,
- struct snd_pcm *pcm)
-{
- struct snd_pcm_substream *substream;
-
- substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
- if (substream)
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
.open = stm32_adfsdm_pcm_open,
.close = stm32_adfsdm_pcm_close,
.hw_params = stm32_adfsdm_pcm_hw_params,
- .hw_free = stm32_adfsdm_pcm_hw_free,
.trigger = stm32_adfsdm_trigger,
.pointer = stm32_adfsdm_pcm_pointer,
.pcm_construct = stm32_adfsdm_pcm_new,
- .pcm_destruct = stm32_adfsdm_pcm_free,
};
static const struct of_device_id stm32_adfsdm_of_match[] = {
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 3fd28ee01675..3769d9ce5dbe 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_platform.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -220,6 +219,7 @@
* @slave_config: dma slave channel runtime config pointer
* @phys_addr: SPDIFRX registers physical base address
* @lock: synchronization enabling lock
+ * @irq_lock: prevent race condition with IRQ on stream state
* @cs: channel status buffer
* @ub: user data buffer
* @irq: SPDIFRX interrupt line
@@ -240,6 +240,7 @@ struct stm32_spdifrx_data {
struct dma_slave_config slave_config;
dma_addr_t phys_addr;
spinlock_t lock; /* Sync enabling lock */
+ spinlock_t irq_lock; /* Prevent race condition on stream state */
unsigned char cs[SPDIFRX_CS_BYTES_NB];
unsigned char ub[SPDIFRX_UB_BYTES_NB];
int irq;
@@ -320,6 +321,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx)
static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
{
int cr, cr_mask, imr, ret;
+ unsigned long flags;
/* Enable IRQs */
imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE;
@@ -327,7 +329,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
if (ret)
return ret;
- spin_lock(&spdifrx->lock);
+ spin_lock_irqsave(&spdifrx->lock, flags);
spdifrx->refcount++;
@@ -362,7 +364,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
"Failed to start synchronization\n");
}
- spin_unlock(&spdifrx->lock);
+ spin_unlock_irqrestore(&spdifrx->lock, flags);
return ret;
}
@@ -370,11 +372,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx)
{
int cr, cr_mask, reg;
+ unsigned long flags;
- spin_lock(&spdifrx->lock);
+ spin_lock_irqsave(&spdifrx->lock, flags);
if (--spdifrx->refcount) {
- spin_unlock(&spdifrx->lock);
+ spin_unlock_irqrestore(&spdifrx->lock, flags);
return;
}
@@ -393,7 +396,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx)
regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, &reg);
regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, &reg);
- spin_unlock(&spdifrx->lock);
+ spin_unlock_irqrestore(&spdifrx->lock, flags);
}
static int stm32_spdifrx_dma_ctrl_register(struct device *dev,
@@ -480,8 +483,6 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx)
memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB);
memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB);
- pinctrl_pm_select_default_state(&spdifrx->pdev->dev);
-
ret = stm32_spdifrx_dma_ctrl_start(spdifrx);
if (ret < 0)
return ret;
@@ -513,7 +514,6 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx)
end:
clk_disable_unprepare(spdifrx->kclk);
- pinctrl_pm_select_sleep_state(&spdifrx->pdev->dev);
return ret;
}
@@ -665,7 +665,6 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = {
static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
{
struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid;
- struct snd_pcm_substream *substream = spdifrx->substream;
struct platform_device *pdev = spdifrx->pdev;
unsigned int cr, mask, sr, imr;
unsigned int flags, sync_state;
@@ -745,14 +744,19 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
return IRQ_HANDLED;
}
- if (substream)
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ spin_lock(&spdifrx->irq_lock);
+ if (spdifrx->substream)
+ snd_pcm_stop(spdifrx->substream,
+ SNDRV_PCM_STATE_DISCONNECTED);
+ spin_unlock(&spdifrx->irq_lock);
return IRQ_HANDLED;
}
- if (err_xrun && substream)
- snd_pcm_stop_xrun(substream);
+ spin_lock(&spdifrx->irq_lock);
+ if (err_xrun && spdifrx->substream)
+ snd_pcm_stop_xrun(spdifrx->substream);
+ spin_unlock(&spdifrx->irq_lock);
return IRQ_HANDLED;
}
@@ -761,9 +765,12 @@ static int stm32_spdifrx_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
int ret;
+ spin_lock_irqsave(&spdifrx->irq_lock, flags);
spdifrx->substream = substream;
+ spin_unlock_irqrestore(&spdifrx->irq_lock, flags);
ret = clk_prepare_enable(spdifrx->kclk);
if (ret)
@@ -839,8 +846,12 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
+ spin_lock_irqsave(&spdifrx->irq_lock, flags);
spdifrx->substream = NULL;
+ spin_unlock_irqrestore(&spdifrx->irq_lock, flags);
+
clk_disable_unprepare(spdifrx->kclk);
}
@@ -944,6 +955,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
spdifrx->pdev = pdev;
init_completion(&spdifrx->cs_completion);
spin_lock_init(&spdifrx->lock);
+ spin_lock_init(&spdifrx->irq_lock);
platform_set_drvdata(pdev, spdifrx);
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 6211dfda2195..f08d3489c3cf 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -186,7 +186,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
static int tegra_wm8903_remove(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd =
- snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_component *component = codec_dai->component;
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 8e5371801d88..e1e937eb1dc1 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -664,18 +664,39 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
pm_runtime_get_sync(mcasp->dev);
- if (dir == SND_SOC_CLOCK_OUT) {
+
+ if (dir == SND_SOC_CLOCK_IN) {
+ switch (clk_id) {
+ case MCASP_CLK_HCLK_AHCLK:
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
+ AHCLKXE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
+ AHCLKRE);
+ clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
+ break;
+ case MCASP_CLK_HCLK_AUXCLK:
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
+ AHCLKXE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
+ AHCLKRE);
+ set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
+ break;
+ default:
+ dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id);
+ goto out;
+ }
+ } else {
+ /* Select AUXCLK as HCLK */
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
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);
- clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
}
-
+ /*
+ * When AHCLK X/R is selected to be output it means that the HCLK is
+ * the same clock - coming via AUXCLK.
+ */
mcasp->sysclk_freq = freq;
-
+out:
pm_runtime_put(mcasp->dev);
return 0;
}
diff --git a/sound/soc/ti/davinci-mcasp.h b/sound/soc/ti/davinci-mcasp.h
index bc705d6ca48b..5de2b8a31061 100644
--- a/sound/soc/ti/davinci-mcasp.h
+++ b/sound/soc/ti/davinci-mcasp.h
@@ -295,6 +295,10 @@
#define NUMEVT(x) (((x) & 0xFF) << 8)
#define NUMDMA_MASK (0xFF)
+/* Source of High-frequency transmit/receive clock */
+#define MCASP_CLK_HCLK_AHCLK 0 /* AHCLKX/R */
+#define MCASP_CLK_HCLK_AUXCLK 1 /* Internal functional clock */
+
/* clock divider IDs */
#define MCASP_CLKDIV_AUXCLK 0 /* HCLK divider from AUXCLK */
#define MCASP_CLKDIV_BCLK 1 /* BCLK divider from HCLK */
diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c
index 588f680a9c24..fdb0dc85fe67 100644
--- a/sound/soc/ti/rx51.c
+++ b/sound/soc/ti/rx51.c
@@ -328,11 +328,11 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
static struct snd_soc_codec_conf rx51_codec_conf[] = {
{
- .dev_name = "tlv320aic3x-codec.2-0019",
+ .dlc = COMP_CODEC_CONF("tlv320aic3x-codec.2-0019"),
.name_prefix = "b",
},
{
- .dev_name = "tpa6130a2.2-0060",
+ .dlc = COMP_CODEC_CONF("tpa6130a2.2-0060"),
.name_prefix = "TPA6130A2",
},
};
@@ -397,8 +397,8 @@ static int rx51_soc_probe(struct platform_device *pdev)
}
rx51_aux_dev[0].dlc.name = NULL;
rx51_aux_dev[0].dlc.of_node = dai_node;
- rx51_codec_conf[0].dev_name = NULL;
- rx51_codec_conf[0].of_node = dai_node;
+ rx51_codec_conf[0].dlc.name = NULL;
+ rx51_codec_conf[0].dlc.of_node = dai_node;
dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
if (!dai_node) {
@@ -407,8 +407,8 @@ static int rx51_soc_probe(struct platform_device *pdev)
}
rx51_aux_dev[1].dlc.name = NULL;
rx51_aux_dev[1].dlc.of_node = dai_node;
- rx51_codec_conf[1].dev_name = NULL;
- rx51_codec_conf[1].of_node = dai_node;
+ rx51_codec_conf[1].dlc.name = NULL;
+ rx51_codec_conf[1].dlc.of_node = dai_node;
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 33c78d33e5a1..dba13543911c 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -54,11 +54,6 @@ static int txx9aclc_pcm_hw_params(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct txx9aclc_dmadata *dmadata = runtime->private_data;
- int ret;
-
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (ret < 0)
- return ret;
dev_dbg(component->dev,
"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
@@ -76,12 +71,6 @@ static int txx9aclc_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
-static int txx9aclc_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static int txx9aclc_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -306,7 +295,7 @@ static int txx9aclc_pcm_new(struct snd_soc_component *component,
goto exit;
}
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, 64 * 1024, 4 * 1024 * 1024);
return 0;
@@ -406,9 +395,7 @@ static const struct snd_soc_component_driver txx9aclc_soc_component = {
.remove = txx9aclc_pcm_remove,
.open = txx9aclc_pcm_open,
.close = txx9aclc_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = txx9aclc_pcm_hw_params,
- .hw_free = txx9aclc_pcm_hw_free,
.prepare = txx9aclc_pcm_prepare,
.trigger = txx9aclc_pcm_trigger,
.pointer = txx9aclc_pcm_pointer,
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
index 700d936ed94e..da83423c52e2 100644
--- a/sound/soc/uniphier/aio-dma.c
+++ b/sound/soc/uniphier/aio-dma.c
@@ -104,25 +104,6 @@ static int uniphier_aiodma_open(struct snd_soc_component *component,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256);
}
-static int uniphier_aiodma_hw_params(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
- substream->runtime->dma_bytes = params_buffer_bytes(params);
-
- return 0;
-}
-
-static int uniphier_aiodma_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- snd_pcm_set_runtime_buffer(substream, NULL);
- substream->runtime->dma_bytes = 0;
-
- return 0;
-}
-
static int uniphier_aiodma_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -232,30 +213,20 @@ static int uniphier_aiodma_new(struct snd_soc_component *component,
if (ret)
return ret;
- snd_pcm_lib_preallocate_pages_for_all(pcm,
+ snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_DEV, dev,
uniphier_aiodma_hw.buffer_bytes_max,
uniphier_aiodma_hw.buffer_bytes_max);
return 0;
}
-static void uniphier_aiodma_free(struct snd_soc_component *component,
- struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static const struct snd_soc_component_driver uniphier_soc_platform = {
.open = uniphier_aiodma_open,
- .ioctl = snd_soc_pcm_lib_ioctl,
- .hw_params = uniphier_aiodma_hw_params,
- .hw_free = uniphier_aiodma_hw_free,
.prepare = uniphier_aiodma_prepare,
.trigger = uniphier_aiodma_trigger,
.pointer = uniphier_aiodma_pointer,
.mmap = uniphier_aiodma_mmap,
.pcm_construct = uniphier_aiodma_new,
- .pcm_destruct = uniphier_aiodma_free,
.compr_ops = &uniphier_aio_compr_ops,
};
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 296c4caf96a0..1d59fb668c77 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -426,7 +426,6 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
{
u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;
u32 aes_reg1_val, aes_reg2_val;
- int status;
u64 size;
struct snd_pcm_runtime *runtime = substream->runtime;
struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
@@ -450,9 +449,6 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
}
size = params_buffer_bytes(params);
- status = snd_pcm_lib_malloc_pages(substream, size);
- if (status < 0)
- return status;
stream_data->buffer_size = size;
@@ -495,12 +491,6 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
-static int xlnx_formatter_pcm_hw_free(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
static int xlnx_formatter_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
int cmd)
@@ -532,7 +522,7 @@ static int xlnx_formatter_pcm_trigger(struct snd_soc_component *component,
static int xlnx_formatter_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+ snd_pcm_set_managed_buffer_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV, component->dev,
xlnx_pcm_hardware.buffer_bytes_max,
xlnx_pcm_hardware.buffer_bytes_max);
@@ -543,9 +533,7 @@ static const struct snd_soc_component_driver xlnx_asoc_component = {
.name = DRV_NAME,
.open = xlnx_formatter_pcm_open,
.close = xlnx_formatter_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = xlnx_formatter_pcm_hw_params,
- .hw_free = xlnx_formatter_pcm_hw_free,
.trigger = xlnx_formatter_pcm_trigger,
.pointer = xlnx_formatter_pcm_pointer,
.pcm_construct = xlnx_formatter_pcm_new,
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index e08f4fee932a..bcf442faff7c 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -390,7 +390,6 @@ static int xtfpga_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- int ret;
struct snd_pcm_runtime *runtime = substream->runtime;
struct xtfpga_i2s *i2s = runtime->private_data;
unsigned channels = params_channels(hw_params);
@@ -422,9 +421,7 @@ static int xtfpga_pcm_hw_params(struct snd_soc_component *component,
return -EINVAL;
}
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- return ret;
+ return 0;
}
static int xtfpga_pcm_trigger(struct snd_soc_component *component,
@@ -472,8 +469,8 @@ static int xtfpga_pcm_new(struct snd_soc_component *component,
struct snd_card *card = rtd->card->snd_card;
size_t size = xtfpga_pcm_hardware.buffer_bytes_max;
- snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
- card->dev, size, size);
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+ card->dev, size, size);
return 0;
}
@@ -481,7 +478,6 @@ static const struct snd_soc_component_driver xtfpga_i2s_component = {
.name = DRV_NAME,
.open = xtfpga_pcm_open,
.close = xtfpga_pcm_close,
- .ioctl = snd_soc_pcm_lib_ioctl,
.hw_params = xtfpga_pcm_hw_params,
.trigger = xtfpga_pcm_trigger,
.pointer = xtfpga_pcm_pointer,