summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml36
-rw-r--r--Documentation/devicetree/bindings/sound/mvebu-audio.txt14
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8961.yaml40
-rw-r--r--include/sound/acp62_chip_offset_byte.h214
-rw-r--r--include/sound/hdaudio.h26
-rw-r--r--include/sound/hdaudio_ext.h66
-rw-r--r--include/sound/soc-dapm.h188
-rw-r--r--include/sound/soc-dpcm.h2
-rw-r--r--sound/hda/ext/hdac_ext_controller.c116
-rw-r--r--sound/hda/ext/hdac_ext_stream.c203
-rw-r--r--sound/hda/hdac_stream.c136
-rw-r--r--sound/soc/amd/acp/acp-i2s.c16
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c62
-rw-r--r--sound/soc/codecs/Kconfig2
-rw-r--r--sound/soc/codecs/ak4458.c13
-rw-r--r--sound/soc/codecs/cs35l36.c4
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c2
-rw-r--r--sound/soc/codecs/hda.c12
-rw-r--r--sound/soc/codecs/hdac_hda.c6
-rw-r--r--sound/soc/codecs/hdac_hdmi.c8
-rw-r--r--sound/soc/codecs/jz4725b.c81
-rw-r--r--sound/soc/codecs/rt298.c7
-rw-r--r--sound/soc/codecs/twl4030.c6
-rw-r--r--sound/soc/codecs/wm8961.c7
-rw-r--r--sound/soc/codecs/wm8978.c2
-rw-r--r--sound/soc/fsl/fsl_micfil.c434
-rw-r--r--sound/soc/fsl/fsl_micfil.h6
-rw-r--r--sound/soc/fsl/fsl_rpmsg.c6
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c3
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c10
-rw-r--r--sound/soc/fsl/imx-rpmsg.c6
-rw-r--r--sound/soc/intel/avs/apl.c6
-rw-r--r--sound/soc/intel/avs/avs.h4
-rw-r--r--sound/soc/intel/avs/board_selection.c14
-rw-r--r--sound/soc/intel/avs/boards/Kconfig10
-rw-r--r--sound/soc/intel/avs/boards/Makefile2
-rw-r--r--sound/soc/intel/avs/boards/da7219.c6
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c1
-rw-r--r--sound/soc/intel/avs/boards/max98927.c236
-rw-r--r--sound/soc/intel/avs/boards/rt298.c24
-rw-r--r--sound/soc/intel/avs/core.c19
-rw-r--r--sound/soc/intel/avs/ipc.c5
-rw-r--r--sound/soc/intel/avs/loader.c18
-rw-r--r--sound/soc/intel/avs/messages.c19
-rw-r--r--sound/soc/intel/avs/messages.h2
-rw-r--r--sound/soc/intel/avs/pcm.c22
-rw-r--r--sound/soc/intel/avs/skl.c4
-rw-r--r--sound/soc/intel/skylake/skl-messages.c6
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c35
-rw-r--r--sound/soc/intel/skylake/skl.c11
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c135
-rw-r--r--sound/soc/kirkwood/kirkwood.h2
-rw-r--r--sound/soc/meson/axg-pdm.c2
-rw-r--r--sound/soc/sh/rcar/core.c7
-rw-r--r--sound/soc/soc-dapm.c189
-rw-r--r--sound/soc/soc-pcm.c12
-rw-r--r--sound/soc/sof/intel/cnl.c26
-rw-r--r--sound/soc/sof/intel/hda-dai.c42
-rw-r--r--sound/soc/sof/intel/hda-dsp.c14
-rw-r--r--sound/soc/sof/intel/hda-ipc.c27
-rw-r--r--sound/soc/sof/intel/hda-pcm.c3
-rw-r--r--sound/soc/sof/intel/hda-stream.c16
-rw-r--r--sound/soc/sof/intel/hda.c13
-rw-r--r--sound/soc/sof/intel/hda.h9
-rw-r--r--sound/soc/sof/intel/mtl.c24
-rw-r--r--sound/soc/sof/ipc3.c4
-rw-r--r--sound/soc/sof/ipc4.c4
-rw-r--r--sound/soc/ti/davinci-mcasp.c7
68 files changed, 1999 insertions, 715 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
index d370c98a62c7..e847611a85f7 100644
--- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
@@ -11,8 +11,11 @@ maintainers:
description: |
fsl_rpmsg is a virtual audio device. Mapping to real hardware devices
- are SAI, DMA controlled by Cortex M core. What we see from Linux
- side is a device which provides audio service by rpmsg channel.
+ are SAI, MICFIL, DMA controlled by Cortex M core. What we see from
+ Linux side is a device which provides audio service by rpmsg channel.
+ We can create different sound cards which access different hardwares
+ such as SAI, MICFIL, .etc through building rpmsg channels between
+ Cortex-A and Cortex-M.
properties:
compatible:
@@ -85,6 +88,16 @@ properties:
This is a boolean property. If present, the receiving function
will be enabled.
+ fsl,rpmsg-channel-name:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: |
+ A string property to assign rpmsg channel this sound card sits on.
+ This property can be omitted if there is only one sound card and it sits
+ on "rpmsg-audio-channel".
+ enum:
+ - rpmsg-audio-channel
+ - rpmsg-micfil-channel
+
required:
- compatible
- model
@@ -107,3 +120,22 @@ examples:
<&clk IMX8MN_AUDIO_PLL2_OUT>;
clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
};
+
+ - |
+ #include <dt-bindings/clock/imx8mm-clock.h>
+
+ rpmsg_micfil: audio-controller {
+ compatible = "fsl,imx8mm-rpmsg-audio";
+ model = "micfil-audio";
+ fsl,rpmsg-channel-name = "rpmsg-micfil-channel";
+ fsl,enable-lpa;
+ fsl,rpmsg-in;
+ clocks = <&clk IMX8MM_CLK_PDM_IPG>,
+ <&clk IMX8MM_CLK_PDM_ROOT>,
+ <&clk IMX8MM_CLK_SDMA3_ROOT>,
+ <&clk IMX8MM_AUDIO_PLL1_OUT>,
+ <&clk IMX8MM_AUDIO_PLL2_OUT>;
+ clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/mvebu-audio.txt b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
index cb8c07c81ce4..4f5dec5cb3c2 100644
--- a/Documentation/devicetree/bindings/sound/mvebu-audio.txt
+++ b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
@@ -6,9 +6,14 @@ Required properties:
"marvell,kirkwood-audio" for Kirkwood platforms
"marvell,dove-audio" for Dove platforms
"marvell,armada370-audio" for Armada 370 platforms
+ "marvell,armada-380-audio" for Armada 38x platforms
- reg: physical base address of the controller and length of memory mapped
- region.
+ region (named "i2s_regs").
+ With "marvell,armada-380-audio" two other regions are required:
+ first of those is dedicated for Audio PLL Configuration registers
+ (named "pll_regs") and the second one ("soc_ctrl") - for register
+ where one of exceptive I/O types (I2S or S/PDIF) is set.
- interrupts:
with "marvell,kirkwood-audio", the audio interrupt
@@ -23,6 +28,13 @@ Required properties:
"internal" for the internal clock
"extclk" for the external clock
+Optional properties:
+
+- spdif-mode:
+ Enable S/PDIF mode on Armada 38x SoC. Using this property
+ disables standard I2S I/O. Valid only with "marvell,armada-380-audio"
+ compatible string.
+
Example:
i2s1: audio-controller@b4000 {
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml
new file mode 100644
index 000000000000..795d34e1e97a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8961.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wolfson WM8961 Ultra-Low Power Stereo CODEC
+
+maintainers:
+ - patches@opensource.cirrus.com
+
+properties:
+ compatible:
+ const: wlf,wm8961
+
+ reg:
+ maxItems: 1
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wm8961: codec@4a {
+ compatible = "wlf,wm8961";
+ reg = <0x4a>;
+ #sound-dai-cells = <0>;
+ };
+ };
diff --git a/include/sound/acp62_chip_offset_byte.h b/include/sound/acp62_chip_offset_byte.h
index f03992f81168..ca38f8a0966e 100644
--- a/include/sound/acp62_chip_offset_byte.h
+++ b/include/sound/acp62_chip_offset_byte.h
@@ -131,6 +131,23 @@
#define ACP_I2S_WAKE_EN 0x000145C
#define ACP_SW1_WAKE_EN 0x0001460
+#define ACP_SW_I2S_ERROR_REASON 0x00018B4
+#define ACP_SW_POS_TRACK_I2S_TX_CTRL 0x00018B8
+#define ACP_SW_I2S_TX_DMA_POS 0x00018BC
+#define ACP_SW_POS_TRACK_BT_TX_CTRL 0x00018C0
+#define ACP_SW_BT_TX_DMA_POS 0x00018C4
+#define ACP_SW_POS_TRACK_HS_TX_CTRL 0x00018C8
+#define ACP_SW_HS_TX_DMA_POS 0x00018CC
+#define ACP_SW_POS_TRACK_I2S_RX_CTRL 0x00018D0
+#define ACP_SW_I2S_RX_DMA_POS 0x00018D4
+#define ACP_SW_POS_TRACK_BT_RX_CTRL 0x00018D8
+#define ACP_SW_BT_RX_DMA_POS 0x00018DC
+#define ACP_SW_POS_TRACK_HS_RX_CTRL 0x00018E0
+#define ACP_SW_HS_RX_DMA_POS 0x00018E4
+#define ACP_ERROR_INTR_MASK1 0X0001974
+#define ACP_ERROR_INTR_MASK2 0X0001978
+#define ACP_ERROR_INTR_MASK3 0X000197C
+
/* Registers from ACP_P1_MISC block */
#define ACP_EXTERNAL_INTR_ENB 0x0001A00
#define ACP_EXTERNAL_INTR_CNTL 0x0001A04
@@ -154,6 +171,8 @@
#define ACP_P1_SW_BT_RX_DMA_POS 0x0001A9C
#define ACP_P1_SW_POS_TRACK_HS_RX_CTRL 0x0001AA0
#define ACP_P1_SW_HS_RX_DMA_POS 0x0001AA4
+#define ACP_ERROR_INTR_MASK4 0X0001AEC
+#define ACP_ERROR_INTR_MASK5 0X0001AF0
/* Registers from ACP_AUDIO_BUFFERS block */
#define ACP_I2S_RX_RINGBUFADDR 0x0002000
@@ -210,6 +229,24 @@
#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x00020CC
#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x00020D0
#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x00020D4
+#define ACP_AUDIO_RX_RINGBUFADDR ACP_I2S_RX_RINGBUFADDR
+#define ACP_AUDIO_RX_RINGBUFSIZE ACP_I2S_RX_RINGBUFSIZE
+#define ACP_AUDIO_RX_LINKPOSITIONCNTR ACP_I2S_RX_LINKPOSITIONCNTR
+#define ACP_AUDIO_RX_FIFOADDR ACP_I2S_RX_FIFOADDR
+#define ACP_AUDIO_RX_FIFOSIZE ACP_I2S_RX_FIFOSIZE
+#define ACP_AUDIO_RX_DMA_SIZE ACP_I2S_RX_DMA_SIZE
+#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_HIGH ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH
+#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_LOW ACP_I2S_RX_LINEARPOSITIONCNTR_LOW
+#define ACP_AUDIO_RX_INTR_WATERMARK_SIZE ACP_I2S_RX_INTR_WATERMARK_SIZE
+#define ACP_AUDIO_TX_RINGBUFADDR ACP_I2S_TX_RINGBUFADDR
+#define ACP_AUDIO_TX_RINGBUFSIZE ACP_I2S_TX_RINGBUFSIZE
+#define ACP_AUDIO_TX_LINKPOSITIONCNTR ACP_I2S_TX_LINKPOSITIONCNTR
+#define ACP_AUDIO_TX_FIFOADDR ACP_I2S_TX_FIFOADDR
+#define ACP_AUDIO_TX_FIFOSIZE ACP_I2S_TX_FIFOSIZE
+#define ACP_AUDIO_TX_DMA_SIZE ACP_I2S_TX_DMA_SIZE
+#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_HIGH ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH
+#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_LOW ACP_I2S_TX_LINEARPOSITIONCNTR_LOW
+#define ACP_AUDIO_TX_INTR_WATERMARK_SIZE ACP_I2S_TX_INTR_WATERMARK_SIZE
/* Registers from ACP_I2S_TDM block */
#define ACP_I2STDM_IER 0x0002400
@@ -255,6 +292,102 @@
#define ACP_WOV_ERROR_STATUS_REGISTER 0x0002C68
#define ACP_PDM_CLKDIV 0x0002C6C
+/* Registers from ACP_SW_SWCLK block */
+#define ACP_SW_EN 0x0003000
+#define ACP_SW_EN_STATUS 0x0003004
+#define ACP_SW_FRAMESIZE 0x0003008
+#define ACP_SW_SSP_COUNTER 0x000300C
+#define ACP_SW_AUDIO_TX_EN 0x0003010
+#define ACP_SW_AUDIO_TX_EN_STATUS 0x0003014
+#define ACP_SW_AUDIO_TX_FRAME_FORMAT 0x0003018
+#define ACP_SW_AUDIO_TX_SAMPLEINTERVAL 0x000301C
+#define ACP_SW_AUDIO_TX_HCTRL_DP0 0x0003020
+#define ACP_SW_AUDIO_TX_HCTRL_DP1 0x0003024
+#define ACP_SW_AUDIO_TX_HCTRL_DP2 0x0003028
+#define ACP_SW_AUDIO_TX_HCTRL_DP3 0x000302C
+#define ACP_SW_AUDIO_TX_OFFSET_DP0 0x0003030
+#define ACP_SW_AUDIO_TX_OFFSET_DP1 0x0003034
+#define ACP_SW_AUDIO_TX_OFFSET_DP2 0x0003038
+#define ACP_SW_AUDIO_TX_OFFSET_DP3 0x000303C
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP0 0x0003040
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP1 0x0003044
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP2 0x0003048
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP3 0x000304C
+#define ACP_SW_BT_TX_EN 0x0003050
+#define ACP_SW_BT_TX_EN_STATUS 0x0003054
+#define ACP_SW_BT_TX_FRAME_FORMAT 0x0003058
+#define ACP_SW_BT_TX_SAMPLEINTERVAL 0x000305C
+#define ACP_SW_BT_TX_HCTRL 0x0003060
+#define ACP_SW_BT_TX_OFFSET 0x0003064
+#define ACP_SW_BT_TX_CHANNEL_ENABLE_DP0 0x0003068
+#define ACP_SW_HEADSET_TX_EN 0x000306C
+#define ACP_SW_HEADSET_TX_EN_STATUS 0x0003070
+#define ACP_SW_HEADSET_TX_FRAME_FORMAT 0x0003074
+#define ACP_SW_HEADSET_TX_SAMPLEINTERVAL 0x0003078
+#define ACP_SW_HEADSET_TX_HCTRL 0x000307C
+#define ACP_SW_HEADSET_TX_OFFSET 0x0003080
+#define ACP_SW_HEADSET_TX_CHANNEL_ENABLE_DP0 0x0003084
+#define ACP_SW_AUDIO_RX_EN 0x0003088
+#define ACP_SW_AUDIO_RX_EN_STATUS 0x000308C
+#define ACP_SW_AUDIO_RX_FRAME_FORMAT 0x0003090
+#define ACP_SW_AUDIO_RX_SAMPLEINTERVAL 0x0003094
+#define ACP_SW_AUDIO_RX_HCTRL_DP0 0x0003098
+#define ACP_SW_AUDIO_RX_HCTRL_DP1 0x000309C
+#define ACP_SW_AUDIO_RX_HCTRL_DP2 0x0003100
+#define ACP_SW_AUDIO_RX_HCTRL_DP3 0x0003104
+#define ACP_SW_AUDIO_RX_OFFSET_DP0 0x0003108
+#define ACP_SW_AUDIO_RX_OFFSET_DP1 0x000310C
+#define ACP_SW_AUDIO_RX_OFFSET_DP2 0x0003110
+#define ACP_SW_AUDIO_RX_OFFSET_DP3 0x0003114
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP0 0x0003118
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP1 0x000311C
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP2 0x0003120
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP3 0x0003124
+#define ACP_SW_BT_RX_EN 0x0003128
+#define ACP_SW_BT_RX_EN_STATUS 0x000312C
+#define ACP_SW_BT_RX_FRAME_FORMAT 0x0003130
+#define ACP_SW_BT_RX_SAMPLEINTERVAL 0x0003134
+#define ACP_SW_BT_RX_HCTRL 0x0003138
+#define ACP_SW_BT_RX_OFFSET 0x000313C
+#define ACP_SW_BT_RX_CHANNEL_ENABLE_DP0 0x0003140
+#define ACP_SW_HEADSET_RX_EN 0x0003144
+#define ACP_SW_HEADSET_RX_EN_STATUS 0x0003148
+#define ACP_SW_HEADSET_RX_FRAME_FORMAT 0x000314C
+#define ACP_SW_HEADSET_RX_SAMPLEINTERVAL 0x0003150
+#define ACP_SW_HEADSET_RX_HCTRL 0x0003154
+#define ACP_SW_HEADSET_RX_OFFSET 0x0003158
+#define ACP_SW_HEADSET_RX_CHANNEL_ENABLE_DP0 0x000315C
+#define ACP_SW_BPT_PORT_EN 0x0003160
+#define ACP_SW_BPT_PORT_EN_STATUS 0x0003164
+#define ACP_SW_BPT_PORT_FRAME_FORMAT 0x0003168
+#define ACP_SW_BPT_PORT_SAMPLEINTERVAL 0x000316C
+#define ACP_SW_BPT_PORT_HCTRL 0x0003170
+#define ACP_SW_BPT_PORT_OFFSET 0x0003174
+#define ACP_SW_BPT_PORT_CHANNEL_ENABLE 0x0003178
+#define ACP_SW_BPT_PORT_FIRST_BYTE_ADDR 0x000317C
+#define ACP_SW_CLK_RESUME_CTRL 0x0003180
+#define ACP_SW_CLK_RESUME_DELAY_CNTR 0x0003184
+#define ACP_SW_BUS_RESET_CTRL 0x0003188
+#define ACP_SW_PRBS_ERR_STATUS 0x000318C
+#define SW_IMM_CMD_UPPER_WORD 0x0003230
+#define SW_IMM_CMD_LOWER_QWORD 0x0003234
+#define SW_IMM_RESP_UPPER_WORD 0x0003238
+#define SW_IMM_RESP_LOWER_QWORD 0x000323C
+#define SW_IMM_CMD_STS 0x0003240
+#define SW_BRA_BASE_ADDRESS 0x0003244
+#define SW_BRA_TRANSFER_SIZE 0x0003248
+#define SW_BRA_DMA_BUSY 0x000324C
+#define SW_BRA_RESP 0x0003250
+#define SW_BRA_RESP_FRAME_ADDR 0x0003254
+#define SW_BRA_CURRENT_TRANSFER_SIZE 0x0003258
+#define SW_STATE_CHANGE_STATUS_0TO7 0x000325C
+#define SW_STATE_CHANGE_STATUS_8TO11 0x0003260
+#define SW_STATE_CHANGE_STATUS_MASK_0TO7 0x0003264
+#define SW_STATE_CHANGE_STATUS_MASK_8TO11 0x0003268
+#define SW_CLK_FREQUENCY_CTRL 0x000326C
+#define SW_ERROR_INTR_MASK 0x0003270
+#define SW_PHY_TEST_MODE_DATA_OFF 0x0003274
+
/* Registers from ACP_P1_AUDIO_BUFFERS block */
#define ACP_P1_I2S_RX_RINGBUFADDR 0x0003A00
#define ACP_P1_I2S_RX_RINGBUFSIZE 0x0003A04
@@ -310,6 +443,87 @@
#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_HIGH 0x0003ACC
#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_LOW 0x0003AD0
#define ACP_P1_HS_TX_INTR_WATERMARK_SIZE 0x0003AD4
+#define ACP_P1_AUDIO_RX_RINGBUFADDR ACP_P1_I2S_RX_RINGBUFADDR
+#define ACP_P1_AUDIO_RX_RINGBUFSIZE ACP_P1_I2S_RX_RINGBUFSIZE
+#define ACP_P1_AUDIO_RX_LINKPOSITIONCNTR ACP_P1_I2S_RX_LINKPOSITIONCNTR
+#define ACP_P1_AUDIO_RX_FIFOADDR ACP_P1_I2S_RX_FIFOADDR
+#define ACP_P1_AUDIO_RX_FIFOSIZE ACP_P1_I2S_RX_FIFOSIZE
+#define ACP_P1_AUDIO_RX_DMA_SIZE ACP_P1_I2S_RX_DMA_SIZE
+#define ACP_P1_AUDIO_RX_LINEARPOSITIONCNTR_HIGH ACP_P1_I2S_RX_LINEARPOSITIONCNTR_HIGH
+#define ACP_P1_AUDIO_RX_LINEARPOSITIONCNTR_LOW ACP_P1_I2S_RX_LINEARPOSITIONCNTR_LOW
+#define ACP_P1_AUDIO_RX_INTR_WATERMARK_SIZE ACP_P1_I2S_RX_INTR_WATERMARK_SIZE
+#define ACP_P1_AUDIO_TX_RINGBUFADDR ACP_P1_I2S_TX_RINGBUFADDR
+#define ACP_P1_AUDIO_TX_RINGBUFSIZE ACP_P1_I2S_TX_RINGBUFSIZE
+#define ACP_P1_AUDIO_TX_LINKPOSITIONCNTR ACP_P1_I2S_TX_LINKPOSITIONCNTR
+#define ACP_P1_AUDIO_TX_FIFOADDR ACP_P1_I2S_TX_FIFOADDR
+#define ACP_P1_AUDIO_TX_FIFOSIZE ACP_P1_I2S_TX_FIFOSIZE
+#define ACP_P1_AUDIO_TX_DMA_SIZE ACP_P1_I2S_TX_DMA_SIZE
+#define ACP_P1_AUDIO_TX_LINEARPOSITIONCNTR_HIGH ACP_P1_I2S_TX_LINEARPOSITIONCNTR_HIGH
+#define ACP_P1_AUDIO_TX_LINEARPOSITIONCNTR_LOW ACP_P1_I2S_TX_LINEARPOSITIONCNTR_LOW
+#define ACP_P1_AUDIO_TX_INTR_WATERMARK_SIZE ACP_P1_I2S_TX_INTR_WATERMARK_SIZE
+
+/* Registers from ACP_P1_SW_SWCLK block */
+#define ACP_P1_SW_EN 0x0003C00
+#define ACP_P1_SW_EN_STATUS 0x0003C04
+#define ACP_P1_SW_FRAMESIZE 0x0003C08
+#define ACP_P1_SW_SSP_COUNTER 0x0003C0C
+#define ACP_P1_SW_BT_TX_EN 0x0003C50
+#define ACP_P1_SW_BT_TX_EN_STATUS 0x0003C54
+#define ACP_P1_SW_BT_TX_FRAME_FORMAT 0x0003C58
+#define ACP_P1_SW_BT_TX_SAMPLEINTERVAL 0x0003C5C
+#define ACP_P1_SW_BT_TX_HCTRL 0x0003C60
+#define ACP_P1_SW_BT_TX_OFFSET 0x0003C64
+#define ACP_P1_SW_BT_TX_CHANNEL_ENABLE_DP0 0x0003C68
+#define ACP_P1_SW_BT_RX_EN 0x0003D28
+#define ACP_P1_SW_BT_RX_EN_STATUS 0x0003D2C
+#define ACP_P1_SW_BT_RX_FRAME_FORMAT 0x0003D30
+#define ACP_P1_SW_BT_RX_SAMPLEINTERVAL 0x0003D34
+#define ACP_P1_SW_BT_RX_HCTRL 0x0003D38
+#define ACP_P1_SW_BT_RX_OFFSET 0x0003D3C
+#define ACP_P1_SW_BT_RX_CHANNEL_ENABLE_DP0 0x0003D40
+#define ACP_P1_SW_BPT_PORT_EN 0x0003D60
+#define ACP_P1_SW_BPT_PORT_EN_STATUS 0x0003D64
+#define ACP_P1_SW_BPT_PORT_FRAME_FORMAT 0x0003D68
+#define ACP_P1_SW_BPT_PORT_SAMPLEINTERVAL 0x0003D6C
+#define ACP_P1_SW_BPT_PORT_HCTRL 0x0003D70
+#define ACP_P1_SW_BPT_PORT_OFFSET 0x0003D74
+#define ACP_P1_SW_BPT_PORT_CHANNEL_ENABLE 0x0003D78
+#define ACP_P1_SW_BPT_PORT_FIRST_BYTE_ADDR 0x0003D7C
+#define ACP_P1_SW_CLK_RESUME_CTRL 0x0003D80
+#define ACP_P1_SW_CLK_RESUME_DELAY_CNTR 0x0003D84
+#define ACP_P1_SW_BUS_RESET_CTRL 0x0003D88
+#define ACP_P1_SW_PRBS_ERR_STATUS 0x0003D8C
+
+/* Registers from ACP_P1_SW_ACLK block */
+#define P1_SW_CORB_BASE_ADDRESS 0x0003E00
+#define P1_SW_CORB_WRITE_POINTER 0x0003E04
+#define P1_SW_CORB_READ_POINTER 0x0003E08
+#define P1_SW_CORB_CONTROL 0x0003E0C
+#define P1_SW_CORB_SIZE 0x0003E14
+#define P1_SW_RIRB_BASE_ADDRESS 0x0003E18
+#define P1_SW_RIRB_WRITE_POINTER 0x0003E1C
+#define P1_SW_RIRB_RESPONSE_INTERRUPT_COUNT 0x0003E20
+#define P1_SW_RIRB_CONTROL 0x0003E24
+#define P1_SW_RIRB_SIZE 0x0003E28
+#define P1_SW_RIRB_FIFO_MIN_THDL 0x0003E2C
+#define P1_SW_IMM_CMD_UPPER_WORD 0x0003E30
+#define P1_SW_IMM_CMD_LOWER_QWORD 0x0003E34
+#define P1_SW_IMM_RESP_UPPER_WORD 0x0003E38
+#define P1_SW_IMM_RESP_LOWER_QWORD 0x0003E3C
+#define P1_SW_IMM_CMD_STS 0x0003E40
+#define P1_SW_BRA_BASE_ADDRESS 0x0003E44
+#define P1_SW_BRA_TRANSFER_SIZE 0x0003E48
+#define P1_SW_BRA_DMA_BUSY 0x0003E4C
+#define P1_SW_BRA_RESP 0x0003E50
+#define P1_SW_BRA_RESP_FRAME_ADDR 0x0003E54
+#define P1_SW_BRA_CURRENT_TRANSFER_SIZE 0x0003E58
+#define P1_SW_STATE_CHANGE_STATUS_0TO7 0x0003E5C
+#define P1_SW_STATE_CHANGE_STATUS_8TO11 0x0003E60
+#define P1_SW_STATE_CHANGE_STATUS_MASK_0TO7 0x0003E64
+#define P1_SW_STATE_CHANGE_STATUS_MASK_8TO11 0x0003E68
+#define P1_SW_CLK_FREQUENCY_CTRL 0x0003E6C
+#define P1_SW_ERROR_INTR_MASK 0x0003E70
+#define P1_SW_PHY_TEST_MODE_DATA_OFF 0x0003E74
/* Registers from ACP_SCRATCH block */
#define ACP_SCRATCH_REG_0 0x0010000
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 35778f953a3f..78f1809a4ad6 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -495,6 +495,13 @@ static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr)
snd_hdac_chip_writeb(chip, reg, \
(snd_hdac_chip_readb(chip, reg) & ~(mask)) | (val))
+/* update register macro */
+#define snd_hdac_updatel(addr, reg, mask, val) \
+ writel(((readl(addr + reg) & ~(mask)) | (val)), addr + reg)
+
+#define snd_hdac_updatew(addr, reg, mask, val) \
+ writew(((readw(addr + reg) & ~(mask)) | (val)), addr + reg)
+
/*
* HD-audio stream
*/
@@ -511,6 +518,13 @@ struct hdac_stream {
void __iomem *sd_addr; /* stream descriptor pointer */
+ void __iomem *spib_addr; /* software position in buffers stream pointer */
+ void __iomem *fifo_addr; /* software position Max fifos stream pointer */
+
+ void __iomem *dpibr_addr; /* DMA position in buffer resume pointer */
+ u32 dpib; /* DMA position in buffer */
+ u32 lpib; /* Linear position in buffer */
+
u32 sd_int_sta_mask; /* stream int status mask */
/* pcm support */
@@ -575,6 +589,18 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
struct snd_pcm_substream *substream);
+void snd_hdac_stream_spbcap_enable(struct hdac_bus *chip,
+ bool enable, int index);
+int snd_hdac_stream_set_spib(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value);
+int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev);
+void snd_hdac_stream_drsm_enable(struct hdac_bus *bus,
+ bool enable, int index);
+int snd_hdac_stream_set_dpibr(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value);
+int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value);
+
/*
* macros for easy use
*/
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index 83aed26ab143..90fd47e05370 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -23,13 +23,10 @@ void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus);
void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable);
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable);
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip,
- bool enable, int index);
-
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus);
-struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr);
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
- const char *codec_name);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus,
+ const char *codec_name);
enum hdac_ext_stream_type {
HDAC_EXT_STREAM_TYPE_COUPLED = 0,
@@ -43,11 +40,6 @@ enum hdac_ext_stream_type {
* @hstream: hdac_stream
* @pphc_addr: processing pipe host stream pointer
* @pplc_addr: processing pipe link stream pointer
- * @spib_addr: software position in buffers stream pointer
- * @fifo_addr: software position Max fifos stream pointer
- * @dpibr_addr: DMA position in buffer resume pointer
- * @dpib: DMA position in buffer
- * @lpib: Linear position in buffer
* @decoupled: stream host and link is decoupled
* @link_locked: link is locked
* @link_prepared: link is prepared
@@ -59,13 +51,6 @@ struct hdac_ext_stream {
void __iomem *pphc_addr;
void __iomem *pplc_addr;
- void __iomem *spib_addr;
- void __iomem *fifo_addr;
-
- void __iomem *dpibr_addr;
-
- u32 dpib;
- u32 lpib;
bool decoupled:1;
bool link_locked:1;
bool link_prepared;
@@ -80,7 +65,7 @@ struct hdac_ext_stream {
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
int num_stream, int dir);
void snd_hdac_ext_stream_free_all(struct hdac_bus *bus);
-void snd_hdac_link_free_all(struct hdac_bus *bus);
+void snd_hdac_ext_link_free_all(struct hdac_bus *bus);
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream,
int type);
@@ -90,20 +75,10 @@ void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
struct hdac_ext_stream *azx_dev, bool decouple);
-int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value);
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
- bool enable, int index);
-int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value);
-int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value);
-
-void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream);
-int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
+void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream);
+void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream);
+void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream);
+int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
struct hdac_ext_link {
struct hdac_bus *bus;
@@ -117,29 +92,20 @@ struct hdac_ext_link {
struct list_head list;
};
-int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink);
+int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink);
int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus);
int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus);
-void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
- int stream);
-void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
- int stream);
+void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *hlink,
+ int stream);
+void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *hlink,
+ int stream);
-int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *hlink);
+int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *hlink);
void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable);
-/* update register macro */
-#define snd_hdac_updatel(addr, reg, mask, val) \
- writel(((readl(addr + reg) & ~(mask)) | (val)), \
- addr + reg)
-
-#define snd_hdac_updatew(addr, reg, mask, val) \
- writew(((readw(addr + reg) & ~(mask)) | (val)), \
- addr + reg)
-
#define snd_hdac_adsp_writeb(chip, reg, value) \
snd_hdac_reg_writeb(chip, (chip)->dsp_ba + (reg), value)
#define snd_hdac_adsp_readb(chip, reg) \
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index ebb8e7a7fc29..77495e5988c1 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -341,31 +341,27 @@ struct soc_enum;
#define SND_SOC_DAPM_STREAM_STOP 0x2
#define SND_SOC_DAPM_STREAM_SUSPEND 0x4
#define SND_SOC_DAPM_STREAM_RESUME 0x8
-#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
+#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20
/* dapm event types */
-#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
-#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
-#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
-#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
-#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
-#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
-#define SND_SOC_DAPM_WILL_PMU 0x40 /* called at start of sequence */
-#define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */
-#define SND_SOC_DAPM_PRE_POST_PMD \
- (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
-#define SND_SOC_DAPM_PRE_POST_PMU \
- (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
+#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
+#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
+#define SND_SOC_DAPM_WILL_PMU 0x40 /* called at start of sequence */
+#define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */
+#define SND_SOC_DAPM_PRE_POST_PMD (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
+#define SND_SOC_DAPM_PRE_POST_PMU (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
/* convenience event type detection */
-#define SND_SOC_DAPM_EVENT_ON(e) \
- (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
-#define SND_SOC_DAPM_EVENT_OFF(e) \
- (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
+#define SND_SOC_DAPM_EVENT_ON(e) (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
+#define SND_SOC_DAPM_EVENT_OFF(e) (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
/* regulator widget flags */
-#define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */
+#define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */
struct snd_soc_dapm_widget;
enum snd_soc_dapm_type;
@@ -396,18 +392,13 @@ enum snd_soc_bias_level {
SND_SOC_BIAS_ON = 3,
};
-int dapm_regulator_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
-int dapm_clock_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
-int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
+int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
+int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
+int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
/* dapm controls */
-int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
@@ -419,30 +410,24 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uncontrol);
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_widget *widget,
- int num);
-struct snd_soc_dapm_widget *snd_soc_dapm_new_control(
- struct snd_soc_dapm_context *dapm,
+ const struct snd_soc_dapm_widget *widget, int num);
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget);
-struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(
- struct snd_soc_dapm_context *dapm,
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget);
-int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dai *dai);
+int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai);
void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai);
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
- struct snd_soc_card *card,
- struct snd_soc_component *component);
+ struct snd_soc_card *card, struct snd_soc_component *component);
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
@@ -450,49 +435,36 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
-void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm);
/* dapm events */
-void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
- int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event);
void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream);
void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* external DAPM widget events */
int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
- struct snd_kcontrol *kcontrol, int connect,
- struct snd_soc_dapm_update *update);
+ struct snd_kcontrol *kcontrol, int connect, struct snd_soc_dapm_update *update);
int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
struct snd_soc_dapm_update *update);
/* dapm sys fs - used by the core */
extern struct attribute *soc_dapm_dev_attrs[];
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
- struct dentry *parent);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent);
/* dapm audio pin control and status */
-int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
+int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
-int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
- const char *pin);
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
-int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin);
-int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
- const char *pin);
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin);
unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
/* Mostly internal - should not normally be used */
@@ -501,40 +473,35 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
/* dapm path query */
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_widget_list **list,
- bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
- enum snd_soc_dapm_direction));
+ bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction));
void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list);
-struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
- struct snd_kcontrol *kcontrol);
-
-struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
- struct snd_kcontrol *kcontrol);
+struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol);
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol);
-int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level);
+int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level);
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
- snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
- snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
- snd_soc_dapm_mixer, /* mixes several analog signals together */
- snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
- snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
- snd_soc_dapm_out_drv, /* output driver */
- snd_soc_dapm_adc, /* analog to digital converter */
- snd_soc_dapm_dac, /* digital to analog converter */
+ snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
+ snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
+ snd_soc_dapm_mixer, /* mixes several analog signals together */
+ snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
+ snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
+ snd_soc_dapm_out_drv, /* output driver */
+ snd_soc_dapm_adc, /* analog to digital converter */
+ snd_soc_dapm_dac, /* digital to analog converter */
snd_soc_dapm_micbias, /* microphone bias (power) - DEPRECATED: use snd_soc_dapm_supply */
- snd_soc_dapm_mic, /* microphone */
- snd_soc_dapm_hp, /* headphones */
- snd_soc_dapm_spk, /* speaker */
- snd_soc_dapm_line, /* line input/output */
+ snd_soc_dapm_mic, /* microphone */
+ snd_soc_dapm_hp, /* headphones */
+ snd_soc_dapm_spk, /* speaker */
+ snd_soc_dapm_line, /* line input/output */
snd_soc_dapm_switch, /* analog switch */
- snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
- snd_soc_dapm_pre, /* machine specific pre widget - exec first */
- snd_soc_dapm_post, /* machine specific post widget - exec last */
+ snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
+ snd_soc_dapm_pre, /* machine specific pre widget - exec first */
+ snd_soc_dapm_post, /* machine specific post widget - exec last */
snd_soc_dapm_supply, /* power/clock supply */
snd_soc_dapm_pinctrl, /* pinctrl */
snd_soc_dapm_regulator_supply, /* external regulator */
@@ -600,9 +567,9 @@ struct snd_soc_dapm_path {
};
/* status */
- u32 connect:1; /* source and sink widgets are connected */
- u32 walking:1; /* path is in the process of being walked */
- u32 weak:1; /* path ignored for power management */
+ u32 connect:1; /* source and sink widgets are connected */
+ u32 walking:1; /* path is in the process of being walked */
+ u32 weak:1; /* path ignored for power management */
u32 is_supply:1; /* At least one of the connected widgets is a supply */
int (*connected)(struct snd_soc_dapm_widget *source,
@@ -616,8 +583,8 @@ struct snd_soc_dapm_path {
/* dapm widget */
struct snd_soc_dapm_widget {
enum snd_soc_dapm_type id;
- const char *name; /* widget name */
- const char *sname; /* stream name */
+ const char *name; /* widget name */
+ const char *sname; /* stream name */
struct list_head list;
struct snd_soc_dapm_context *dapm;
@@ -636,7 +603,7 @@ struct snd_soc_dapm_widget {
unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */
unsigned char force:1; /* force state */
- unsigned char ignore_suspend:1; /* kept enabled over suspend */
+ unsigned char ignore_suspend:1; /* kept enabled over suspend */
unsigned char new_power:1; /* power from this run */
unsigned char power_checked:1; /* power checked this run */
unsigned char is_supply:1; /* Widget is a supply type widget */
@@ -680,27 +647,24 @@ struct snd_soc_dapm_update {
bool has_second_set;
};
-struct snd_soc_dapm_wcache {
- struct snd_soc_dapm_widget *widget;
-};
-
/* DAPM context */
struct snd_soc_dapm_context {
enum snd_soc_bias_level bias_level;
- unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
- /* Go to BIAS_OFF in suspend if the DAPM context is idle */
- unsigned int suspend_bias_off:1;
- struct device *dev; /* from parent - for debug */
- struct snd_soc_component *component; /* parent component */
- struct snd_soc_card *card; /* parent card */
+ /* bit field */
+ unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+ unsigned int suspend_bias_off:1; /* Use BIAS_OFF in suspend if the DAPM is idle */
+
+ struct device *dev; /* from parent - for debug */
+ struct snd_soc_component *component; /* parent component */
+ struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */
enum snd_soc_bias_level target_bias_level;
struct list_head list;
- struct snd_soc_dapm_wcache path_sink_cache;
- struct snd_soc_dapm_wcache path_source_cache;
+ struct snd_soc_dapm_widget *wcache_sink;
+ struct snd_soc_dapm_widget *wcache_source;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dapm;
@@ -767,11 +731,11 @@ enum snd_soc_dapm_direction {
#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x)
-#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
-#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
+#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
+#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
/**
- * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
+ * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the
* specified direction of a widget
* @w: The widget
* @dir: Whether to iterate over the paths where the specified widget is the
@@ -782,7 +746,7 @@ enum snd_soc_dapm_direction {
list_for_each_entry(p, &w->edges[dir], list_node[dir])
/**
- * snd_soc_dapm_widget_for_each_sink_path_safe - Iterates over all paths in the
+ * snd_soc_dapm_widget_for_each_path_safe - Iterates over all paths in the
* specified direction of a widget
* @w: The widget
* @dir: Whether to iterate over the paths where the specified widget is the
@@ -790,7 +754,7 @@ enum snd_soc_dapm_direction {
* @p: The path iterator variable
* @next_p: Temporary storage for the next path
*
- * This function works like snd_soc_dapm_widget_for_each_sink_path, expect that
+ * This function works like snd_soc_dapm_widget_for_each_path, expect that
* it is safe to remove the current path from the list while iterating
*/
#define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
index 5b689c663290..2864aed72998 100644
--- a/include/sound/soc-dpcm.h
+++ b/include/sound/soc-dpcm.h
@@ -78,8 +78,6 @@ struct snd_soc_dpcm {
struct list_head list_be;
struct list_head list_fe;
- /* hw params for this link - may be different for each link */
- struct snd_pcm_hw_params hw_params;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_state;
#endif
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 80876b9a87f4..6199bb60ccf0 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -108,50 +108,48 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
/**
- * snd_hdac_link_free_all- free hdac extended link objects
+ * snd_hdac_ext_link_free_all- free hdac extended link objects
*
* @bus: the pointer to HDAC bus object
*/
-void snd_hdac_link_free_all(struct hdac_bus *bus)
+void snd_hdac_ext_link_free_all(struct hdac_bus *bus)
{
- struct hdac_ext_link *l;
+ struct hdac_ext_link *hlink;
while (!list_empty(&bus->hlink_list)) {
- l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
- list_del(&l->list);
- kfree(l);
+ hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
+ list_del(&hlink->list);
+ kfree(hlink);
}
}
-EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all);
/**
- * snd_hdac_ext_bus_link_at - get link at specified address
- * @bus: link's parent bus device
+ * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address
+ * @bus: hlink's parent bus device
* @addr: codec device address
*
- * Returns link object or NULL if matching link is not found.
+ * Returns hlink object or NULL if matching hlink is not found.
*/
-struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr)
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr)
{
struct hdac_ext_link *hlink;
- int i;
list_for_each_entry(hlink, &bus->hlink_list, list)
- for (i = 0; i < HDA_MAX_CODECS; i++)
- if (hlink->lsdiid & (0x1 << addr))
- return hlink;
+ if (hlink->lsdiid & (0x1 << addr))
+ return hlink;
return NULL;
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_addr);
/**
- * snd_hdac_ext_bus_get_link - get link based on codec name
+ * snd_hdac_ext_bus_get_hlink_by_name - get hlink based on codec name
* @bus: the pointer to HDAC bus object
* @codec_name: codec name
*/
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
- const char *codec_name)
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus,
+ const char *codec_name)
{
int bus_idx, addr;
@@ -162,11 +160,11 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
if (addr < 0 || addr > 31)
return NULL;
- return snd_hdac_ext_bus_link_at(bus, addr);
+ return snd_hdac_ext_bus_get_hlink_by_addr(bus, addr);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_name);
-static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
+static int check_hdac_link_power_active(struct hdac_ext_link *hlink, bool enable)
{
int timeout;
u32 val;
@@ -176,7 +174,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
timeout = 150;
do {
- val = readl(link->ml_addr + AZX_REG_ML_LCTL);
+ val = readl(hlink->ml_addr + AZX_REG_ML_LCTL);
if (enable) {
if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT))
return 0;
@@ -192,26 +190,26 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
/**
* snd_hdac_ext_bus_link_power_up -power up hda link
- * @link: HD-audio extended link
+ * @hlink: HD-audio extended link
*/
-int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
+int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink)
{
- snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
+ snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
- return check_hdac_link_power_active(link, true);
+ return check_hdac_link_power_active(hlink, true);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up);
/**
* snd_hdac_ext_bus_link_power_down -power down hda link
- * @link: HD-audio extended link
+ * @hlink: HD-audio extended link
*/
-int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
+int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink)
{
- snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
+ snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
- return check_hdac_link_power_active(link, false);
+ return check_hdac_link_power_active(hlink, false);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
@@ -225,9 +223,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
int ret;
list_for_each_entry(hlink, &bus->hlink_list, list) {
- snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
- AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
- ret = check_hdac_link_power_active(hlink, true);
+ ret = snd_hdac_ext_bus_link_power_up(hlink);
if (ret < 0)
return ret;
}
@@ -246,9 +242,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
int ret;
list_for_each_entry(hlink, &bus->hlink_list, list) {
- snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
- AZX_ML_LCTL_SPA, 0);
- ret = check_hdac_link_power_active(hlink, false);
+ ret = snd_hdac_ext_bus_link_power_down(hlink);
if (ret < 0)
return ret;
}
@@ -257,8 +251,32 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
+/**
+ * snd_hdac_ext_bus_link_set_stream_id - maps stream id to link output
+ * @link: HD-audio ext link to set up
+ * @stream: stream id
+ */
+void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *link,
+ int stream)
+{
+ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_set_stream_id);
+
+/**
+ * snd_hdac_ext_bus_link_clear_stream_id - maps stream id to link output
+ * @link: HD-audio ext link to set up
+ * @stream: stream id
+ */
+void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *link,
+ int stream)
+{
+ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_clear_stream_id);
+
int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
- struct hdac_ext_link *link)
+ struct hdac_ext_link *hlink)
{
unsigned long codec_mask;
int ret = 0;
@@ -269,18 +287,18 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
* if we move from 0 to 1, count will be 1 so power up this link
* as well, also check the dma status and trigger that
*/
- if (++link->ref_count == 1) {
+ if (++hlink->ref_count == 1) {
if (!bus->cmd_dma_state) {
snd_hdac_bus_init_cmd_io(bus);
bus->cmd_dma_state = true;
}
- ret = snd_hdac_ext_bus_link_power_up(link);
+ ret = snd_hdac_ext_bus_link_power_up(hlink);
/*
* clear the register to invalidate all the output streams
*/
- snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV,
+ snd_hdac_updatew(hlink->ml_addr, AZX_REG_ML_LOSIDV,
AZX_ML_LOSIDV_STREAM_MASK, 0);
/*
* wait for 521usec for codec to report status
@@ -300,10 +318,10 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
- struct hdac_ext_link *link)
+ struct hdac_ext_link *hlink)
{
int ret = 0;
- struct hdac_ext_link *hlink;
+ struct hdac_ext_link *hlink_tmp;
bool link_up = false;
mutex_lock(&bus->lock);
@@ -312,15 +330,15 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
* if we move from 1 to 0, count will be 0
* so power down this link as well
*/
- if (--link->ref_count == 0) {
- ret = snd_hdac_ext_bus_link_power_down(link);
+ if (--hlink->ref_count == 0) {
+ ret = snd_hdac_ext_bus_link_power_down(hlink);
/*
* now check if all links are off, if so turn off
* cmd dma as well
*/
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (hlink->ref_count) {
+ list_for_each_entry(hlink_tmp, &bus->hlink_list, list) {
+ if (hlink_tmp->ref_count) {
link_up = true;
break;
}
@@ -341,7 +359,7 @@ static void hdac_ext_codec_link_up(struct hdac_device *codec)
{
const char *devname = dev_name(&codec->dev);
struct hdac_ext_link *hlink =
- snd_hdac_ext_bus_get_link(codec->bus, devname);
+ snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname);
if (hlink)
snd_hdac_ext_bus_link_get(codec->bus, hlink);
@@ -351,7 +369,7 @@ static void hdac_ext_codec_link_down(struct hdac_device *codec)
{
const char *devname = dev_name(&codec->dev);
struct hdac_ext_link *hlink =
- snd_hdac_ext_bus_get_link(codec->bus, devname);
+ snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname);
if (hlink)
snd_hdac_ext_bus_link_put(codec->bus, hlink);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 70f3ad71aaf0..2a071a09224d 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -39,20 +39,6 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
AZX_PPLC_INTERVAL * idx;
}
- if (bus->spbcap) {
- hext_stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
- AZX_SPB_INTERVAL * idx +
- AZX_SPB_SPIB;
-
- hext_stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
- AZX_SPB_INTERVAL * idx +
- AZX_SPB_MAXFIFO;
- }
-
- if (bus->drsmcap)
- hext_stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
- AZX_DRSM_INTERVAL * idx;
-
hext_stream->decoupled = false;
snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag);
}
@@ -140,36 +126,36 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
/**
- * snd_hdac_ext_link_stream_start - start a stream
+ * snd_hdac_ext_stream_start - start a stream
* @hext_stream: HD-audio ext core stream to start
*/
-void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream)
{
snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_start);
/**
- * snd_hdac_ext_link_stream_clear - stop a stream DMA
+ * snd_hdac_ext_stream_clear - stop a stream DMA
* @hext_stream: HD-audio ext core stream to stop
*/
-void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream)
{
snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_clear);
/**
- * snd_hdac_ext_link_stream_reset - reset a stream
+ * snd_hdac_ext_stream_reset - reset a stream
* @hext_stream: HD-audio ext core stream to reset
*/
-void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream)
{
unsigned char val;
int timeout;
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST);
@@ -196,20 +182,20 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
} while (--timeout);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_reset);
/**
- * snd_hdac_ext_link_stream_setup - set up the SD for streaming
+ * snd_hdac_ext_stream_setup - set up the SD for streaming
* @hext_stream: HD-audio ext core stream to set up
* @fmt: stream format
*/
-int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
+int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
{
struct hdac_stream *hstream = &hext_stream->hstream;
unsigned int val;
/* make sure the run bit is zero for SD */
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
/* program the stream_tag */
val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL);
val = (val & ~AZX_PPLCCTL_STRM_MASK) |
@@ -221,35 +207,11 @@ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
return 0;
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup);
-
-/**
- * snd_hdac_ext_link_set_stream_id - maps stream id to link output
- * @link: HD-audio ext link to set up
- * @stream: stream id
- */
-void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
- int stream)
-{
- snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id);
-
-/**
- * snd_hdac_ext_link_clear_stream_id - maps stream id to link output
- * @link: HD-audio ext link to set up
- * @stream: stream id
- */
-void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
- int stream)
-{
- snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_setup);
static struct hdac_ext_stream *
-hdac_ext_link_stream_assign(struct hdac_bus *bus,
- struct snd_pcm_substream *substream)
+hdac_ext_link_dma_stream_assign(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
@@ -284,8 +246,8 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus,
}
static struct hdac_ext_stream *
-hdac_ext_host_stream_assign(struct hdac_bus *bus,
- struct snd_pcm_substream *substream)
+hdac_ext_host_dma_stream_assign(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
@@ -353,10 +315,10 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
return hext_stream;
case HDAC_EXT_STREAM_TYPE_HOST:
- return hdac_ext_host_stream_assign(bus, substream);
+ return hdac_ext_host_dma_stream_assign(bus, substream);
case HDAC_EXT_STREAM_TYPE_LINK:
- return hdac_ext_link_stream_assign(bus, substream);
+ return hdac_ext_link_dma_stream_assign(bus, substream);
default:
return NULL;
@@ -405,128 +367,3 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
-
-/**
- * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
- * @bus: HD-audio core bus
- * @enable: flag to enable/disable SPIB
- * @index: stream index for which SPIB need to be enabled
- */
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
- bool enable, int index)
-{
- u32 mask = 0;
-
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return;
- }
-
- mask |= (1 << index);
-
- if (enable)
- snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask);
- else
- snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
-
-/**
- * snd_hdac_ext_stream_set_spib - sets the spib value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- * @value: spib value to set
- */
-int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value)
-{
-
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return -EINVAL;
- }
-
- writel(value, hext_stream->spib_addr);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
-
-/**
- * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- *
- * Return maxfifo for the stream
- */
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream)
-{
-
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return -EINVAL;
- }
-
- return readl(hext_stream->fifo_addr);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
-
-/**
- * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
- * @bus: HD-audio core bus
- * @enable: flag to enable/disable DRSM
- * @index: stream index for which DRSM need to be enabled
- */
-void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
- bool enable, int index)
-{
- u32 mask = 0;
-
- if (!bus->drsmcap) {
- dev_err(bus->dev, "Address of DRSM capability is NULL\n");
- return;
- }
-
- mask |= (1 << index);
-
- if (enable)
- snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
- else
- snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
-
-/**
- * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- * @value: dpib value to set
- */
-int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream, u32 value)
-{
-
- if (!bus->drsmcap) {
- dev_err(bus->dev, "Address of DRSM capability is NULL\n");
- return -EINVAL;
- }
-
- writel(value, hext_stream->dpibr_addr);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
-
-/**
- * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
- * @hext_stream: hdac_ext_stream
- * @value: lpib value to set
- */
-int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value)
-{
- snd_hdac_stream_writel(&hext_stream->hstream, SD_LPIB, value);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index 1b8be39c38a9..35fe2bd582ac 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -103,6 +103,20 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
azx_dev->stream_tag = tag;
snd_hdac_dsp_lock_init(azx_dev);
list_add_tail(&azx_dev->list, &bus->stream_list);
+
+ if (bus->spbcap) {
+ azx_dev->spib_addr = bus->spbcap + AZX_SPB_BASE +
+ AZX_SPB_INTERVAL * idx +
+ AZX_SPB_SPIB;
+
+ azx_dev->fifo_addr = bus->spbcap + AZX_SPB_BASE +
+ AZX_SPB_INTERVAL * idx +
+ AZX_SPB_MAXFIFO;
+ }
+
+ if (bus->drsmcap)
+ azx_dev->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
+ AZX_DRSM_INTERVAL * idx;
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_init);
@@ -718,6 +732,128 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_sync);
+/**
+ * snd_hdac_stream_spbcap_enable - enable SPIB for a stream
+ * @bus: HD-audio core bus
+ * @enable: flag to enable/disable SPIB
+ * @index: stream index for which SPIB need to be enabled
+ */
+void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus,
+ bool enable, int index)
+{
+ u32 mask = 0;
+
+ if (!bus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL\n");
+ return;
+ }
+
+ mask |= (1 << index);
+
+ if (enable)
+ snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask);
+ else
+ snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_spbcap_enable);
+
+/**
+ * snd_hdac_stream_set_spib - sets the spib value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ * @value: spib value to set
+ */
+int snd_hdac_stream_set_spib(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value)
+{
+ if (!bus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL\n");
+ return -EINVAL;
+ }
+
+ writel(value, azx_dev->spib_addr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib);
+
+/**
+ * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ *
+ * Return maxfifo for the stream
+ */
+int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev)
+{
+ if (!bus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL\n");
+ return -EINVAL;
+ }
+
+ return readl(azx_dev->fifo_addr);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo);
+
+/**
+ * snd_hdac_stream_drsm_enable - enable DMA resume for a stream
+ * @bus: HD-audio core bus
+ * @enable: flag to enable/disable DRSM
+ * @index: stream index for which DRSM need to be enabled
+ */
+void snd_hdac_stream_drsm_enable(struct hdac_bus *bus,
+ bool enable, int index)
+{
+ u32 mask = 0;
+
+ if (!bus->drsmcap) {
+ dev_err(bus->dev, "Address of DRSM capability is NULL\n");
+ return;
+ }
+
+ mask |= (1 << index);
+
+ if (enable)
+ snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
+ else
+ snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_drsm_enable);
+
+/**
+ * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ * @value: dpib value to set
+ */
+int snd_hdac_stream_set_dpibr(struct hdac_bus *bus,
+ struct hdac_stream *azx_dev, u32 value)
+{
+ if (!bus->drsmcap) {
+ dev_err(bus->dev, "Address of DRSM capability is NULL\n");
+ return -EINVAL;
+ }
+
+ writel(value, azx_dev->dpibr_addr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_dpibr);
+
+/**
+ * snd_hdac_stream_set_lpib - sets the lpib value of a stream
+ * @azx_dev: hdac_stream
+ * @value: lpib value to set
+ */
+int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value)
+{
+ snd_hdac_stream_writel(azx_dev, SD_LPIB, value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_lpib);
+
#ifdef CONFIG_SND_HDA_DSP_LOADER
/**
* snd_hdac_dsp_prepare - prepare for DSP loading
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index ac416572db0d..09b6511c0a26 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -51,7 +51,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
struct acp_stream *stream;
- int slot_len;
+ int slot_len, no_of_slots;
switch (slot_width) {
case SLOT_WIDTH_8:
@@ -71,6 +71,20 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
return -EINVAL;
}
+ switch (slots) {
+ case 1 ... 7:
+ no_of_slots = slots;
+ break;
+ case 8:
+ no_of_slots = 0;
+ break;
+ default:
+ dev_err(dev, "Unsupported slots %d\n", slots);
+ return -EINVAL;
+ }
+
+ slots = no_of_slots;
+
spin_lock_irq(&adata->acp_lock);
list_for_each_entry(stream, &adata->stream_list, list) {
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 4c69cb6e3400..a78cf29387a7 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -167,11 +167,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- if (!drvdata->soc_mclk) {
- ret = acp_clk_enable(drvdata);
- if (ret < 0) {
- dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
- return ret;
+
+ if (strcmp(codec_dai->name, "rt5682s-aif1") && strcmp(codec_dai->name, "rt5682s-aif2")) {
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+ return ret;
+ }
}
}
@@ -280,7 +283,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
static const struct snd_soc_ops acp_card_rt5682s_ops = {
.startup = acp_card_hs_startup,
- .shutdown = acp_card_shutdown,
};
static const unsigned int dmic_channels[] = {
@@ -570,6 +572,52 @@ SND_SOC_DAILINK_DEF(sof_dmic,
SND_SOC_DAILINK_DEF(pdm_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-pdm-dmic")));
+static int acp_rtk_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
+ enum snd_soc_bias_level level)
+{
+ struct snd_soc_component *component = dapm->component;
+ struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret = 0;
+
+ if (!component)
+ return 0;
+
+ if (strncmp(component->name, "i2c-RTL5682", 11) &&
+ strncmp(component->name, "i2c-10EC1019", 12))
+ return 0;
+
+ /*
+ * For Realtek's codec and amplifier components,
+ * the lrck and bclk must be enabled brfore their all dapms be powered on,
+ * and must be disabled after their all dapms be powered down
+ * to avoid any pop.
+ */
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
+ clk_set_rate(drvdata->wclk, 48000);
+ clk_set_rate(drvdata->bclk, 48000 * 64);
+
+ /* Increase bclk's enable_count */
+ ret = clk_prepare_enable(drvdata->bclk);
+ if (ret < 0)
+ dev_err(component->dev, "Failed to enable bclk %d\n", ret);
+ } else {
+ /*
+ * Decrease bclk's enable_count.
+ * While the enable_count is 0, the bclk would be closed.
+ */
+ clk_disable_unprepare(drvdata->bclk);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
{
struct snd_soc_dai_link *links;
@@ -730,6 +778,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
card->dai_link = links;
card->num_links = num_links;
+ card->set_bias_level = acp_rtk_set_bias_level;
return 0;
}
@@ -907,6 +956,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
card->dai_link = links;
card->num_links = num_links;
+ card->set_bias_level = acp_rtk_set_bias_level;
return 0;
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7022e6286e6c..7a13e750751a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1930,7 +1930,7 @@ config SND_SOC_WM8960
depends on I2C
config SND_SOC_WM8961
- tristate
+ tristate "Wolfson Microelectronics WM8961 CODEC"
depends on I2C
config SND_SOC_WM8962
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 1db73552c746..8c69c8cf9b67 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -13,6 +13,7 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
@@ -46,6 +47,7 @@ struct ak4458_priv {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpiod;
+ struct reset_control *reset;
struct gpio_desc *mute_gpiod;
int digfil; /* SSLOW, SD, SLOW bits */
int fs; /* sampling rate */
@@ -633,6 +635,12 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
if (ak4458->reset_gpiod) {
gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
usleep_range(1000, 2000);
+ } else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+ if (active)
+ reset_control_assert(ak4458->reset);
+ else
+ reset_control_deassert(ak4458->reset);
+ usleep_range(1000, 2000);
}
}
@@ -668,7 +676,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
- ak4458_reset(ak4458, true);
ak4458_reset(ak4458, false);
regcache_cache_only(ak4458->regmap, false);
@@ -748,6 +755,10 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
ak4458->drvdata = of_device_get_match_data(&i2c->dev);
+ ak4458->reset = devm_reset_control_get_optional_shared(ak4458->dev, NULL);
+ if (IS_ERR(ak4458->reset))
+ return PTR_ERR(ak4458->reset);
+
ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(ak4458->reset_gpiod))
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index 31ae752e242f..a078dd422ea1 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -918,8 +918,8 @@ static int cs35l36_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
fs1 = CS35L36_FS1_DEFAULT_VAL;
fs2 = CS35L36_FS2_DEFAULT_VAL;
} else {
- fs1 = 3 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
- fs2 = 5 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
+ fs1 = 3 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
+ fs2 = 5 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
}
regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL,
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index f90d43996a51..37629ebd90e0 100644
--- a/sound/soc/codecs/cs42l83-i2c.c
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -145,7 +145,7 @@ static const struct reg_default cs42l83_reg_defaults[] = {
* This is all the same as for CS42L42 but we
* replace the on-reset register defaults.
*/
-const struct regmap_config cs42l83_regmap = {
+static const struct regmap_config cs42l83_regmap = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index 61e8e9be6b8d..4b8ec6f77337 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -130,10 +130,8 @@ static void hda_codec_unregister_dais(struct hda_codec *codec,
if (strcmp(dai->driver->name, pcm->name))
continue;
- if (dai->playback_widget)
- snd_soc_dapm_free_widget(dai->playback_widget);
- if (dai->capture_widget)
- snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ snd_soc_dapm_free_widget(dai->capture_widget);
snd_soc_unregister_dai(dai);
break;
}
@@ -181,7 +179,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
!pm_runtime_status_suspended(&hdev->dev));
#endif
- hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -213,7 +211,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
patch = (hda_codec_patch_t)codec->preset->driver_data;
if (!patch) {
- dev_err(&hdev->dev, "no patch specified?\n");
+ dev_err(&hdev->dev, "no patch specified\n");
ret = -EINVAL;
goto err;
}
@@ -289,7 +287,7 @@ static void hda_codec_remove(struct snd_soc_component *component)
if (hda_codec_is_display(codec))
snd_hdac_display_power(bus, hdev->addr, false);
- hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
if (hlink)
snd_hdac_ext_bus_link_put(bus, hlink);
/*
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 8af434e14bfb..be66853afbe2 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -400,7 +400,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
hda_codec_patch_t patch;
int ret;
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -516,7 +516,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
struct hda_codec *codec = hda_pvt->codec;
struct hdac_ext_link *hlink = NULL;
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return;
@@ -584,7 +584,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
int ret;
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index cb23650ad522..ed4f7cdda04f 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1967,7 +1967,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
* hold the ref while we probe, also no need to drop the ref on
* exit, we call pm_runtime_suspend() so that will do for us
*/
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -2144,7 +2144,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -2244,7 +2244,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D3);
- hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
@@ -2270,7 +2270,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
if (!bus)
return 0;
- hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c
index 71ea576f7e67..39cebaa167be 100644
--- a/sound/soc/codecs/jz4725b.c
+++ b/sound/soc/codecs/jz4725b.c
@@ -136,6 +136,24 @@ enum {
#define REG_CGR3_GO1L_OFFSET 0
#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET)
+#define REG_CGR4_GO2R_OFFSET 0
+#define REG_CGR4_GO2R_MASK (0x1f << REG_CGR4_GO2R_OFFSET)
+
+#define REG_CGR5_GO2L_OFFSET 0
+#define REG_CGR5_GO2L_MASK (0x1f << REG_CGR5_GO2L_OFFSET)
+
+#define REG_CGR6_GO3R_OFFSET 0
+#define REG_CGR6_GO3R_MASK (0x1f << REG_CGR6_GO3R_OFFSET)
+
+#define REG_CGR7_GO3L_OFFSET 0
+#define REG_CGR7_GO3L_MASK (0x1f << REG_CGR7_GO3L_OFFSET)
+
+#define REG_CGR8_GOR_OFFSET 0
+#define REG_CGR8_GOR_MASK (0x1f << REG_CGR8_GOR_OFFSET)
+
+#define REG_CGR9_GOL_OFFSET 0
+#define REG_CGR9_GOL_MASK (0x1f << REG_CGR9_GOL_OFFSET)
+
#define REG_CGR10_GIL_OFFSET 0
#define REG_CGR10_GIR_OFFSET 4
@@ -147,9 +165,28 @@ struct jz_icdc {
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv,
+ 0, 11, TLV_DB_SCALE_ITEM(-2250, 0, 0),
+ 12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0),
+);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv,
+ 0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0),
+ 12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0),
+ 24, 31, TLV_DB_SCALE_ITEM( 100, 50, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0);
+
+static const char * const jz4725b_mic_mode_texts[] = {
+ "Single Ended", "Differential",
+};
+
+static const struct soc_enum jz4725b_mic_mode_enum =
+ SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET,
+ 2, jz4725b_mic_mode_texts);
static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
- SOC_DOUBLE_TLV("Master Playback Volume",
+ SOC_DOUBLE_TLV("DAC Playback Volume",
JZ4725B_CODEC_REG_CGR1,
REG_CGR1_GODL_OFFSET,
REG_CGR1_GODR_OFFSET,
@@ -159,8 +196,29 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
REG_CGR10_GIL_OFFSET,
REG_CGR10_GIR_OFFSET,
0xf, 0, jz4725b_adc_tlv),
-
- SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
+ SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR3,
+ JZ4725B_CODEC_REG_CGR2,
+ REG_CGR2_GO1R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR5,
+ JZ4725B_CODEC_REG_CGR4,
+ REG_CGR4_GO2R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR7,
+ JZ4725B_CODEC_REG_CGR6,
+ REG_CGR6_GO3R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+
+ SOC_DOUBLE_R_TLV("Master Playback Volume",
+ JZ4725B_CODEC_REG_CGR9,
+ JZ4725B_CODEC_REG_CGR8,
+ REG_CGR8_GOR_OFFSET,
+ 0x1f, 1, jz4725b_out_tlv),
+
+ SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1,
REG_CR1_DAC_MUTE_OFFSET, 1, 1),
SOC_SINGLE("Deemphasize Filter Playback Switch",
@@ -170,6 +228,13 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
SOC_SINGLE("High-Pass Filter Capture Switch",
JZ4725B_CODEC_REG_CR2,
REG_CR2_ADC_HPF_OFFSET, 1, 0),
+
+ SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum),
+
+ SOC_SINGLE_TLV("Mic1 Boost Capture Volume",
+ JZ4725B_CODEC_REG_PMR2,
+ REG_PMR2_GIM_OFFSET,
+ 1, 0, jz4725b_mic_boost_tlv),
};
static const char * const jz4725b_codec_adc_src_texts[] = {
@@ -186,8 +251,12 @@ static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum);
static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
+ SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1,
REG_CR1_BYPASS_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+ REG_CR3_SIDETONE1_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+ REG_CR3_SIDETONE2_OFFSET, 1, 0),
};
static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
@@ -282,7 +351,9 @@ static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
{"Line In", NULL, "LLINEIN"},
{"Line In", NULL, "RLINEIN"},
- {"Mixer", "Line In Bypass", "Line In"},
+ {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"},
+ {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"},
+ {"Mixer", "Line In Bypass Playback Switch", "Line In"},
{"DAC to Mixer", NULL, "DAC"},
{"Mixer", NULL, "DAC to Mixer"},
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index a2ce52dafea8..cea26f3a02b6 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1166,6 +1166,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
}
},
+ {
+ .ident = "Intel Kabylake R RVP",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
+ }
+ },
{ }
};
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index e48768233e20..9c50ac356c89 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -700,8 +700,10 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
struct twl4030_board_params *board_params = twl4030->board_params;
/* Base values for ramp delay calculation: 2^19 - 2^26 */
- unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
- 8388608, 16777216, 33554432, 67108864};
+ static const unsigned int ramp_base[] = {
+ 524288, 1048576, 2097152, 4194304,
+ 8388608, 16777216, 33554432, 67108864
+ };
unsigned int delay;
hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 7dc6aaf65576..a4857024711d 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -971,9 +971,16 @@ static const struct i2c_device_id wm8961_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
+static const struct of_device_id wm8961_of_match[] __maybe_unused = {
+ { .compatible = "wlf,wm8961", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8961_of_match);
+
static struct i2c_driver wm8961_i2c_driver = {
.driver = {
.name = "wm8961",
+ .of_match_table = of_match_ptr(wm8961_of_match),
},
.probe_new = wm8961_i2c_probe,
.id_table = wm8961_i2c_id,
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index a682f8020eb6..aa2f55401a88 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -498,7 +498,7 @@ static int wm8978_configure_pll(struct snd_soc_component *component)
if (4 * f_opclk < 3 * f_mclk)
/* Have to use OPCLKDIV */
- opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
+ opclk_div = DIV_ROUND_UP(3 * f_mclk / 4, f_opclk);
else
opclk_div = 1;
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 79ef4e269bc9..eeaa75fb9196 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -47,11 +47,15 @@ struct fsl_micfil {
struct clk *pll11k_clk;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct sdma_peripheral_config sdmacfg;
+ struct snd_soc_card *card;
unsigned int dataline;
char name[32];
int irq[MICFIL_IRQ_LINES];
enum quality quality;
int dc_remover;
+ int vad_init_mode;
+ int vad_enabled;
+ int vad_detected;
};
struct fsl_micfil_soc_data {
@@ -152,6 +156,152 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol,
return micfil_set_quality(micfil);
}
+static const char * const micfil_hwvad_enable[] = {
+ "Disable (Record only)",
+ "Enable (Record with Vad)",
+};
+
+static const char * const micfil_hwvad_init_mode[] = {
+ "Envelope mode", "Energy mode",
+};
+
+static const char * const micfil_hwvad_hpf_texts[] = {
+ "Filter bypass",
+ "Cut-off @1750Hz",
+ "Cut-off @215Hz",
+ "Cut-off @102Hz",
+};
+
+/*
+ * DC Remover Control
+ * Filter Bypassed 1 1
+ * Cut-off @21Hz 0 0
+ * Cut-off @83Hz 0 1
+ * Cut-off @152HZ 1 0
+ */
+static const char * const micfil_dc_remover_texts[] = {
+ "Cut-off @21Hz", "Cut-off @83Hz",
+ "Cut-off @152Hz", "Bypass",
+};
+
+static const struct soc_enum hwvad_enable_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_enable),
+ micfil_hwvad_enable);
+static const struct soc_enum hwvad_init_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_init_mode),
+ micfil_hwvad_init_mode);
+static const struct soc_enum hwvad_hpf_enum =
+ SOC_ENUM_SINGLE(REG_MICFIL_VAD0_CTRL2, 0,
+ ARRAY_SIZE(micfil_hwvad_hpf_texts),
+ micfil_hwvad_hpf_texts);
+static const struct soc_enum fsl_micfil_dc_remover_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_dc_remover_texts),
+ micfil_dc_remover_texts);
+
+static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+ unsigned int *item = ucontrol->value.enumerated.item;
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+ int i = 0, ret = 0;
+ u32 reg_val = 0;
+
+ if (val < 0 || val > 3)
+ return -EINVAL;
+
+ micfil->dc_remover = val;
+
+ /* Calculate total value for all channels */
+ for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++)
+ reg_val |= val << MICFIL_DC_CHX_SHIFT(i);
+
+ /* Update DC Remover mode for all channels */
+ ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL,
+ MICFIL_DC_CTRL_CONFIG, reg_val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->dc_remover;
+
+ return 0;
+}
+
+static int hwvad_put_enable(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+
+ micfil->vad_enabled = val;
+
+ return 0;
+}
+
+static int hwvad_get_enable(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->vad_enabled;
+
+ return 0;
+}
+
+static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+
+ /* 0 - Envelope-based Mode
+ * 1 - Energy-based Mode
+ */
+ micfil->vad_init_mode = val;
+
+ return 0;
+}
+
+static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->vad_init_mode;
+
+ return 0;
+}
+
+static int hwvad_detected(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+ ucontrol->value.enumerated.item[0] = micfil->vad_detected;
+
+ return 0;
+}
+
static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv),
@@ -172,6 +322,27 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_ENUM_EXT("MICFIL Quality Select",
fsl_micfil_quality_enum,
micfil_quality_get, micfil_quality_set),
+ SOC_ENUM_EXT("HWVAD Enablement Switch", hwvad_enable_enum,
+ hwvad_get_enable, hwvad_put_enable),
+ SOC_ENUM_EXT("HWVAD Initialization Mode", hwvad_init_mode_enum,
+ hwvad_get_init_mode, hwvad_put_init_mode),
+ SOC_ENUM("HWVAD High-Pass Filter", hwvad_hpf_enum),
+ SOC_SINGLE("HWVAD ZCD Switch", REG_MICFIL_VAD0_ZCD, 0, 1, 0),
+ SOC_SINGLE("HWVAD ZCD Auto Threshold Switch",
+ REG_MICFIL_VAD0_ZCD, 2, 1, 0),
+ SOC_ENUM_EXT("MICFIL DC Remover Control", fsl_micfil_dc_remover_enum,
+ micfil_get_dc_remover_state, micfil_put_dc_remover_state),
+ SOC_SINGLE("HWVAD Input Gain", REG_MICFIL_VAD0_CTRL2, 8, 15, 0),
+ SOC_SINGLE("HWVAD Sound Gain", REG_MICFIL_VAD0_SCONFIG, 0, 15, 0),
+ SOC_SINGLE("HWVAD Noise Gain", REG_MICFIL_VAD0_NCONFIG, 0, 15, 0),
+ SOC_SINGLE_RANGE("HWVAD Detector Frame Time", REG_MICFIL_VAD0_CTRL2, 16, 0, 63, 0),
+ SOC_SINGLE("HWVAD Detector Initialization Time", REG_MICFIL_VAD0_CTRL1, 8, 31, 0),
+ SOC_SINGLE("HWVAD Noise Filter Adjustment", REG_MICFIL_VAD0_NCONFIG, 8, 31, 0),
+ SOC_SINGLE("HWVAD ZCD Threshold", REG_MICFIL_VAD0_ZCD, 16, 1023, 0),
+ SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0),
+ SOC_SINGLE("HWVAD ZCD And Behavior Switch",
+ REG_MICFIL_VAD0_ZCD, 4, 1, 0),
+ SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
};
/* The SRES is a self-negated bit which provides the CPU with the
@@ -210,6 +381,167 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
return 0;
}
+/* Enable/disable hwvad interrupts */
+static int fsl_micfil_configure_hwvad_interrupts(struct fsl_micfil *micfil, int enable)
+{
+ u32 vadie_reg = enable ? MICFIL_VAD0_CTRL1_IE : 0;
+ u32 vaderie_reg = enable ? MICFIL_VAD0_CTRL1_ERIE : 0;
+
+ /* Voice Activity Detector Error Interruption */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_ERIE, vaderie_reg);
+
+ /* Voice Activity Detector Interruption */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_IE, vadie_reg);
+
+ return 0;
+}
+
+/* Configuration done only in energy-based initialization mode */
+static int fsl_micfil_init_hwvad_energy_mode(struct fsl_micfil *micfil)
+{
+ /* Keep the VADFRENDIS bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_FRENDIS);
+
+ /* Keep the VADPREFEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_PREFEN);
+
+ /* Keep the VADSFILEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SFILEN);
+
+ /* Keep the VADSMAXEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SMAXEN);
+
+ /* Keep the VADNFILAUTO bitfield asserted. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NFILAUT);
+
+ /* Keep the VADNMINEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NMINEN);
+
+ /* Keep the VADNDECEN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NDECEN);
+
+ /* Keep the VADNOREN bitfield cleared. */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NOREN);
+
+ return 0;
+}
+
+/* Configuration done only in envelope-based initialization mode */
+static int fsl_micfil_init_hwvad_envelope_mode(struct fsl_micfil *micfil)
+{
+ /* Assert the VADFRENDIS bitfield */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_FRENDIS);
+
+ /* Assert the VADPREFEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+ MICFIL_VAD0_CTRL2_PREFEN);
+
+ /* Assert the VADSFILEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SFILEN);
+
+ /* Assert the VADSMAXEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+ MICFIL_VAD0_SCONFIG_SMAXEN);
+
+ /* Clear the VADNFILAUTO bitfield */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NFILAUT);
+
+ /* Assert the VADNMINEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NMINEN);
+
+ /* Assert the VADNDECEN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NDECEN);
+
+ /* Assert VADNOREN bitfield. */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+ MICFIL_VAD0_NCONFIG_NOREN);
+
+ return 0;
+}
+
+/*
+ * Hardware Voice Active Detection: The HWVAD takes data from the input
+ * of a selected PDM microphone to detect if there is any
+ * voice activity. When a voice activity is detected, an interrupt could
+ * be delivered to the system. Initialization in section 8.4:
+ * Can work in two modes:
+ * -> Eneveope-based mode (section 8.4.1)
+ * -> Energy-based mode (section 8.4.2)
+ *
+ * It is important to remark that the HWVAD detector could be enabled
+ * or reset only when the MICFIL isn't running i.e. when the BSY_FIL
+ * bit in STAT register is cleared
+ */
+static int fsl_micfil_hwvad_enable(struct fsl_micfil *micfil)
+{
+ int ret;
+
+ micfil->vad_detected = 0;
+
+ /* envelope-based specific initialization */
+ if (micfil->vad_init_mode == MICFIL_HWVAD_ENVELOPE_MODE)
+ ret = fsl_micfil_init_hwvad_envelope_mode(micfil);
+ else
+ ret = fsl_micfil_init_hwvad_energy_mode(micfil);
+ if (ret)
+ return ret;
+
+ /* Voice Activity Detector Internal Filters Initialization*/
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_ST10);
+
+ /* Voice Activity Detector Internal Filter */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_ST10);
+
+ /* Enable Interrupts */
+ ret = fsl_micfil_configure_hwvad_interrupts(micfil, 1);
+ if (ret)
+ return ret;
+
+ /* Voice Activity Detector Reset */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_RST);
+
+ /* Voice Activity Detector Enabled */
+ regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_EN);
+
+ return 0;
+}
+
+static int fsl_micfil_hwvad_disable(struct fsl_micfil *micfil)
+{
+ struct device *dev = &micfil->pdev->dev;
+ int ret = 0;
+
+ /* Disable HWVAD */
+ regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_EN);
+
+ /* Disable hwvad interrupts */
+ ret = fsl_micfil_configure_hwvad_interrupts(micfil, 0);
+ if (ret)
+ dev_err(dev, "Failed to disable interrupts\n");
+
+ return ret;
+}
+
static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
@@ -245,10 +577,16 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret)
return ret;
+ if (micfil->vad_enabled)
+ fsl_micfil_hwvad_enable(micfil);
+
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (micfil->vad_enabled)
+ fsl_micfil_hwvad_disable(micfil);
+
/* Disable the module */
ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1,
MICFIL_CTRL1_PDMIEN);
@@ -328,6 +666,16 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) |
FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr));
+ /* Configure CIC OSR in VADCICOSR */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_CICOSR,
+ FIELD_PREP(MICFIL_VAD0_CTRL1_CICOSR, 16 - osr));
+
+ /* Configure source channel in VADCHSEL */
+ regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+ MICFIL_VAD0_CTRL1_CHSEL,
+ FIELD_PREP(MICFIL_VAD0_CTRL1_CHSEL, (channels - 1)));
+
micfil->dma_params_rx.peripheral_config = &micfil->sdmacfg;
micfil->dma_params_rx.peripheral_size = sizeof(micfil->sdmacfg);
micfil->sdmacfg.n_fifos_src = channels;
@@ -351,6 +699,7 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
int ret, i;
micfil->quality = QUALITY_VLOW0;
+ micfil->card = cpu_dai->component->card;
/* set default gain to 2 */
regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
@@ -585,6 +934,71 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
return IRQ_HANDLED;
}
+static irqreturn_t voice_detected_fn(int irq, void *devid)
+{
+ struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+ struct snd_kcontrol *kctl;
+
+ if (!micfil->card)
+ return IRQ_HANDLED;
+
+ kctl = snd_soc_card_get_kcontrol(micfil->card, "VAD Detected");
+ if (!kctl)
+ return IRQ_HANDLED;
+
+ if (micfil->vad_detected)
+ snd_ctl_notify(micfil->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &kctl->id);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t hwvad_isr(int irq, void *devid)
+{
+ struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+ struct device *dev = &micfil->pdev->dev;
+ u32 vad0_reg;
+ int ret;
+
+ regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg);
+
+ /*
+ * The only difference between MICFIL_VAD0_STAT_EF and
+ * MICFIL_VAD0_STAT_IF is that the former requires Write
+ * 1 to Clear. Since both flags are set, it is enough
+ * to only read one of them
+ */
+ if (vad0_reg & MICFIL_VAD0_STAT_IF) {
+ /* Write 1 to clear */
+ regmap_write_bits(micfil->regmap, REG_MICFIL_VAD0_STAT,
+ MICFIL_VAD0_STAT_IF,
+ MICFIL_VAD0_STAT_IF);
+
+ micfil->vad_detected = 1;
+ }
+
+ ret = fsl_micfil_hwvad_disable(micfil);
+ if (ret)
+ dev_err(dev, "Failed to disable hwvad\n");
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t hwvad_err_isr(int irq, void *devid)
+{
+ struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+ struct device *dev = &micfil->pdev->dev;
+ u32 vad0_reg;
+
+ regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg);
+
+ if (vad0_reg & MICFIL_VAD0_STAT_INSATF)
+ dev_dbg(dev, "voice activity input overflow/underflow detected\n");
+
+ return IRQ_HANDLED;
+}
+
static int fsl_micfil_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -677,6 +1091,26 @@ static int fsl_micfil_probe(struct platform_device *pdev)
return ret;
}
+ /* Digital Microphone interface voice activity detector event */
+ ret = devm_request_threaded_irq(&pdev->dev, micfil->irq[2],
+ hwvad_isr, voice_detected_fn,
+ IRQF_SHARED, micfil->name, micfil);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim hwvad event irq %u\n",
+ micfil->irq[0]);
+ return ret;
+ }
+
+ /* Digital Microphone interface voice activity detector error */
+ ret = devm_request_irq(&pdev->dev, micfil->irq[3],
+ hwvad_err_isr, IRQF_SHARED,
+ micfil->name, micfil);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim hwvad error irq %u\n",
+ micfil->irq[1]);
+ return ret;
+ }
+
micfil->dma_params_rx.chan_name = "rx";
micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0;
micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX;
diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h
index d60285dd07bc..9237a1c4cb8f 100644
--- a/sound/soc/fsl/fsl_micfil.h
+++ b/sound/soc/fsl/fsl_micfil.h
@@ -136,10 +136,14 @@
#define FIFO_PTRWID 3
#define FIFO_LEN BIT(FIFO_PTRWID)
-#define MICFIL_IRQ_LINES 2
+#define MICFIL_IRQ_LINES 4
#define MICFIL_MAX_RETRY 25
#define MICFIL_SLEEP_MIN 90000 /* in us */
#define MICFIL_SLEEP_MAX 100000 /* in us */
#define MICFIL_DMA_MAXBURST_RX 6
+/* HWVAD Constants */
+#define MICFIL_HWVAD_ENVELOPE_MODE 0
+#define MICFIL_HWVAD_ENERGY_MODE 1
+
#endif /* _FSL_MICFIL_H */
diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c
index bf94838bdbef..46c7868a2653 100644
--- a/sound/soc/fsl/fsl_rpmsg.c
+++ b/sound/soc/fsl/fsl_rpmsg.c
@@ -117,14 +117,14 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = {
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 32,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_RPMSG_FORMATS,
},
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 32,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_RPMSG_FORMATS,
},
@@ -235,7 +235,7 @@ static int fsl_rpmsg_probe(struct platform_device *pdev)
rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
"imx-audio-rpmsg",
- PLATFORM_DEVID_NONE,
+ PLATFORM_DEVID_AUTO,
NULL,
0);
if (IS_ERR(rpmsg->card_pdev)) {
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index 905c3a071300..d5234ac4b09b 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -88,7 +88,7 @@ static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
/* Register platform driver for rpmsg routine */
data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
IMX_PCM_DRV_NAME,
- PLATFORM_DEVID_NONE,
+ PLATFORM_DEVID_AUTO,
NULL, 0);
if (IS_ERR(data->rpmsg_pdev)) {
dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
@@ -110,6 +110,7 @@ static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
{ .name = "rpmsg-audio-channel" },
+ { .name = "rpmsg-micfil-channel" },
{ },
};
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 35049043e532..2f310994f7ee 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -178,7 +178,7 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
msg->s_msg.param.channels = RPMSG_CH_STEREO;
break;
default:
- ret = -EINVAL;
+ msg->s_msg.param.channels = params_channels(params);
break;
}
@@ -684,7 +684,7 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
info->dev = &pdev->dev;
/* Setup work queue */
- info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
+ info->rpmsg_wq = alloc_ordered_workqueue(info->rpdev->id.name,
WQ_HIGHPRI |
WQ_UNBOUND |
WQ_FREEZABLE);
@@ -723,11 +723,15 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
if (ret)
goto fail;
- component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
+ component = snd_soc_lookup_component(&pdev->dev, NULL);
if (!component) {
ret = -EINVAL;
goto fail;
}
+
+ /* platform component name is used by machine driver to link with */
+ component->name = info->rpdev->id.name;
+
#ifdef CONFIG_DEBUG_FS
component->debugfs_prefix = "rpmsg";
#endif
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index 4d99f4858a14..89178106fe2c 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -58,6 +58,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
struct platform_device *rpmsg_pdev = to_platform_device(dev);
struct device_node *np = rpmsg_pdev->dev.of_node;
struct of_phandle_args args;
+ const char *platform_name;
struct imx_rpmsg *data;
int ret = 0;
@@ -109,7 +110,10 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
}
data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev);
- data->dai.platforms->name = IMX_PCM_DRV_NAME;
+ if (!of_property_read_string(np, "fsl,rpmsg-channel-name", &platform_name))
+ data->dai.platforms->name = platform_name;
+ else
+ data->dai.platforms->name = "rpmsg-audio-channel";
data->dai.playback_only = true;
data->dai.capture_only = true;
data->card.num_links = 1;
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index b8e2b23c9f64..7c8ce98eda9d 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -133,12 +133,14 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
buf = apl_log_payload_addr(addr);
memcpy_fromio(&layout, addr, sizeof(layout));
if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
+ union avs_notify_msg lbs_msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
+
/*
* DSP awaits the remaining logs to be
* gathered before dumping stack
*/
- msg->log.core = msg->ext.coredump.core_id;
- avs_dsp_op(adev, log_buffer_status, msg);
+ lbs_msg.log.core = msg->ext.coredump.core_id;
+ avs_dsp_op(adev, log_buffer_status, &lbs_msg);
}
pos = dump + AVS_FW_REGS_SIZE;
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 92e37722d280..91f78eb11bc1 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -220,8 +220,10 @@ static inline void avs_ipc_err(struct avs_dev *adev, struct avs_ipc_msg *tx,
/*
* If IPC channel is blocked e.g.: due to ongoing recovery,
* -EPERM error code is expected and thus it's not an actual error.
+ *
+ * Unsupported IPCs are of no harm either.
*/
- if (error == -EPERM)
+ if (error == -EPERM || error == AVS_IPC_NOT_SUPPORTED)
dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
tx->glb.primary, tx->glb.ext.val, error);
else
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 87f9c18be238..01c1a5324b51 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -29,6 +29,12 @@ static const struct dmi_system_id kbl_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
+ },
+ },
{}
};
@@ -122,6 +128,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "rt298-tplg.bin",
},
{
+ .id = "MX98927",
+ .drv_name = "avs_max98927",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "max98927-tplg.bin",
+ },
+ {
.id = "MX98373",
.drv_name = "avs_max98373",
.mach_params = {
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 4d68e3ef992b..9bd40fdd9028 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -36,6 +36,16 @@ config SND_SOC_INTEL_AVS_MACH_I2S_TEST
This adds support for I2S test-board which can be used to verify
transfer over I2S interface with SSP loopback scenarios.
+config SND_SOC_INTEL_AVS_MACH_MAX98927
+ tristate "max98927 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98927
+ help
+ This adds support for AVS with MAX98927 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
config SND_SOC_INTEL_AVS_MACH_MAX98357A
tristate "max98357A I2S board"
depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index bc75376d58c2..4d70b8d09ce5 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -4,6 +4,7 @@ snd-soc-avs-da7219-objs := da7219.o
snd-soc-avs-dmic-objs := dmic.o
snd-soc-avs-hdaudio-objs := hdaudio.o
snd-soc-avs-i2s-test-objs := i2s_test.o
+snd-soc-avs-max98927-objs := max98927.o
snd-soc-avs-max98357a-objs := max98357a.o
snd-soc-avs-max98373-objs := max98373.o
snd-soc-avs-nau8825-objs := nau8825.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 02ae542ad779..503a967a1c3a 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -6,6 +6,7 @@
//
#include <linux/module.h>
+#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -80,7 +81,10 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
int ret;
jack = snd_soc_card_get_drvdata(card);
- clk_freq = 19200000;
+ if (soc_intel_is_apl())
+ clk_freq = 19200000;
+ else /* kbl */
+ clk_freq = 24576000;
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
if (ret) {
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index 073663ba140d..e68c4c7aa2ba 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/hda_codec.h>
#include <sound/hda_i915.h>
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
new file mode 100644
index 000000000000..35c4f8f55035
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98927_DEV0_NAME "i2c-MX98927:00"
+#define MAX98927_DEV1_NAME "i2c-MX98927:01"
+#define MAX98927_CODEC_NAME "max98927-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME),
+ .name_prefix = "Left",
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98927_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 16 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ return 0;
+}
+
+static int avs_max98927_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+ int i;
+
+ for_each_rtd_codec_dais(runtime, i, codec_dai) {
+ if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME))
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+ else if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME))
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+
+ if (ret < 0) {
+ dev_err(runtime->dev, "hw_params for %s failed: %d\n",
+ codec_dai->component->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_max98927_ops = {
+ .hw_params = avs_max98927_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV0_NAME);
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV1_NAME);
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+ if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+ !dl->codecs[1].name || !dl->codecs[1].dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 2;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->be_hw_params_fixup = avs_max98927_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ignore_pmdown_time = 1;
+ dl->ops = &avs_max98927_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_max98927_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_max98927";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->codec_conf = card_codec_conf;
+ card->num_configs = ARRAY_SIZE(card_codec_conf);
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98927_driver = {
+ .probe = avs_max98927_probe,
+ .driver = {
+ .name = "avs_max98927",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98927_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98927");
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index b28d36872dcb..58c9d9edecf0 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/dmi.h>
#include <linux/module.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -14,6 +15,16 @@
#include <sound/soc-acpi.h>
#include "../../../codecs/rt298.h"
+static const struct dmi_system_id kblr_dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
+ },
+ },
+ {}
+};
+
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Mic Jack"),
@@ -96,9 +107,15 @@ avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_param
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ unsigned int clk_freq;
int ret;
- ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+ if (dmi_first_match(kblr_dmi_table))
+ clk_freq = 24000000;
+ else
+ clk_freq = 19200000;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, clk_freq, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
@@ -139,7 +156,10 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ if (dmi_first_match(kblr_dmi_table))
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ else
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
dl->init = avs_rt298_codec_init;
dl->be_hw_params_fixup = avs_rt298_be_fixup;
dl->ops = &avs_rt298_ops;
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index bb0719c58ca4..0aaded90a99a 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -440,7 +440,7 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
- if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
dma_set_max_seg_size(dev, UINT_MAX);
@@ -504,7 +504,7 @@ static void avs_pci_remove(struct pci_dev *pci)
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
/* reverse ml_capabilities */
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
snd_hdac_ext_bus_exit(bus);
avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0));
@@ -580,7 +580,6 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
{
struct hdac_bus *bus = &adev->base.core;
- struct hdac_ext_link *hlink;
int ret;
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
@@ -595,16 +594,6 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
return ret;
}
- /* turn off the links that were off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- /* check dma status and clean up CORB/RIRB buffers */
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
-
return 0;
}
@@ -667,7 +656,11 @@ static const struct avs_spec apl_desc = {
static const struct pci_device_id avs_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
+ { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
{ PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
+ { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
+ { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
+ { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
{ PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
{ PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
{ 0 }
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 020d85c7520d..152f8d0bdf8e 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -74,7 +74,7 @@ int avs_dsp_disable_d0ix(struct avs_dev *adev)
struct avs_ipc *ipc = adev->ipc;
/* Prevent PG only on the first disable. */
- if (atomic_add_return(1, &ipc->d0ix_disable_depth) == 1) {
+ if (atomic_inc_return(&ipc->d0ix_disable_depth) == 1) {
cancel_delayed_work_sync(&ipc->d0ix_work);
return avs_dsp_set_d0ix(adev, false);
}
@@ -192,7 +192,8 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
/* update size in case of LARGE_CONFIG_GET */
if (msg.msg_target == AVS_MOD_MSG &&
msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
- ipc->rx.size = msg.ext.large_config.data_off_size;
+ ipc->rx.size = min_t(u32, AVS_MAILBOX_SIZE,
+ msg.ext.large_config.data_off_size);
memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), ipc->rx.size);
trace_avs_msg_payload(ipc->rx.data, ipc->rx.size);
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 9e3f8ff33a87..eb10e45790e7 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -43,7 +43,7 @@
/* Occasionally, engineering (release candidate) firmware is provided for testing. */
static bool debug_ignore_fw_version;
module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444);
-MODULE_PARM_DESC(ignore_fw_version, "Verify FW version 0=yes (default), 1=no");
+MODULE_PARM_DESC(ignore_fw_version, "Ignore firmware version check 0=no (default), 1=yes");
#define AVS_LIB_NAME_SIZE 8
@@ -369,8 +369,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
goto release_stream;
/* enable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index);
- ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size);
+ snd_hdac_stream_spbcap_enable(bus, true, hstream->index);
+ ret = snd_hdac_stream_set_spib(bus, hstream, fw->size);
if (ret)
goto cleanup_resources;
@@ -400,8 +400,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
cleanup_resources:
/* disable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, 0);
+ snd_hdac_stream_spbcap_enable(bus, false, hstream->index);
+ snd_hdac_stream_set_spib(bus, hstream, 0);
snd_hdac_dsp_cleanup(hstream, &dmab);
release_stream:
@@ -436,8 +436,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
goto release_stream;
/* enable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
+ snd_hdac_stream_spbcap_enable(bus, true, stream->index);
+ snd_hdac_stream_set_spib(bus, stream, lib->size);
memcpy(dmab.area, lib->data, lib->size);
@@ -451,8 +451,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
}
/* disable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, 0);
+ snd_hdac_stream_spbcap_enable(bus, false, stream->index);
+ snd_hdac_stream_set_spib(bus, stream, 0);
snd_hdac_dsp_cleanup(stream, &dmab);
release_stream:
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index d4bcee1aabcf..6b0fecbf07c3 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -687,20 +687,13 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
{
- int ret;
-
- ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
- AVS_BASEFW_ENABLE_LOGS, log_info, size);
- if (ret)
- dev_err(adev->dev, "enable logs failed: %d\n", ret);
-
- return ret;
+ return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_ENABLE_LOGS, log_info, size);
}
int avs_ipc_set_system_time(struct avs_dev *adev)
{
struct avs_sys_time sys_time;
- int ret;
u64 us;
/* firmware expects UTC time in micro seconds */
@@ -708,12 +701,8 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
sys_time.val_l = us & UINT_MAX;
sys_time.val_u = us >> 32;
- ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
- AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
- if (ret)
- dev_err(adev->dev, "set system time failed: %d\n", ret);
-
- return ret;
+ return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
}
int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index c0f90dba9af8..02b3b7a74783 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -150,6 +150,8 @@ union avs_module_msg {
};
} __packed;
+#define AVS_IPC_NOT_SUPPORTED 15
+
union avs_reply_msg {
u64 val;
struct {
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 8fe5917b1e26..293336c2fc63 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -292,12 +292,12 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn
/* clear link <-> stream mapping */
codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
- link = snd_hdac_ext_bus_link_at(&codec->bus->core, codec->core.addr);
+ link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
return 0;
}
@@ -322,15 +322,15 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
runtime->sample_bits, 0);
snd_hdac_ext_stream_decouple(bus, link_stream, true);
- snd_hdac_ext_link_stream_reset(link_stream);
- snd_hdac_ext_link_stream_setup(link_stream, format_val);
+ snd_hdac_ext_stream_reset(link_stream);
+ snd_hdac_ext_stream_setup(link_stream, format_val);
- link = snd_hdac_ext_bus_link_at(bus, codec->core.addr);
+ link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
if (ret)
@@ -355,7 +355,7 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(link_stream);
+ snd_hdac_ext_stream_start(link_stream);
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
@@ -368,7 +368,7 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0)
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
- snd_hdac_ext_link_stream_clear(link_stream);
+ snd_hdac_ext_stream_clear(link_stream);
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
ret = avs_path_reset(data->path);
@@ -1016,10 +1016,8 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen
if (!strstr(dai->driver->name, name))
continue;
- if (dai->playback_widget)
- snd_soc_dapm_free_widget(dai->playback_widget);
- if (dai->capture_widget)
- snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ snd_soc_dapm_free_widget(dai->capture_widget);
snd_soc_unregister_dai(dai);
}
}
diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c
index bda5ec7510fe..dc98b5cf900f 100644
--- a/sound/soc/intel/avs/skl.c
+++ b/sound/soc/intel/avs/skl.c
@@ -28,12 +28,12 @@ static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
info->core_mask = resource_mask;
if (enable)
- for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0)) {
+ for_each_set_bit(i, &resource_mask, num_cores) {
info->logs_core[i].enable = enable;
info->logs_core[i].min_priority = *priorities++;
}
else
- for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0))
+ for_each_set_bit(i, &resource_mask, num_cores)
info->logs_core[i].enable = enable;
ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index eaad180af42e..5ab0917a2b3d 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -53,17 +53,15 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_stream *stream = snd_hdac_get_stream(bus,
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
- struct hdac_ext_stream *estream;
if (!stream)
return -EINVAL;
- estream = stream_to_hdac_ext_stream(stream);
/* enable/disable SPIB for this hdac stream */
- snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index);
+ snd_hdac_stream_spbcap_enable(bus, enable, stream->index);
/* set the spib value */
- snd_hdac_ext_stream_set_spib(bus, estream, size);
+ snd_hdac_stream_set_spib(bus, stream, size);
return 0;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 1015716f9336..dc627d18518d 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -190,16 +190,16 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format);
- snd_hdac_ext_link_stream_reset(stream);
+ snd_hdac_ext_stream_reset(stream);
- snd_hdac_ext_link_stream_setup(stream, format_val);
+ snd_hdac_ext_stream_setup(stream, format_val);
stream_tag = hstream->stream_tag;
if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
list_for_each_entry(link, &bus->hlink_list, list) {
if (link->index == params->link_index)
- snd_hdac_ext_link_set_stream_id(link,
- stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(link,
+ stream_tag);
}
}
@@ -467,6 +467,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl_module_cfg *mconfig;
struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct hdac_stream *hstream = hdac_stream(stream);
struct snd_soc_dapm_widget *w;
int ret;
@@ -484,11 +485,9 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
* dpib & lpib position to resume before starting the
* DMA
*/
- snd_hdac_ext_stream_drsm_enable(bus, true,
- hdac_stream(stream)->index);
- snd_hdac_ext_stream_set_dpibr(bus, stream,
- stream->lpib);
- snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+ snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+ snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+ snd_hdac_stream_set_lpib(hstream, hstream->lpib);
}
fallthrough;
@@ -520,13 +519,13 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
ret = skl_decoupled_trigger(substream, cmd);
if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
/* save the dpib and lpib positions */
- stream->dpib = readl(bus->remap_addr +
+ hstream->dpib = readl(bus->remap_addr +
AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL *
- hdac_stream(stream)->index));
+ hstream->index));
+
+ hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream);
- stream->lpib = snd_hdac_stream_get_pos_lpib(
- hdac_stream(stream));
snd_hdac_ext_stream_decouple(bus, stream, false);
}
break;
@@ -558,7 +557,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
+ link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -612,13 +611,13 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(link_dev);
+ snd_hdac_ext_stream_start(link_dev);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- snd_hdac_ext_link_stream_clear(link_dev);
+ snd_hdac_ext_stream_clear(link_dev);
if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
snd_hdac_ext_stream_decouple(bus, stream, false);
break;
@@ -643,13 +642,13 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
link_dev->link_prepared = 0;
- link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
+ link = snd_hdac_ext_bus_get_hlink_by_name(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag);
}
snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index bbba2df33aaf..c6f319bcd2c4 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -387,15 +387,6 @@ static int skl_resume(struct device *dev)
snd_hdac_bus_init_cmd_io(bus);
} else {
ret = _skl_resume(bus);
-
- /* turn off the links which are off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
}
return ret;
@@ -445,7 +436,7 @@ static int skl_free(struct hdac_bus *bus)
free_irq(bus->irq, (void *)bus);
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
if (bus->remap_addr)
iounmap(bus->remap_addr);
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 2a4ffe945177..afdf7d61e4c5 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -31,6 +31,122 @@
(SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
+/* These registers are relative to the second register region -
+ * audio pll configuration.
+ */
+#define A38X_PLL_CONF_REG0 0x0
+#define A38X_PLL_FB_CLK_DIV_OFFSET 10
+#define A38X_PLL_FB_CLK_DIV_MASK 0x7fc00
+#define A38X_PLL_CONF_REG1 0x4
+#define A38X_PLL_FREQ_OFFSET_MASK 0xffff
+#define A38X_PLL_FREQ_OFFSET_VALID BIT(16)
+#define A38X_PLL_SW_RESET BIT(31)
+#define A38X_PLL_CONF_REG2 0x8
+#define A38X_PLL_AUDIO_POSTDIV_MASK 0x7f
+
+/* Bit below belongs to SoC control register corresponding to the third
+ * register region.
+ */
+#define A38X_SPDIF_MODE_ENABLE BIT(27)
+
+static int armada_38x_i2s_init_quirk(struct platform_device *pdev,
+ struct kirkwood_dma_data *priv,
+ struct snd_soc_dai_driver *dai_drv)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 reg_val;
+ int i;
+
+ priv->pll_config = devm_platform_ioremap_resource_byname(pdev, "pll_regs");
+ if (IS_ERR(priv->pll_config))
+ return -ENOMEM;
+
+ priv->soc_control = devm_platform_ioremap_resource_byname(pdev, "soc_ctrl");
+ if (IS_ERR(priv->soc_control))
+ return -ENOMEM;
+
+ /* Select one of exceptive modes: I2S or S/PDIF */
+ reg_val = readl(priv->soc_control);
+ if (of_property_read_bool(np, "spdif-mode")) {
+ reg_val |= A38X_SPDIF_MODE_ENABLE;
+ dev_info(&pdev->dev, "using S/PDIF mode\n");
+ } else {
+ reg_val &= ~A38X_SPDIF_MODE_ENABLE;
+ dev_info(&pdev->dev, "using I2S mode\n");
+ }
+ writel(reg_val, priv->soc_control);
+
+ /* Update available rates of mclk's fs */
+ for (i = 0; i < 2; i++) {
+ dai_drv[i].playback.rates |= SNDRV_PCM_RATE_192000;
+ dai_drv[i].capture.rates |= SNDRV_PCM_RATE_192000;
+ }
+
+ return 0;
+}
+
+static inline void armada_38x_set_pll(void __iomem *base, unsigned long rate)
+{
+ u32 reg_val;
+ u16 freq_offset = 0x22b0;
+ u8 audio_postdiv, fb_clk_div = 0x1d;
+
+ /* Set frequency offset value to not valid and enable PLL reset */
+ reg_val = readl(base + A38X_PLL_CONF_REG1);
+ reg_val &= ~A38X_PLL_FREQ_OFFSET_VALID;
+ reg_val &= ~A38X_PLL_SW_RESET;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+ udelay(1);
+
+ /* Update PLL parameters */
+ switch (rate) {
+ default:
+ case 44100:
+ freq_offset = 0x735;
+ fb_clk_div = 0x1b;
+ audio_postdiv = 0xc;
+ break;
+ case 48000:
+ audio_postdiv = 0xc;
+ break;
+ case 96000:
+ audio_postdiv = 0x6;
+ break;
+ case 192000:
+ audio_postdiv = 0x3;
+ break;
+ }
+
+ reg_val = readl(base + A38X_PLL_CONF_REG0);
+ reg_val &= ~A38X_PLL_FB_CLK_DIV_MASK;
+ reg_val |= (fb_clk_div << A38X_PLL_FB_CLK_DIV_OFFSET);
+ writel(reg_val, base + A38X_PLL_CONF_REG0);
+
+ reg_val = readl(base + A38X_PLL_CONF_REG2);
+ reg_val &= ~A38X_PLL_AUDIO_POSTDIV_MASK;
+ reg_val |= audio_postdiv;
+ writel(reg_val, base + A38X_PLL_CONF_REG2);
+
+ reg_val = readl(base + A38X_PLL_CONF_REG1);
+ reg_val &= ~A38X_PLL_FREQ_OFFSET_MASK;
+ reg_val |= freq_offset;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+ udelay(1);
+
+ /* Disable reset */
+ reg_val |= A38X_PLL_SW_RESET;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+ /* Wait 50us for PLL to lock */
+ udelay(50);
+
+ /* Restore frequency offset value validity */
+ reg_val |= A38X_PLL_FREQ_OFFSET_VALID;
+ writel(reg_val, base + A38X_PLL_CONF_REG1);
+}
+
static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
@@ -106,7 +222,10 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
* defined in kirkwood_i2s_dai */
dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
__func__, rate);
- kirkwood_set_dco(priv->io, rate);
+ if (priv->pll_config)
+ armada_38x_set_pll(priv->pll_config, rate);
+ else
+ kirkwood_set_dco(priv->io, rate);
clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
} else {
@@ -532,7 +651,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, priv);
- priv->io = devm_platform_ioremap_resource(pdev, 0);
+ if (of_device_is_compatible(np, "marvell,armada-380-audio"))
+ priv->io = devm_platform_ioremap_resource_byname(pdev, "i2s_regs");
+ else
+ priv->io = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
@@ -540,6 +662,14 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
if (priv->irq < 0)
return priv->irq;
+ if (of_device_is_compatible(np, "marvell,armada-380-audio")) {
+ err = armada_38x_i2s_init_quirk(pdev, priv, soc_dai);
+ if (err < 0)
+ return err;
+ /* Set initial pll frequency */
+ armada_38x_set_pll(priv->pll_config, 44100);
+ }
+
if (np) {
priv->burst = 128; /* might be 32 or 128 */
} else if (data) {
@@ -623,6 +753,7 @@ static const struct of_device_id mvebu_audio_of_match[] = {
{ .compatible = "marvell,kirkwood-audio" },
{ .compatible = "marvell,dove-audio" },
{ .compatible = "marvell,armada370-audio" },
+ { .compatible = "marvell,armada-380-audio" },
{ }
};
MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index a1733a6aace5..79bb9aa7f086 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -131,6 +131,8 @@
struct kirkwood_dma_data {
void __iomem *io;
+ void __iomem *pll_config;
+ void __iomem *soc_control;
struct clk *clk;
struct clk *extclk;
uint32_t ctl_play;
diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c
index 88ac58272f95..ad43cb2a1e3f 100644
--- a/sound/soc/meson/axg-pdm.c
+++ b/sound/soc/meson/axg-pdm.c
@@ -169,7 +169,7 @@ static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os,
/*
* Set the default system clock rate unless it is too fast for
- * for the requested sample rate. In this case, the sample pointer
+ * the requested sample rate. In this case, the sample pointer
* counter could overflow so set a lower system clock rate
*/
if (sys_rate < priv->cfg->sys_rate)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 7e380d71b0f8..2d269ac8c137 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1518,7 +1518,8 @@ static int rsnd_hw_params(struct snd_soc_component *component,
int stream = substream->stream;
for_each_dpcm_be(fe, stream, dpcm) {
- struct snd_pcm_hw_params *be_params = &dpcm->hw_params;
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params;
if (params_channels(hw_params) != params_channels(be_params))
io->converted_chan = params_channels(be_params);
@@ -1581,9 +1582,9 @@ static int rsnd_hw_params(struct snd_soc_component *component,
hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
} else if (params_rate(hw_params) * k_up < io->converted_rate) {
hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
- (io->converted_rate + k_up - 1) / k_up;
+ DIV_ROUND_UP(io->converted_rate, k_up);
hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
- (io->converted_rate + k_up - 1) / k_up;
+ DIV_ROUND_UP(io->converted_rate, k_up);
hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d515e7a78ea8..954ca9af3e48 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -71,9 +71,9 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_pinctrl] = 2,
[snd_soc_dapm_clock_supply] = 2,
[snd_soc_dapm_supply] = 3,
+ [snd_soc_dapm_dai_link] = 3,
[snd_soc_dapm_micbias] = 4,
[snd_soc_dapm_vmid] = 4,
- [snd_soc_dapm_dai_link] = 3,
[snd_soc_dapm_dai_in] = 5,
[snd_soc_dapm_dai_out] = 5,
[snd_soc_dapm_aif_in] = 5,
@@ -652,10 +652,8 @@ static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
}
static struct snd_soc_dapm_widget *
-dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
+dapm_wcache_lookup(struct snd_soc_dapm_widget *w, const char *name)
{
- struct snd_soc_dapm_widget *w = wcache->widget;
-
if (w) {
struct list_head *wlist = &w->dapm->card->widgets;
const int depth = 2;
@@ -673,12 +671,6 @@ dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
return NULL;
}
-static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
- struct snd_soc_dapm_widget *w)
-{
- wcache->widget = w;
-}
-
/**
* snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
* @dapm: The DAPM context for which to set the level
@@ -1881,58 +1873,52 @@ static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
dapm_mark_dirty(peer, "peer state change");
}
-static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
+static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
struct list_head *up_list,
struct list_head *down_list)
{
struct snd_soc_dapm_path *path;
+ int power;
+
+ switch (w->id) {
+ case snd_soc_dapm_pre:
+ power = 0;
+ goto end;
+ case snd_soc_dapm_post:
+ power = 1;
+ goto end;
+ default:
+ break;
+ }
+
+ power = dapm_widget_power_check(w);
if (w->power == power)
return;
trace_snd_soc_dapm_widget_power(w, power);
- /* If we changed our power state perhaps our neigbours changed
- * also.
+ /*
+ * If we changed our power state perhaps our neigbours
+ * changed also.
*/
snd_soc_dapm_widget_for_each_source_path(w, path)
dapm_widget_set_peer_power(path->source, power, path->connect);
- /* Supplies can't affect their outputs, only their inputs */
- if (!w->is_supply) {
+ /*
+ * Supplies can't affect their outputs, only their inputs
+ */
+ if (!w->is_supply)
snd_soc_dapm_widget_for_each_sink_path(w, path)
- dapm_widget_set_peer_power(path->sink, power,
- path->connect);
- }
+ dapm_widget_set_peer_power(path->sink, power, path->connect);
+end:
if (power)
dapm_seq_insert(w, up_list, true);
else
dapm_seq_insert(w, down_list, false);
}
-static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
- struct list_head *up_list,
- struct list_head *down_list)
-{
- int power;
-
- switch (w->id) {
- case snd_soc_dapm_pre:
- dapm_seq_insert(w, down_list, false);
- break;
- case snd_soc_dapm_post:
- dapm_seq_insert(w, up_list, true);
- break;
-
- default:
- power = dapm_widget_power_check(w);
-
- dapm_widget_set_power(w, power, up_list, down_list);
- break;
- }
-}
-
static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
{
if (dapm->idle_bias_off)
@@ -2497,6 +2483,9 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
struct snd_soc_dapm_path *p, *next_p;
enum snd_soc_dapm_direction dir;
+ if (!w)
+ return;
+
list_del(&w->list);
list_del(&w->dirty);
/*
@@ -2516,12 +2505,6 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free_widget);
-void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
-{
- dapm->path_sink_cache.widget = NULL;
- dapm->path_source_cache.widget = NULL;
-}
-
/* free all dapm widgets and resources */
static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
{
@@ -2532,7 +2515,9 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
continue;
snd_soc_dapm_free_widget(w);
}
- snd_soc_dapm_reset_cache(dapm);
+
+ dapm->wcache_sink = NULL;
+ dapm->wcache_source = NULL;
}
static struct snd_soc_dapm_widget *dapm_find_widget(
@@ -2838,7 +2823,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink))
{
- struct snd_soc_dapm_widget *widgets[2];
enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_path *path;
int ret;
@@ -2874,8 +2858,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
path->node[SND_SOC_DAPM_DIR_IN] = wsource;
path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
- widgets[SND_SOC_DAPM_DIR_IN] = wsource;
- widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
path->connected = connected;
INIT_LIST_HEAD(&path->list);
@@ -2917,12 +2899,13 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
}
list_add(&path->list, &dapm->card->paths);
+
snd_soc_dapm_for_each_direction(dir)
- list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
+ list_add(&path->list_node[dir], &path->node[dir]->edges[dir]);
snd_soc_dapm_for_each_direction(dir) {
- dapm_update_widget_flags(widgets[dir]);
- dapm_mark_dirty(widgets[dir], "Route added");
+ dapm_update_widget_flags(path->node[dir]);
+ dapm_mark_dirty(path->node[dir], "Route added");
}
if (dapm->card->instantiated && path->connect)
@@ -2961,8 +2944,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
source = route->source;
}
- wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
- wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
+ wsource = dapm_wcache_lookup(dapm->wcache_source, source);
+ wsink = dapm_wcache_lookup(dapm->wcache_sink, sink);
if (wsink && wsource)
goto skip_search;
@@ -3006,30 +2989,27 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
if (!wsource)
wsource = wtsource;
- if (wsource == NULL) {
- dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
- route->source);
- return -ENODEV;
- }
- if (wsink == NULL) {
- dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
- route->sink);
- return -ENODEV;
- }
+ ret = -ENODEV;
+ if (!wsource)
+ goto err;
+ if (!wsink)
+ goto err;
skip_search:
- dapm_wcache_update(&dapm->path_sink_cache, wsink);
- dapm_wcache_update(&dapm->path_source_cache, wsource);
+ /* update cache */
+ dapm->wcache_sink = wsink;
+ dapm->wcache_source = wsource;
ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
route->connected);
- if (ret)
- goto err;
-
- return 0;
err:
- dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
- source, route->control, sink);
+ if (ret)
+ dev_err(dapm->dev, "ASoC: Failed to add route %s%s -%s%s%s> %s%s\n",
+ source, !wsource ? "(*)" : "",
+ !route->control ? "" : "> [",
+ !route->control ? "" : route->control,
+ !route->control ? "" : "] -",
+ sink, !wsink ? "(*)" : "");
return ret;
}
@@ -3115,13 +3095,8 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
for (i = 0; i < num; i++) {
int r = snd_soc_dapm_add_route(dapm, route);
- if (r < 0) {
- dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
- route->source,
- route->control ? route->control : "direct",
- route->sink);
+ if (r < 0)
ret = r;
- }
route++;
}
mutex_unlock(&dapm->card->dapm_mutex);
@@ -4157,56 +4132,53 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
+ const struct snd_kcontrol_new *kcontrol_news;
+ int num_kcontrols;
const char **w_param_text;
unsigned long private_value = 0;
char *link_name;
- int ret;
+ int ret = -ENOMEM;
link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
rtd->dai_link->name, id);
if (!link_name)
- return ERR_PTR(-ENOMEM);
-
- memset(&template, 0, sizeof(template));
- template.reg = SND_SOC_NOPM;
- template.id = snd_soc_dapm_dai_link;
- template.name = link_name;
- template.event = snd_soc_dai_link_event;
- template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
- template.kcontrol_news = NULL;
+ goto name_fail;
/* allocate memory for control, only in case of multiple configs */
+ w_param_text = NULL;
+ kcontrol_news = NULL;
+ num_kcontrols = 0;
if (rtd->dai_link->num_params > 1) {
w_param_text = devm_kcalloc(card->dev,
rtd->dai_link->num_params,
sizeof(char *), GFP_KERNEL);
- if (!w_param_text) {
- ret = -ENOMEM;
+ if (!w_param_text)
goto param_fail;
- }
- template.num_kcontrols = 1;
- template.kcontrol_news =
- snd_soc_dapm_alloc_kcontrol(card,
- link_name,
- rtd->dai_link->params,
- rtd->dai_link->num_params,
- w_param_text, &private_value);
- if (!template.kcontrol_news) {
- ret = -ENOMEM;
+ num_kcontrols = 1;
+ kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, link_name,
+ rtd->dai_link->params,
+ rtd->dai_link->num_params,
+ w_param_text, &private_value);
+ if (!kcontrol_news)
goto param_fail;
- }
- } else {
- w_param_text = NULL;
}
+
+ memset(&template, 0, sizeof(template));
+ template.reg = SND_SOC_NOPM;
+ template.id = snd_soc_dapm_dai_link;
+ template.name = link_name;
+ template.event = snd_soc_dai_link_event;
+ template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
+ template.kcontrol_news = kcontrol_news;
+ template.num_kcontrols = num_kcontrols;
+
dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
- dev_err(rtd->dev, "ASoC: Failed to create %s widget: %d\n",
- link_name, ret);
goto outfree_kcontrol_news;
}
@@ -4220,6 +4192,9 @@ outfree_kcontrol_news:
rtd->dai_link->num_params, w_param_text);
param_fail:
devm_kfree(card->dev, link_name);
+name_fail:
+ dev_err(rtd->dev, "ASoC: Failed to create %s-%s widget: %d\n",
+ rtd->dai_link->name, id, ret);
return ERR_PTR(ret);
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index fb87d6d23408..d8e4677f3002 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -155,7 +155,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
for_each_dpcm_be(fe, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
- params = &dpcm->hw_params;
+ params = &be->dpcm[stream].hw_params;
offset += scnprintf(buf + offset, size - offset,
"- %s\n", be->dai_link->name);
@@ -1980,6 +1980,8 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
int ret;
for_each_dpcm_be(fe, stream, dpcm) {
+ struct snd_pcm_hw_params hw_params;
+
be = dpcm->be;
be_substream = snd_soc_dpcm_get_substream(be, stream);
@@ -1988,16 +1990,16 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
continue;
/* copy params for each dpcm */
- memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
+ memcpy(&hw_params, &fe->dpcm[stream].hw_params,
sizeof(struct snd_pcm_hw_params));
/* perform any hw_params fixups */
- ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
+ ret = snd_soc_link_be_hw_params_fixup(be, &hw_params);
if (ret < 0)
goto unwind;
/* copy the fixed-up hw params for BE dai */
- memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
+ memcpy(&be->dpcm[stream].hw_params, &hw_params,
sizeof(struct snd_pcm_hw_params));
/* only allow hw_params() if no connected FEs are running */
@@ -2012,7 +2014,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
be->dai_link->name);
- ret = __soc_pcm_hw_params(be, be_substream, &dpcm->hw_params);
+ ret = __soc_pcm_hw_params(be, be_substream, &hw_params);
if (ret < 0)
goto unwind;
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index f1e74b49deda..2553afe6f27d 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -37,10 +37,12 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcida, hipctdr;
hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
+ hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) {
/* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
@@ -49,9 +51,9 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
cnl_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
- hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
/* Message from DSP (reply or notification) */
u32 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -70,6 +72,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
+ cnl_ipc_host_done(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
@@ -86,10 +89,10 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
- }
- /* Let DSP know that we have finished processing the message */
- cnl_ipc_host_done(sdev);
+ /* Let DSP know that we have finished processing the message */
+ cnl_ipc_host_done(sdev);
+ }
ipc_irq = true;
}
@@ -98,6 +101,13 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
/* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ cnl_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}
@@ -251,8 +261,16 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 556e883a32ed..64e8ca016b21 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -146,19 +146,19 @@ static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
struct hdac_bus *bus = hstream->bus;
struct sof_intel_hda_stream *hda_stream;
- struct hdac_ext_link *link;
+ struct hdac_ext_link *hlink;
int stream_tag;
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
- if (!link)
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
+ if (!hlink)
return -EINVAL;
if (trigger_suspend_stop)
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
}
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
@@ -177,10 +177,10 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
struct hdac_stream *hstream = &hext_stream->hstream;
unsigned char stream_tag = hstream->stream_tag;
struct hdac_bus *bus = hstream->bus;
- struct hdac_ext_link *link;
+ struct hdac_ext_link *hlink;
unsigned int format_val;
- snd_hdac_ext_link_stream_reset(hext_stream);
+ snd_hdac_ext_stream_reset(hext_stream);
format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
params->format,
@@ -189,13 +189,13 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format);
- snd_hdac_ext_link_stream_setup(hext_stream, format_val);
+ snd_hdac_ext_stream_setup(hext_stream, format_val);
if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
- list_for_each_entry(link, &bus->hlink_list, list) {
- if (link->index == params->link_index)
- snd_hdac_ext_link_set_stream_id(link,
- stream_tag);
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
+ if (hlink->index == params->link_index)
+ snd_hdac_ext_bus_link_set_stream_id(hlink,
+ stream_tag);
}
}
@@ -214,7 +214,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct hda_pipe_params p_params = {0};
struct hdac_bus *bus = hstream->bus;
- struct hdac_ext_link *link;
+ struct hdac_ext_link *hlink;
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream) {
@@ -225,8 +225,8 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
}
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
- if (!link)
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
+ if (!hlink)
return -EINVAL;
/* set the hdac_stream in the codec dai */
@@ -236,7 +236,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
p_params.ch = params_channels(params);
p_params.s_freq = params_rate(params);
p_params.stream = substream->stream;
- p_params.link_index = link->index;
+ p_params.link_index = hlink->index;
p_params.format = params_format(params);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -270,7 +270,7 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(hext_stream);
+ snd_hdac_ext_stream_start(hext_stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
@@ -280,7 +280,7 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
break;
default:
@@ -476,7 +476,7 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(hext_stream);
+ snd_hdac_ext_stream_start(hext_stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
@@ -491,7 +491,7 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
pipeline->state = SOF_IPC4_PIPE_PAUSED;
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_RESET);
@@ -519,7 +519,7 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
pipeline->state = SOF_IPC4_PIPE_PAUSED;
- snd_hdac_ext_link_stream_clear(hext_stream);
+ snd_hdac_ext_stream_clear(hext_stream);
break;
}
default:
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 3c76f843454b..799c50fe24da 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -677,10 +677,6 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- struct hdac_bus *bus = sof_to_bus(sdev);
- struct hdac_ext_link *hlink = NULL;
-#endif
int ret;
/* display codec must be powered before link reset */
@@ -707,16 +703,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
if (sdev->system_suspend_target == SOF_SUSPEND_NONE)
hda_codec_jack_check(sdev);
}
-
- /* turn off the links that were off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- /* check dma status and clean up CORB/RIRB buffers */
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
#endif
/* enable ppcap interrupt */
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index 9b3667c705e4..a7c454e03952 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -69,8 +69,16 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -122,10 +130,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcie, hipct;
hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
+ hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
+
if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
/* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
@@ -133,9 +144,9 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
hda_dsp_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
- hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
/* Message from DSP (reply or notification) */
u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -158,6 +169,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
+ hda_dsp_ipc_host_done(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
@@ -174,10 +186,10 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
- }
- /* Let DSP know that we have finished processing the message */
- hda_dsp_ipc_host_done(sdev);
+ /* Let DSP know that we have finished processing the message */
+ hda_dsp_ipc_host_done(sdev);
+ }
ipc_irq = true;
}
@@ -186,6 +198,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
/* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ hda_dsp_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 0a9c80216a8c..dc0b359ed9b6 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -142,7 +142,6 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
struct snd_pcm_runtime *runtime = substream->runtime;
ssize_t appl_pos, buf_size;
u32 spib;
@@ -156,7 +155,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea
if (!spib)
spib = buf_size;
- sof_io_write(sdev, hext_stream->spib_addr, spib);
+ sof_io_write(sdev, hstream->spib_addr, spib);
return 0;
}
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index be60e7785da9..8cb91788912c 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -173,7 +173,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
enable << hstream->index);
/* set the SPIB value */
- sof_io_write(sdev, hext_stream->spib_addr, size);
+ sof_io_write(sdev, hstream->spib_addr, size);
return 0;
}
@@ -883,18 +883,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
SOF_HDA_PPLC_INTERVAL * i;
+ hstream = &hext_stream->hstream;
+
/* do we support SPIB */
if (sdev->bar[HDA_DSP_SPIB_BAR]) {
- hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_SPIB;
- hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_MAXFIFO;
}
- hstream = &hext_stream->hstream;
hstream->bus = bus;
hstream->sd_int_sta_mask = 1 << i;
hstream->index = i;
@@ -939,18 +940,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
SOF_HDA_PPLC_INTERVAL * i;
+ hstream = &hext_stream->hstream;
+
/* do we support SPIB */
if (sdev->bar[HDA_DSP_SPIB_BAR]) {
- hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_SPIB;
- hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+ hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
SOF_HDA_SPIB_MAXFIFO;
}
- hstream = &hext_stream->hstream;
hstream->bus = bus;
hstream->sd_int_sta_mask = 1 << i;
hstream->index = i;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 1188ec51816b..d63f843dc7aa 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -681,6 +681,17 @@ void hda_ipc4_dump(struct snd_sof_dev *sdev)
hipci, hipcie, hipct, hipcte, hipcctl);
}
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+ u32 val;
+
+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req);
+
+ return !!(val & chip->ipc_req_mask);
+}
+
static int hda_init(struct snd_sof_dev *sdev)
{
struct hda_bus *hbus;
@@ -1224,7 +1235,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
hda_dsp_stream_free(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
#endif
iounmap(sdev->bar[HDA_DSP_BAR]);
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 4b9f3819f644..c91fc3637823 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -522,6 +522,14 @@ struct sof_intel_hda_dev {
/* Intel NHLT information */
struct nhlt_acpi_table *nhlt;
+
+ /*
+ * Pointing to the IPC message if immediate sending was not possible
+ * because the downlink communication channel was BUSY at the time.
+ * The message will be re-tried when the channel becomes free (the ACK
+ * is received from the DSP for the previous message)
+ */
+ struct snd_sof_ipc_msg *delayed_ipc_tx_msg;
};
static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@@ -853,6 +861,7 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask);
irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context);
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev);
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void hda_ipc4_dump(struct snd_sof_dev *sdev);
extern struct sdw_intel_ops sdw_callback;
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 459da05f4d7a..7e8b298786df 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -90,8 +90,16 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -492,11 +500,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcida;
u32 hipctdr;
hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
+ hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
/* reply message from DSP */
if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) {
@@ -507,9 +517,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
mtl_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
- hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
/* Message from DSP (reply or notification) */
u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
@@ -530,6 +540,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
+ mtl_ipc_host_done(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
@@ -546,9 +557,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
- }
- mtl_ipc_host_done(sdev);
+ mtl_ipc_host_done(sdev);
+ }
ipc_irq = true;
}
@@ -558,6 +569,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
}
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index b28af3a48b70..1fef4dcc0936 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -329,6 +329,8 @@ static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
struct snd_sof_dev *sdev = ipc->sdev;
int ret;
+ ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
+
ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
if (ret) {
@@ -338,8 +340,6 @@ static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
return ret;
}
- ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
-
/* now wait for completion */
return ipc3_wait_tx_done(ipc, reply_data);
}
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 3e81bc5d7d44..74cd7e956019 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -343,6 +343,8 @@ static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
if (msg_bytes > ipc->max_payload_size || reply_bytes > ipc->max_payload_size)
return -EINVAL;
+ sof_ipc4_log_header(sdev->dev, "ipc tx ", msg_data, true);
+
ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
if (ret) {
dev_err_ratelimited(sdev->dev,
@@ -351,8 +353,6 @@ static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
return ret;
}
- sof_ipc4_log_header(sdev->dev, "ipc tx ", msg_data, true);
-
/* now wait for completion */
return ipc4_wait_tx_done(ipc, reply_data);
}
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index ca5d1bb6ac59..f5ac2ab77f5b 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -869,7 +869,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
max_active_serializers = 1;
else
- max_active_serializers = (channels + slots - 1) / slots;
+ max_active_serializers = DIV_ROUND_UP(channels, slots);
/* Default configuration */
if (mcasp->version < MCASP_VERSION_3)
@@ -1002,8 +1002,7 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
*/
if (mcasp->tdm_mask[stream]) {
active_slots = hweight32(mcasp->tdm_mask[stream]);
- active_serializers = (channels + active_slots - 1) /
- active_slots;
+ active_serializers = DIV_ROUND_UP(channels, active_slots);
if (active_serializers == 1)
active_slots = channels;
for (i = 0; i < total_slots; i++) {
@@ -1014,7 +1013,7 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
}
}
} else {
- active_serializers = (channels + total_slots - 1) / total_slots;
+ active_serializers = DIV_ROUND_UP(channels, total_slots);
if (active_serializers == 1)
active_slots = channels;
else