Merge tag 'v5.2-rc1' into asoc-5.3
authorMark Brown <broonie@kernel.org>
Mon, 20 May 2019 10:53:50 +0000 (11:53 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 20 May 2019 10:53:50 +0000 (11:53 +0100)
Linux 5.2-rc1

42 files changed:
Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt [deleted file]
include/dt-bindings/sound/meson-g12a-tohdmitx.h [new file with mode: 0644]
include/sound/soc.h
include/uapi/sound/sof/eq.h [deleted file]
include/uapi/sound/sof/manifest.h [deleted file]
include/uapi/sound/sof/tone.h [deleted file]
include/uapi/sound/sof/trace.h [deleted file]
sound/soc/amd/raven/acp3x-pcm-dma.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/rt5677-spi.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/tlv320aic3x.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/intel/Kconfig
sound/soc/intel/boards/kbl_da7219_max98927.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl.c
sound/soc/mediatek/common/mtk-afe-fe-dai.c
sound/soc/mediatek/common/mtk-base-afe.h
sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
sound/soc/meson/Kconfig
sound/soc/meson/Makefile
sound/soc/meson/axg-card.c
sound/soc/meson/g12a-tohdmitx.c [new file with mode: 0644]
sound/soc/soc-acpi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/sof/intel/Kconfig
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/hda.h
sound/soc/sof/pcm.c
sound/soc/sof/sof-pci-dev.c
sound/soc/stm/stm32_i2s.c
sound/soc/stm/stm32_spdifrx.c

diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml
new file mode 100644 (file)
index 0000000..a49ef22
--- /dev/null
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/allwinner,sun4i-a10-spdif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 S/PDIF Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Liam Girdwood <lgirdwood@gmail.com>
+  - Mark Brown <broonie@kernel.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#sound-dai-cells":
+    const: 0
+
+  compatible:
+    oneOf:
+      - const: allwinner,sun4i-a10-spdif
+      - const: allwinner,sun6i-a31-spdif
+      - const: allwinner,sun8i-h3-spdif
+      - items:
+          - const: allwinner,sun8i-a83t-spdif
+          - const: allwinner,sun8i-h3-spdif
+      - items:
+          - const: allwinner,sun50i-a64-spdif
+          - const: allwinner,sun8i-h3-spdif
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+
+  clock-names:
+    items:
+      - const: apb
+      - const: spdif
+
+  # Even though it only applies to subschemas under the conditionals,
+  # not listing them here will trigger a warning because of the
+  # additionalsProperties set to false.
+  dmas: true
+  dma-names: true
+  resets:
+    maxItems: 1
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun6i-a31-spdif
+              - allwinner,sun8i-h3-spdif
+
+    then:
+      required:
+        - resets
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: allwinner,sun8i-h3-spdif
+
+    then:
+      properties:
+        dmas:
+          description: TX DMA Channel
+
+        dma-names:
+          const: tx
+
+    else:
+      properties:
+        dmas:
+          items:
+            - description: RX DMA Channel
+            - description: TX DMA Channel
+
+        dma-names:
+          items:
+            - const: rx
+            - const: tx
+
+required:
+  - "#sound-dai-cells"
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - dmas
+  - dma-names
+
+additionalProperties: false
+
+examples:
+  - |
+    spdif: spdif@1c21000 {
+        #sound-dai-cells = <0>;
+        compatible = "allwinner,sun4i-a10-spdif";
+        reg = <0x01c21000 0x40>;
+        interrupts = <13>;
+        clocks = <&apb0_gates 1>, <&spdif_clk>;
+        clock-names = "apb", "spdif";
+        dmas = <&dma 0 2>, <&dma 0 2>;
+        dma-names = "rx", "tx";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt
new file mode 100644 (file)
index 0000000..aa6c355
--- /dev/null
@@ -0,0 +1,55 @@
+* Amlogic HDMI Tx control glue
+
+Required properties:
+- compatible: "amlogic,g12a-tohdmitx"
+- reg: physical base address of the controller and length of memory
+       mapped region.
+- #sound-dai-cells: should be 1.
+
+Example on the S905X2 SoC:
+
+tohdmitx: audio-controller@744 {
+       compatible = "amlogic,g12a-tohdmitx";
+       reg = <0x0 0x744 0x0 0x4>;
+       #sound-dai-cells = <1>;
+};
+
+Example of an 'amlogic,axg-sound-card':
+
+sound {
+       compatible = "amlogic,axg-sound-card";
+
+[...]
+
+       dai-link-x {
+               sound-dai = <&tdmif_a>;
+               dai-format = "i2s";
+               dai-tdm-slot-tx-mask-0 = <1 1>;
+
+               codec-0 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>;
+               };
+
+               codec-1 {
+                       sound-dai = <&external_dac>;
+               };
+       };
+
+       dai-link-y {
+               sound-dai = <&tdmif_c>;
+               dai-format = "i2s";
+               dai-tdm-slot-tx-mask-0 = <1 1>;
+
+               codec {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>;
+               };
+       };
+
+       dai-link-z {
+               sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+               codec {
+                       sound-dai = <&hdmi_tx>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
deleted file mode 100644 (file)
index 0c64a20..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
-
-The Allwinner S/PDIF audio block is a transceiver that allows the
-processor to receive and transmit digital audio via an coaxial cable or
-a fibre cable.
-For now only playback is supported.
-
-Required properties:
-
-  - compatible         : should be one of the following:
-    - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
-    - "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
-    - "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC
-
-  - reg                        : Offset and length of the register set for the device.
-
-  - interrupts         : Contains the spdif interrupt.
-
-  - dmas               : Generic dma devicetree binding as described in
-                         Documentation/devicetree/bindings/dma/dma.txt.
-
-  - dma-names          : Two dmas have to be defined, "tx" and "rx".
-
-  - clocks             : Contains an entry for each entry in clock-names.
-
-  - clock-names                : Includes the following entries:
-       "apb"             clock for the spdif bus.
-       "spdif"           clock for spdif controller.
-
-  - resets             : reset specifier for the ahb reset (A31 and newer only)
-
-Example:
-
-spdif: spdif@1c21000 {
-       compatible = "allwinner,sun4i-a10-spdif";
-       reg = <0x01c21000 0x40>;
-       interrupts = <13>;
-       clocks = <&apb0_gates 1>, <&spdif_clk>;
-       clock-names = "apb", "spdif";
-       dmas = <&dma 0 2>, <&dma 0 2>;
-       dma-names = "rx", "tx";
-};
diff --git a/include/dt-bindings/sound/meson-g12a-tohdmitx.h b/include/dt-bindings/sound/meson-g12a-tohdmitx.h
new file mode 100644 (file)
index 0000000..c5e1f48
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __DT_MESON_G12A_TOHDMITX_H
+#define __DT_MESON_G12A_TOHDMITX_H
+
+#define TOHDMITX_I2S_IN_A      0
+#define TOHDMITX_I2S_IN_B      1
+#define TOHDMITX_I2S_IN_C      2
+#define TOHDMITX_I2S_OUT       3
+#define TOHDMITX_SPDIF_IN_A    4
+#define TOHDMITX_SPDIF_IN_B    5
+#define TOHDMITX_SPDIF_OUT     6
+
+#endif /* __DT_MESON_G12A_TOHDMITX_H */
index 482b4ea87c3c4bd9fac786fa7165b30123174ea2..f20785aa7b4a3536c56ca718a02c124ac1d15346 100644 (file)
@@ -1214,7 +1214,6 @@ struct snd_soc_pcm_runtime {
 
        /* Dynamic PCM BE runtime data */
        struct snd_soc_dpcm_runtime dpcm[2];
-       int fe_compr;
 
        long pmdown_time;
 
@@ -1239,6 +1238,7 @@ struct snd_soc_pcm_runtime {
        /* bit field */
        unsigned int dev_registered:1;
        unsigned int pop_wait:1;
+       unsigned int fe_compr:1; /* for Dynamic PCM */
 };
 #define for_each_rtd_codec_dai(rtd, i, dai)\
        for ((i) = 0;                                                  \
diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h
deleted file mode 100644 (file)
index 666c2b6..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) 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) 2018 Intel Corporation. All rights reserved.
- */
-
-#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__
-#define __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__
-
-/* FIR EQ type */
-
-#define SOF_EQ_FIR_IDX_SWITCH  0
-
-#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */
-
-#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */
-
-#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */
-
-/*
- * eq_fir_configuration data structure contains this information
- *     uint32_t size
- *        This is the number of bytes need to store the received EQ
- *        configuration.
- *     uint16_t channels_in_config
- *         This describes the number of channels in this EQ config data. It
- *         can be different from PLATFORM_MAX_CHANNELS.
- *     uint16_t number_of_responses
- *         0=no responses, 1=one response defined, 2=two responses defined, etc.
- *     int16_t data[]
- *         assign_response[channels_in_config]
- *             0 = use first response, 1 = use 2nd response, etc.
- *             E.g. {0, 0, 0, 0, 1, 1, 1, 1} would apply to channels 0-3 the
- *            same first defined response and for to channels 4-7 the second.
- *         coef_data[]
- *             Repeated data
- *             { filter_length, output_shift, h[] }
- *            for every EQ response defined where vector h has filter_length
- *             number of coefficients. Coefficients in h[] are in Q1.15 format.
- *             E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts.
- *
- * NOTE: The channels_in_config must be even to have coef_data aligned to
- * 32 bit word in RAM. Therefore a mono EQ assign must be duplicated to 2ch
- * even if it would never used. Similarly a 5ch EQ assign must be increased
- * to 6ch. EQ init will return an error if this is not met.
- *
- * NOTE: The filter_length must be multiple of four. Therefore the filter must
- * be padded from the end with zeros have this condition met.
- */
-
-struct sof_eq_fir_config {
-       uint32_t size;
-       uint16_t channels_in_config;
-       uint16_t number_of_responses;
-
-       /* reserved */
-       uint32_t reserved[4];
-
-       int16_t data[];
-} __packed;
-
-struct sof_eq_fir_coef_data {
-       int16_t length; /* Number of FIR taps */
-       int16_t out_shift; /* Amount of right shifts at output */
-
-       /* reserved */
-       uint32_t reserved[4];
-
-       int16_t coef[]; /* FIR coefficients */
-} __packed;
-
-/* In the struct above there's two 16 bit words (length, shift) and four
- * reserved 32 bit words before the actual FIR coefficients. This information
- * is used in parsing of the configuration blob.
- */
-#define SOF_EQ_FIR_COEF_NHEADER \
-       (sizeof(struct sof_eq_fir_coef_data) / sizeof(int16_t))
-
-/* IIR EQ type */
-
-#define SOF_EQ_IIR_IDX_SWITCH   0
-
-#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */
-
-#define SOF_EQ_IIR_MAX_RESPONSES 8 /* A blob can define max 8 IIR EQs */
-
-/* eq_iir_configuration
- *     uint32_t channels_in_config
- *         This describes the number of channels in this EQ config data. It
- *         can be different from PLATFORM_MAX_CHANNELS.
- *     uint32_t number_of_responses_defined
- *         0=no responses, 1=one response defined, 2=two responses defined, etc.
- *     int32_t data[]
- *         Data consist of two parts. First is the response assign vector that
- *        has length of channels_in_config. The latter part is coefficient
- *         data.
- *         uint32_t assign_response[channels_in_config]
- *             -1 = not defined, 0 = use first response, 1 = use 2nd, etc.
- *             E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the
- *             same first defined response and leave channels 4-7 unequalized.
- *         coefficient_data[]
- *             <1st EQ>
- *             uint32_t num_biquads
- *             uint32_t num_biquads_in_series
- *             <1st biquad>
- *             int32_t coef_a2       Q2.30 format
- *             int32_t coef_a1       Q2.30 format
- *             int32_t coef_b2       Q2.30 format
- *             int32_t coef_b1       Q2.30 format
- *             int32_t coef_b0       Q2.30 format
- *             int32_t output_shift  number of shifts right, shift left is negative
- *             int32_t output_gain   Q2.14 format
- *             <2nd biquad>
- *             ...
- *             <2nd EQ>
- *
- *         Note: A flat response biquad can be made with a section set to
- *         b0 = 1.0, gain = 1.0, and other parameters set to 0
- *         {0, 0, 0, 0, 1073741824, 0, 16484}
- */
-
-struct sof_eq_iir_config {
-       uint32_t size;
-       uint32_t channels_in_config;
-       uint32_t number_of_responses;
-
-       /* reserved */
-       uint32_t reserved[4];
-
-       int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */
-} __packed;
-
-struct sof_eq_iir_header_df2t {
-       uint32_t num_sections;
-       uint32_t num_sections_in_series;
-
-       /* reserved */
-       uint32_t reserved[4];
-
-       int32_t biquads[]; /* Repeated biquad coefficients */
-} __packed;
-
-struct sof_eq_iir_biquad_df2t {
-       int32_t a2; /* Q2.30 */
-       int32_t a1; /* Q2.30 */
-       int32_t b2; /* Q2.30 */
-       int32_t b1; /* Q2.30 */
-       int32_t b0; /* Q2.30 */
-       int32_t output_shift; /* Number of right shifts */
-       int32_t output_gain;  /* Q2.14 */
-} __packed;
-
-/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in
- * in the 0 - 20 kHz bandwidth.
- */
-#define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11
-
-/* The number of int32_t words in sof_eq_iir_header_df2t:
- *     num_sections, num_sections_in_series, reserved[4]
- */
-#define SOF_EQ_IIR_NHEADER_DF2T \
-       (sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t))
-
-/* The number of int32_t words in sof_eq_iir_biquad_df2t:
- *     a2, a1, b2, b1, b0, output_shift, output_gain
- */
-#define SOF_EQ_IIR_NBIQUAD_DF2T \
-       (sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t))
-
-#endif
diff --git a/include/uapi/sound/sof/manifest.h b/include/uapi/sound/sof/manifest.h
deleted file mode 100644 (file)
index 2009ee3..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) 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) 2018 Intel Corporation. All rights reserved.
- */
-
-#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__
-#define __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__
-
-/* start offset for base FW module */
-#define SOF_MAN_ELF_TEXT_OFFSET                0x2000
-
-/* FW Extended Manifest Header id = $AE1 */
-#define SOF_MAN_EXT_HEADER_MAGIC       0x31454124
-
-/* module type load type */
-#define SOF_MAN_MOD_TYPE_BUILTIN       0
-#define SOF_MAN_MOD_TYPE_MODULE                1
-
-struct sof_man_module_type {
-       uint32_t load_type:4;   /* SOF_MAN_MOD_TYPE_ */
-       uint32_t auto_start:1;
-       uint32_t domain_ll:1;
-       uint32_t domain_dp:1;
-       uint32_t rsvd_:25;
-};
-
-/* segment flags.type */
-#define SOF_MAN_SEGMENT_TEXT           0
-#define SOF_MAN_SEGMENT_RODATA         1
-#define SOF_MAN_SEGMENT_DATA           1
-#define SOF_MAN_SEGMENT_BSS            2
-#define SOF_MAN_SEGMENT_EMPTY          15
-
-union sof_man_segment_flags {
-       uint32_t ul;
-       struct {
-               uint32_t contents:1;
-               uint32_t alloc:1;
-               uint32_t load:1;
-               uint32_t readonly:1;
-               uint32_t code:1;
-               uint32_t data:1;
-               uint32_t _rsvd0:2;
-               uint32_t type:4;        /* MAN_SEGMENT_ */
-               uint32_t _rsvd1:4;
-               uint32_t length:16;     /* of segment in pages */
-       } r;
-} __packed;
-
-/*
- * Module segment descriptor. Used by ROM - Immutable.
- */
-struct sof_man_segment_desc {
-       union sof_man_segment_flags flags;
-       uint32_t v_base_addr;
-       uint32_t file_offset;
-} __packed;
-
-/*
- * The firmware binary can be split into several modules.
- */
-
-#define SOF_MAN_MOD_ID_LEN             4
-#define SOF_MAN_MOD_NAME_LEN           8
-#define SOF_MAN_MOD_SHA256_LEN         32
-#define SOF_MAN_MOD_ID                 {'$', 'A', 'M', 'E'}
-
-/*
- * Each module has an entry in the FW header. Used by ROM - Immutable.
- */
-struct sof_man_module {
-       uint8_t struct_id[SOF_MAN_MOD_ID_LEN];  /* SOF_MAN_MOD_ID */
-       uint8_t name[SOF_MAN_MOD_NAME_LEN];
-       uint8_t uuid[16];
-       struct sof_man_module_type type;
-       uint8_t hash[SOF_MAN_MOD_SHA256_LEN];
-       uint32_t entry_point;
-       uint16_t cfg_offset;
-       uint16_t cfg_count;
-       uint32_t affinity_mask;
-       uint16_t instance_max_count;    /* max number of instances */
-       uint16_t instance_bss_size;     /* instance (pages) */
-       struct sof_man_segment_desc segment[3];
-} __packed;
-
-/*
- * Each module has a configuration in the FW header. Used by ROM - Immutable.
- */
-struct sof_man_mod_config {
-       uint32_t par[4];        /* module parameters */
-       uint32_t is_pages;      /* actual size of instance .bss (pages) */
-       uint32_t cps;           /* cycles per second */
-       uint32_t ibs;           /* input buffer size (bytes) */
-       uint32_t obs;           /* output buffer size (bytes) */
-       uint32_t module_flags;  /* flags, reserved for future use */
-       uint32_t cpc;           /* cycles per single run */
-       uint32_t obls;          /* output block size, reserved for future use */
-} __packed;
-
-/*
- * FW Manifest Header
- */
-
-#define SOF_MAN_FW_HDR_FW_NAME_LEN     8
-#define SOF_MAN_FW_HDR_ID              {'$', 'A', 'M', '1'}
-#define SOF_MAN_FW_HDR_NAME            "ADSPFW"
-#define SOF_MAN_FW_HDR_FLAGS           0x0
-#define SOF_MAN_FW_HDR_FEATURES                0xff
-
-/*
- * The firmware has a standard header that is checked by the ROM on firmware
- * loading. preload_page_count is used by DMA code loader and is entire
- * image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata
- * Used by ROM - Immutable.
- */
-struct sof_man_fw_header {
-       uint8_t header_id[4];
-       uint32_t header_len;
-       uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN];
-       /* number of pages of preloaded image loaded by driver */
-       uint32_t preload_page_count;
-       uint32_t fw_image_flags;
-       uint32_t feature_mask;
-       uint16_t major_version;
-       uint16_t minor_version;
-       uint16_t hotfix_version;
-       uint16_t build_version;
-       uint32_t num_module_entries;
-       uint32_t hw_buf_base_addr;
-       uint32_t hw_buf_length;
-       /* target address for binary loading as offset in IMR - must be == base offset */
-       uint32_t load_offset;
-} __packed;
-
-/*
- * Firmware manifest descriptor. This can contain N modules and N module
- * configs. Used by ROM - Immutable.
- */
-struct sof_man_fw_desc {
-       struct sof_man_fw_header header;
-
-       /* Warning - hack for module arrays. For some unknown reason the we
-        * have a variable size array of struct man_module followed by a
-        * variable size array of struct mod_config. These should have been
-        * merged into a variable array of a parent structure. We have to hack
-        * around this in many places....
-        *
-        * struct sof_man_module man_module[];
-        * struct sof_man_mod_config mod_config[];
-        */
-
-} __packed;
-
-/*
- * Component Descriptor. Used by ROM - Immutable.
- */
-struct sof_man_component_desc {
-       uint32_t reserved[2];   /* all 0 */
-       uint32_t version;
-       uint8_t hash[SOF_MAN_MOD_SHA256_LEN];
-       uint32_t base_offset;
-       uint32_t limit_offset;
-       uint32_t attributes[4];
-} __packed;
-
-/*
- * Audio DSP extended metadata. Used by ROM - Immutable.
- */
-struct sof_man_adsp_meta_file_ext {
-       uint32_t ext_type;      /* always 17 for ADSP extension */
-       uint32_t ext_len;
-       uint32_t imr_type;
-       uint8_t reserved[16];   /* all 0 */
-       struct sof_man_component_desc comp_desc[1];
-} __packed;
-
-/*
- * Module Manifest for rimage module metadata. Not used by ROM.
- */
-struct sof_man_module_manifest {
-       struct sof_man_module module;
-       uint32_t text_size;
-} __packed;
-
-#endif
diff --git a/include/uapi/sound/sof/tone.h b/include/uapi/sound/sof/tone.h
deleted file mode 100644 (file)
index d7c6e5d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) 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) 2018 Intel Corporation. All rights reserved.
-*/
-
-#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__
-#define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__
-
-#define SOF_TONE_IDX_FREQUENCY         0
-#define SOF_TONE_IDX_AMPLITUDE         1
-#define SOF_TONE_IDX_FREQ_MULT         2
-#define SOF_TONE_IDX_AMPL_MULT         3
-#define SOF_TONE_IDX_LENGTH            4
-#define SOF_TONE_IDX_PERIOD            5
-#define SOF_TONE_IDX_REPEATS           6
-#define SOF_TONE_IDX_LIN_RAMP_STEP     7
-
-#endif
diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h
deleted file mode 100644 (file)
index ffa7288..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) 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) 2018 Intel Corporation. All rights reserved.
- */
-
-#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__
-#define __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__
-
-/*
- * Host system time.
- *
- * This property is used by the driver to pass down information about
- * current system time. It is expressed in us.
- * FW translates timestamps (in log entries, probe pockets) to this time
- * domain.
- *
- * (cavs: SystemTime).
- */
-struct system_time {
-       uint32_t val_l;  /* Lower dword of current host time value */
-       uint32_t val_u;  /* Upper dword of current host time value */
-} __packed;
-
-#define LOG_ENABLE             1  /* Enable logging */
-#define LOG_DISABLE            0  /* Disable logging */
-
-#define LOG_LEVEL_CRITICAL     1  /* (FDK fatal) */
-#define LOG_LEVEL_VERBOSE      2
-
-/*
- * Layout of a log fifo.
- */
-struct log_buffer_layout {
-       uint32_t read_ptr;  /*read pointer */
-       uint32_t write_ptr; /* write pointer */
-       uint32_t buffer[0]; /* buffer */
-} __packed;
-
-/*
- * Log buffer status reported by FW.
- */
-struct log_buffer_status {
-       uint32_t core_id;  /* ID of core that logged to other half */
-} __packed;
-
-#define TRACE_ID_LENGTH 12
-
-/*
- *  Log entry header.
- *
- * The header is followed by an array of arguments (uint32_t[]).
- * Number of arguments is specified by the params_num field of log_entry
- */
-struct log_entry_header {
-       uint32_t id_0 : TRACE_ID_LENGTH;        /* e.g. Pipeline ID */
-       uint32_t id_1 : TRACE_ID_LENGTH;        /* e.g. Component ID */
-       uint32_t core_id : 8;           /* Reporting core's id */
-
-       uint64_t timestamp;             /* Timestamp (in dsp ticks) */
-       uint32_t log_entry_address;     /* Address of log entry in ELF */
-} __packed;
-
-#endif
index 9775bda2a4ca3e6c380959ef5c7acbf33bb97694..a4ade6bb5bebea57f499f3d113eff5eec14ada1d 100644 (file)
@@ -32,6 +32,7 @@ struct i2s_stream_instance {
        u16 channels;
        u32 xfer_resolution;
        struct page *pg;
+       u64 bytescount;
        void __iomem *acp3x_base;
 };
 
