diff options
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 = ¬ification_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 = ¬ification_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 = ¬ification_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 |