@@ -317,6 +318,24 @@ static int acp3x_dma_open(struct snd_pcm_substream *substream)
        return 0;
 }
 
+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_pcm_substream *substream,
                               struct snd_pcm_hw_params *params)
 {
@@ -350,18 +369,17 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
 static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
 {
        u32 pos = 0;
-       struct i2s_stream_instance *rtd = substream->runtime->private_data;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               pos = rv_readl(rtd->acp3x_base +
-                              mmACP_BT_TX_LINKPOSITIONCNTR);
-       else
-               pos = rv_readl(rtd->acp3x_base +
-                              mmACP_BT_RX_LINKPOSITIONCNTR);
-
-       if (pos >= MAX_BUFFER)
-               pos = 0;
-
+       u32 buffersize = 0;
+       u64 bytescount = 0;
+       struct i2s_stream_instance *rtd =
+               substream->runtime->private_data;
+
+       buffersize = frames_to_bytes(substream->runtime,
+                                    substream->runtime->buffer_size);
+       bytescount = acp_get_byte_count(rtd, substream->stream);
+       if (bytescount > rtd->bytescount)
+               bytescount -= rtd->bytescount;
+       pos = do_div(bytescount, buffersize);
        return bytes_to_frames(substream->runtime, pos);
 }
 
@@ -521,6 +539,7 @@ static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
        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);
index ebb9e0cf83647b80fae1b9949fcd04e556ba9eed..3e8dbf63adbe42484c9db2898197601a5decc7f6 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <sound/pcm_params.h>
@@ -45,6 +46,7 @@ struct cs42xx8_priv {
        bool slave_mode;
        unsigned long sysclk;
        u32 tx_channels;
+       struct gpio_desc *gpiod_reset;
 };
 
 /* -127.5dB to 0dB with step of 0.5dB */
@@ -467,6 +469,13 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
                return -EINVAL;
        }
 
+       cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
+                                                       GPIOD_OUT_HIGH);
+       if (IS_ERR(cs42xx8->gpiod_reset))
+               return PTR_ERR(cs42xx8->gpiod_reset);
+
+       gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
+
        cs42xx8->clk = devm_clk_get(dev, "mclk");
        if (IS_ERR(cs42xx8->clk)) {
                dev_err(dev, "failed to get the clock: %ld\n",
@@ -547,6 +556,8 @@ static int cs42xx8_runtime_resume(struct device *dev)
                return ret;
        }
 
+       gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
+
        ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
                                    cs42xx8->supplies);
        if (ret) {
@@ -585,6 +596,8 @@ static int cs42xx8_runtime_suspend(struct device *dev)
        regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
                               cs42xx8->supplies);
 
+       gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);
+
        clk_disable_unprepare(cs42xx8->clk);
 
        return 0;
index 39caf19abb0bcd49e3cf5bc652e00712e688a292..6a0cc8d7e1412b7ed183f13161545d187b978bfc 100644 (file)
@@ -278,13 +278,10 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
 
 struct hdmi_codec_priv {
        struct hdmi_codec_pdata hcd;
-       struct snd_soc_dai_driver *daidrv;
-       struct hdmi_codec_daifmt daifmt[2];
-       struct mutex current_stream_lock;
-       struct snd_pcm_substream *current_stream;
        uint8_t eld[MAX_ELD_BYTES];
        struct snd_pcm_chmap *chmap_info;
        unsigned int chmap_idx;
+       struct mutex lock;
 };
 
 static const struct snd_soc_dapm_widget hdmi_widgets[] = {
@@ -392,44 +389,22 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int hdmi_codec_new_stream(struct snd_pcm_substream *substream,
-                                struct snd_soc_dai *dai)
-{
-       struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
-       int ret = 0;
-
-       mutex_lock(&hcp->current_stream_lock);
-       if (!hcp->current_stream) {
-               hcp->current_stream = substream;
-       } else if (hcp->current_stream != substream) {
-               dev_err(dai->dev, "Only one simultaneous stream supported!\n");
-               ret = -EINVAL;
-       }
-       mutex_unlock(&hcp->current_stream_lock);
-
-       return ret;
-}
-
 static int hdmi_codec_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
        struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
        int ret = 0;
 
-       dev_dbg(dai->dev, "%s()\n", __func__);
-
-       ret = hdmi_codec_new_stream(substream, dai);
-       if (ret)
-               return ret;
+       ret = mutex_trylock(&hcp->lock);
+       if (!ret) {
+               dev_err(dai->dev, "Only one simultaneous stream supported!\n");
+               return -EINVAL;
+       }
 
        if (hcp->hcd.ops->audio_startup) {
                ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data);
-               if (ret) {
-                       mutex_lock(&hcp->current_stream_lock);
-                       hcp->current_stream = NULL;
-                       mutex_unlock(&hcp->current_stream_lock);
-                       return ret;
-               }
+               if (ret)
+                       goto err;
        }
 
        if (hcp->hcd.ops->get_eld) {
@@ -439,17 +414,18 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
                if (!ret) {
                        ret = snd_pcm_hw_constraint_eld(substream->runtime,
                                                        hcp->eld);
-                       if (ret) {
-                               mutex_lock(&hcp->current_stream_lock);
-                               hcp->current_stream = NULL;
-                               mutex_unlock(&hcp->current_stream_lock);
-                               return ret;
-                       }
+                       if (ret)
+                               goto err;
                }
                /* Select chmap supported */
                hdmi_codec_eld_chmap(hcp);
        }
        return 0;
+
+err:
+       /* Release the exclusive lock on error */
+       mutex_unlock(&hcp->lock);
+       return ret;
 }
 
 static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
@@ -457,16 +433,10 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
 {
        struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
 
-       dev_dbg(dai->dev, "%s()\n", __func__);
-
-       WARN_ON(hcp->current_stream != substream);
-
        hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
        hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
 
-       mutex_lock(&hcp->current_stream_lock);
-       hcp->current_stream = NULL;
-       mutex_unlock(&hcp->current_stream_lock);
+       mutex_unlock(&hcp->lock);
 }
 
 static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
@@ -474,6 +444,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+       struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
        struct hdmi_codec_params hp = {
                .iec = {
                        .status = { 0 },
@@ -518,30 +489,27 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
        hp.channels = params_channels(params);
 
        return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data,
-                                      &hcp->daifmt[dai->id], &hp);
+                                      cf, &hp);
 }
 
-static int hdmi_codec_set_fmt(struct snd_soc_dai *dai,
-                             unsigned int fmt)
+static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai,
+                                 unsigned int fmt)
 {
-       struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
-       struct hdmi_codec_daifmt cf = { 0 };
+       struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
 
-       dev_dbg(dai->dev, "%s()\n", __func__);
-
-       if (dai->id == DAI_ID_SPDIF)
-               return 0;
+       /* Reset daifmt */
+       memset(cf, 0, sizeof(*cf));
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               cf.bit_clk_master = 1;
-               cf.frame_clk_master = 1;
+               cf->bit_clk_master = 1;
+               cf->frame_clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBS_CFM:
-               cf.frame_clk_master = 1;
+               cf->frame_clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
-               cf.bit_clk_master = 1;
+               cf->bit_clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
@@ -553,43 +521,41 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai,
        case SND_SOC_DAIFMT_NB_NF:
                break;
        case SND_SOC_DAIFMT_NB_IF:
-               cf.frame_clk_inv = 1;
+               cf->frame_clk_inv = 1;
                break;
        case SND_SOC_DAIFMT_IB_NF:
-               cf.bit_clk_inv = 1;
+               cf->bit_clk_inv = 1;
                break;
        case SND_SOC_DAIFMT_IB_IF:
-               cf.frame_clk_inv = 1;
-               cf.bit_clk_inv = 1;
+               cf->frame_clk_inv = 1;
+               cf->bit_clk_inv = 1;
                break;
        }
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               cf.fmt = HDMI_I2S;
+               cf->fmt = HDMI_I2S;
                break;
        case SND_SOC_DAIFMT_DSP_A:
-               cf.fmt = HDMI_DSP_A;
+               cf->fmt = HDMI_DSP_A;
                break;
        case SND_SOC_DAIFMT_DSP_B:
-               cf.fmt = HDMI_DSP_B;
+               cf->fmt = HDMI_DSP_B;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               cf.fmt = HDMI_RIGHT_J;
+               cf->fmt = HDMI_RIGHT_J;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               cf.fmt = HDMI_LEFT_J;
+               cf->fmt = HDMI_LEFT_J;
                break;
        case SND_SOC_DAIFMT_AC97:
-               cf.fmt = HDMI_AC97;
+               cf->fmt = HDMI_AC97;
                break;
        default:
                dev_err(dai->dev, "Invalid DAI interface format\n");
                return -EINVAL;
        }
 
-       hcp->daifmt[dai->id] = cf;
-
        return 0;
 }
 
@@ -597,8 +563,6 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute)
 {
        struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
 
-       dev_dbg(dai->dev, "%s()\n", __func__);
-
        if (hcp->hcd.ops->digital_mute)
                return hcp->hcd.ops->digital_mute(dai->dev->parent,
                                                  hcp->hcd.data, mute);
@@ -606,14 +570,20 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute)
        return 0;
 }
 
-static const struct snd_soc_dai_ops hdmi_dai_ops = {
+static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
        .startup        = hdmi_codec_startup,
        .shutdown       = hdmi_codec_shutdown,
        .hw_params      = hdmi_codec_hw_params,
-       .set_fmt        = hdmi_codec_set_fmt,
+       .set_fmt        = hdmi_codec_i2s_set_fmt,
        .digital_mute   = hdmi_codec_digital_mute,
 };
 
+static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
+       .startup        = hdmi_codec_startup,
+       .shutdown       = hdmi_codec_shutdown,
+       .hw_params      = hdmi_codec_hw_params,
+       .digital_mute   = hdmi_codec_digital_mute,
+};
 
 #define HDMI_RATES     (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
                         SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
@@ -656,8 +626,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
        };
        int ret;
 
-       dev_dbg(dai->dev, "%s()\n", __func__);
-
        ret =  snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                      NULL, drv->playback.channels_max, 0,
                                      &hcp->chmap_info);
@@ -683,20 +651,52 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
 static int hdmi_dai_probe(struct snd_soc_dai *dai)
 {
        struct snd_soc_dapm_context *dapm;
+       struct hdmi_codec_daifmt *daifmt;
        struct snd_soc_dapm_route route = {
                .sink = "TX",
                .source = dai->driver->playback.stream_name,
        };
+       int ret;
 
        dapm = snd_soc_component_get_dapm(dai->component);
+       ret = snd_soc_dapm_add_routes(dapm, &route, 1);
+       if (ret)
+               return ret;
+
+       daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL);
+       if (!daifmt)
+               return -ENOMEM;
+
+       dai->playback_dma_data = daifmt;
+       return 0;
+}
+
+static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
+{
+       struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
+       int ret;
+
+       ret = hdmi_dai_probe(dai);
+       if (ret)
+               return ret;
+
+       cf = dai->playback_dma_data;
+       cf->fmt = HDMI_SPDIF;
+
+       return 0;
+}
 
-       return snd_soc_dapm_add_routes(dapm, &route, 1);
+static int hdmi_codec_dai_remove(struct snd_soc_dai *dai)
+{
+       kfree(dai->playback_dma_data);
+       return 0;
 }
 
 static const struct snd_soc_dai_driver hdmi_i2s_dai = {
        .name = "i2s-hifi",
        .id = DAI_ID_I2S,
        .probe = hdmi_dai_probe,
+       .remove = hdmi_codec_dai_remove,
        .playback = {
                .stream_name = "I2S Playback",
                .channels_min = 2,
@@ -705,14 +705,15 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
                .formats = I2S_FORMATS,
                .sig_bits = 24,
        },
-       .ops = &hdmi_dai_ops,
+       .ops = &hdmi_codec_i2s_dai_ops,
        .pcm_new = hdmi_codec_pcm_new,
 };
 
 static const struct snd_soc_dai_driver hdmi_spdif_dai = {
        .name = "spdif-hifi",
        .id = DAI_ID_SPDIF,
-       .probe = hdmi_dai_probe,
+       .probe = hdmi_dai_spdif_probe,
+       .remove = hdmi_codec_dai_remove,
        .playback = {
                .stream_name = "SPDIF Playback",
                .channels_min = 2,
@@ -720,7 +721,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
                .rates = HDMI_RATES,
                .formats = SPDIF_FORMATS,
        },
-       .ops = &hdmi_dai_ops,
+       .ops = &hdmi_codec_spdif_dai_ops,
        .pcm_new = hdmi_codec_pcm_new,
 };
 
@@ -749,13 +750,12 @@ static const struct snd_soc_component_driver hdmi_driver = {
 static int hdmi_codec_probe(struct platform_device *pdev)
 {
        struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
+       struct snd_soc_dai_driver *daidrv;
        struct device *dev = &pdev->dev;
        struct hdmi_codec_priv *hcp;
        int dai_count, i = 0;
        int ret;
 
-       dev_dbg(dev, "%s()\n", __func__);
-
        if (!hcd) {
                dev_err(dev, "%s: No platform data\n", __func__);
                return -EINVAL;
@@ -773,29 +773,25 @@ static int hdmi_codec_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        hcp->hcd = *hcd;
-       mutex_init(&hcp->current_stream_lock);
+       mutex_init(&hcp->lock);
 
-       hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv),
-                                  GFP_KERNEL);
-       if (!hcp->daidrv)
+       daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL);
+       if (!daidrv)
                return -ENOMEM;
 
        if (hcd->i2s) {
-               hcp->daidrv[i] = hdmi_i2s_dai;
-               hcp->daidrv[i].playback.channels_max =
-                       hcd->max_i2s_channels;
+               daidrv[i] = hdmi_i2s_dai;
+               daidrv[i].playback.channels_max = hcd->max_i2s_channels;
                i++;
        }
 
-       if (hcd->spdif) {
-               hcp->daidrv[i] = hdmi_spdif_dai;
-               hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF;
-       }
+       if (hcd->spdif)
+               daidrv[i] = hdmi_spdif_dai;
 
        dev_set_drvdata(dev, hcp);
 
-       ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv,
-                                    dai_count);
+       ret = devm_snd_soc_register_component(dev, &hdmi_driver, daidrv,
+                                             dai_count);
        if (ret) {
                dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n",
                        __func__, ret);
index d037a3e4d3232bee2ad3dd6100f693e8975adee6..80080a6415b3c86f511cfaf5c34dfc14ddea8cab 100644 (file)
@@ -59,21 +59,7 @@ static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
        {"Speaker", NULL, "HiFi Playback"},
 };
 
-static int max98357a_component_probe(struct snd_soc_component *component)
-{
-       struct gpio_desc *sdmode;
-
-       sdmode = devm_gpiod_get_optional(component->dev, "sdmode", GPIOD_OUT_LOW);
-       if (IS_ERR(sdmode))
-               return PTR_ERR(sdmode);
-
-       snd_soc_component_set_drvdata(component, sdmode);
-
-       return 0;
-}
-
 static const struct snd_soc_component_driver max98357a_component_driver = {
-       .probe                  = max98357a_component_probe,
        .dapm_widgets           = max98357a_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(max98357a_dapm_widgets),
        .dapm_routes            = max98357a_dapm_routes,
@@ -112,16 +98,20 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
 
 static int max98357a_platform_probe(struct platform_device *pdev)
 {
+       struct gpio_desc *sdmode;
+
+       sdmode = devm_gpiod_get_optional(&pdev->dev,
+                               "sdmode", GPIOD_OUT_LOW);
+       if (IS_ERR(sdmode))
+               return PTR_ERR(sdmode);
+
+       dev_set_drvdata(&pdev->dev, sdmode);
+
        return devm_snd_soc_register_component(&pdev->dev,
                        &max98357a_component_driver,
                        &max98357a_dai_driver, 1);
 }
 
-static int max98357a_platform_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id max98357a_device_id[] = {
        { .compatible = "maxim,max98357a" },
@@ -145,7 +135,6 @@ static struct platform_driver max98357a_platform_driver = {
                .acpi_match_table = ACPI_PTR(max98357a_acpi_match),
        },
        .probe  = max98357a_platform_probe,
-       .remove = max98357a_platform_remove,
 };
 module_platform_driver(max98357a_platform_driver);
 
index 84b6bd8b50e18a8dfeee74b16820b34aacbb0829..871ccb37318daeebc7a9b5e1a925e75595bc124c 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "rt5677-spi.h"
 
+#define DRV_NAME "rt5677spi"
+
 #define RT5677_SPI_BURST_LEN   240
 #define RT5677_SPI_HEADER      5
 #define RT5677_SPI_FREQ                6000000
@@ -232,7 +234,7 @@ MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id);
 
 static struct spi_driver rt5677_spi_driver = {
        .driver = {
-               .name = "rt5677",
+               .name = DRV_NAME,
                .acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id),
        },
        .probe = rt5677_spi_probe,
index 6fc70e441458de27128e0ac36fcbd11790e8d8b8..c49b5c218666638b7cf1f5975b31959d60a5efb4 100644 (file)
@@ -832,13 +832,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 
        /* DAC Digital Volume */
        SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL,
-               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv),
        SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL,
-               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv),
        SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL,
-               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv),
        SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL,
-               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+               RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv),
 
        /* IN1/IN2 Control */
        SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv),
@@ -4650,7 +4650,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
 }
 
 static const struct gpio_chip rt5677_template_chip = {
-       .label                  = "rt5677",
+       .label                  = RT5677_DRV_NAME,
        .owner                  = THIS_MODULE,
        .direction_output       = rt5677_gpio_direction_out,
        .set                    = rt5677_gpio_set,
@@ -4958,6 +4958,7 @@ static struct snd_soc_dai_driver rt5677_dai[] = {
 };
 
 static const struct snd_soc_component_driver soc_component_dev_rt5677 = {
+       .name                   = RT5677_DRV_NAME,
        .probe                  = rt5677_probe,
        .remove                 = rt5677_remove,
        .suspend                = rt5677_suspend,
@@ -5079,7 +5080,7 @@ static struct regmap_irq rt5677_irqs[] = {
 };
 
 static struct regmap_irq_chip rt5677_irq_chip = {
-       .name = "rt5677",
+       .name = RT5677_DRV_NAME,
        .irqs = rt5677_irqs,
        .num_irqs = ARRAY_SIZE(rt5677_irqs),
 
@@ -5267,7 +5268,7 @@ static int rt5677_i2c_remove(struct i2c_client *i2c)
 
 static struct i2c_driver rt5677_i2c_driver = {
        .driver = {
-               .name = "rt5677",
+               .name = RT5677_DRV_NAME,
                .of_match_table = rt5677_of_match,
                .acpi_match_table = ACPI_PTR(rt5677_acpi_match),
        },
index 183d92b030459f3323112b137b86fee74dffe741..11a2ffceec3b6d7aea52e0d4db466d3ca7237a15 100644 (file)
 #define RT5677_FIRMWARE1       "rt5677_dsp_fw1.bin"
 #define RT5677_FIRMWARE2       "rt5677_dsp_fw2.bin"
 
+#define RT5677_DRV_NAME                "rt5677"
+
 /* System Clock Source */
 enum {
        RT5677_SCLK_S_MCLK,
index 516d17cb2182287f8f739a072fe3128687cecd93..599e4ed3850b44d76381599fe7a6fb528c0b40e5 100644 (file)
@@ -324,6 +324,9 @@ static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0);
  */
 static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
 
+/* Output volumes. From 0 to 9 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(out_tlv, 0, 100, 0);
+
 static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        /* Output */
        SOC_DOUBLE_R_TLV("PCM Playback Volume",
@@ -386,11 +389,17 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                         DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
 
-       /* Output pin mute controls */
+       /* Output pin controls */
+       SOC_DOUBLE_R_TLV("Line Playback Volume", LLOPM_CTRL, RLOPM_CTRL, 4,
+                        9, 0, out_tlv),
        SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
                     0x01, 0),
+       SOC_DOUBLE_R_TLV("HP Playback Volume", HPLOUT_CTRL, HPROUT_CTRL, 4,
+                        9, 0, out_tlv),
        SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
                     0x01, 0),
+       SOC_DOUBLE_R_TLV("HPCOM Playback Volume", HPLCOM_CTRL, HPRCOM_CTRL,
+                        4, 9, 0, out_tlv),
        SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
                     0x01, 0),
 
@@ -472,6 +481,9 @@ static const struct snd_kcontrol_new aic3x_mono_controls[] = {
                         0, 118, 1, output_stage_tlv),
 
        SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+       SOC_SINGLE_TLV("Mono Playback Volume", MONOLOPM_CTRL, 4, 9, 0,
+                       out_tlv),
+
 };
 
 /*
index 0b937924d2e47961d697d068edf3944772058baa..71793d3dc75ca58bf3ec7d96ee19bbd9b072b3d4 100644 (file)
 #define pair_dbg(fmt, ...) \
        dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
 
-/* Sample rates are aligned with that defined in pcm.h file */
-static const u8 process_option[][12][2] = {
-       /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz   64kHz   88.2kHz 96kHz   176kHz  192kHz */
-       {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 5512Hz */
-       {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 8kHz */
-       {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 11025Hz */
-       {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 16kHz */
-       {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},      /* 22050Hz */
-       {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},},      /* 32kHz */
-       {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},      /* 44.1kHz */
-       {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},      /* 48kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},},      /* 64kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},      /* 88.2kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},      /* 96kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},      /* 176kHz */
-       {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},      /* 192kHz */
-};
-
 /* Corresponding to process_option */
 static int supported_input_rate[] = {
        5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200,
@@ -79,6 +61,52 @@ static unsigned char output_clk_map_imx53[] = {
 
 static unsigned char *clk_map[2];
 
+/**
+ * Select the pre-processing and post-processing options
+ * Make sure to exclude following unsupported cases before
+ * calling this function:
+ * 1) inrate > 8.125 * outrate
+ * 2) inrate > 16.125 * outrate
+ *
+ * inrate: input sample rate
+ * outrate: output sample rate
+ * pre_proc: return value for pre-processing option
+ * post_proc: return value for post-processing option
+ */
+static void fsl_asrc_sel_proc(int inrate, int outrate,
+                            int *pre_proc, int *post_proc)
+{
+       bool post_proc_cond2;
+       bool post_proc_cond0;
+
+       /* select pre_proc between [0, 2] */
+       if (inrate * 8 > 33 * outrate)
+               *pre_proc = 2;
+       else if (inrate * 8 > 15 * outrate) {
+               if (inrate > 152000)
+                       *pre_proc = 2;
+               else
+                       *pre_proc = 1;
+       } else if (inrate < 76000)
+               *pre_proc = 0;
+       else if (inrate > 152000)
+               *pre_proc = 2;
+       else
+               *pre_proc = 1;
+
+       /* Condition for selection of post-processing */
+       post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) ||
+                         (inrate > 56000 && outrate < 56000);
+       post_proc_cond0 = inrate * 23 < outrate * 8;
+
+       if (post_proc_cond2)
+               *post_proc = 2;
+       else if (post_proc_cond0)
+               *post_proc = 0;
+       else
+               *post_proc = 1;
+}
+
 /**
  * Request ASRC pair
  *
@@ -239,6 +267,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
        u32 inrate, outrate, indiv, outdiv;
        u32 clk_index[2], div[2];
        int in, out, channels;
+       int pre_proc, post_proc;
        struct clk *clk;
        bool ideal;
 
@@ -377,11 +406,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
                           ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index),
                           ASRCTR_IDR(index) | ASRCTR_USR(index));
 
+       fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc);
+
        /* Apply configurations for pre- and post-processing */
        regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
                           ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index),
-                          ASRCFG_PREMOD(index, process_option[in][out][0]) |
-                          ASRCFG_POSTMOD(index, process_option[in][out][1]));
+                          ASRCFG_PREMOD(index, pre_proc) |
+                          ASRCFG_POSTMOD(index, post_proc));
 
        return fsl_asrc_set_ideal_ratio(pair, inrate, outrate);
 }
index bad0dfed6b68fca896473e1f09a5913b3aef3630..10d2210c91effd5ee384c36fa08286d94aaf6450 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm_params.h>
 
@@ -466,30 +467,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
-       int ret;
-
-       /*
-        * Some platforms might use the same bit to gate all three or two of
-        * clocks, so keep all clocks open/close at the same time for safety
-        */
-       ret = clk_prepare_enable(esai_priv->coreclk);
-       if (ret)
-               return ret;
-       if (!IS_ERR(esai_priv->spbaclk)) {
-               ret = clk_prepare_enable(esai_priv->spbaclk);
-               if (ret)
-                       goto err_spbaclk;
-       }
-       if (!IS_ERR(esai_priv->extalclk)) {
-               ret = clk_prepare_enable(esai_priv->extalclk);
-               if (ret)
-                       goto err_extalck;
-       }
-       if (!IS_ERR(esai_priv->fsysclk)) {
-               ret = clk_prepare_enable(esai_priv->fsysclk);
-               if (ret)
-                       goto err_fsysclk;
-       }
 
        if (!dai->active) {
                /* Set synchronous mode */
@@ -506,16 +483,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
 
        return 0;
 
-err_fsysclk:
-       if (!IS_ERR(esai_priv->extalclk))
-               clk_disable_unprepare(esai_priv->extalclk);
-err_extalck:
-       if (!IS_ERR(esai_priv->spbaclk))
-               clk_disable_unprepare(esai_priv->spbaclk);
-err_spbaclk:
-       clk_disable_unprepare(esai_priv->coreclk);
-
-       return ret;
 }
 
 static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
@@ -576,20 +543,6 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
-                             struct snd_soc_dai *dai)
-{
-       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
-
-       if (!IS_ERR(esai_priv->fsysclk))
-               clk_disable_unprepare(esai_priv->fsysclk);
-       if (!IS_ERR(esai_priv->extalclk))
-               clk_disable_unprepare(esai_priv->extalclk);
-       if (!IS_ERR(esai_priv->spbaclk))
-               clk_disable_unprepare(esai_priv->spbaclk);
-       clk_disable_unprepare(esai_priv->coreclk);
-}
-
 static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
                            struct snd_soc_dai *dai)
 {
@@ -658,7 +611,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
        .startup = fsl_esai_startup,
-       .shutdown = fsl_esai_shutdown,
        .trigger = fsl_esai_trigger,
        .hw_params = fsl_esai_hw_params,
        .set_sysclk = fsl_esai_set_dai_sysclk,
@@ -947,6 +899,10 @@ static int fsl_esai_probe(struct platform_device *pdev)
                return ret;
        }
 
+       pm_runtime_enable(&pdev->dev);
+
+       regcache_cache_only(esai_priv->regmap, true);
+
        ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE);
        if (ret)
                dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
@@ -954,6 +910,13 @@ static int fsl_esai_probe(struct platform_device *pdev)
        return ret;
 }
 
+static int fsl_esai_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
 static const struct of_device_id fsl_esai_dt_ids[] = {
        { .compatible = "fsl,imx35-esai", },
        { .compatible = "fsl,vf610-esai", },
@@ -961,22 +924,35 @@ static const struct of_device_id fsl_esai_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
 
-#ifdef CONFIG_PM_SLEEP
-static int fsl_esai_suspend(struct device *dev)
-{
-       struct fsl_esai *esai = dev_get_drvdata(dev);
-
-       regcache_cache_only(esai->regmap, true);
-       regcache_mark_dirty(esai->regmap);
-
-       return 0;
-}
-
-static int fsl_esai_resume(struct device *dev)
+#ifdef CONFIG_PM
+static int fsl_esai_runtime_resume(struct device *dev)
 {
        struct fsl_esai *esai = dev_get_drvdata(dev);
        int ret;
 
+       /*
+        * Some platforms might use the same bit to gate all three or two of
+        * clocks, so keep all clocks open/close at the same time for safety
+        */
+       ret = clk_prepare_enable(esai->coreclk);
+       if (ret)
+               return ret;
+       if (!IS_ERR(esai->spbaclk)) {
+               ret = clk_prepare_enable(esai->spbaclk);
+               if (ret)
+                       goto err_spbaclk;
+       }
+       if (!IS_ERR(esai->extalclk)) {
+               ret = clk_prepare_enable(esai->extalclk);
+               if (ret)
+                       goto err_extalclk;
+       }
+       if (!IS_ERR(esai->fsysclk)) {
+               ret = clk_prepare_enable(esai->fsysclk);
+               if (ret)
+                       goto err_fsysclk;
+       }
+
        regcache_cache_only(esai->regmap, false);
 
        /* FIFO reset for safety */
@@ -987,22 +963,59 @@ static int fsl_esai_resume(struct device *dev)
 
        ret = regcache_sync(esai->regmap);
        if (ret)
-               return ret;
+               goto err_regcache_sync;
 
        /* FIFO reset done */
        regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);
        regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);
 
+       return 0;
+
+err_regcache_sync:
+       if (!IS_ERR(esai->fsysclk))
+               clk_disable_unprepare(esai->fsysclk);
+err_fsysclk:
+       if (!IS_ERR(esai->extalclk))
+               clk_disable_unprepare(esai->extalclk);
+err_extalclk:
+       if (!IS_ERR(esai->spbaclk))
+               clk_disable_unprepare(esai->spbaclk);
+err_spbaclk:
+       clk_disable_unprepare(esai->coreclk);
+
+       return ret;
+}
+
+static int fsl_esai_runtime_suspend(struct device *dev)
+{
+       struct fsl_esai *esai = dev_get_drvdata(dev);
+
+       regcache_cache_only(esai->regmap, true);
+       regcache_mark_dirty(esai->regmap);
+
+       if (!IS_ERR(esai->fsysclk))
+               clk_disable_unprepare(esai->fsysclk);
+       if (!IS_ERR(esai->extalclk))
+               clk_disable_unprepare(esai->extalclk);
+       if (!IS_ERR(esai->spbaclk))
+               clk_disable_unprepare(esai->spbaclk);
+       clk_disable_unprepare(esai->coreclk);
+
        return 0;
 }
-#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
 
 static const struct dev_pm_ops fsl_esai_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(fsl_esai_suspend, fsl_esai_resume)
+       SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend,
+                          fsl_esai_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver fsl_esai_driver = {
        .probe = fsl_esai_probe,
+       .remove = fsl_esai_remove,
        .driver = {
                .name = "fsl-esai-dai",
                .pm = &fsl_esai_pm_ops,
index 8593269156bddf58f8e737ca122627b1a124605b..d58cc3ae90d861522338a91f70a876707a187c92 100644 (file)
@@ -596,15 +596,8 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-       struct device *dev = &sai->pdev->dev;
        int ret;
 
-       ret = clk_prepare_enable(sai->bus_clk);
-       if (ret) {
-               dev_err(dev, "failed to enable bus clock: %d\n", ret);
-               return ret;
-       }
-
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
                           FSL_SAI_CR3_TRCE);
 
@@ -621,8 +614,6 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
-
-       clk_disable_unprepare(sai->bus_clk);
 }
 
 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -935,6 +926,14 @@ static int fsl_sai_runtime_suspend(struct device *dev)
 {
        struct fsl_sai *sai = dev_get_drvdata(dev);
 
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
+
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]);
+
+       clk_disable_unprepare(sai->bus_clk);
+
        regcache_cache_only(sai->regmap, true);
        regcache_mark_dirty(sai->regmap);
 
@@ -944,6 +943,25 @@ static int fsl_sai_runtime_suspend(struct device *dev)
 static int fsl_sai_runtime_resume(struct device *dev)
 {
        struct fsl_sai *sai = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(sai->bus_clk);
+       if (ret) {
+               dev_err(dev, "failed to enable bus clock: %d\n", ret);
+               return ret;
+       }
+
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) {
+               ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]);
+               if (ret)
+                       goto disable_bus_clk;
+       }
+
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) {
+               ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]);
+               if (ret)
+                       goto disable_tx_clk;
+       }
 
        regcache_cache_only(sai->regmap, false);
        regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
@@ -951,7 +969,23 @@ static int fsl_sai_runtime_resume(struct device *dev)
        usleep_range(1000, 2000);
        regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
        regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
-       return regcache_sync(sai->regmap);
+
+       ret = regcache_sync(sai->regmap);
+       if (ret)
+               goto disable_rx_clk;
+
+       return 0;
+
+disable_rx_clk:
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
+disable_tx_clk:
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]);
+disable_bus_clk:
+       clk_disable_unprepare(sai->bus_clk);
+
+       return ret;
 }
 #endif /* CONFIG_PM */
 
index fc1396adde714088fcc4be0e9ee18421e5e3ab03..b089ed3bf77f6848ef0b425bb0b61fa7f10c7ae0 100644 (file)
@@ -165,6 +165,22 @@ config SND_SOC_INTEL_CFL
          If you have a Intel CoffeeLake platform with the DSP
          enabled in the BIOS then enable this option by saying Y or m.
 
+config SND_SOC_INTEL_CML_H
+       tristate "CometLake-H Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel CometLake-H platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CML_LP
+       tristate "CometLake-LP Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel CometLake-LP platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
 config SND_SOC_INTEL_SKYLAKE_FAMILY
        tristate
        select SND_SOC_INTEL_SKYLAKE_COMMON
index f72a7bf028d725f80a8f24fed6bbd6ec23f3499f..1efe7fdad2cb4fe583b2f4b58b52c248fd3016f4 100644 (file)
@@ -219,8 +219,60 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int j, ret;
+
+       for (j = 0; j < rtd->num_codecs; j++) {
+               struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+               const char *name = codec_dai->component->name;
+               struct snd_soc_component *component = codec_dai->component;
+               struct snd_soc_dapm_context *dapm =
+                               snd_soc_component_get_dapm(component);
+               char pin_name[20];
+
+               if (strcmp(name, MAX98927_DEV0_NAME) &&
+                       strcmp(name, MAX98927_DEV1_NAME) &&
+                       strcmp(name, MAX98373_DEV0_NAME) &&
+                       strcmp(name, MAX98373_DEV1_NAME))
+                       continue;
+
+               snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
+                       codec_dai->component->name_prefix);
+
+               switch (cmd) {
+               case SNDRV_PCM_TRIGGER_START:
+               case SNDRV_PCM_TRIGGER_RESUME:
+               case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+                       ret = snd_soc_dapm_enable_pin(dapm, pin_name);
+                       if (ret) {
+                               dev_err(rtd->dev, "failed to enable %s: %d\n",
+                               pin_name, ret);
+                               return ret;
+                       }
+                       snd_soc_dapm_sync(dapm);
+                       break;
+               case SNDRV_PCM_TRIGGER_STOP:
+               case SNDRV_PCM_TRIGGER_SUSPEND:
+               case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+                       ret = snd_soc_dapm_disable_pin(dapm, pin_name);
+                       if (ret) {
+                               dev_err(rtd->dev, "failed to disable %s: %d\n",
+                               pin_name, ret);
+                               return ret;
+                       }
+                       snd_soc_dapm_sync(dapm);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 static struct snd_soc_ops kabylake_ssp0_ops = {
        .hw_params = kabylake_ssp0_hw_params,
+       .trigger = kabylake_ssp0_trigger,
 };
 
 static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -950,6 +1002,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
        struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
        struct kbl_hdmi_pcm *pcm;
+       struct snd_soc_dapm_context *dapm = &card->dapm;
        struct snd_soc_component *component = NULL;
        int err, i = 0;
        char jack_name[NAME_SIZE];
@@ -976,9 +1029,25 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
        if (!component)
                return -EINVAL;
 
-       return hdac_hdmi_jack_port_init(component, &card->dapm);
 
-       return 0;
+       err = hdac_hdmi_jack_port_init(component, &card->dapm);
+
+       if (err < 0)
+               return err;
+
+       err = snd_soc_dapm_disable_pin(dapm, "Left Spk");
+       if (err) {
+               dev_err(card->dev, "failed to disable Left Spk: %d\n", err);
+               return err;
+       }
+
+       err = snd_soc_dapm_disable_pin(dapm, "Right Spk");
+       if (err) {
+               dev_err(card->dev, "failed to disable Right Spk: %d\n", err);
+               return err;
+       }
+
+       return snd_soc_dapm_sync(dapm);
 }
 
 /* kabylake audio machine driver for SPT + DA7219 */
index 4bf70b4429f03075b07d877c67f6003d15d5336d..df01dc9525217110550a6dbcaa85541175552218 100644 (file)
@@ -255,6 +255,22 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .init_fw = cnl_sst_init_fw,
                .cleanup = cnl_sst_dsp_cleanup
        },
+       {
+               .id = 0x02c8,
+               .num_cores = 4,
+               .loader_ops = bxt_get_loader_ops,
+               .init = cnl_sst_dsp_init,
+               .init_fw = cnl_sst_init_fw,
+               .cleanup = cnl_sst_dsp_cleanup
+       },
+       {
+               .id = 0x06c8,
+               .num_cores = 4,
+               .loader_ops = bxt_get_loader_ops,
+               .init = cnl_sst_dsp_init,
+               .init_fw = cnl_sst_init_fw,
+               .cleanup = cnl_sst_dsp_cleanup
+       },
 };
 
 const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
index 4ed5b7e17d44aad3e09e6d6a8726ae3742bc92a1..f864f7b3df3a5064ee0a94d9025c067aa67a8412 100644 (file)
@@ -1166,6 +1166,16 @@ static const struct pci_device_id skl_ids[] = {
        /* CFL */
        { PCI_DEVICE(0x8086, 0xa348),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP)
+       /* CML-LP */
+       { PCI_DEVICE(0x8086, 0x02c8),
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H)
+       /* CML-H */
+       { PCI_DEVICE(0x8086, 0x06c8),
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
 #endif
        { 0, }
 };
index fded11d14cde28d981fa2ee04b6b423bca5eaf69..19048c3dc3244559daf1cf6a0591343b276019cb 100644 (file)
@@ -241,6 +241,7 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
        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 = 1;
 
        /* set hd mode */
        switch (substream->runtime->format) {
@@ -249,9 +250,11 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                hd_audio = 1;
+               hd_align = 1;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                hd_audio = 1;
+               hd_align = 0;
                break;
        default:
                dev_err(afe->dev, "%s() error: unsupported format %d\n",
@@ -262,6 +265,10 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
        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,
+                              memif->data->hd_align_mshift,
+                              hd_align ? memif->data->hd_align_mshift : 0);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
index bd8d5e0c68430dbe5d20d535e65b62bd374d8c95..60cb609a9790083e372a79210ca772bc4450069c 100644 (file)
@@ -24,7 +24,9 @@ struct mtk_base_memif_data {
        int enable_reg;
        int enable_shift;
        int hd_reg;
+       int hd_align_reg;
        int hd_shift;
+       int hd_align_mshift;
        int msb_reg;
        int msb_shift;
        int agent_disable_reg;
index 1bc0fafe5e2902a7b8964047c857e591226a3db4..ab2bce1d9b3d08fffed26a7a7d1dbd494007729b 100644 (file)
@@ -437,7 +437,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = DL1_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = DL1_HD_SFT,
+               .hd_align_mshift = DL1_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -456,7 +458,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = DL2_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = DL2_HD_SFT,
+               .hd_align_mshift = DL2_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -475,7 +479,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = DL3_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = DL3_HD_SFT,
+               .hd_align_mshift = DL3_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -494,7 +500,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = VUL2_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = VUL2_HD_SFT,
+               .hd_align_mshift = VUL2_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -513,7 +521,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = AWB_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = AWB_HD_SFT,
+               .hd_align_mshift = AWB_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -532,7 +542,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = AWB2_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = AWB2_HD_SFT,
+               .hd_align_mshift = AWB2_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -551,7 +563,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = VUL12_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = VUL12_HD_SFT,
+               .hd_align_mshift = VUL12_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -570,7 +584,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = AFE_DAC_CON0,
                .enable_shift = MOD_DAI_ON_SFT,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = MOD_DAI_HD_SFT,
+               .hd_align_mshift = MOD_DAI_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
@@ -589,7 +605,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
                .enable_reg = -1,       /* control in tdm for sync start */
                .enable_shift = -1,
                .hd_reg = AFE_MEMIF_HD_MODE,
+               .hd_align_reg = AFE_MEMIF_HDALIGN,
                .hd_shift = HDMI_HD_SFT,
+               .hd_align_mshift = HDMI_HD_ALIGN_MASK_SFT,
                .agent_disable_reg = -1,
                .agent_disable_shift = -1,
                .msb_reg = -1,
index 8779fe23671d6cd4cff7c416a66f52b9f58ff4da..4e5b4d4f353158268d27dd55240ca17d5f71a381 100644 (file)
@@ -56,6 +56,7 @@ config SND_MESON_AXG_SOUND_CARD
        imply SND_MESON_AXG_SPDIFOUT
        imply SND_MESON_AXG_SPDIFIN
        imply SND_MESON_AXG_PDM
+       imply SND_MESON_G12A_TOHDMITX if DRM_MESON_DW_HDMI
        help
          Select Y or M to add support for the AXG SoC sound card
 
@@ -82,4 +83,11 @@ config SND_MESON_AXG_PDM
        help
          Select Y or M to add support for PDM input embedded
          in the Amlogic AXG SoC family
+
+config SND_MESON_G12A_TOHDMITX
+       tristate "Amlogic G12A To HDMI TX Control Support"
+       imply SND_SOC_HDMI_CODEC
+       help
+         Select Y or M to add support for HDMI audio on the g12a SoC
+         family
 endmenu
index b45dfb9e2f88803e5698581f40f00403a574c84a..1a8b1470ed843e8b98ae7d6eaac4d9ce6e777398 100644 (file)
@@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o
 snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
 snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
 snd-soc-meson-axg-pdm-objs := axg-pdm.o
+snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
 
 obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
 obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
 obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o
 obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
 obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
+obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o
index aa54d2c612c98f4f58fc811973f8e46ada86a7d8..db0a7fc18928dbe183b06e0d97243939fa635bd0 100644 (file)
@@ -29,6 +29,18 @@ struct axg_dai_link_tdm_data {
        struct axg_dai_link_tdm_mask *codec_masks;
 };
 
+/*
+ * Base params for the codec to codec links
+ * Those will be over-written by the CPU side of the link
+ */
+static const struct snd_soc_pcm_stream codec_params = {
+       .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       .rate_min = 5525,
+       .rate_max = 192000,
+       .channels_min = 1,
+       .channels_max = 8,
+};
+
 #define PREFIX "amlogic,"
 
 static int axg_card_reallocate_links(struct axg_card *priv,
@@ -80,10 +92,11 @@ static int axg_card_parse_dai(struct snd_soc_card *card,
 
 static int axg_card_set_link_name(struct snd_soc_card *card,
                                  struct snd_soc_dai_link *link,
+                                 struct device_node *node,
                                  const char *prefix)
 {
        char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
-                                   prefix, link->cpu_of_node->full_name);
+                                   prefix, node->full_name);
        if (!name)
                return -ENOMEM;
 
@@ -474,7 +487,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card,
                codec++;
        }
 
-       ret = axg_card_set_link_name(card, link, "be");
+       ret = axg_card_set_link_name(card, link, node, "be");
        if (ret)
                dev_err(card->dev, "error setting %pOFn link name\n", np);
 
@@ -483,6 +496,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card,
 
 static int axg_card_set_fe_link(struct snd_soc_card *card,
                                struct snd_soc_dai_link *link,
+                               struct device_node *node,
                                bool is_playback)
 {
        link->dynamic = 1;
@@ -497,7 +511,7 @@ static int axg_card_set_fe_link(struct snd_soc_card *card,
        else
                link->dpcm_capture = 1;
 
-       return axg_card_set_link_name(card, link, "fe");
+       return axg_card_set_link_name(card, link, node, "fe");
 }
 
 static int axg_card_cpu_is_capture_fe(struct device_node *np)
@@ -515,6 +529,11 @@ static int axg_card_cpu_is_tdm_iface(struct device_node *np)
        return of_device_is_compatible(np, PREFIX "axg-tdm-iface");
 }
 
+static int axg_card_cpu_is_codec(struct device_node *np)
+{
+       return of_device_is_compatible(np, PREFIX "g12a-tohdmitx");
+}
+
 static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
                             int *index)
 {
@@ -527,9 +546,9 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
                return ret;
 
        if (axg_card_cpu_is_playback_fe(dai_link->cpu_of_node))
-               ret = axg_card_set_fe_link(card, dai_link, true);
+               ret = axg_card_set_fe_link(card, dai_link, np, true);
        else if (axg_card_cpu_is_capture_fe(dai_link->cpu_of_node))
-               ret = axg_card_set_fe_link(card, dai_link, false);
+               ret = axg_card_set_fe_link(card, dai_link, np, false);
        else
                ret = axg_card_set_be_link(card, dai_link, np);
 
@@ -538,6 +557,8 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
 
        if (axg_card_cpu_is_tdm_iface(dai_link->cpu_of_node))
                ret = axg_card_parse_tdm(card, np, index);
+       else if (axg_card_cpu_is_codec(dai_link->cpu_of_node))
+               dai_link->params = &codec_params;
 
        return ret;
 }
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
new file mode 100644 (file)
index 0000000..707ccb1
--- /dev/null
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2019 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <sound/pcm_params.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
+
+#define G12A_TOHDMITX_DRV_NAME "g12a-tohdmitx"
+
+#define TOHDMITX_CTRL0                 0x0
+#define  CTRL0_ENABLE_SHIFT            31
+#define  CTRL0_I2S_DAT_SEL             GENMASK(13, 12)
+#define  CTRL0_I2S_LRCLK_SEL           GENMASK(9, 8)
+#define  CTRL0_I2S_BLK_CAP_INV         BIT(7)
+#define  CTRL0_I2S_BCLK_O_INV          BIT(6)
+#define  CTRL0_I2S_BCLK_SEL            GENMASK(5, 4)
+#define  CTRL0_SPDIF_CLK_CAP_INV       BIT(3)
+#define  CTRL0_SPDIF_CLK_O_INV         BIT(2)
+#define  CTRL0_SPDIF_SEL               BIT(1)
+#define  CTRL0_SPDIF_CLK_SEL           BIT(0)
+
+struct g12a_tohdmitx_input {
+       struct snd_pcm_hw_params params;
+       unsigned int fmt;
+};
+
+static struct snd_soc_dapm_widget *
+g12a_tohdmitx_get_input(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_path *p = NULL;
+       struct snd_soc_dapm_widget *in;
+
+       snd_soc_dapm_widget_for_each_source_path(w, p) {
+               if (!p->connect)
+                       continue;
+
+               /* Check that we still are in the same component */
+               if (snd_soc_dapm_to_component(w->dapm) !=
+                   snd_soc_dapm_to_component(p->source->dapm))
+                       continue;
+
+               if (p->source->id == snd_soc_dapm_dai_in)
+                       return p->source;
+
+               in = g12a_tohdmitx_get_input(p->source);
+               if (in)
+                       return in;
+       }
+
+       return NULL;
+}
+
+static struct g12a_tohdmitx_input *
+g12a_tohdmitx_get_input_data(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_widget *in =
+               g12a_tohdmitx_get_input(w);
+       struct snd_soc_dai *dai;
+
+       if (WARN_ON(!in))
+               return NULL;
+
+       dai = in->priv;
+
+       return dai->playback_dma_data;
+}
+
+static const char * const g12a_tohdmitx_i2s_mux_texts[] = {
+       "I2S A", "I2S B", "I2S C",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_i2s_mux_enum,
+                               g12a_tohdmitx_i2s_mux_texts);
+
+static int g12a_tohdmitx_get_input_val(struct snd_soc_component *component,
+                                      unsigned int mask)
+{
+       unsigned int val;
+
+       snd_soc_component_read(component, TOHDMITX_CTRL0, &val);
+       return (val & mask) >> __ffs(mask);
+}
+
+static int g12a_tohdmitx_i2s_mux_get_enum(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_kcontrol_component(kcontrol);
+
+       ucontrol->value.enumerated.item[0] =
+               g12a_tohdmitx_get_input_val(component, CTRL0_I2S_DAT_SEL);
+
+       return 0;
+}
+
+static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_kcontrol_component(kcontrol);
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int mux = ucontrol->value.enumerated.item[0];
+       unsigned int val = g12a_tohdmitx_get_input_val(component,
+                                                      CTRL0_I2S_DAT_SEL);
+
+       /* Force disconnect of the mux while updating */
+       if (val != mux)
+               snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
+
+       snd_soc_component_update_bits(component, TOHDMITX_CTRL0,
+                                     CTRL0_I2S_DAT_SEL |
+                                     CTRL0_I2S_LRCLK_SEL |
+                                     CTRL0_I2S_BCLK_SEL,
+                                     FIELD_PREP(CTRL0_I2S_DAT_SEL, mux) |
+                                     FIELD_PREP(CTRL0_I2S_LRCLK_SEL, mux) |
+                                     FIELD_PREP(CTRL0_I2S_BCLK_SEL, mux));
+
+       snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new g12a_tohdmitx_i2s_mux =
+       SOC_DAPM_ENUM_EXT("I2S Source", g12a_tohdmitx_i2s_mux_enum,
+                         g12a_tohdmitx_i2s_mux_get_enum,
+                         g12a_tohdmitx_i2s_mux_put_enum);
+
+static const char * const g12a_tohdmitx_spdif_mux_texts[] = {
+       "SPDIF A", "SPDIF B",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_spdif_mux_enum,
+                               g12a_tohdmitx_spdif_mux_texts);
+
+static int g12a_tohdmitx_spdif_mux_get_enum(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_kcontrol_component(kcontrol);
+
+       ucontrol->value.enumerated.item[0] =
+               g12a_tohdmitx_get_input_val(component, CTRL0_SPDIF_SEL);
+
+       return 0;
+}
+
+static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_kcontrol_component(kcontrol);
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int mux = ucontrol->value.enumerated.item[0];
+       unsigned int val = g12a_tohdmitx_get_input_val(component,
+                                                      CTRL0_SPDIF_SEL);
+
+       /* Force disconnect of the mux while updating */
+       if (val != mux)
+               snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
+
+       snd_soc_component_update_bits(component, TOHDMITX_CTRL0,
+                                     CTRL0_SPDIF_SEL |
+                                     CTRL0_SPDIF_CLK_SEL,
+                                     FIELD_PREP(CTRL0_SPDIF_SEL, mux) |
+                                     FIELD_PREP(CTRL0_SPDIF_CLK_SEL, mux));
+
+       snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new g12a_tohdmitx_spdif_mux =
+       SOC_DAPM_ENUM_EXT("SPDIF Source", g12a_tohdmitx_spdif_mux_enum,
+                         g12a_tohdmitx_spdif_mux_get_enum,
+                         g12a_tohdmitx_spdif_mux_put_enum);
+
+static const struct snd_kcontrol_new g12a_tohdmitx_out_enable =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOHDMITX_CTRL0,
+                                   CTRL0_ENABLE_SHIFT, 1, 0);
+
+static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = {
+       SND_SOC_DAPM_MUX("I2S SRC", SND_SOC_NOPM, 0, 0,
+                        &g12a_tohdmitx_i2s_mux),
+       SND_SOC_DAPM_SWITCH("I2S OUT EN", SND_SOC_NOPM, 0, 0,
+                           &g12a_tohdmitx_out_enable),
+       SND_SOC_DAPM_MUX("SPDIF SRC", SND_SOC_NOPM, 0, 0,
+                        &g12a_tohdmitx_spdif_mux),
+       SND_SOC_DAPM_SWITCH("SPDIF OUT EN", SND_SOC_NOPM, 0, 0,
+                           &g12a_tohdmitx_out_enable),
+};
+
+static int g12a_tohdmitx_input_probe(struct snd_soc_dai *dai)
+{
+       struct g12a_tohdmitx_input *data;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       dai->playback_dma_data = data;
+       return 0;
+}
+
+static int g12a_tohdmitx_input_remove(struct snd_soc_dai *dai)
+{
+       kfree(dai->playback_dma_data);
+       return 0;
+}
+
+static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *params,
+                                        struct snd_soc_dai *dai)
+{
+       struct g12a_tohdmitx_input *data = dai->playback_dma_data;
+
+       /* Save the stream params for the downstream link */
+       memcpy(&data->params, params, sizeof(*params));
+
+       return 0;
+}
+
+static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream,
+                                         struct snd_pcm_hw_params *params,
+                                         struct snd_soc_dai *dai)
+{
+       struct g12a_tohdmitx_input *in_data =
+               g12a_tohdmitx_get_input_data(dai->capture_widget);
+
+       if (!in_data)
+               return -ENODEV;
+
+       memcpy(params, &in_data->params, sizeof(*params));
+
+       return 0;
+}
+
+static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai,
+                                      unsigned int fmt)
+{
+       struct g12a_tohdmitx_input *data = dai->playback_dma_data;
+
+       /* Save the source stream format for the downstream link */
+       data->fmt = fmt;
+       return 0;
+}
+
+static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct g12a_tohdmitx_input *in_data =
+               g12a_tohdmitx_get_input_data(dai->capture_widget);
+
+       if (!in_data)
+               return -ENODEV;
+
+       if (!in_data->fmt)
+               return 0;
+
+       return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
+}
+
+static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = {
+       .hw_params      = g12a_tohdmitx_input_hw_params,
+       .set_fmt        = g12a_tohdmitx_input_set_fmt,
+};
+
+static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = {
+       .hw_params      = g12a_tohdmitx_output_hw_params,
+       .startup        = g12a_tohdmitx_output_startup,
+};
+
+#define TOHDMITX_SPDIF_FORMATS                                 \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |   \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+#define TOHDMITX_I2S_FORMATS                                   \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |   \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE |   \
+        SNDRV_PCM_FMTBIT_S32_LE)
+
+#define TOHDMITX_STREAM(xname, xsuffix, xfmt, xchmax)          \
+{                                                              \
+       .stream_name    = xname " " xsuffix,                    \
+       .channels_min   = 1,                                    \
+       .channels_max   = (xchmax),                             \
+       .rate_min       = 8000,                                 \
+       .rate_max       = 192000,                               \
+       .formats        = (xfmt),                               \
+}
+
+#define TOHDMITX_IN(xname, xid, xfmt, xchmax) {                                \
+       .name = xname,                                                  \
+       .id = (xid),                                                    \
+       .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax),   \
+       .ops = &g12a_tohdmitx_input_ops,                                \
+       .probe = g12a_tohdmitx_input_probe,                             \
+       .remove = g12a_tohdmitx_input_remove,                           \
+}
+
+#define TOHDMITX_OUT(xname, xid, xfmt, xchmax) {                       \
+       .name = xname,                                                  \
+       .id = (xid),                                                    \
+       .capture = TOHDMITX_STREAM(xname, "Capture", xfmt, xchmax),     \
+       .ops = &g12a_tohdmitx_output_ops,                               \
+}
+
+static struct snd_soc_dai_driver g12a_tohdmitx_dai_drv[] = {
+       TOHDMITX_IN("I2S IN A", TOHDMITX_I2S_IN_A,
+                   TOHDMITX_I2S_FORMATS, 8),
+       TOHDMITX_IN("I2S IN B", TOHDMITX_I2S_IN_B,
+                   TOHDMITX_I2S_FORMATS, 8),
+       TOHDMITX_IN("I2S IN C", TOHDMITX_I2S_IN_C,
+                   TOHDMITX_I2S_FORMATS, 8),
+       TOHDMITX_OUT("I2S OUT", TOHDMITX_I2S_OUT,
+                    TOHDMITX_I2S_FORMATS, 8),
+       TOHDMITX_IN("SPDIF IN A", TOHDMITX_SPDIF_IN_A,
+                   TOHDMITX_SPDIF_FORMATS, 2),
+       TOHDMITX_IN("SPDIF IN B", TOHDMITX_SPDIF_IN_B,
+                   TOHDMITX_SPDIF_FORMATS, 2),
+       TOHDMITX_OUT("SPDIF OUT", TOHDMITX_SPDIF_OUT,
+                    TOHDMITX_SPDIF_FORMATS, 2),
+};
+
+static int g12a_tohdmi_component_probe(struct snd_soc_component *c)
+{
+       /* Initialize the static clock parameters */
+       return snd_soc_component_write(c, TOHDMITX_CTRL0,
+                    CTRL0_I2S_BLK_CAP_INV | CTRL0_SPDIF_CLK_CAP_INV);
+}
+
+static const struct snd_soc_dapm_route g12a_tohdmitx_routes[] = {
+       { "I2S SRC", "I2S A", "I2S IN A Playback" },
+       { "I2S SRC", "I2S B", "I2S IN B Playback" },
+       { "I2S SRC", "I2S C", "I2S IN C Playback" },
+       { "I2S OUT EN", "Switch", "I2S SRC" },
+       { "I2S OUT Capture", NULL, "I2S OUT EN" },
+       { "SPDIF SRC", "SPDIF A", "SPDIF IN A Playback" },
+       { "SPDIF SRC", "SPDIF B", "SPDIF IN B Playback" },
+       { "SPDIF OUT EN", "Switch", "SPDIF SRC" },
+       { "SPDIF OUT Capture", NULL, "SPDIF OUT EN" },
+};
+
+static const struct snd_soc_component_driver g12a_tohdmitx_component_drv = {
+       .probe                  = g12a_tohdmi_component_probe,
+       .dapm_widgets           = g12a_tohdmitx_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(g12a_tohdmitx_widgets),
+       .dapm_routes            = g12a_tohdmitx_routes,
+       .num_dapm_routes        = ARRAY_SIZE(g12a_tohdmitx_routes),
+       .endianness             = 1,
+       .non_legacy_dai_naming  = 1,
+};
+
+static const struct regmap_config g12a_tohdmitx_regmap_cfg = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+};
+
+static const struct of_device_id g12a_tohdmitx_of_match[] = {
+       { .compatible = "amlogic,g12a-tohdmitx", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, g12a_tohdmitx_of_match);
+
+static int g12a_tohdmitx_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       void __iomem *regs;
+       struct regmap *map;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       map = devm_regmap_init_mmio(dev, regs, &g12a_tohdmitx_regmap_cfg);
+       if (IS_ERR(map)) {
+               dev_err(dev, "failed to init regmap: %ld\n",
+                       PTR_ERR(map));
+               return PTR_ERR(map);
+       }
+
+       return devm_snd_soc_register_component(dev,
+                       &g12a_tohdmitx_component_drv, g12a_tohdmitx_dai_drv,
+                       ARRAY_SIZE(g12a_tohdmitx_dai_drv));
+}
+
+static struct platform_driver g12a_tohdmitx_pdrv = {
+       .driver = {
+               .name = G12A_TOHDMITX_DRV_NAME,
+               .of_match_table = g12a_tohdmitx_of_match,
+       },
+       .probe = g12a_tohdmitx_probe,
+};
+module_platform_driver(g12a_tohdmitx_pdrv);
+
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_DESCRIPTION("Amlogic G12a To HDMI Tx Control Codec Driver");
+MODULE_LICENSE("GPL v2");
index 4fb29f0e561ef3b1a558ebe93f201efb105628df..444ce0602f7613bdee68167484bef51c8c615117 100644 (file)
@@ -4,6 +4,8 @@
 //
 // Copyright (c) 2013-15, Intel Corporation.
 
+#include <linux/export.h>
+#include <linux/module.h>
 #include <sound/soc-acpi.h>
 
 struct snd_soc_acpi_mach *
index 2403bec2fccf35ad4b1752bba204454c4bd2b6cf..e83edbe270419feacf567785e9a50f5f92aaceda 100644 (file)
@@ -687,6 +687,8 @@ int snd_soc_resume(struct device *dev)
        struct snd_soc_card *card = dev_get_drvdata(dev);
        bool bus_control = false;
        struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_dai *codec_dai;
+       int i;
 
        /* If the card is not initialized yet there is nothing to do */
        if (!card->instantiated)
@@ -694,14 +696,12 @@ int snd_soc_resume(struct device *dev)
 
        /* activate pins from sleep state */
        for_each_card_rtds(card, rtd) {
-               struct snd_soc_dai *codec_dai;
                struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-               int j;
 
                if (cpu_dai->active)
                        pinctrl_pm_select_default_state(cpu_dai->dev);
 
-               for_each_rtd_codec_dai(rtd, j, codec_dai) {
+               for_each_rtd_codec_dai(rtd, i, codec_dai) {
                        if (codec_dai->active)
                                pinctrl_pm_select_default_state(codec_dai->dev);
                }
@@ -738,6 +738,18 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
 static const struct snd_soc_dai_ops null_dai_ops = {
 };
 
+static struct device_node
+*soc_component_to_node(struct snd_soc_component *component)
+{
+       struct device_node *of_node;
+
+       of_node = component->dev->of_node;
+       if (!of_node && component->dev->parent)
+               of_node = component->dev->parent->of_node;
+
+       return of_node;
+}
+
 static struct snd_soc_component *soc_find_component(
        const struct device_node *of_node, const char *name)
 {
@@ -748,9 +760,7 @@ static struct snd_soc_component *soc_find_component(
 
        for_each_component(component) {
                if (of_node) {
-                       component_of_node = component->dev->of_node;
-                       if (!component_of_node && component->dev->parent)
-                               component_of_node = component->dev->parent->of_node;
+                       component_of_node = soc_component_to_node(component);
 
                        if (component_of_node == of_node)
                                return component;
@@ -768,9 +778,7 @@ static int snd_soc_is_matching_component(
 {
        struct device_node *component_of_node;
 
-       component_of_node = component->dev->of_node;
-       if (!component_of_node && component->dev->parent)
-               component_of_node = component->dev->parent->of_node;
+       component_of_node = soc_component_to_node(component);
 
        if (dlc->of_node && component_of_node != dlc->of_node)
                return 0;
@@ -878,7 +886,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
        struct snd_soc_dai_link_component *codecs;
        struct snd_soc_dai_link_component cpu_dai_component;
        struct snd_soc_component *component;
-       struct snd_soc_dai **codec_dais;
        int i;
 
        if (dai_link->ignore)
@@ -907,24 +914,22 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
        }
        snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
 
-       rtd->num_codecs = dai_link->num_codecs;
-
        /* Find CODEC from registered CODECs */
-       codec_dais = rtd->codec_dais;
+       rtd->num_codecs = dai_link->num_codecs;
        for_each_link_codecs(dai_link, i, codecs) {
-               codec_dais[i] = snd_soc_find_dai(codecs);
-               if (!codec_dais[i]) {
+               rtd->codec_dais[i] = snd_soc_find_dai(codecs);
+               if (!rtd->codec_dais[i]) {
                        dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
                                 codecs->dai_name);
                        goto _err_defer;
                }
-               snd_soc_rtdcom_add(rtd, codec_dais[i]->component);
+               snd_soc_rtdcom_add(rtd, rtd->codec_dais[i]->component);
        }
 
        /* Single codec links expect codec and codec_dai in runtime data */
-       rtd->codec_dai = codec_dais[0];
+       rtd->codec_dai = rtd->codec_dais[0];
 
-       /* find one from the set of registered platforms */
+       /* Find PLATFORM from registered PLATFORMs */
        for_each_component(component) {
                if (!snd_soc_is_matching_component(dai_link->platforms,
                                                   component))
@@ -1320,13 +1325,10 @@ EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
 
 static void soc_set_of_name_prefix(struct snd_soc_component *component)
 {
-       struct device_node *component_of_node = component->dev->of_node;
+       struct device_node *component_of_node = soc_component_to_node(component);
        const char *str;
        int ret;
 
-       if (!component_of_node && component->dev->parent)
-               component_of_node = component->dev->parent->of_node;
-
        ret = of_property_read_string(component_of_node, "sound-name-prefix",
                                      &str);
        if (!ret)
@@ -1340,10 +1342,7 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
 
        for (i = 0; i < card->num_configs && card->codec_conf; i++) {
                struct snd_soc_codec_conf *map = &card->codec_conf[i];
-               struct device_node *component_of_node = component->dev->of_node;
-
-               if (!component_of_node && component->dev->parent)
-                       component_of_node = component->dev->parent->of_node;
+               struct device_node *component_of_node = soc_component_to_node(component);
 
                if (map->of_node && component_of_node != map->of_node)
                        continue;
@@ -3752,7 +3751,7 @@ EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
 
 int snd_soc_get_dai_id(struct device_node *ep)
 {
-       struct snd_soc_component *pos;
+       struct snd_soc_component *component;
        struct device_node *node;
        int ret;
 
@@ -3766,20 +3765,10 @@ int snd_soc_get_dai_id(struct device_node *ep)
         */
        ret = -ENOTSUPP;
        mutex_lock(&client_mutex);
-       for_each_component(pos) {
-               struct device_node *component_of_node = pos->dev->of_node;
-
-               if (!component_of_node && pos->dev->parent)
-                       component_of_node = pos->dev->parent->of_node;
-
-               if (component_of_node != node)
-                       continue;
-
-               if (pos->driver->of_xlate_dai_id)
-                       ret = pos->driver->of_xlate_dai_id(pos, ep);
-
-               break;
-       }
+       component = soc_find_component(node, NULL);
+       if (component &&
+           component->driver->of_xlate_dai_id)
+               ret = component->driver->of_xlate_dai_id(component, ep);
        mutex_unlock(&client_mutex);
 
        of_node_put(node);
@@ -3797,9 +3786,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args,
 
        mutex_lock(&client_mutex);
        for_each_component(pos) {
-               component_of_node = pos->dev->of_node;
-               if (!component_of_node && pos->dev->parent)
-                       component_of_node = pos->dev->parent->of_node;
+               component_of_node = soc_component_to_node(pos);
 
                if (component_of_node != args->np)
                        continue;
index 81a7a12196ffed084305126b14b31deca9f4be8e..a4d6c068b5453386f7015a3ebdd791931b9a18dd 100644 (file)
@@ -2245,7 +2245,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card,
        dapm_kcontrol_for_each_path(path, kcontrol) {
                found = 1;
                /* we now need to match the string in the enum to the path */
-               if (!(strcmp(path->name, e->texts[mux])))
+               if (e && !(strcmp(path->name, e->texts[mux])))
                        connect = true;
                else
                        connect = false;
index 0a4f60c7a188cd6c81122f5dbe5d413921df897e..74c7d38af2c68e26baebb8db113e4393cbee29ab 100644 (file)
@@ -446,6 +446,42 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
        hw->rate_max = min_not_zero(hw->rate_max, rate_max);
 }
 
+static int soc_pcm_components_open(struct snd_pcm_substream *substream,
+                                  struct snd_soc_component **last)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_rtdcom_list *rtdcom;
+       struct snd_soc_component *component;
+       int ret = 0;
+
+       for_each_rtdcom(rtd, rtdcom) {
+               component = rtdcom->component;
+               *last = component;
+
+               if (!component->driver->ops ||
+                   !component->driver->ops->open)
+                       continue;
+
+               if (component->driver->module_get_upon_open &&
+                   !try_module_get(component->dev->driver->owner)) {
+                       dev_err(component->dev,
+                               "ASoC: can't get module %s\n",
+                               component->name);
+                       return -ENODEV;
+               }
+
+               ret = component->driver->ops->open(substream);
+               if (ret < 0) {
+                       dev_err(component->dev,
+                               "ASoC: can't open component %s: %d\n",
+                               component->name, ret);
+                       return ret;
+               }
+       }
+       *last = NULL;
+       return 0;
+}
+
 static int soc_pcm_components_close(struct snd_pcm_substream *substream,
                                    struct snd_soc_component *last)
 {
@@ -510,28 +546,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       for_each_rtdcom(rtd, rtdcom) {
-               component = rtdcom->component;
-
-               if (!component->driver->ops ||
-                   !component->driver->ops->open)
-                       continue;
-
-               if (component->driver->module_get_upon_open &&
-                   !try_module_get(component->dev->driver->owner)) {
-                       ret = -ENODEV;
-                       goto module_err;
-               }
-
-               ret = component->driver->ops->open(substream);
-               if (ret < 0) {
-                       dev_err(component->dev,
-                               "ASoC: can't open component %s: %d\n",
-                               component->name, ret);
-                       goto component_err;
-               }
-       }
-       component = NULL;
+       ret = soc_pcm_components_open(substream, &component);
+       if (ret < 0)
+               goto component_err;
 
        for_each_rtd_codec_dai(rtd, i, codec_dai) {
                if (codec_dai->driver->ops->startup) {
@@ -638,7 +655,7 @@ codec_dai_err:
 
 component_err:
        soc_pcm_components_close(substream, component);
-module_err:
+
        if (cpu_dai->driver->ops->shutdown)
                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 out:
@@ -990,6 +1007,14 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                goto interface_err;
 
+       /* store the parameters for each DAIs */
+       cpu_dai->rate = params_rate(params);
+       cpu_dai->channels = params_channels(params);
+       cpu_dai->sample_bits =
+               snd_pcm_format_physical_width(params_format(params));
+
+       snd_soc_dapm_update_dai(substream, params, cpu_dai);
+
        for_each_rtdcom(rtd, rtdcom) {
                component = rtdcom->component;
 
@@ -1007,14 +1032,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        }
        component = NULL;
 
-       /* store the parameters for each DAIs */
-       cpu_dai->rate = params_rate(params);
-       cpu_dai->channels = params_channels(params);
-       cpu_dai->sample_bits =
-               snd_pcm_format_physical_width(params_format(params));
-
-       snd_soc_dapm_update_dai(substream, params, cpu_dai);
-
        ret = soc_pcm_params_symmetry(substream, params);
         if (ret)
                goto component_err;
@@ -1027,6 +1044,7 @@ component_err:
 
        if (cpu_dai->driver->ops->hw_free)
                cpu_dai->driver->ops->hw_free(substream, cpu_dai);
+       cpu_dai->rate = 0;
 
 interface_err:
        i = rtd->num_codecs;
index 603e0db4f01281f2e54434093d83ff86dd0f7a98..17e10d65fc0c464291f51dea4270a6109873059c 100644 (file)
@@ -24,6 +24,8 @@ config SND_SOC_SOF_INTEL_PCI
        select SND_SOC_SOF_CANNONLAKE  if SND_SOC_SOF_CANNONLAKE_SUPPORT
        select SND_SOC_SOF_COFFEELAKE  if SND_SOC_SOF_COFFEELAKE_SUPPORT
        select SND_SOC_SOF_ICELAKE     if SND_SOC_SOF_ICELAKE_SUPPORT
+       select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT
+       select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level
@@ -179,6 +181,36 @@ config SND_SOC_SOF_ICELAKE
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level
 
+config SND_SOC_SOF_COMETLAKE_LP
+       tristate
+       select SND_SOC_SOF_HDA_COMMON
+       help
+         This option is not user-selectable but automagically handled by
+         'select' statements at a higher level
+
+config SND_SOC_SOF_COMETLAKE_LP_SUPPORT
+       bool "SOF support for CometLake-LP"
+       help
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the Cometlake-LP processors.
+         Say Y if you have such a device.
+         If unsure select "N".
+
+config SND_SOC_SOF_COMETLAKE_H
+       tristate
+       select SND_SOC_SOF_HDA_COMMON
+       help
+         This option is not user-selectable but automagically handled by
+         'select' statements at a higher level
+
+config SND_SOC_SOF_COMETLAKE_H_SUPPORT
+       bool "SOF support for CometLake-H"
+       help
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the Cometlake-H processors.
+         Say Y if you have such a device.
+         If unsure select "N".
+
 config SND_SOC_SOF_HDA_COMMON
        tristate
        select SND_SOC_SOF_INTEL_COMMON
index 08a1a3d3c08d6529f634a8308bee026c06fcf244..c059d1170bab999945fcc603da385a54fd676e39 100644 (file)
@@ -266,3 +266,22 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
 };
 EXPORT_SYMBOL(cnl_chip_info);
+
+const struct sof_intel_dsp_desc icl_chip_info = {
+       /* Icelake */
+       .cores_num = 4,
+       .init_core_mask = 1,
+       .cores_mask = HDA_DSP_CORE_MASK(0) |
+                               HDA_DSP_CORE_MASK(1) |
+                               HDA_DSP_CORE_MASK(2) |
+                               HDA_DSP_CORE_MASK(3),
+       .ipc_req = CNL_DSP_REG_HIPCIDR,
+       .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+       .ipc_ack = CNL_DSP_REG_HIPCIDA,
+       .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+       .ipc_ctl = CNL_DSP_REG_HIPCCTL,
+       .rom_init_timeout       = 300,
+       .ssp_count = ICL_SSP_COUNT,
+       .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL(icl_chip_info);
index 92d45c43b4b1c1f08801f579eb19ccd8e97b5d3d..455046612b9494188b3893beebda2c287f8e1fbb 100644 (file)
 /* SSP Count of the Platform */
 #define APL_SSP_COUNT          6
 #define CNL_SSP_COUNT          3
+#define ICL_SSP_COUNT          6
 
 /* SSP Registers */
 #define SSP_SSC1_OFFSET                0x4
@@ -579,5 +580,6 @@ extern const struct snd_sof_dsp_ops sof_skl_ops;
 extern const struct sof_intel_dsp_desc apl_chip_info;
 extern const struct sof_intel_dsp_desc cnl_chip_info;
 extern const struct sof_intel_dsp_desc skl_chip_info;
+extern const struct sof_intel_dsp_desc icl_chip_info;
 
 #endif
index 649968841dad9f59078155b4c2cb3c2bd081c8f1..4f536c0de0a55f40c627e178c2622d542a246138 100644 (file)
@@ -416,7 +416,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
        struct snd_sof_pcm *spcm;
        struct snd_soc_tplg_stream_caps *caps;
        int ret;
-       int err;
 
        /* nothing to do for BE */
        if (rtd->dai_link->no_pcm)
@@ -434,14 +433,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
 
        caps = &spcm->pcm.caps[substream->stream];
 
-       ret = pm_runtime_get_sync(sdev->dev);
-       if (ret < 0) {
-               dev_err(sdev->dev, "error: pcm open failed to resume %d\n",
-                       ret);
-               pm_runtime_put_noidle(sdev->dev);
-               return ret;
-       }
-
        /* set any runtime constraints based on topology */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
                                   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
@@ -485,17 +476,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
        spcm->stream[substream->stream].substream = substream;
 
        ret = snd_sof_pcm_platform_open(sdev, substream);
-       if (ret < 0) {
-               dev_err(sdev->dev, "error: pcm open failed %d\n",
-                       ret);
-
-               pm_runtime_mark_last_busy(sdev->dev);
-
-               err = pm_runtime_put_autosuspend(sdev->dev);
-               if (err < 0)
-                       dev_err(sdev->dev, "error: pcm close failed to idle %d\n",
-                               err);
-       }
+       if (ret < 0)
+               dev_err(sdev->dev, "error: pcm open failed %d\n", ret);
 
        return ret;
 }
@@ -530,13 +512,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream)
                 */
        }
 
-       pm_runtime_mark_last_busy(sdev->dev);
-
-       err = pm_runtime_put_autosuspend(sdev->dev);
-       if (err < 0)
-               dev_err(sdev->dev, "error: pcm close failed to idle %d\n",
-                       err);
-
        return 0;
 }
 
index b778dffb2d25c081134d321fe8208820fcc56305..e2b19782f01ac474ca2e746085b112b897e4755e 100644 (file)
@@ -129,6 +129,26 @@ static const struct sof_dev_desc cfl_desc = {
 };
 #endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) || \
+       IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
+
+static const struct sof_dev_desc cml_desc = {
+       .machines               = snd_soc_acpi_intel_cnl_machines,
+       .resindex_lpe_base      = 0,
+       .resindex_pcicfg_base   = -1,
+       .resindex_imr_base      = -1,
+       .irqindex_host_ipc      = -1,
+       .resindex_dma_base      = -1,
+       .chip_info = &cnl_chip_info,
+       .default_fw_path = "intel/sof",
+       .default_tplg_path = "intel/sof-tplg",
+       .nocodec_fw_filename = "sof-cnl.ri",
+       .nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
+       .ops = &sof_cnl_ops,
+       .arch_ops = &sof_xtensa_arch_ops
+};
+#endif
+
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
 static const struct sof_dev_desc icl_desc = {
        .machines               = snd_soc_acpi_intel_icl_machines,
@@ -137,7 +157,7 @@ static const struct sof_dev_desc icl_desc = {
        .resindex_imr_base      = -1,
        .irqindex_host_ipc      = -1,
        .resindex_dma_base      = -1,
-       .chip_info = &cnl_chip_info,
+       .chip_info = &icl_chip_info,
        .default_fw_path = "intel/sof",
        .default_tplg_path = "intel/sof-tplg",
        .nocodec_fw_filename = "sof-icl.ri",
@@ -353,6 +373,14 @@ static const struct pci_device_id sof_pci_ids[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
        { PCI_DEVICE(0x8086, 0x34C8),
                .driver_data = (unsigned long)&icl_desc},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP)
+       { PCI_DEVICE(0x8086, 0x02c8),
+               .driver_data = (unsigned long)&cml_desc},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
+       { PCI_DEVICE(0x8086, 0x06c8),
+               .driver_data = (unsigned long)&cml_desc},
 #endif
        { 0, }
 };
index 8ee697ff1f86f7efbe6fc53fa42da5dfae82bb38..8846f49b2951ba30651cd2de5f4a9091a4bc2b1d 100644 (file)
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #define STM32_I2S_TXDR_REG     0X20
 #define STM32_I2S_RXDR_REG     0x30
 #define STM32_I2S_CGFR_REG     0X50
+#define STM32_I2S_HWCFGR_REG   0x3F0
+#define STM32_I2S_VERR_REG     0x3F4
+#define STM32_I2S_IPIDR_REG    0x3F8
+#define STM32_I2S_SIDR_REG     0x3FC
 
 /* Bit definition for SPI2S_CR1 register */
 #define I2S_CR1_SPE            BIT(0)
 #define I2S_CGFR_ODD           BIT(I2S_CGFR_ODD_SHIFT)
 #define I2S_CGFR_MCKOE         BIT(25)
 
+/* Registers below apply to I2S version 1.1 and more */
+
+/* Bit definition for SPI_HWCFGR register */
+#define I2S_HWCFGR_I2S_SUPPORT_MASK    GENMASK(15, 12)
+
+/* Bit definition for SPI_VERR register */
+#define I2S_VERR_MIN_MASK      GENMASK(3, 0)
+#define I2S_VERR_MAJ_MASK      GENMASK(7, 4)
+
+/* Bit definition for SPI_IPIDR register */
+#define I2S_IPIDR_ID_MASK      GENMASK(31, 0)
+
+/* Bit definition for SPI_SIDR register */
+#define I2S_SIDR_ID_MASK       GENMASK(31, 0)
+
+#define I2S_IPIDR_NUMBER       0x00130022
+
 enum i2s_master_mode {
        I2S_MS_NOT_SET,
        I2S_MS_MASTER,
@@ -280,6 +302,10 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg)
        case STM32_I2S_SR_REG:
        case STM32_I2S_RXDR_REG:
        case STM32_I2S_CGFR_REG:
+       case STM32_I2S_HWCFGR_REG:
+       case STM32_I2S_VERR_REG:
+       case STM32_I2S_IPIDR_REG:
+       case STM32_I2S_SIDR_REG:
                return true;
        default:
                return false;
@@ -711,10 +737,11 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
-       .max_register = STM32_I2S_CGFR_REG,
+       .max_register = STM32_I2S_SIDR_REG,
        .readable_reg = stm32_i2s_readable_reg,
        .volatile_reg = stm32_i2s_volatile_reg,
        .writeable_reg = stm32_i2s_writeable_reg,
+       .num_reg_defaults_raw = STM32_I2S_SIDR_REG / sizeof(u32) + 1,
        .fast_io = true,
        .cache_type = REGCACHE_FLAT,
 };
@@ -865,6 +892,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
 static int stm32_i2s_probe(struct platform_device *pdev)
 {
        struct stm32_i2s_data *i2s;
+       u32 val;
        int ret;
 
        i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
@@ -903,8 +931,34 @@ static int stm32_i2s_probe(struct platform_device *pdev)
                return ret;
 
        /* Set SPI/I2S in i2s mode */
-       return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
-                                 I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
+       ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+                                I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(i2s->regmap, STM32_I2S_IPIDR_REG, &val);
+       if (ret)
+               return ret;
+
+       if (val == I2S_IPIDR_NUMBER) {
+               ret = regmap_read(i2s->regmap, STM32_I2S_HWCFGR_REG, &val);
+               if (ret)
+                       return ret;
+
+               if (!FIELD_GET(I2S_HWCFGR_I2S_SUPPORT_MASK, val)) {
+                       dev_err(&pdev->dev,
+                               "Device does not support i2s mode\n");
+                       return -EPERM;
+               }
+
+               ret = regmap_read(i2s->regmap, STM32_I2S_VERR_REG, &val);
+
+               dev_dbg(&pdev->dev, "I2S version: %lu.%lu registered\n",
+                       FIELD_GET(I2S_VERR_MAJ_MASK, val),
+                       FIELD_GET(I2S_VERR_MIN_MASK, val));
+       }
+
+       return ret;
 }
 
 MODULE_DEVICE_TABLE(of, stm32_i2s_ids);
index 3d64200edbb5a13f08ba5b1a6089a6d1e1605cb7..4a3fad4a711f29de4a5749af94816b00e21ea8d8 100644 (file)
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
@@ -36,6 +37,9 @@
 #define STM32_SPDIFRX_DR       0x10
 #define STM32_SPDIFRX_CSR      0x14
 #define STM32_SPDIFRX_DIR      0x18
+#define STM32_SPDIFRX_VERR     0x3F4
+#define STM32_SPDIFRX_IDR      0x3F8
+#define STM32_SPDIFRX_SIDR     0x3FC
 
 /* Bit definition for SPDIF_CR register */
 #define SPDIFRX_CR_SPDIFEN_SHIFT       0
 #define SPDIFRX_SPDIFEN_SYNC   0x1
 #define SPDIFRX_SPDIFEN_ENABLE 0x3
 
+/* Bit definition for SPDIFRX_VERR register */
+#define SPDIFRX_VERR_MIN_MASK  GENMASK(3, 0)
+#define SPDIFRX_VERR_MAJ_MASK  GENMASK(7, 4)
+
+/* Bit definition for SPDIFRX_IDR register */
+#define SPDIFRX_IDR_ID_MASK    GENMASK(31, 0)
+
+/* Bit definition for SPDIFRX_SIDR register */
+#define SPDIFRX_SIDR_SID_MASK  GENMASK(31, 0)
+
+#define SPDIFRX_IPIDR_NUMBER   0x00130041
+
 #define SPDIFRX_IN1            0x1
 #define SPDIFRX_IN2            0x2
 #define SPDIFRX_IN3            0x3
@@ -607,6 +623,9 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg)
        case STM32_SPDIFRX_DR:
        case STM32_SPDIFRX_CSR:
        case STM32_SPDIFRX_DIR:
+       case STM32_SPDIFRX_VERR:
+       case STM32_SPDIFRX_IDR:
+       case STM32_SPDIFRX_SIDR:
                return true;
        default:
                return false;
@@ -642,10 +661,11 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
-       .max_register = STM32_SPDIFRX_DIR,
+       .max_register = STM32_SPDIFRX_SIDR,
        .readable_reg = stm32_spdifrx_readable_reg,
        .volatile_reg = stm32_spdifrx_volatile_reg,
        .writeable_reg = stm32_spdifrx_writeable_reg,
+       .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1,
        .fast_io = true,
        .cache_type = REGCACHE_FLAT,
 };
@@ -912,6 +932,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
        struct stm32_spdifrx_data *spdifrx;
        struct reset_control *rst;
        const struct snd_dmaengine_pcm_config *pcm_config = NULL;
+       u32 ver, idr;
        int ret;
 
        spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL);
@@ -968,7 +989,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
                goto error;
        }
 
-       return 0;
+       ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr);
+       if (ret)
+               goto error;
+
+       if (idr == SPDIFRX_IPIDR_NUMBER) {
+               ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver);
+
+               dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n",
+                       FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver),
+                       FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver));
+       }
+
+       return ret;
 
 error:
        if (!IS_ERR(spdifrx->ctrl_chan))