diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml index 8445c5d63395a..56ed095837837 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml @@ -66,6 +66,7 @@ allOf: compatible: enum: - qcom,sc7280-lpass-rx-macro + - qcom,shikra-lpass-rx-macro then: properties: clock-names: diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index 92e1f3299b76c..814cdf8f6dde4 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -146,6 +146,21 @@ allOf: minItems: 3 maxItems: 3 + - if: + properties: + compatible: + contains: + const: qcom,shikra-lpass-va-macro + then: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + items: + - const: mclk + - const: npl + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/qcom,qaif.yaml b/Documentation/devicetree/bindings/sound/qcom,qaif.yaml deleted file mode 100644 index 9c4371f13ff3b..0000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,qaif.yaml +++ /dev/null @@ -1,361 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/sound/qcom,qaif.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm Audio Interface (QAIF) CPU DAI Controller - -maintainers: - - Harendra Gautam - -description: - | - The Qualcomm Audio Interface (QAIF) is a fully configurable DMA-based - audio subsystem controller. It serialises and deserialises PCM audio - between system memory and external serial audio peripherals (PCM, TDM, - I2S, MI2S) through the AIF path, and transfers parallel audio between - memory and an internal WCD codec through the CIF path. - - AIF (Audio Interface): up to 13 multi-lane Unified Audio Interfaces, - each supporting up to 8 independent data lanes. Each lane is individually - configurable as TX (output/speaker) or RX (input/mic). All lanes of an - interface share a single bit clock and frame sync. Supported modes are - PCM (short/long sync), TDM, and MI2S (stereo/mono). Per-interface - configuration includes sync source (master/slave), sync mode, sync delay, - sync inversion, slot width (8/16/24/32-bit), sample width, active slot - masks (up to 32 slots), bits-per-lane frame size, lane enable/direction - masks, loopback, output-enable control, and full-cycle path support for - long chip-to-chip connections. - - CIF (Codec Interface): up to 32 RDDMA (playback) and 32 WRDMA (capture) - channels connecting to an internal codec over a parallel bus. Each channel - supports active-channel enable mask (up to 16 channels), frame-sync - selection, frame-sync delay, frame-sync output gating, dynamic clock - gating, and 16-bit packing/unpacking. - - Note on RX/TX naming convention: in QAIF, RX refers to the capture path - (audio received from the interface into memory) and TX refers to the - playback path (audio transmitted from memory to the interface). This - applies to both AIF lane directions and CIF slot/mask properties. - - DMA engine: RDDMA fetches audio from DDR/TCM/LPM into a shared SRAM - latency buffer (SHRAM) and drains it to the interface. WRDMA collects - data from the interface into SHRAM and writes it to memory. Each DMA - owns a private SHRAM region defined by start address and length registers. - Burst sizes of 1/2/4/8/16 beats (64-bit) are supported with up to 4 - outstanding transactions per DMA. Two QSB master ports (QXM0 for TCM, - QXM1 for DDR/LPM) provide the memory interface. - - Resources are partitioned among up to 5 Execution Engines (EEs) via - EE map registers. Each EE owns a set of DMAs, audio interfaces, and - interface groups, and receives its own independent interrupt output. - The interrupt hierarchy has a two-level structure: a summary register - identifies the event class (DMA period, underflow/overflow, error - response, audio interface underflow/overflow, group done, rate detector, - VFR), and per-resource status registers identify the specific channel. - - Interface grouping (bonding) allows up to 6 groups of audio and codec - interfaces to start synchronously and align their DMA period interrupts - within half a frame duration using the RDDMA padding feature. - - Two rate detector blocks measure the frequency of incoming frame sync or - word select signals and generate interrupts on rate change, undetected - rate, or sync timeout. - - Block diagram:: - - System Memory (DDR / LPM / TCM) - +---------------------------------+ - | Circular Buffers (ping-pong) | - +----------+----------+-----------+ - | ^ - 64-bit AXI 64-bit AXI - | | - +----------v----------+-----------+ - | QSB Master Ports | - | +----------+ +----------+ | - | | QXM0 | | QXM1 | | - | +----+-----+ +-----+----+ | - +-------|--------------|----------+ - | | - +-------v--------------v----------+ - | Shared RAM (SHRAM) | - | +------------+ +------------+ | - | | QXM0 Read | | QXM0 Write | | - | | SHRAM | | SHRAM | | - | +------------+ +------------+ | - | +------------+ +------------+ | - | | QXM1 Read | | QXM1 Write | | - | | SHRAM | | SHRAM | | - | +------------+ +------------+ | - +---+--------+--------+-------+---+ - | | | | - +---v--+ +--v---+ +--v---+ +-v----+ - |RDDMA | |RDDMA | |WRDMA | |WRDMA | - | AIF | | CIF | | AIF | | CIF | - |[0..n]| |[0..n]| |[0..n]| |[0..n]| - +--+---+ +--+---+ +--+---+ +-+----+ - | | ^ ^ - | TX | TX | RX | RX - v v | | - +--+--------------------+ +----+----------+ - | Unified Audio Intf | | Codec DMA | - | (AIF 0..12) | | Interface | - | | | (CIF) | - | AUD_INTFa block: | | | - | - Serializer (TX) | | RDDMA: DDR -> | - | - De-serializer (RX) | | internal | - | - Sync gen/detect | | codec | - | - Up to 8 data lanes | | WRDMA: codec | - | - PCM / TDM / MI2S | | -> DDR | - | - Near Pad Logic | | Up to 16 ch | - +--+--------------------+ +----+----------+ - | Lane 0..7 (TX/RX) | Parallel bus - | Bit clk + Frame sync | + Frame sync - v v - +--+--------+ +------+------+ - | External | | Internal | - | Serial | | Digital | - | Peripherals| | Codec | - | (PCM/TDM/ | | (Bolero/ | - | MI2S) | | WCD) | - +-----------+ +-------------+ - -properties: - compatible: - enum: - - qcom,shikra-qaif-cpu - - reg: - maxItems: 1 - - iommus: - maxItems: 1 - - clocks: - minItems: 15 - maxItems: 15 - - clock-names: - items: - - const: lpass_config_clk - - const: lpass_core_axim_clk - - const: aud_dma_clk - - const: aud_dma_mem_clk - - const: bus_clk - - const: aif_if0_ebit_clk - - const: aif_if0_ibit_clk - - const: aif_if1_ebit_clk - - const: aif_if1_ibit_clk - - const: aif_if2_ebit_clk - - const: aif_if2_ibit_clk - - const: aif_if3_ebit_clk - - const: aif_if3_ibit_clk - - const: ext_mclka_clk - - const: ext_mclkb_clk - - interrupts: - maxItems: 1 - - '#sound-dai-cells': - const: 1 - - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - - status: true - -patternProperties: - "^aif-interface@[0-9a-f]+$": - type: object - description: - AIF interface configuration child node. The compatible string - identifies the serial protocol the interface is wired for on the - board. The unit address matches the hardware AIF interface index. - properties: - compatible: - enum: - - qcom,qaif-pcm-dai - - qcom,qaif-tdm-dai - - qcom,qaif-mi2s-dai - reg: - maxItems: 1 - description: | - Hardware AIF interface index (AUD_INTFa block index). This value - also serves as the ALSA DAI ID; it corresponds directly to the - QAIF_MI2S_TDM_AIFn constants in - (e.g. reg = <2> selects QAIF_MI2S_TDM_AIF2). - qcom,qaif-aif-sync-mode: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Sync mode. Use QAIF_AIF_SYNC_MODE_SHORT (0) for short (pulse) - sync or QAIF_AIF_SYNC_MODE_LONG (1) for long (level) sync. - qcom,qaif-aif-sync-src: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Sync source. Use QAIF_AIF_SYNC_SRC_SLAVE (0) for slave mode - or QAIF_AIF_SYNC_SRC_MASTER (1) for master mode. - qcom,qaif-aif-invert-sync: - type: boolean - description: Invert the frame sync polarity. - qcom,qaif-aif-sync-delay: - $ref: /schemas/types.yaml#/definitions/uint32 - description: Number of bit-clock cycles to delay the data relative to sync. - qcom,qaif-aif-slot-width-rx: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - RX slot width in bits. This is a board-specific hardware constraint - determined by the wiring of the serial audio interface. - qcom,qaif-aif-slot-width-tx: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - TX slot width in bits. This is a board-specific hardware constraint - determined by the wiring of the serial audio interface. - qcom,qaif-aif-slot-en-rx-mask: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Bitmask of active RX slots. Board-specific — determined by which - TDM slots the codec is wired to on this board. - qcom,qaif-aif-slot-en-tx-mask: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Bitmask of active TX slots. Board-specific — determined by which - TDM slots the codec is wired to on this board. - qcom,qaif-aif-loopback: - type: boolean - description: Enable loopback mode (presence enables loopback). - qcom,qaif-aif-ctrl-data-oe: - type: boolean - description: Enable output drive on the control/data line. - qcom,qaif-aif-lane-config: - $ref: /schemas/types.yaml#/definitions/uint32-matrix - description: - Lane configuration matrix. Each row is a pair - for one lane starting from lane 0, up to 8 lanes. Use - QAIF_AIF_LANE_ENABLE (1) or QAIF_AIF_LANE_DISABLE (0) for enable. - Use QAIF_AIF_LANE_DIR_TX (0) for TX (speaker) or QAIF_AIF_LANE_DIR_RX - (1) for RX (mic). TX and RX lanes should each be grouped contiguously. - maxItems: 8 - items: - items: - - description: Lane enable (0 = disabled, 1 = enabled) - enum: [0, 1] - - description: Lane direction (0 = TX/speaker, 1 = RX/mic) - enum: [0, 1] - qcom,qaif-aif-full-cycle-en: - type: boolean - description: Enable full-cycle sync (effective in sync master mode). - qcom,qaif-aif-bits-per-lane: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Number of slots per lane. The frame length is computed as - slot-width multiplied by bits-per-lane. - if: - properties: - compatible: - const: qcom,qaif-mi2s-dai - then: - description: - MI2S interface. Sync mode and slot-enable masks are fixed by the - MI2S protocol and must not be set in DT. Mono/stereo mode is - determined at runtime from the stream channel count. - properties: - qcom,qaif-aif-sync-mode: false - qcom,qaif-aif-slot-en-rx-mask: false - qcom,qaif-aif-slot-en-tx-mask: false - else: - description: - PCM or TDM interface. Sync mode and slot-enable masks are - board-specific and must be provided. Mono mode does not apply. - required: - - qcom,qaif-aif-sync-mode - - qcom,qaif-aif-slot-en-rx-mask - - qcom,qaif-aif-slot-en-tx-mask - - required: - - compatible - - reg - additionalProperties: false - -required: - - compatible - - reg - - iommus - - clocks - - clock-names - - interrupts - - '#sound-dai-cells' - -additionalProperties: false - -examples: - - | - /* Shikra platform example */ - #include - #include - #include - #include - #include - - qaif_cpu: audio@a000000 { - compatible = "qcom,shikra-qaif-cpu"; - reg = <0x0 0x0a000000 0x0 0x20000>; - iommus = <&apps_smmu 0x1c0 0x0>; - clocks = <&gcc GCC_LPASS_CONFIG_CLK>, - <&gcc GCC_LPASS_CORE_AXIM_CLK>, - <&audiocorecc AUDIO_CORE_CC_AUD_DMA_CLK>, - <&audiocorecc AUDIO_CORE_CC_AUD_DMA_MEM_CLK>, - <&audiocorecc AUDIO_CORE_CC_BUS_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF0_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF0_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF1_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF1_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF2_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF2_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF3_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF3_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_EXT_MCLKA_OUT_CLK>, - <&audiocorecc AUDIO_CORE_CC_EXT_MCLKB_OUT_CLK>; - clock-names = "lpass_config_clk", - "lpass_core_axim_clk", - "aud_dma_clk", - "aud_dma_mem_clk", - "bus_clk", - "aif_if0_ebit_clk", - "aif_if0_ibit_clk", - "aif_if1_ebit_clk", - "aif_if1_ibit_clk", - "aif_if2_ebit_clk", - "aif_if2_ibit_clk", - "aif_if3_ebit_clk", - "aif_if3_ibit_clk", - "ext_mclka_clk", - "ext_mclkb_clk"; - #sound-dai-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - interrupts = ; - status = "okay"; - - qaif_aif_if2: aif-interface@2 { - compatible = "qcom,qaif-tdm-dai"; - reg = ; - qcom,qaif-aif-sync-mode = ; - qcom,qaif-aif-sync-src = ; - qcom,qaif-aif-sync-delay = <1>; - qcom,qaif-aif-slot-width-rx = <32>; - qcom,qaif-aif-slot-width-tx = <32>; - qcom,qaif-aif-slot-en-rx-mask = <0x3>; - qcom,qaif-aif-slot-en-tx-mask = <0x3>; - qcom,qaif-aif-ctrl-data-oe; - /* Lane 0: RX (mic); Lane 1: TX (speaker) */ - qcom,qaif-aif-lane-config = , - ; - /* frame length = slot-width (32) * bits-per-lane (2) = 64 bits */ - qcom,qaif-aif-bits-per-lane = <2>; - }; - }; diff --git a/Documentation/devicetree/bindings/sound/qcom,shikra-qaif-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,shikra-qaif-cpu.yaml new file mode 100644 index 0000000000000..9d0616ac75543 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,shikra-qaif-cpu.yaml @@ -0,0 +1,308 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,shikra-qaif-cpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Audio Interface (QAIF) CPU DAI Controller + +maintainers: + - Harendra Gautam + +description: | + The Qualcomm Audio Interface (QAIF) is a fully configurable DMA-based + audio subsystem controller. It serialises and deserialises PCM audio + between system memory and external serial audio peripherals (PCM, TDM, + I2S, MI2S) through the AIF path, and transfers parallel audio between + memory and an internal WCD codec through the CIF path. + + AIF (Audio Interface): up to 13 multi-lane Unified Audio Interfaces, + each supporting up to 8 independent data lanes. Each lane is individually + configurable as TX (output/speaker) or RX (input/mic). All lanes of an + interface share a single bit clock and frame sync. Supported modes are + PCM (short/long sync), TDM, and MI2S (stereo/mono). Per-interface + configuration includes sync source (master/slave), sync mode, sync delay, + sync inversion, slot width (8/16/24/32-bit), sample width, active slot + masks (up to 32 slots), bits-per-lane frame size, lane enable/direction + masks, loopback, output-enable control, and full-cycle path support for + long chip-to-chip connections. + + CIF (Codec Interface): up to 10 RDDMA (playback) and 10 WRDMA (capture) + channels connecting to an internal codec over a parallel bus. Each channel + supports active-channel enable mask (up to 16 channels), frame-sync + selection, frame-sync delay, frame-sync output gating, dynamic clock + gating, and 16-bit packing/unpacking. + + Note on RX/TX naming convention: in QAIF, TX refers to the output + (speaker/playback) direction and RX refers to the input (mic/capture) + direction. This applies to both AIF lane directions and CIF slot/mask + properties. + + DMA engine: RDDMA fetches audio from DDR/TCM/LPM into a shared SRAM + latency buffer (SHRAM) and drains it to the interface. WRDMA collects + data from the interface into SHRAM and writes it to memory. Each DMA + owns a private SHRAM region defined by start address and length registers. + Burst sizes of 1/2/4/8/16 beats (64-bit) are supported with up to 4 + outstanding transactions per DMA. Two QSB master ports (QXM0 for TCM, + QXM1 for DDR/LPM) provide the memory interface. + + Resources are partitioned among up to 5 Execution Engines (EEs) via + EE map registers. Each EE owns a set of DMAs, audio interfaces, and + interface groups, and receives its own independent interrupt output. + The interrupt hierarchy has a two-level structure: a summary register + identifies the event class (DMA period, underflow/overflow, error + response, audio interface underflow/overflow, group done, rate detector, + VFR), and per-resource status registers identify the specific channel. + + Interface grouping (bonding) allows up to 6 groups of audio and codec + interfaces to start synchronously and align their DMA period interrupts + within half a frame duration using the RDDMA padding feature. + + Two rate detector blocks measure the frequency of incoming frame sync or + word select signals and generate interrupts on rate change, undetected + rate, or sync timeout. + + Block diagram:: + + System Memory (DDR / LPM / TCM) + +---------------------------------+ + | Circular Buffers (ping-pong) | + +----------+----------+-----------+ + | ^ + 64-bit AXI 64-bit AXI + | | + +----------v----------+-----------+ + | QSB Master Ports | + | +----------+ +----------+ | + | | QXM0 | | QXM1 | | + | +----+-----+ +-----+----+ | + +-------|--------------|----------+ + | | + +-------v--------------v----------+ + | Shared RAM (SHRAM) | + | +------------+ +------------+ | + | | QXM0 Read | | QXM0 Write | | + | | SHRAM | | SHRAM | | + | +------------+ +------------+ | + | +------------+ +------------+ | + | | QXM1 Read | | QXM1 Write | | + | | SHRAM | | SHRAM | | + | +------------+ +------------+ | + +---+--------+--------+-------+---+ + | | | | + +---v--+ +--v---+ +--v---+ +-v----+ + |RDDMA | |RDDMA | |WRDMA | |WRDMA | + | AIF | | CIF | | AIF | | CIF | + |[0..n]| |[0..n]| |[0..n]| |[0..n]| + +--+---+ +--+---+ +--+---+ +-+----+ + | | ^ ^ + | TX | TX | RX | RX + v v | | + +--+--------------------+ +----+----------+ + | Unified Audio Intf | | Codec DMA | + | (AIF 0..12) | | Interface | + | | | (CIF) | + | AUD_INTFa block: | | | + | - Serializer (TX) | | RDDMA: DDR -> | + | - De-serializer (RX) | | internal | + | - Sync gen/detect | | codec | + | - Up to 8 data lanes | | WRDMA: codec | + | - PCM / TDM / MI2S | | -> DDR | + | - Near Pad Logic | | Up to 16 ch | + +--+--------------------+ +----+----------+ + | Lane 0..7 (TX/RX) | Parallel bus + | Bit clk + Frame sync | + Frame sync + v v + +--+--------+ +------+------+ + | External | | Internal | + | Serial | | Digital | + | Peripherals| | Codec | + | (PCM/TDM/ | | (Bolero/ | + | MI2S) | | WCD) | + +-----------+ +-------------+ + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: qcom,shikra-qaif-cpu + + reg: + maxItems: 1 + description: QAIF core registers + + interrupts: + maxItems: 1 + description: + QAIF summary interrupt for this Execution Engine. Signals DMA period + completion, buffer underflow/overflow, error response, audio interface + underflow/overflow, interface-group done, rate detector and VFR events. + + iommus: + maxItems: 1 + description: Phandle to apps_smmu node with sid mask + + dma-coherent: true + + clocks: + minItems: 5 + maxItems: 9 + + clock-names: + description: + The first five clocks are always required. Any further entries are the + per-AIF bit clocks (aif_if_ibit), supplied in order starting from + AIF interface 0 for as many serial AIF interfaces as the board uses. + minItems: 5 + items: + - const: lpass_config + - const: lpass_core_axim + - const: aud_dma + - const: aud_dma_mem + - const: bus + - const: aif_if0_ibit + - const: aif_if1_ibit + - const: aif_if2_ibit + - const: aif_if3_ibit + + '#sound-dai-cells': + const: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^aif@[0-9a-f]+$': + type: object + description: + QAIF AIF interface child node for PCM, TDM or MI2S configuration. + + properties: + reg: + maxItems: 1 + description: + DAI ID of the AIF interface (QAIF_MI2S_AIF* or QAIF_TDM_AIF*). + + dai-format: + description: Serial audio interface format (MI2S, TDM or PCM). + enum: [i2s, dsp_a, dsp_b] + + dai-tdm-slot-width: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [8, 16, 24, 32] + description: + Slot width in bits. + + dai-tdm-slot-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of slots per lane. + minimum: 1 + maximum: 32 + + dai-tdm-slot-rx-mask: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Active RX slots, one entry per slot. A nonzero value marks the + slot as active. + minItems: 1 + maxItems: 32 + + dai-tdm-slot-tx-mask: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Active TX slots, one entry per slot. A nonzero value marks the + slot as active. + minItems: 1 + maxItems: 32 + + qcom,qaif-aif-lane-map: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Per-lane direction map, one entry per lane starting from lane 0. + Use 0 for TX (output/speaker) and 1 for RX (input/mic). + minItems: 1 + maxItems: 8 + items: + enum: [0, 1] + + required: + - reg + - dai-format + - qcom,qaif-aif-lane-map + + if: + properties: + dai-format: + enum: [dsp_a, dsp_b] + then: + required: + - dai-tdm-slot-width + - dai-tdm-slot-num + - dai-tdm-slot-rx-mask + - dai-tdm-slot-tx-mask + + additionalProperties: false + +required: + - compatible + - reg + - interrupts + - iommus + - clocks + - clock-names + - '#sound-dai-cells' + - '#address-cells' + - '#size-cells' + +unevaluatedProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + qaif_cpu: audio-controller@a000000 { + compatible = "qcom,shikra-qaif-cpu"; + reg = <0x0 0x0a000000 0x0 0x20000>; + interrupts = ; + iommus = <&apps_smmu 0x1c0 0x0>; + clocks = <&gcc 213>, + <&gcc 214>, + <&audiocorecc 15>, + <&audiocorecc 17>, + <&audiocorecc 18>, + <&audiocorecc 5>, + <&audiocorecc 8>, + <&audiocorecc 11>, + <&audiocorecc 14>; + clock-names = "lpass_config", + "lpass_core_axim", + "aud_dma", + "aud_dma_mem", + "bus", + "aif_if0_ibit", + "aif_if1_ibit", + "aif_if2_ibit", + "aif_if3_ibit"; + #sound-dai-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + aif@b5 { + reg = <181>; + dai-format = "dsp_a"; + dai-tdm-slot-width = <32>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-rx-mask = <1 1>; + dai-tdm-slot-tx-mask = <1 1>; + qcom,qaif-aif-lane-map = <1 0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml new file mode 100644 index 0000000000000..00a6a05e94431 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,wsa8855.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WSA8855 stereo smart speaker amplifier + +maintainers: + - Srinivas Kandagatla + - Prasad Kumpatla + +description: + WSA885X is a Qualcomm Aqstic stereo smart speaker amplifier. It uses a PCM + audio interface, an I2C control interface, and a Class-H amplifier path for + high efficiency, low output noise, and low idle power consumption. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: qcom,wsa8855 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + powerdown-gpios: + description: GPIO controlling the SD_N powerdown pin. + maxItems: 1 + + reset-gpios: + description: GPIO controlling the SD_N powerdown pin. + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-1p8-supply: true + + vdd-io-supply: true + + qcom,battery-config: + description: + Battery topology connected to the speaker amplifier. 1S indicates one + battery cell in series, while 2S indicates two battery cells in series. + $ref: /schemas/types.yaml#/definitions/string + default: 1s + enum: + - 1s + - 2s + +required: + - compatible + - reg + - '#sound-dai-cells' + - interrupts + - vdd-1p8-supply + - vdd-io-supply + +oneOf: + - required: + - powerdown-gpios + - required: + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + speaker@c { + compatible = "qcom,wsa8855"; + reg = <0x0c>; + #sound-dai-cells = <0>; + powerdown-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>; + interrupt-parent = <&tlmm>; + interrupts = <77 IRQ_TYPE_EDGE_FALLING>; + vdd-1p8-supply = <&vreg_l2g_1p8>; + vdd-io-supply = <&vreg_l1g_1p2>; + qcom,battery-config = "1s"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa885x-i2c.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa885x-i2c.yaml deleted file mode 100644 index 1069f470dea5d..0000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,wsa885x-i2c.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/sound/qcom,wsa885x-i2c.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm WSA885x I2C smart speaker amplifier - -maintainers: - - Srinivas Kandagatla - - Prasad Kumpatla - -description: | - WSA885x is a Qualcomm Aqstic smart speaker amplifier with an I2C control - interface and a digital audio interface exposed through ASoC DAI callbacks. - -allOf: - - $ref: dai-common.yaml# - -properties: - compatible: - const: qcom,wsa885x-i2c - - reg: - maxItems: 1 - - '#sound-dai-cells': - const: 0 - - powerdown-gpios: - description: GPIO controlling the SD_N powerdown pin. - maxItems: 1 - - interrupt-gpios: - description: GPIO used for the codec interrupt output. - maxItems: 1 - - vdd-1p8-supply: true - - vdd-io-supply: true - - qcom,battery-config: - $ref: /schemas/types.yaml#/definitions/uint32 - description: Speaker battery configuration, 1 for 1S and 2 for 2S. - default: 1 - enum: [1, 2] - - qcom,wsa885x-init-table: - $ref: /schemas/types.yaml#/definitions/uint32-array - minItems: 2 - maxItems: 256 - description: | - Sequence of register/value pairs applied during codec hardware - initialization. Entries are encoded as alternating register address and - register value cells. The number of entries must be even (register/value - pairs); maxItems is 256 (128 pairs). - -required: - - compatible - - reg - - '#sound-dai-cells' - - powerdown-gpios - - interrupt-gpios - - vdd-1p8-supply - - vdd-io-supply - -additionalProperties: false - -examples: - - | - #include - - i2c { - #address-cells = <1>; - #size-cells = <0>; - - speaker@c { - compatible = "qcom,wsa885x-i2c"; - reg = <0x0c>; - #sound-dai-cells = <0>; - powerdown-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>; - interrupt-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; - vdd-1p8-supply = <&vreg_l2g_1p8>; - vdd-io-supply = <&vreg_l1g_1p2>; - qcom,battery-config = <1>; - qcom,wsa885x-init-table = <0x8606 0x24 0x8626 0x24>; - }; - }; -... diff --git a/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml b/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml index e72ceefb85981..f1be0bc2ad2e4 100644 --- a/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml +++ b/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml @@ -17,6 +17,7 @@ properties: compatible: oneOf: - enum: + - qcom,shikra-soundwire - qcom,soundwire-v1.3.0 - qcom,soundwire-v1.5.0 - qcom,soundwire-v1.5.1 diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts index 9633ef96bf97b..900e40829528f 100644 --- a/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts @@ -5,7 +5,6 @@ /dts-v1/; -#include #include "shikra-cqm-som.dtsi" #include "shikra-evk.dtsi" #include @@ -46,7 +45,11 @@ audio-routing = "IN1_HPHL", "HPHL_OUT", "IN2_HPHR", "HPHR_OUT", + "AMIC1", "MIC BIAS1", "AMIC2", "MIC BIAS2", + "AMIC3", "MIC BIAS3", + "VA SWR_INPUT0", "ADC1_OUTPUT", + "VA SWR_INPUT1", "ADC2_OUTPUT", "VA DMIC0", "vdd-micb", "VA DMIC1", "vdd-micb", "VA DMIC2", "vdd-micb", @@ -65,7 +68,7 @@ }; cpu { - sound-dai = <&qaif_cpu QAIF_CDC_DMA_VA_TX0>; + sound-dai = <&qaif_cpu VA_CODEC_DMA_TX_1>; }; }; @@ -79,7 +82,7 @@ }; cpu { - sound-dai = <&qaif_cpu QAIF_CDC_DMA_RX0>; + sound-dai = <&qaif_cpu RX_CODEC_DMA_RX_1>; }; }; @@ -87,11 +90,18 @@ link-name = "WSA Speaker Playback"; codec { - sound-dai = <&wsa885x_i2c>; + sound-dai = <&wsa8855>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + dai-tdm-slot-rx-mask = <1 1>; }; cpu { - sound-dai = <&qaif_cpu QAIF_MI2S_TDM_AIF2>; + sound-dai = <&qaif_cpu AIF_TDM_RX_2>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <32>; + dai-tdm-slot-rx-mask = <1 1>; + dai-tdm-slot-tx-mask = <1 1>; }; }; @@ -103,7 +113,7 @@ }; cpu { - sound-dai = <&qaif_cpu QAIF_CDC_DMA_VA_TX0>; + sound-dai = <&qaif_cpu VA_CODEC_DMA_TX_0>; }; }; }; @@ -255,10 +265,6 @@ }; }; -&gpr { - status = "disabled"; -}; - &gpu { status = "okay"; }; @@ -267,50 +273,27 @@ firmware-name = "qcom/shikra/a704_zap.mbn"; }; +&gpr { + status = "disabled"; +}; + &i2c3 { status = "okay"; - wsa885x_i2c: speaker@c { - compatible = "qcom,wsa885x-i2c"; + wsa8855: speaker@c { + compatible = "qcom,wsa8855"; reg = <0x0c>; + pinctrl-0 = <&wsa8855_spkr_sd_n>; pinctrl-names = "default"; - pinctrl-0 = <&wsa885x_i2c_spkr_sd_n>; - interrupt-gpios = <&tlmm 77 GPIO_ACTIVE_HIGH>; powerdown-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + interrupt-parent = <&tlmm>; + interrupts = <77 IRQ_TYPE_EDGE_FALLING>; vdd-1p8-supply = <&pm4125_l15>; vdd-io-supply = <&pm4125_l15>; - qcom,battery-config = <2>; - - qcom,wsa885x-init-table = - <0x8470 0x2 - 0x8470 0x0 - 0x8470 0x1 - 0x0004 0x1 - 0x8602 0x60 - 0x8622 0x60 - 0x8458 0x79 - 0x810B 0xD9 - 0x8111 0xD9 - 0x813C 0x08 - 0x8102 0x04 - 0x811C 0x29 - 0x811D 0x40 - 0x8129 0x40 - 0x811A 0x80 - 0x8126 0x80 - 0x8103 0x6 - 0x80CA 0x85 - 0x80CB 0xE - 0x80CC 0xC - 0x80D0 0x80 - 0x80BA 0xC0 - 0x841C 0x4E - 0x8435 0x47 - 0x86CE 0x09 - 0x8667 0x34 - 0x800D 0x08>; + qcom,battery-config = "1s"; + #sound-dai-cells = <0>; }; }; @@ -478,28 +461,6 @@ remote-endpoint = <&usb_qmpphy_out>; }; -&qaif_cpu { - status = "okay"; - - qaif_aif_if2: aif-interface@2 { - compatible = "qcom,qaif-tdm-dai"; - reg = ; - qcom,qaif-aif-sync-mode = ; - qcom,qaif-aif-sync-src = ; - qcom,qaif-aif-sync-delay = <1>; - qcom,qaif-aif-slot-width-rx = <32>; - qcom,qaif-aif-slot-width-tx = <32>; - qcom,qaif-aif-slot-en-rx-mask = <0x3>; - qcom,qaif-aif-slot-en-tx-mask = <0x3>; - qcom,qaif-aif-ctrl-data-oe; - /* Lane 0: RX (mic); Lane 1: TX (speaker) */ - qcom,qaif-aif-lane-config = , - ; - /* frame length = slot-width (32) * bits-per-lane (2) = 64 bits */ - qcom,qaif-aif-bits-per-lane = <2>; - }; -}; - &remoteproc_cdsp { firmware-name = "qcom/shikra/cdsp.mbn"; @@ -594,7 +555,7 @@ pm4125_tx: codec@0,3 { compatible = "sdw20217010c00"; reg = <0 3>; - qcom,tx-port-mapping = <2 2 3 4>; + qcom,tx-port-mapping = <2 3>; }; }; @@ -701,7 +662,7 @@ output-high; }; - wsa885x_i2c_spkr_sd_n: wsa885x-i2c-spkr-sd-n-active-state { + wsa8855_spkr_sd_n: wsa8855-spkr-sd-n-active-state { pins = "gpio2"; function = "gpio"; input-disable; @@ -759,14 +720,6 @@ status = "okay"; }; -&vamacro { - pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&tx_swr_active>; - pinctrl-names = "default"; - - qcom,dmic-sample-rate = <4800000>; - status = "okay"; -}; - &wifi { vdd-0.8-cx-mx-supply = <&pm4125_l7>; vdd-1.8-xo-supply = <&vreg_pmu_xo>; @@ -777,3 +730,11 @@ status = "okay"; }; + +&vamacro { + pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&tx_swr_active>; + pinctrl-names = "default"; + + qcom,dmic-sample-rate = <4800000>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts index 3399777c2d8e0..c537f76960baf 100644 --- a/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts @@ -27,6 +27,18 @@ stdout-path = "serial0:115200n8"; }; + lcd_bias: regulator-lcd-bias { + compatible = "regulator-fixed"; + regulator-name = "lcd_bias"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&pm4125_l17>; + gpio = <&tlmm 151 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&lcd_bias_en>; + pinctrl-names = "default"; + }; + sound { compatible = "qcom,shikra-cqs-sndcard"; model = "shikra-cqs-evk"; @@ -37,7 +49,50 @@ audio-routing = "VA DMIC0", "vdd-micb", "VA DMIC1", "vdd-micb", "VA DMIC2", "vdd-micb", - "VA DMIC3", "vdd-micb"; + "VA DMIC3", "vdd-micb", + "VA SWR_INPUT0", "ADC1_OUTPUT", + "VA SWR_INPUT1", "ADC2_OUTPUT", + "AMIC1", "MIC BIAS1", + "AMIC2", "MIC BIAS2", + "AMIC3", "MIC BIAS3", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT"; + + wcd-playback-dai-link { + link-name = "Headphones Playback"; + + codec { + sound-dai = <&pmic4125_codec 0>, + <&swr0 0>, + <&rxmacro 0>; + }; + + cpu { + sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_1>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; + + wcd-capture-dai-link { + link-name = "Headphones capture"; + + codec { + sound-dai = <&pmic4125_codec 1>, + <&swr1 0>, + <&vamacro 0>; + }; + + cpu { + sound-dai = <&q6apmbedai VA_CODEC_DMA_TX_1>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; va-dmic-dai-link { link-name = "VA DMIC Capture"; @@ -59,7 +114,7 @@ link-name = "WSA Playback"; codec { - sound-dai = <&wsa885x_i2c>; + sound-dai = <&wsa8855>; dai-tdm-slot-num = <2>; dai-tdm-slot-width = <32>; dai-tdm-slot-rx-mask = <1 1>; @@ -78,18 +133,6 @@ }; }; - lcd_bias: regulator-lcd-bias { - compatible = "regulator-fixed"; - regulator-name = "lcd_bias"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&pm4125_l17>; - gpio = <&tlmm 151 GPIO_ACTIVE_HIGH>; - enable-active-high; - pinctrl-0 = <&lcd_bias_en>; - pinctrl-names = "default"; - }; - vreg_0p9: regulator-0v9 { compatible = "regulator-fixed"; regulator-name = "VREG_0P9"; @@ -145,7 +188,6 @@ }; }; }; - }; &audiocorecc { @@ -250,47 +292,19 @@ &i2c3 { status = "okay"; - wsa885x_i2c: speaker@c { - compatible = "qcom,wsa885x-i2c"; + wsa8855: speaker@c { + compatible = "qcom,wsa8855"; reg = <0x0c>; + pinctrl-0 = <&wsa8855_spkr_sd_n>; pinctrl-names = "default"; - pinctrl-0 = <&wsa885x_i2c_spkr_sd_n>; - interrupt-gpios = <&tlmm 77 GPIO_ACTIVE_HIGH>; powerdown-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + interrupt-parent = <&tlmm>; + interrupts = <77 IRQ_TYPE_EDGE_FALLING>; vdd-1p8-supply = <&pm4125_l15>; vdd-io-supply = <&pm4125_l15>; - qcom,battery-config = <2>; - - qcom,wsa885x-init-table = - <0x8470 0x2 - 0x8470 0x0 - 0x8470 0x1 - 0x0004 0x1 - 0x8602 0x60 - 0x8622 0x60 - 0x8458 0x79 - 0x810B 0xD9 - 0x8111 0xD9 - 0x813C 0x08 - 0x8102 0x04 - 0x811C 0x29 - 0x811D 0x40 - 0x8129 0x40 - 0x811A 0x80 - 0x8126 0x80 - 0x8103 0x6 - 0x80CA 0x85 - 0x80CB 0xE - 0x80CC 0xC - 0x80D0 0x80 - 0x80BA 0xC0 - 0x841C 0x4E - 0x8435 0x47 - 0x86CE 0x09 - 0x8667 0x34 - 0x800D 0x08>; + qcom,battery-config = "1s"; #sound-dai-cells = <0>; }; @@ -464,8 +478,7 @@ #size-cells = <0>; dai@40 { reg = ; - clocks = <&q6prmcc LPASS_CLK_ID_AUD_INTF2_IBIT - LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clocks = <&q6prmcc LPASS_CLK_ID_AUD_INTF2_IBIT LPASS_CLK_ATTRIBUTE_COUPLE_NO>; clock-names = "bclk"; }; }; @@ -489,6 +502,18 @@ status = "okay"; }; +&rxmacro { + clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_CLK_ID_RX_CORE_NPL_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&vamacro>; + + clock-names = "mclk", + "npl", + "fsgen"; + + status = "okay"; +}; + &sdhc_1 { vmmc-supply = <&pm4125_l20>; vqmmc-supply = <&pm4125_l14>; @@ -623,7 +648,7 @@ output-high; }; - wsa885x_i2c_spkr_sd_n: wsa885x-i2c-spkr-sd-n-active-state { + wsa8855_spkr_sd_n: wsa8855-spkr-sd-n-active-state { pins = "gpio2"; function = "gpio"; drive-strength = <8>; @@ -642,6 +667,49 @@ }; }; +&spmi_bus { + pmic@0 { + pmic4125_codec: audio-codec@f000 { + compatible = "qcom,pm4125-codec"; + reg = <0xf000>; + vdd-io-supply = <&pm4125_l15>; + vdd-cp-supply = <&pm4125_s1>; + vdd-pa-vpos-supply = <&pm4125_s1>; + + vdd-mic-bias-supply = <&pm4125_l22>; + qcom,micbias1-microvolt = <1800000>; + qcom,micbias2-microvolt = <1800000>; + qcom,micbias3-microvolt = <1800000>; + + qcom,rx-device = <&pm4125_rx>; + qcom,tx-device = <&pm4125_tx>; + #sound-dai-cells = <1>; + + status = "okay"; + }; + }; +}; + +&swr0 { + status = "okay"; + + pm4125_rx: codec@0,4 { + compatible = "sdw20217010c00"; + reg = <0 4>; + qcom,rx-port-mapping = <1 2 3 4 5 >; + }; +}; + +&swr1 { + status = "okay"; + + pm4125_tx: codec@0,3 { + compatible = "sdw20217010c00"; + reg = <0 3>; + qcom,tx-port-mapping = <2 3>; + }; +}; + &uart8 { status = "okay"; @@ -682,6 +750,17 @@ status = "okay"; }; +&wifi { + vdd-0.8-cx-mx-supply = <&pm4125_l7>; + vdd-1.8-xo-supply = <&vreg_pmu_xo>; + vdd-1.3-rfa-supply = <&vreg_pmu_rf>; + vdd-3.3-ch0-supply = <&vreg_pmu_ch0>; + qcom,calibration-variant = "Shikra_EVK"; + firmware-name = "shikra"; + + status = "okay"; +}; + &vamacro { pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&tx_swr_active>; pinctrl-names = "default"; @@ -694,14 +773,3 @@ qcom,dmic-sample-rate = <4800000>; status = "okay"; }; - -&wifi { - vdd-0.8-cx-mx-supply = <&pm4125_l7>; - vdd-1.8-xo-supply = <&vreg_pmu_xo>; - vdd-1.3-rfa-supply = <&vreg_pmu_rf>; - vdd-3.3-ch0-supply = <&vreg_pmu_ch0>; - qcom,calibration-variant = "Shikra_EVK"; - firmware-name = "shikra"; - - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts index f829e0082ce7f..bf1110aedc437 100644 --- a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts @@ -795,20 +795,6 @@ status = "okay"; }; -&vamacro { - clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, - <&q6prmcc LPASS_CLK_ID_TX_CORE_NPL_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - clock-names = "mclk", - "npl"; - - pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&dmic_eldo_en_default>; - pinctrl-names = "default"; - - qcom,dmic-sample-rate = <4800000>; - - status = "okay"; -}; - &wifi { vdd-0.8-cx-mx-supply = <&pm8150_s4>; vdd-1.8-xo-supply = <&vreg_pmu_xo>; @@ -847,3 +833,17 @@ output-high; }; }; + +&vamacro { + clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_CLK_ID_TX_CORE_NPL_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "mclk", + "npl"; + + pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&dmic_eldo_en_default>; + pinctrl-names = "default"; + + qcom,dmic-sample-rate = <4800000>; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi index 4509a1f6c8ef8..afc2e5a42e41b 100644 --- a/arch/arm64/boot/dts/qcom/shikra.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi @@ -3331,159 +3331,6 @@ #power-domain-cells = <1>; }; - qaif_cpu: audio@a000000 { - compatible = "qcom,shikra-qaif-cpu"; - reg = <0x0 0x0a000000 0x0 0x20000>; - - interrupts = ; - - clocks = <&gcc GCC_LPASS_CONFIG_CLK>, - <&gcc GCC_LPASS_CORE_AXIM_CLK>, - <&audiocorecc AUDIO_CORE_CC_AUD_DMA_CLK>, - <&audiocorecc AUDIO_CORE_CC_AUD_DMA_MEM_CLK>, - <&audiocorecc AUDIO_CORE_CC_BUS_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF0_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF0_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF1_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF1_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF2_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF2_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF3_EBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_AIF_IF3_IBIT_CLK>, - <&audiocorecc AUDIO_CORE_CC_EXT_MCLKA_OUT_CLK>, - <&audiocorecc AUDIO_CORE_CC_EXT_MCLKB_OUT_CLK>; - clock-names = "lpass_config_clk", - "lpass_core_axim_clk", - "aud_dma_clk", - "aud_dma_mem_clk", - "bus_clk", - "aif_if0_ebit_clk", - "aif_if0_ibit_clk", - "aif_if1_ebit_clk", - "aif_if1_ibit_clk", - "aif_if2_ebit_clk", - "aif_if2_ibit_clk", - "aif_if3_ebit_clk", - "aif_if3_ibit_clk", - "ext_mclka_clk", - "ext_mclkb_clk"; - - iommus = <&apps_smmu 0x1c0 0x0>; - - #sound-dai-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - - status = "disabled"; - }; - - rxmacro: codec@a040000 { - compatible = "qcom,shikra-lpass-rx-macro"; - reg = <0x0 0x0a040000 0x0 0x1000>; - - pinctrl-0 = <&rx_swr_active>; - pinctrl-names = "default"; - - clocks = <&audiocorecc AUDIO_CORE_CC_RX_MCLK_CLK>, - <&audiocorecc AUDIO_CORE_CC_RX_MCLK_2X_CLK>, - <&vamacro>; - clock-names = "mclk", - "npl", - "fsgen"; - - #clock-cells = <0>; - clock-output-names = "mclk"; - #sound-dai-cells = <1>; - status = "disabled"; - }; - - swr0: soundwire@a060000 { - compatible = "qcom,soundwire-v3.1.0"; - reg = <0x0 0x0a060000 0x0 0x10000>; - qcom,swr-master-ee-val = <0>; - - interrupts = ; - - clocks = <&rxmacro>; - clock-names = "iface"; - - label = "RX"; - qcom,din-ports = <0>; - qcom,dout-ports = <5>; - - resets = <&audiocorecc AUDIO_CORE_CSR_RX_SWR_CGCR>; - reset-names = "swr_audio_cgcr"; - - qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1f 0x1f 0x07 0x00>; - qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00>; - qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00>; - qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff>; - qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff>; - qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff>; - qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff>; - qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00>; - qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00>; - - #sound-dai-cells = <1>; - #address-cells = <2>; - #size-cells = <0>; - status = "disabled"; - }; - - vamacro: codec@a078000 { - compatible = "qcom,shikra-lpass-va-macro"; - reg = <0x0 0x0a078000 0x0 0x2000>; - - pinctrl-0 = <&tx_swr_active>; - pinctrl-names = "default"; - - clocks = <&audiocorecc AUDIO_CORE_CC_TX_MCLK_CLK>, - <&audiocorecc AUDIO_CORE_CC_TX_MCLK_2X_CLK>; - clock-names = "mclk", - "npl"; - - #clock-cells = <0>; - #sound-dai-cells = <1>; - clock-output-names = "fsgen"; - status = "disabled"; - }; - - swr1: soundwire@a080000 { - compatible = "qcom,soundwire-v3.1.0"; - reg = <0x0 0x0a080000 0x0 0x10000>; - qcom,swr-master-ee-val = <0>; - - interrupts = , - ; - interrupt-names = "core", "wakeup"; - - clocks = <&vamacro>; - clock-names = "iface"; - - label = "VA_TX"; - - qcom,din-ports = <4>; - qcom,dout-ports = <0>; - - resets = <&audiocorecc AUDIO_CORE_CSR_TX_SWR_CGCR>; - reset-names = "swr_audio_cgcr"; - - qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>; - qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x01 0x01>; - qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00>; - qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff>; - qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff>; - qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff>; - qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff>; - qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff>; - qcom,ports-lane-control = /bits/ 8 <0x01 0x02 0x00 0x00>; - - #sound-dai-cells = <1>; - #address-cells = <2>; - #size-cells = <0>; - status = "disabled"; - }; - audiocorecc: clock-controller@a0a0000 { compatible = "qcom,shikra-cqm-audiocorecc"; reg = <0x0 0x0a0a0000 0x0 0x10000>, @@ -4753,6 +4600,148 @@ qcom,vmid = ; }; + qaif_cpu: audio@a000000 { + compatible = "qcom,shikra-qaif-cpu"; + reg = <0x0 0x0a000000 0x0 0x20000>; + + interrupts = ; + + clocks = <&gcc GCC_LPASS_CONFIG_CLK>, + <&gcc GCC_LPASS_CORE_AXIM_CLK>, + <&audiocorecc AUDIO_CORE_CC_AUD_DMA_CLK>, + <&audiocorecc AUDIO_CORE_CC_AUD_DMA_MEM_CLK>, + <&audiocorecc AUDIO_CORE_CC_BUS_CLK>, + <&audiocorecc AUDIO_CORE_CC_AIF_IF0_IBIT_CLK>, + <&audiocorecc AUDIO_CORE_CC_AIF_IF1_IBIT_CLK>, + <&audiocorecc AUDIO_CORE_CC_AIF_IF2_IBIT_CLK>, + <&audiocorecc AUDIO_CORE_CC_AIF_IF3_IBIT_CLK>; + clock-names = "lpass_config", + "lpass_core_axim", + "aud_dma", + "aud_dma_mem", + "bus", + "aif_if0_ibit", + "aif_if1_ibit", + "aif_if2_ibit", + "aif_if3_ibit"; + + iommus = <&apps_smmu 0x1c0 0x0>; + + #sound-dai-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + rxmacro: codec@a040000 { + compatible = "qcom,shikra-lpass-rx-macro"; + reg = <0x0 0x0a040000 0x0 0x1000>; + + clocks = <&audiocorecc AUDIO_CORE_CC_RX_MCLK_CLK>, + <&audiocorecc AUDIO_CORE_CC_RX_MCLK_2X_CLK>, + <&vamacro>; + clock-names = "mclk", + "npl", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + + status = "disabled"; + }; + + swr0: soundwire@a060000 { + compatible = "qcom,shikra-soundwire"; + reg = <0x0 0x0a060000 0x0 0x10000>; + + interrupts = ; + + clocks = <&rxmacro>; + clock-names = "iface"; + label = "RX"; + + pinctrl-0 = <&rx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <0>; + qcom,dout-ports = <5>; + + resets = <&audiocorecc AUDIO_CORE_CSR_RX_SWR_CGCR>; + reset-names = "swr_audio_cgcr"; + + qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1f 0x1f 0x07 0x00>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00>; + qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00>; + + #sound-dai-cells = <1>; + #address-cells = <2>; + #size-cells = <0>; + + status = "disabled"; + }; + + vamacro: codec@a078000 { + compatible = "qcom,shikra-lpass-va-macro"; + reg = <0x0 0x0a078000 0x0 0x2000>; + + clocks = <&audiocorecc AUDIO_CORE_CC_TX_MCLK_CLK>, + <&audiocorecc AUDIO_CORE_CC_TX_MCLK_2X_CLK>; + clock-names = "mclk", + "npl"; + + #clock-cells = <0>; + clock-output-names = "fsgen"; + #sound-dai-cells = <1>; + + status = "disabled"; + }; + + swr1: soundwire@a080000 { + compatible = "qcom,shikra-soundwire"; + reg = <0x0 0x0a080000 0x0 0x10000>; + + interrupts = , + ; + interrupt-names = "core", "wakeup"; + + clocks = <&vamacro>; + clock-names = "iface"; + label = "VA_TX"; + + pinctrl-0 = <&tx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <0>; + + resets = <&audiocorecc AUDIO_CORE_CSR_TX_SWR_CGCR>; + reset-names = "swr_audio_cgcr"; + + qcom,ports-sinterval-low = /bits/ 8 <0x01 0x03 0x03 0x03>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x01 0x01 0x01>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00>; + + #sound-dai-cells = <1>; + #address-cells = <2>; + #size-cells = <0>; + + status = "disabled"; + }; + sram@c11e000 { compatible = "qcom,shikra-imem", "mmio-sram"; reg = <0x0 0x0c11e000 0x0 0x1000>; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index a0f9924c797d5..7d4a45575ae1e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1136,7 +1136,7 @@ CONFIG_SND_SOC_WM8978=m CONFIG_SND_SOC_WSA881X=m CONFIG_SND_SOC_WSA883X=m CONFIG_SND_SOC_WSA884X=m -CONFIG_SND_SOC_WSA885X_I2C=m +CONFIG_SND_SOC_WSA885X=m CONFIG_SND_SOC_NAU8822=m CONFIG_SND_SOC_LPASS_WSA_MACRO=m CONFIG_SND_SOC_LPASS_VA_MACRO=m diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 03f20a929e4ba..2f215c0b8e11a 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -25,8 +25,9 @@ #define SWRM_COMP_SW_RESET 0x008 #define SWRM_COMP_STATUS 0x014 #define SWRM_LINK_MANAGER_EE 0x018 -#define SWRM_EE_CPU 1 -#define SWRM_MAX_EE 1 +#define SWRM_EE_CPU0 0 +#define SWRM_EE_CPU1 1 +#define SWRM_EE_CPU SWRM_EE_CPU1 #define SWRM_FRM_GEN_ENABLED BIT(0) #define SWRM_VERSION_1_3_0 0x01030000 #define SWRM_VERSION_1_5_1 0x01050001 @@ -225,8 +226,8 @@ struct qcom_swrm_ctrl { u32 slave_status; u32 wr_fifo_depth; u32 rd_fifo_depth; - bool clock_stop_not_supported; unsigned int reg_layout_local[SWRM_OFFSET_DP_SAMPLECTRL2_BANK + 1]; + bool clock_stop_not_supported; }; struct qcom_swrm_data { @@ -235,6 +236,7 @@ struct qcom_swrm_data { bool sw_clk_gate_required; u32 max_reg; const unsigned int *reg_layout; + u32 ee; }; static const unsigned int swrm_v1_3_reg_layout[] = { @@ -261,6 +263,7 @@ static const struct qcom_swrm_data swrm_v1_3_data = { .default_cols = 16, .max_reg = SWR_V1_3_MSTR_MAX_REG_ADDR, .reg_layout = swrm_v1_3_reg_layout, + .ee = SWRM_EE_CPU, }; static const struct qcom_swrm_data swrm_v1_5_data = { @@ -268,6 +271,7 @@ static const struct qcom_swrm_data swrm_v1_5_data = { .default_cols = 16, .max_reg = SWR_V1_3_MSTR_MAX_REG_ADDR, .reg_layout = swrm_v1_3_reg_layout, + .ee = SWRM_EE_CPU, }; static const struct qcom_swrm_data swrm_v1_6_data = { @@ -276,6 +280,7 @@ static const struct qcom_swrm_data swrm_v1_6_data = { .sw_clk_gate_required = true, .max_reg = SWR_V1_3_MSTR_MAX_REG_ADDR, .reg_layout = swrm_v1_3_reg_layout, + .ee = SWRM_EE_CPU, }; static const unsigned int swrm_v2_0_reg_layout[] = { @@ -303,6 +308,7 @@ static const struct qcom_swrm_data swrm_v2_0_data = { .sw_clk_gate_required = true, .max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR, .reg_layout = swrm_v2_0_reg_layout, + .ee = SWRM_EE_CPU, }; static const unsigned int swrm_v3_0_reg_layout[] = { @@ -330,6 +336,16 @@ static const struct qcom_swrm_data swrm_v3_0_data = { .sw_clk_gate_required = true, .max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR, .reg_layout = swrm_v3_0_reg_layout, + .ee = SWRM_EE_CPU, +}; + +static const struct qcom_swrm_data swrm_shikra_data = { + .default_rows = 50, + .default_cols = 16, + .sw_clk_gate_required = true, + .max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR, + .reg_layout = swrm_v3_0_reg_layout, + .ee = SWRM_EE_CPU0, }; #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus) @@ -346,8 +362,10 @@ static void qcom_swrm_set_ee_register_layout(struct qcom_swrm_ctrl *ctrl, return; /* - * Current register constants map EE1. For EE0, use the EE register - * window stride to access status/IRQ/FIFO registers. + * The register layout constants are defined for EE1 (the default for + * most Qualcomm SoCs). For SoCs where the SoundWire master is assigned + * to EE0, the interrupt, FIFO and status register windows are shifted + * by one EE stride (0x1000) relative to the EE1 base addresses. */ ee_offset = ((int)ctrl->ee - SWRM_EE_CPU) * SWRM_V2_REG_EE_STRIDE; if (!ee_offset) @@ -1598,22 +1616,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) return -ENOMEM; data = of_device_get_match_data(dev); - ctrl->ee = SWRM_EE_CPU; - ret = of_property_read_u32(dev->of_node, "qcom,swr-master-ee-val", &ctrl->ee); - if (ret) - ret = of_property_read_u32(dev->of_node, "qcom,ee", &ctrl->ee); - if (ret) - ctrl->ee = SWRM_EE_CPU; - if (ctrl->ee > SWRM_MAX_EE) { - dev_warn(dev, "invalid SoundWire EE %u, using EE%u\n", - ctrl->ee, SWRM_EE_CPU); - ctrl->ee = SWRM_EE_CPU; - } + ctrl->ee = data->ee; ctrl->max_reg = data->max_reg; - /* - * Defer EE register window selection until HW version is known. - * For v2.0+ the IRQ/FIFO window is EE-banked. - */ ctrl->reg_layout = data->reg_layout; ctrl->rows_index = sdw_find_row_index(data->default_rows); ctrl->cols_index = sdw_find_col_index(data->default_cols); @@ -1890,6 +1894,7 @@ static const struct of_device_id qcom_swrm_of_match[] = { { .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data }, { .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data }, { .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data }, + { .compatible = "qcom,shikra-soundwire", .data = &swrm_shikra_data }, {/* sentinel */}, }; diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index c79d6dc37a5ee..c2c16b617e64c 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -156,6 +156,58 @@ #define LPI_MI2S_TX_5 150 #define LPI_MI2S_RX_6 151 #define LPI_MI2S_TX_6 152 +#define AIF_MI2S_RX_0 153 +#define AIF_MI2S_RX_1 154 +#define AIF_MI2S_RX_2 155 +#define AIF_MI2S_RX_3 156 +#define AIF_MI2S_RX_4 157 +#define AIF_MI2S_RX_5 158 +#define AIF_MI2S_RX_6 159 +#define AIF_MI2S_RX_7 160 +#define AIF_MI2S_RX_8 161 +#define AIF_MI2S_RX_9 162 +#define AIF_MI2S_RX_10 163 +#define AIF_MI2S_RX_11 164 +#define AIF_MI2S_RX_12 165 +#define AIF_MI2S_TX_0 166 +#define AIF_MI2S_TX_1 167 +#define AIF_MI2S_TX_2 168 +#define AIF_MI2S_TX_3 169 +#define AIF_MI2S_TX_4 170 +#define AIF_MI2S_TX_5 171 +#define AIF_MI2S_TX_6 172 +#define AIF_MI2S_TX_7 173 +#define AIF_MI2S_TX_8 174 +#define AIF_MI2S_TX_9 175 +#define AIF_MI2S_TX_10 176 +#define AIF_MI2S_TX_11 177 +#define AIF_MI2S_TX_12 178 +#define AIF_TDM_RX_0 179 +#define AIF_TDM_RX_1 180 +#define AIF_TDM_RX_2 181 +#define AIF_TDM_RX_3 182 +#define AIF_TDM_RX_4 183 +#define AIF_TDM_RX_5 184 +#define AIF_TDM_RX_6 185 +#define AIF_TDM_RX_7 186 +#define AIF_TDM_RX_8 187 +#define AIF_TDM_RX_9 188 +#define AIF_TDM_RX_10 189 +#define AIF_TDM_RX_11 190 +#define AIF_TDM_RX_12 191 +#define AIF_TDM_TX_0 192 +#define AIF_TDM_TX_1 193 +#define AIF_TDM_TX_2 194 +#define AIF_TDM_TX_3 195 +#define AIF_TDM_TX_4 196 +#define AIF_TDM_TX_5 197 +#define AIF_TDM_TX_6 198 +#define AIF_TDM_TX_7 199 +#define AIF_TDM_TX_8 200 +#define AIF_TDM_TX_9 201 +#define AIF_TDM_TX_10 202 +#define AIF_TDM_TX_11 203 +#define AIF_TDM_TX_12 204 #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 #define LPASS_CLK_ID_PRI_MI2S_EBIT 2 diff --git a/include/dt-bindings/sound/qcom,qaif.h b/include/dt-bindings/sound/qcom,qaif.h deleted file mode 100644 index 80d87ce23bb32..0000000000000 --- a/include/dt-bindings/sound/qcom,qaif.h +++ /dev/null @@ -1,92 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * - * DAI IDs for the Qualcomm Audio Interface (QAIF) controller. - * These values are used in devicetree sound-dai references and as - * the reg value of aif-interface child nodes. - */ -#ifndef __DT_QCOM_QAIF_H -#define __DT_QCOM_QAIF_H - -/* qcom,qaif-aif-sync-mode values */ -#define QAIF_AIF_SYNC_MODE_SHORT 0 /* Short (pulse) sync */ -#define QAIF_AIF_SYNC_MODE_LONG 1 /* Long (level) sync */ - -/* qcom,qaif-aif-sync-src values */ -#define QAIF_AIF_SYNC_SRC_SLAVE 0 /* Sync slave -- clock from external */ -#define QAIF_AIF_SYNC_SRC_MASTER 1 /* Sync master -- drive clock/frame */ - -/* qcom,qaif-aif-lane-config enable values */ -#define QAIF_AIF_LANE_DISABLE 0 -#define QAIF_AIF_LANE_ENABLE 1 - -/* qcom,qaif-aif-lane-config direction values */ -#define QAIF_AIF_LANE_DIR_TX 0 /* TX (playback, speaker) */ -#define QAIF_AIF_LANE_DIR_RX 1 /* RX (capture, mic) */ - -/* - * AIF (Unified Audio Interface) DAI IDs -- AIF0 through AIF12. - * Each AIF supports PCM, TDM and MI2S serial protocols over up to - * 8 independent data lanes sharing a single bit clock and frame sync. - */ -#define QAIF_MI2S_TDM_AIF0 0 -#define QAIF_MI2S_TDM_AIF1 1 -#define QAIF_MI2S_TDM_AIF2 2 -#define QAIF_MI2S_TDM_AIF3 3 -#define QAIF_MI2S_TDM_AIF4 4 -#define QAIF_MI2S_TDM_AIF5 5 -#define QAIF_MI2S_TDM_AIF6 6 -#define QAIF_MI2S_TDM_AIF7 7 -#define QAIF_MI2S_TDM_AIF8 8 -#define QAIF_MI2S_TDM_AIF9 9 -#define QAIF_MI2S_TDM_AIF10 10 -#define QAIF_MI2S_TDM_AIF11 11 -#define QAIF_MI2S_TDM_AIF12 12 - -/* - * CIF (Codec Interface) RX DAI IDs -- playback to internal codec. - * RDDMA channels fetch audio from memory and drain it to the codec. - */ -#define QAIF_CDC_DMA_RX0 13 -#define QAIF_CDC_DMA_RX1 14 -#define QAIF_CDC_DMA_RX2 15 -#define QAIF_CDC_DMA_RX3 16 -#define QAIF_CDC_DMA_RX4 17 -#define QAIF_CDC_DMA_RX5 18 -#define QAIF_CDC_DMA_RX6 19 -#define QAIF_CDC_DMA_RX7 20 -#define QAIF_CDC_DMA_RX8 21 -#define QAIF_CDC_DMA_RX9 22 - -/* - * CIF (Codec Interface) TX DAI IDs -- capture from internal codec. - * WRDMA channels collect audio from the codec and write it to memory. - */ -#define QAIF_CDC_DMA_TX0 23 -#define QAIF_CDC_DMA_TX1 24 -#define QAIF_CDC_DMA_TX2 25 -#define QAIF_CDC_DMA_TX3 26 -#define QAIF_CDC_DMA_TX4 27 -#define QAIF_CDC_DMA_TX5 28 -#define QAIF_CDC_DMA_TX6 29 -#define QAIF_CDC_DMA_TX7 30 -#define QAIF_CDC_DMA_TX8 31 -#define QAIF_CDC_DMA_TX9 32 - -/* - * CIF (Codec Interface) VA TX DAI IDs -- capture from voice activity codec. - * WRDMA channels collect audio from the VA codec and write it to memory. - */ -#define QAIF_CDC_DMA_VA_TX0 33 -#define QAIF_CDC_DMA_VA_TX1 34 -#define QAIF_CDC_DMA_VA_TX2 35 -#define QAIF_CDC_DMA_VA_TX3 36 -#define QAIF_CDC_DMA_VA_TX4 37 -#define QAIF_CDC_DMA_VA_TX5 38 -#define QAIF_CDC_DMA_VA_TX6 39 -#define QAIF_CDC_DMA_VA_TX7 40 -#define QAIF_CDC_DMA_VA_TX8 41 -#define QAIF_CDC_DMA_VA_TX9 42 - -#endif /* __DT_QCOM_QAIF_H */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 33968935d00a9..f1a2dfdb860be 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1338,6 +1338,9 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *rx_mask, unsigned int *slots, unsigned int *slot_width); +int snd_soc_of_xlate_dai_name(struct snd_soc_component *component, + const struct of_phandle_args *args, + const char **dai_name); void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2932eb9915606..f24e8b74796d5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -362,7 +362,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WSA881X imply SND_SOC_WSA883X imply SND_SOC_WSA884X - imply SND_SOC_WSA885X_I2C + imply SND_SOC_WSA885X imply SND_SOC_ZL38060 help Normally ASoC codec drivers are only built if a machine driver which @@ -2640,15 +2640,15 @@ config SND_SOC_WSA884X This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D Smart Speaker Amplifier. -config SND_SOC_WSA885X_I2C - tristate "WSA885X I2C Codec" +config SND_SOC_WSA885X + tristate "WSA885X Codec" depends on I2C select REGMAP_I2C help - This enables support for Qualcomm WSA885X Smart Speaker - Amplifiers connected over an I2C control bus. The codec - driver programs the amplifier register map and exposes the - DAI and mixer controls used by Qualcomm audio machine drivers. + This enables support for Qualcomm WSA885X Stereo Smart Speaker + Amplifier. The codec driver programs the amplifier register + map and exposes the DAI and mixer controls used by Qualcomm + audio machine drivers. config SND_SOC_ZL38060 tristate "Microsemi ZL38060 Connected Home Audio Processor" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1602454e593c4..3fbdd2fa52002 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -417,7 +417,7 @@ snd-soc-wm-hubs-y := wm_hubs.o snd-soc-wsa881x-y := wsa881x.o snd-soc-wsa883x-y := wsa883x.o snd-soc-wsa884x-y := wsa884x.o -snd-soc-wsa885x-i2c-y := wsa885x-i2c.o +snd-soc-wsa885x-y := wsa885x.o snd-soc-zl38060-y := zl38060.o # Amp snd-soc-max9877-y := max9877.o @@ -860,7 +860,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o -obj-$(CONFIG_SND_SOC_WSA885X_I2C) += snd-soc-wsa885x-i2c.o +obj-$(CONFIG_SND_SOC_WSA885X) += snd-soc-wsa885x.o obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index 86adad190a102..b52665b11e354 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -10,8 +10,6 @@ #define LPASS_MACRO_FLAG_HAS_NPL_CLOCK BIT(0) /* The soundwire block should be internally reset at probe */ #define LPASS_MACRO_FLAG_RESET_SWR BIT(1) -/* FS counter control bit[7] must be toggled (v4.0) */ -#define LPASS_MACRO_FLAG_BYPASS_FS_CONTROL BIT(2) enum lpass_version { LPASS_VER_9_0_0, @@ -32,7 +30,7 @@ enum lpass_codec_version { LPASS_CODEC_VERSION_2_7, LPASS_CODEC_VERSION_2_8, LPASS_CODEC_VERSION_2_9, - LPASS_CODEC_VERSION_4_0, + LPASS_CODEC_VERSION_4_1, }; struct lpass_macro { @@ -71,8 +69,10 @@ static inline const char *lpass_macro_get_codec_version_string(int version) return "v2.7"; case LPASS_CODEC_VERSION_2_8: return "v2.8"; - case LPASS_CODEC_VERSION_4_0: - return "v4.0"; + case LPASS_CODEC_VERSION_2_9: + return "v2.9"; + case LPASS_CODEC_VERSION_4_1: + return "v4.1"; default: break; } diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 19f4c76ceaffa..6a7489cdb860d 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -59,6 +59,7 @@ #define CDC_RX_FS_MCLK_CNT_ENABLE BIT(0) #define CDC_RX_FS_MCLK_CNT_CLR_MASK BIT(1) #define CDC_RX_FS_MCLK_CNT_CLR BIT(1) +#define CDC_RX_FS_CNT_BYPASS BIT(7) #define CDC_RX_CLK_RST_CTRL_SWR_CONTROL (0x0108) #define CDC_RX_SWR_CLK_EN_MASK BIT(0) #define CDC_RX_SWR_RESET_MASK BIT(1) @@ -646,7 +647,6 @@ struct rx_macro { int clsh_users; int rx_mclk_cnt; enum lpass_codec_version codec_version; - bool bypass_fs_control; int rxn_reg_stride; int rxn_reg_stride2; bool is_ear_mode_on; @@ -1613,7 +1613,7 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg) case LPASS_CODEC_VERSION_2_6: case LPASS_CODEC_VERSION_2_7: case LPASS_CODEC_VERSION_2_8: - case LPASS_CODEC_VERSION_4_0: + case LPASS_CODEC_VERSION_4_1: return rx_2_5_is_rw_register(dev, reg); default: break; @@ -2050,10 +2050,15 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, CDC_RX_FS_MCLK_CNT_CLR_MASK, 0x00); - if (rx->bypass_fs_control) - regmap_update_bits(regmap, - CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, - 0x80, 0x80); + /* + * From LPASS codec v4.1 onwards the FS counter has to be + * bypassed before it is enabled, otherwise the fsgen + * output does not come up. + */ + if (rx->codec_version >= LPASS_CODEC_VERSION_4_1) + regmap_set_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_RX_FS_CNT_BYPASS); + regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, CDC_RX_FS_MCLK_CNT_EN_MASK, CDC_RX_FS_MCLK_CNT_ENABLE); @@ -3662,7 +3667,7 @@ static int rx_macro_component_probe(struct snd_soc_component *component) case LPASS_CODEC_VERSION_2_6: case LPASS_CODEC_VERSION_2_7: case LPASS_CODEC_VERSION_2_8: - case LPASS_CODEC_VERSION_4_0: + case LPASS_CODEC_VERSION_4_1: controls = rx_macro_2_5_snd_controls; num_controls = ARRAY_SIZE(rx_macro_2_5_snd_controls); widgets = rx_macro_2_5_dapm_widgets; @@ -3824,7 +3829,6 @@ static int rx_macro_probe(struct platform_device *pdev) return PTR_ERR(base); rx->codec_version = lpass_macro_get_codec_version(); - rx->bypass_fs_control = !!(flags & LPASS_MACRO_FLAG_BYPASS_FS_CONTROL); struct reg_default *reg_defaults __free(kfree) = NULL; switch (rx->codec_version) { @@ -3847,7 +3851,7 @@ static int rx_macro_probe(struct platform_device *pdev) case LPASS_CODEC_VERSION_2_6: case LPASS_CODEC_VERSION_2_7: case LPASS_CODEC_VERSION_2_8: - case LPASS_CODEC_VERSION_4_0: + case LPASS_CODEC_VERSION_4_1: rx->rxn_reg_stride = 0xc0; rx->rxn_reg_stride2 = 0x0; def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults); @@ -3977,8 +3981,7 @@ static const struct of_device_id rx_macro_dt_match[] = { .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK, }, { .compatible = "qcom,shikra-lpass-rx-macro", - .data = (void *)(LPASS_MACRO_FLAG_HAS_NPL_CLOCK | - LPASS_MACRO_FLAG_BYPASS_FS_CONTROL), + .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK, }, { } }; diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 74fb6b62307f2..ef80c5fb079b0 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -25,6 +25,7 @@ #define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004) #define CDC_VA_FS_CONTROL_EN BIT(0) #define CDC_VA_FS_COUNTER_CLR BIT(1) +#define CDC_VA_FS_CNT_BYPASS BIT(7) #define CDC_VA_CLK_RST_CTRL_SWR_CONTROL (0x0008) #define CDC_VA_SWR_RESET_MASK BIT(1) #define CDC_VA_SWR_RESET_ENABLE BIT(1) @@ -148,57 +149,54 @@ #define CDC_VA_TX3_TX_PATH_SEC5 (0x05A4) #define CDC_VA_TX3_TX_PATH_SEC6 (0x05A8) -/* ADPT control registers - Shikra adaptive filter blocks */ -#define CDC_VA_CDC_ADPT0_ADPT_CTRL (0x0800) -#define CDC_VA_CDC_ADPT0_ADPT_GAIN_0 (0x0804) -#define CDC_VA_CDC_ADPT0_ADPT_GAIN_1 (0x0808) -#define CDC_VA_CDC_ADPT0_DH_FSM_CTRL (0x080C) -#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_0 (0x0810) -#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_1 (0x0814) -#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_2 (0x0818) -#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_3 (0x081C) -#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_4 (0x0820) -#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_5 (0x0824) - -#define CDC_VA_CDC_ADPT1_ADPT_CTRL (0x0880) -#define CDC_VA_CDC_ADPT1_ADPT_GAIN_0 (0x0884) -#define CDC_VA_CDC_ADPT1_ADPT_GAIN_1 (0x0888) -#define CDC_VA_CDC_ADPT1_DH_FSM_CTRL (0x088C) -#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_0 (0x0890) -#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_1 (0x0894) -#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_2 (0x0898) -#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_3 (0x089C) -#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_4 (0x08A0) -#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_5 (0x08A4) -#define CDC_VA_CDC_ADPT1_DBG_CTRL (0x08B0) -#define CDC_VA_CDC_ADPT1_DBG_PDM_RATE_CTRL_0 (0x08B2) -#define CDC_VA_CDC_ADPT1_DBG_PDM_RATE_CTRL_1 (0x08B4) -#define CDC_VA_CDC_ADPT1_SPARE0 (0x08B8) - -#define CDC_VA_CDC_ADPT2_ADPT_CTRL (0x0900) -#define CDC_VA_CDC_ADPT2_ADPT_GAIN_0 (0x0904) -#define CDC_VA_CDC_ADPT2_ADPT_GAIN_1 (0x0908) -#define CDC_VA_CDC_ADPT2_DH_FSM_CTRL (0x090C) -#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_0 (0x0910) -#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_1 (0x0914) -#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_2 (0x0918) -#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_3 (0x091C) -#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_4 (0x0920) -#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_5 (0x0924) - -#define CDC_VA_CDC_ADPT3_ADPT_CTRL (0x0980) -#define CDC_VA_CDC_ADPT3_ADPT_GAIN_0 (0x0984) -#define CDC_VA_CDC_ADPT3_ADPT_GAIN_1 (0x0988) -#define CDC_VA_CDC_ADPT3_DH_FSM_CTRL (0x098C) -#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_0 (0x0990) -#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_1 (0x0994) -#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_2 (0x0998) -#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_3 (0x099C) -#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_4 (0x09A0) -#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_5 (0x09A4) +/* LPASS codec v4.1 adaptive filter (ADPT) blocks */ +#define CDC_VA_CDC_ADPT0_ADPT_CTRL 0x0800 +#define CDC_VA_ADPT_CTRL_EN_MASK GENMASK(7, 0) +#define CDC_VA_CDC_ADPT0_ADPT_GAIN_0 0x0804 +#define CDC_VA_CDC_ADPT0_ADPT_GAIN_1 0x0808 +#define CDC_VA_CDC_ADPT0_DH_FSM_CTRL 0x080c +#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_0 0x0810 +#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_1 0x0814 +#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_2 0x0818 +#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_3 0x081c +#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_4 0x0820 +#define CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_5 0x0824 + +#define CDC_VA_CDC_ADPT1_ADPT_CTRL 0x0880 +#define CDC_VA_CDC_ADPT1_ADPT_GAIN_0 0x0884 +#define CDC_VA_CDC_ADPT1_ADPT_GAIN_1 0x0888 +#define CDC_VA_CDC_ADPT1_DH_FSM_CTRL 0x088c +#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_0 0x0890 +#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_1 0x0894 +#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_2 0x0898 +#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_3 0x089c +#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_4 0x08a0 +#define CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_5 0x08a4 + +#define CDC_VA_CDC_ADPT2_ADPT_CTRL 0x0900 +#define CDC_VA_CDC_ADPT2_ADPT_GAIN_0 0x0904 +#define CDC_VA_CDC_ADPT2_ADPT_GAIN_1 0x0908 +#define CDC_VA_CDC_ADPT2_DH_FSM_CTRL 0x090c +#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_0 0x0910 +#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_1 0x0914 +#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_2 0x0918 +#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_3 0x091c +#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_4 0x0920 +#define CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_5 0x0924 + +#define CDC_VA_CDC_ADPT3_ADPT_CTRL 0x0980 +#define CDC_VA_CDC_ADPT3_ADPT_GAIN_0 0x0984 +#define CDC_VA_CDC_ADPT3_ADPT_GAIN_1 0x0988 +#define CDC_VA_CDC_ADPT3_DH_FSM_CTRL 0x098c +#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_0 0x0990 +#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_1 0x0994 +#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_2 0x0998 +#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_3 0x099c +#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_4 0x09a0 +#define CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_5 0x09a4 #define VA_MAX_OFFSET (0x07A8) -#define VA_SHIKRA_MAX_OFFSET (0x0980) +#define VA_4_1_MAX_OFFSET 0x09a4 #define VA_MACRO_NUM_DECIMATORS 4 #define VA_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ @@ -252,9 +250,6 @@ struct va_macro { u16 dmic_clk_div; bool has_swr_master; bool has_npl_clk; - bool bypass_fs_control; - bool has_adpt_block; - int dec_mode[VA_MACRO_NUM_DECIMATORS]; struct regmap *regmap; struct clk *mclk; @@ -280,12 +275,31 @@ struct va_macro { struct va_macro_data { bool has_swr_master; bool has_npl_clk; - bool bypass_fs_control; - bool has_adpt_block; int version; const struct regmap_config *regmap_config; }; +static const struct va_macro_data sc7280_va_data = { + .has_swr_master = false, + .has_npl_clk = false, +}; + +static const struct va_macro_data sm8250_va_data = { + .has_swr_master = false, + .has_npl_clk = false, + .version = LPASS_CODEC_VERSION_1_0, +}; + +static const struct va_macro_data sm8450_va_data = { + .has_swr_master = true, + .has_npl_clk = true, +}; + +static const struct va_macro_data sm8550_va_data = { + .has_swr_master = true, + .has_npl_clk = false, +}; + static bool va_is_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -383,117 +397,7 @@ static const struct reg_default va_defaults[] = { { CDC_VA_TX3_TX_PATH_SEC6, 0x00}, }; -static bool va_is_rw_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CDC_VA_CLK_RST_CTRL_MCLK_CONTROL: - case CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL: - case CDC_VA_CLK_RST_CTRL_SWR_CONTROL: - case CDC_VA_TOP_CSR_TOP_CFG0: - case CDC_VA_TOP_CSR_DMIC0_CTL: - case CDC_VA_TOP_CSR_DMIC1_CTL: - case CDC_VA_TOP_CSR_DMIC2_CTL: - case CDC_VA_TOP_CSR_DMIC3_CTL: - case CDC_VA_TOP_CSR_DMIC_CFG: - case CDC_VA_TOP_CSR_SWR_MIC_CTL0: - case CDC_VA_TOP_CSR_SWR_MIC_CTL1: - case CDC_VA_TOP_CSR_SWR_MIC_CTL2: - case CDC_VA_TOP_CSR_DEBUG_BUS: - case CDC_VA_TOP_CSR_DEBUG_EN: - case CDC_VA_TOP_CSR_TX_I2S_CTL: - case CDC_VA_TOP_CSR_I2S_CLK: - case CDC_VA_TOP_CSR_I2S_RESET: - case CDC_VA_INP_MUX_ADC_MUX0_CFG0: - case CDC_VA_INP_MUX_ADC_MUX0_CFG1: - case CDC_VA_INP_MUX_ADC_MUX1_CFG0: - case CDC_VA_INP_MUX_ADC_MUX1_CFG1: - case CDC_VA_INP_MUX_ADC_MUX2_CFG0: - case CDC_VA_INP_MUX_ADC_MUX2_CFG1: - case CDC_VA_INP_MUX_ADC_MUX3_CFG0: - case CDC_VA_INP_MUX_ADC_MUX3_CFG1: - case CDC_VA_TX0_TX_PATH_CTL: - case CDC_VA_TX0_TX_PATH_CFG0: - case CDC_VA_TX0_TX_PATH_CFG1: - case CDC_VA_TX0_TX_VOL_CTL: - case CDC_VA_TX0_TX_PATH_SEC0: - case CDC_VA_TX0_TX_PATH_SEC1: - case CDC_VA_TX0_TX_PATH_SEC2: - case CDC_VA_TX0_TX_PATH_SEC3: - case CDC_VA_TX0_TX_PATH_SEC4: - case CDC_VA_TX0_TX_PATH_SEC5: - case CDC_VA_TX0_TX_PATH_SEC6: - case CDC_VA_TX0_TX_PATH_SEC7: - case CDC_VA_TX1_TX_PATH_CTL: - case CDC_VA_TX1_TX_PATH_CFG0: - case CDC_VA_TX1_TX_PATH_CFG1: - case CDC_VA_TX1_TX_VOL_CTL: - case CDC_VA_TX1_TX_PATH_SEC0: - case CDC_VA_TX1_TX_PATH_SEC1: - case CDC_VA_TX1_TX_PATH_SEC2: - case CDC_VA_TX1_TX_PATH_SEC3: - case CDC_VA_TX1_TX_PATH_SEC4: - case CDC_VA_TX1_TX_PATH_SEC5: - case CDC_VA_TX1_TX_PATH_SEC6: - case CDC_VA_TX2_TX_PATH_CTL: - case CDC_VA_TX2_TX_PATH_CFG0: - case CDC_VA_TX2_TX_PATH_CFG1: - case CDC_VA_TX2_TX_VOL_CTL: - case CDC_VA_TX2_TX_PATH_SEC0: - case CDC_VA_TX2_TX_PATH_SEC1: - case CDC_VA_TX2_TX_PATH_SEC2: - case CDC_VA_TX2_TX_PATH_SEC3: - case CDC_VA_TX2_TX_PATH_SEC4: - case CDC_VA_TX2_TX_PATH_SEC5: - case CDC_VA_TX2_TX_PATH_SEC6: - case CDC_VA_TX3_TX_PATH_CTL: - case CDC_VA_TX3_TX_PATH_CFG0: - case CDC_VA_TX3_TX_PATH_CFG1: - case CDC_VA_TX3_TX_VOL_CTL: - case CDC_VA_TX3_TX_PATH_SEC0: - case CDC_VA_TX3_TX_PATH_SEC1: - case CDC_VA_TX3_TX_PATH_SEC2: - case CDC_VA_TX3_TX_PATH_SEC3: - case CDC_VA_TX3_TX_PATH_SEC4: - case CDC_VA_TX3_TX_PATH_SEC5: - case CDC_VA_TX3_TX_PATH_SEC6: - case CDC_VA_CDC_ADPT0_ADPT_CTRL: - case CDC_VA_CDC_ADPT1_ADPT_CTRL: - case CDC_VA_CDC_ADPT2_ADPT_CTRL: - case CDC_VA_CDC_ADPT3_ADPT_CTRL: - return true; - } - - return false; -} - -static bool va_is_readable_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CDC_VA_TOP_CSR_CORE_ID_0: - case CDC_VA_TOP_CSR_CORE_ID_1: - case CDC_VA_TOP_CSR_CORE_ID_2: - case CDC_VA_TOP_CSR_CORE_ID_3: - return true; - } - - return va_is_rw_register(dev, reg); -} - -static const struct regmap_config va_regmap_config = { - .name = "va_macro", - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .cache_type = REGCACHE_FLAT, - .reg_defaults = va_defaults, - .num_reg_defaults = ARRAY_SIZE(va_defaults), - .max_register = VA_MAX_OFFSET, - .volatile_reg = va_is_volatile_register, - .readable_reg = va_is_readable_register, - .writeable_reg = va_is_rw_register, -}; - -static const struct reg_default va_shikra_defaults[] = { +static const struct reg_default va_4_1_defaults[] = { /* VA macro */ { CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, { CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, @@ -571,49 +475,41 @@ static const struct reg_default va_shikra_defaults[] = { { CDC_VA_TX3_TX_PATH_SEC4, 0x20}, { CDC_VA_TX3_TX_PATH_SEC5, 0x00}, { CDC_VA_TX3_TX_PATH_SEC6, 0x00}, - /* ADPT blocks - Shikra adaptive filter control */ - - /* CDC ADPT0 - adaptive filter */ + /* ADPT blocks */ { CDC_VA_CDC_ADPT0_ADPT_CTRL, 0x51}, - { CDC_VA_CDC_ADPT0_ADPT_GAIN_0, 0x11}, - { CDC_VA_CDC_ADPT0_ADPT_GAIN_1, 0x01}, - { CDC_VA_CDC_ADPT0_DH_FSM_CTRL, 0x02}, + { CDC_VA_CDC_ADPT0_ADPT_GAIN_0, 0x11}, + { CDC_VA_CDC_ADPT0_ADPT_GAIN_1, 0x01}, + { CDC_VA_CDC_ADPT0_DH_FSM_CTRL, 0x02}, { CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_0, 0x77}, { CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_1, 0x64}, { CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_2, 0x00}, { CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_3, 0x41}, { CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_4, 0x04}, { CDC_VA_CDC_ADPT0_CUTOFF_FSM_CTRL_5, 0x01}, - - /* CDC ADPT1 */ { CDC_VA_CDC_ADPT1_ADPT_CTRL, 0x51}, - { CDC_VA_CDC_ADPT1_ADPT_GAIN_0, 0x11}, - { CDC_VA_CDC_ADPT1_ADPT_GAIN_1, 0x01}, - { CDC_VA_CDC_ADPT1_DH_FSM_CTRL, 0x02}, + { CDC_VA_CDC_ADPT1_ADPT_GAIN_0, 0x11}, + { CDC_VA_CDC_ADPT1_ADPT_GAIN_1, 0x01}, + { CDC_VA_CDC_ADPT1_DH_FSM_CTRL, 0x02}, { CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_0, 0x77}, { CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_1, 0x64}, { CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_2, 0x00}, { CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_3, 0x41}, { CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_4, 0x04}, { CDC_VA_CDC_ADPT1_CUTOFF_FSM_CTRL_5, 0x01}, - - /* CDC ADPT2 */ { CDC_VA_CDC_ADPT2_ADPT_CTRL, 0x51}, - { CDC_VA_CDC_ADPT2_ADPT_GAIN_0, 0x11}, - { CDC_VA_CDC_ADPT2_ADPT_GAIN_1, 0x01}, - { CDC_VA_CDC_ADPT2_DH_FSM_CTRL, 0x02}, + { CDC_VA_CDC_ADPT2_ADPT_GAIN_0, 0x11}, + { CDC_VA_CDC_ADPT2_ADPT_GAIN_1, 0x01}, + { CDC_VA_CDC_ADPT2_DH_FSM_CTRL, 0x02}, { CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_0, 0x77}, { CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_1, 0x64}, { CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_2, 0x00}, { CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_3, 0x41}, { CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_4, 0x04}, { CDC_VA_CDC_ADPT2_CUTOFF_FSM_CTRL_5, 0x01}, - - /* CDC ADPT3 */ { CDC_VA_CDC_ADPT3_ADPT_CTRL, 0x51}, - { CDC_VA_CDC_ADPT3_ADPT_GAIN_0, 0x11}, + { CDC_VA_CDC_ADPT3_ADPT_GAIN_0, 0x11}, { CDC_VA_CDC_ADPT3_ADPT_GAIN_1, 0x01}, - { CDC_VA_CDC_ADPT3_DH_FSM_CTRL, 0x02}, + { CDC_VA_CDC_ADPT3_DH_FSM_CTRL, 0x02}, { CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_0, 0x77}, { CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_1, 0x64}, { CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_2, 0x00}, @@ -622,48 +518,135 @@ static const struct reg_default va_shikra_defaults[] = { { CDC_VA_CDC_ADPT3_CUTOFF_FSM_CTRL_5, 0x01}, }; -static const struct regmap_config shikra_va_regmap_config = { +static bool va_is_rw_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_VA_CLK_RST_CTRL_MCLK_CONTROL: + case CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL: + case CDC_VA_CLK_RST_CTRL_SWR_CONTROL: + case CDC_VA_TOP_CSR_TOP_CFG0: + case CDC_VA_TOP_CSR_DMIC0_CTL: + case CDC_VA_TOP_CSR_DMIC1_CTL: + case CDC_VA_TOP_CSR_DMIC2_CTL: + case CDC_VA_TOP_CSR_DMIC3_CTL: + case CDC_VA_TOP_CSR_DMIC_CFG: + case CDC_VA_TOP_CSR_SWR_MIC_CTL0: + case CDC_VA_TOP_CSR_SWR_MIC_CTL1: + case CDC_VA_TOP_CSR_SWR_MIC_CTL2: + case CDC_VA_TOP_CSR_DEBUG_BUS: + case CDC_VA_TOP_CSR_DEBUG_EN: + case CDC_VA_TOP_CSR_TX_I2S_CTL: + case CDC_VA_TOP_CSR_I2S_CLK: + case CDC_VA_TOP_CSR_I2S_RESET: + case CDC_VA_INP_MUX_ADC_MUX0_CFG0: + case CDC_VA_INP_MUX_ADC_MUX0_CFG1: + case CDC_VA_INP_MUX_ADC_MUX1_CFG0: + case CDC_VA_INP_MUX_ADC_MUX1_CFG1: + case CDC_VA_INP_MUX_ADC_MUX2_CFG0: + case CDC_VA_INP_MUX_ADC_MUX2_CFG1: + case CDC_VA_INP_MUX_ADC_MUX3_CFG0: + case CDC_VA_INP_MUX_ADC_MUX3_CFG1: + case CDC_VA_TX0_TX_PATH_CTL: + case CDC_VA_TX0_TX_PATH_CFG0: + case CDC_VA_TX0_TX_PATH_CFG1: + case CDC_VA_TX0_TX_VOL_CTL: + case CDC_VA_TX0_TX_PATH_SEC0: + case CDC_VA_TX0_TX_PATH_SEC1: + case CDC_VA_TX0_TX_PATH_SEC2: + case CDC_VA_TX0_TX_PATH_SEC3: + case CDC_VA_TX0_TX_PATH_SEC4: + case CDC_VA_TX0_TX_PATH_SEC5: + case CDC_VA_TX0_TX_PATH_SEC6: + case CDC_VA_TX0_TX_PATH_SEC7: + case CDC_VA_TX1_TX_PATH_CTL: + case CDC_VA_TX1_TX_PATH_CFG0: + case CDC_VA_TX1_TX_PATH_CFG1: + case CDC_VA_TX1_TX_VOL_CTL: + case CDC_VA_TX1_TX_PATH_SEC0: + case CDC_VA_TX1_TX_PATH_SEC1: + case CDC_VA_TX1_TX_PATH_SEC2: + case CDC_VA_TX1_TX_PATH_SEC3: + case CDC_VA_TX1_TX_PATH_SEC4: + case CDC_VA_TX1_TX_PATH_SEC5: + case CDC_VA_TX1_TX_PATH_SEC6: + case CDC_VA_TX2_TX_PATH_CTL: + case CDC_VA_TX2_TX_PATH_CFG0: + case CDC_VA_TX2_TX_PATH_CFG1: + case CDC_VA_TX2_TX_VOL_CTL: + case CDC_VA_TX2_TX_PATH_SEC0: + case CDC_VA_TX2_TX_PATH_SEC1: + case CDC_VA_TX2_TX_PATH_SEC2: + case CDC_VA_TX2_TX_PATH_SEC3: + case CDC_VA_TX2_TX_PATH_SEC4: + case CDC_VA_TX2_TX_PATH_SEC5: + case CDC_VA_TX2_TX_PATH_SEC6: + case CDC_VA_TX3_TX_PATH_CTL: + case CDC_VA_TX3_TX_PATH_CFG0: + case CDC_VA_TX3_TX_PATH_CFG1: + case CDC_VA_TX3_TX_VOL_CTL: + case CDC_VA_TX3_TX_PATH_SEC0: + case CDC_VA_TX3_TX_PATH_SEC1: + case CDC_VA_TX3_TX_PATH_SEC2: + case CDC_VA_TX3_TX_PATH_SEC3: + case CDC_VA_TX3_TX_PATH_SEC4: + case CDC_VA_TX3_TX_PATH_SEC5: + case CDC_VA_TX3_TX_PATH_SEC6: + case CDC_VA_CDC_ADPT0_ADPT_CTRL: + case CDC_VA_CDC_ADPT1_ADPT_CTRL: + case CDC_VA_CDC_ADPT2_ADPT_CTRL: + case CDC_VA_CDC_ADPT3_ADPT_CTRL: + return true; + } + + return false; +} + +static bool va_is_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_VA_TOP_CSR_CORE_ID_0: + case CDC_VA_TOP_CSR_CORE_ID_1: + case CDC_VA_TOP_CSR_CORE_ID_2: + case CDC_VA_TOP_CSR_CORE_ID_3: + return true; + } + + return va_is_rw_register(dev, reg); +} + +static const struct regmap_config va_regmap_config = { .name = "va_macro", .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .cache_type = REGCACHE_FLAT, - .reg_defaults = va_shikra_defaults, - .num_reg_defaults = ARRAY_SIZE(va_shikra_defaults), - .max_register = VA_SHIKRA_MAX_OFFSET, + .reg_defaults = va_defaults, + .num_reg_defaults = ARRAY_SIZE(va_defaults), + .max_register = VA_MAX_OFFSET, .volatile_reg = va_is_volatile_register, .readable_reg = va_is_readable_register, .writeable_reg = va_is_rw_register, }; -static const struct va_macro_data sm8250_va_data = { - .has_swr_master = false, - .has_npl_clk = false, - .version = LPASS_CODEC_VERSION_1_0, -}; - -static const struct va_macro_data sc7280_va_data = { - .has_swr_master = false, - .has_npl_clk = false, -}; - -static const struct va_macro_data sm8450_va_data = { - .has_swr_master = true, - .has_npl_clk = true, +static const struct regmap_config va_4_1_regmap_config = { + .name = "va_macro", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .cache_type = REGCACHE_FLAT, + .reg_defaults = va_4_1_defaults, + .num_reg_defaults = ARRAY_SIZE(va_4_1_defaults), + .max_register = VA_4_1_MAX_OFFSET, + .volatile_reg = va_is_volatile_register, + .readable_reg = va_is_readable_register, + .writeable_reg = va_is_rw_register, }; static const struct va_macro_data shikra_va_data = { .has_swr_master = true, .has_npl_clk = true, - .bypass_fs_control = true, - .has_adpt_block = true, - .version = LPASS_CODEC_VERSION_4_0, - .regmap_config = &shikra_va_regmap_config, -}; - -static const struct va_macro_data sm8550_va_data = { - .has_swr_master = true, - .has_npl_clk = false, + .version = LPASS_CODEC_VERSION_4_1, + .regmap_config = &va_4_1_regmap_config, }; static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable) @@ -674,14 +657,14 @@ static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, CDC_VA_MCLK_CONTROL_EN, CDC_VA_MCLK_CONTROL_EN); - /* clear the fs counter */ + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR, CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR); - if (va->bypass_fs_control) - regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, - 0x80, 0x80); + if (lpass_macro_get_codec_version() >= LPASS_CODEC_VERSION_4_1) + regmap_set_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_VA_FS_CNT_BYPASS); regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR, CDC_VA_FS_CONTROL_EN); @@ -766,10 +749,16 @@ static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (val != 0) - snd_soc_component_update_bits(component, mic_sel_reg, - CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK, - CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC); + if (val != 0) { + if (strstr(widget->name, "SMIC")) + snd_soc_component_update_bits(component, mic_sel_reg, + CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK, + CDC_VA_TX_PATH_ADC_DMIC_SEL_ADC); + else + snd_soc_component_update_bits(component, mic_sel_reg, + CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK, + CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC); + } return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); } @@ -952,6 +941,16 @@ static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w, return 0; } +static bool is_amic_enabled(struct snd_soc_component *comp, int decimator) +{ + u16 adc_mux_reg; + + adc_mux_reg = CDC_VA_INP_MUX_ADC_MUX0_CFG1 + + VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + + return snd_soc_component_read(comp, adc_mux_reg) & BIT(0); +} + static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -959,9 +958,8 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, unsigned int decimator; u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg; u16 tx_gain_ctl_reg; - u16 adapt_ctrl; + u16 adpt_ctrl_reg; u8 hpf_cut_off_freq; - struct va_macro *va = snd_soc_component_get_drvdata(comp); decimator = w->shift; @@ -974,8 +972,7 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, VA_MACRO_TX_PATH_OFFSET * decimator; tx_gain_ctl_reg = CDC_VA_TX0_TX_VOL_CTL + VA_MACRO_TX_PATH_OFFSET * decimator; - adapt_ctrl = CDC_VA_CDC_ADPT0_ADPT_CTRL + - (decimator * VA_MACRO_TX_PATH_OFFSET); + adpt_ctrl_reg = CDC_VA_CDC_ADPT0_ADPT_CTRL + decimator * VA_MACRO_TX_PATH_OFFSET; switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -985,15 +982,18 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, /* Enable TX PGA Mute */ break; case SND_SOC_DAPM_POST_PMU: - if (va->has_adpt_block) - snd_soc_component_update_bits(comp, adapt_ctrl, 0xFF, 0x00); + if (lpass_macro_get_codec_version() >= LPASS_CODEC_VERSION_4_1) + snd_soc_component_update_bits(comp, adpt_ctrl_reg, + CDC_VA_ADPT_CTRL_EN_MASK, 0x00); + /* Enable TX CLK */ snd_soc_component_update_bits(comp, tx_vol_ctl_reg, CDC_VA_TX_PATH_CLK_EN_MASK, CDC_VA_TX_PATH_CLK_EN); - snd_soc_component_update_bits(comp, hpf_gate_reg, - CDC_VA_TX_HPF_ZERO_GATE_MASK, - CDC_VA_TX_HPF_ZERO_GATE); + if (!is_amic_enabled(comp, decimator)) + snd_soc_component_update_bits(comp, hpf_gate_reg, + CDC_VA_TX_HPF_ZERO_GATE_MASK, + CDC_VA_TX_HPF_ZERO_GATE); usleep_range(1000, 1010); hpf_cut_off_freq = (snd_soc_component_read(comp, dec_cfg_reg) & @@ -1005,21 +1005,20 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, CF_MIN_3DB_150HZ << 5); snd_soc_component_update_bits(comp, hpf_gate_reg, - CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK, - CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ); + CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK, + CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ); /* * Minimum 1 clk cycle delay is required as per HW spec */ usleep_range(1000, 1010); - snd_soc_component_update_bits(comp, - hpf_gate_reg, - CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK, - 0x0); + if (!is_amic_enabled(comp, decimator)) + snd_soc_component_update_bits(comp, hpf_gate_reg, + CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK, + 0x0); } - usleep_range(1000, 1010); snd_soc_component_update_bits(comp, hpf_gate_reg, CDC_VA_TX_HPF_ZERO_GATE_MASK, @@ -1219,6 +1218,39 @@ static const char * const adc_mux_text[] = { "VA_DMIC", "SWR_MIC" }; +static const char * const smic_mux_text[] = { + "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7" +}; + +static SOC_ENUM_SINGLE_DECL(va_smic0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text); + +static SOC_ENUM_SINGLE_DECL(va_smic1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text); + +static SOC_ENUM_SINGLE_DECL(va_smic2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text); + +static SOC_ENUM_SINGLE_DECL(va_smic3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text); + +static const struct snd_kcontrol_new va_smic0_mux = SOC_DAPM_ENUM_EXT("va_smic0", + va_smic0_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_smic1_mux = SOC_DAPM_ENUM_EXT("va_smic1", + va_smic1_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_smic2_mux = SOC_DAPM_ENUM_EXT("va_smic2", + va_smic2_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_smic3_mux = SOC_DAPM_ENUM_EXT("va_smic3", + va_smic3_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + static SOC_ENUM_SINGLE_DECL(va_dec0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG1, 0, adc_mux_text); static SOC_ENUM_SINGLE_DECL(va_dec1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG1, @@ -1354,6 +1386,11 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX("VA DMIC MUX2", SND_SOC_NOPM, 0, 0, &va_dmic2_mux), SND_SOC_DAPM_MUX("VA DMIC MUX3", SND_SOC_NOPM, 0, 0, &va_dmic3_mux), + SND_SOC_DAPM_MUX("VA SMIC MUX0", SND_SOC_NOPM, 0, 0, &va_smic0_mux), + SND_SOC_DAPM_MUX("VA SMIC MUX1", SND_SOC_NOPM, 0, 0, &va_smic1_mux), + SND_SOC_DAPM_MUX("VA SMIC MUX2", SND_SOC_NOPM, 0, 0, &va_smic2_mux), + SND_SOC_DAPM_MUX("VA SMIC MUX3", SND_SOC_NOPM, 0, 0, &va_smic3_mux), + SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micb", 0, 0), SND_SOC_DAPM_INPUT("DMIC0 Pin"), SND_SOC_DAPM_INPUT("DMIC1 Pin"), @@ -1408,6 +1445,14 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = { SND_SOC_DAPM_INPUT("VA SWR_MIC5"), SND_SOC_DAPM_INPUT("VA SWR_MIC6"), SND_SOC_DAPM_INPUT("VA SWR_MIC7"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT0"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT1"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT2"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT3"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT4"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT5"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT6"), + SND_SOC_DAPM_INPUT("VA SWR_INPUT7"), SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0, &va_dec0_mux, va_macro_enable_dec, @@ -1498,6 +1543,46 @@ static const struct snd_soc_dapm_route va_audio_map[] = { {"VA DMIC MUX3", "DMIC6", "VA DMIC6"}, {"VA DMIC MUX3", "DMIC7", "VA DMIC7"}, + {"VA DEC0 MUX", "SWR_MIC", "VA SMIC MUX0"}, + {"VA SMIC MUX0", "SWR_MIC0", "VA SWR_INPUT0"}, + {"VA SMIC MUX0", "SWR_MIC1", "VA SWR_INPUT1"}, + {"VA SMIC MUX0", "SWR_MIC2", "VA SWR_INPUT2"}, + {"VA SMIC MUX0", "SWR_MIC3", "VA SWR_INPUT3"}, + {"VA SMIC MUX0", "SWR_MIC4", "VA SWR_INPUT4"}, + {"VA SMIC MUX0", "SWR_MIC5", "VA SWR_INPUT5"}, + {"VA SMIC MUX0", "SWR_MIC6", "VA SWR_INPUT6"}, + {"VA SMIC MUX0", "SWR_MIC7", "VA SWR_INPUT7"}, + + {"VA DEC1 MUX", "SWR_MIC", "VA SMIC MUX1"}, + {"VA SMIC MUX1", "SWR_MIC0", "VA SWR_INPUT0"}, + {"VA SMIC MUX1", "SWR_MIC1", "VA SWR_INPUT1"}, + {"VA SMIC MUX1", "SWR_MIC2", "VA SWR_INPUT2"}, + {"VA SMIC MUX1", "SWR_MIC3", "VA SWR_INPUT3"}, + {"VA SMIC MUX1", "SWR_MIC4", "VA SWR_INPUT4"}, + {"VA SMIC MUX1", "SWR_MIC5", "VA SWR_INPUT5"}, + {"VA SMIC MUX1", "SWR_MIC6", "VA SWR_INPUT6"}, + {"VA SMIC MUX1", "SWR_MIC7", "VA SWR_INPUT7"}, + + {"VA DEC2 MUX", "SWR_MIC", "VA SMIC MUX2"}, + {"VA SMIC MUX2", "SWR_MIC0", "VA SWR_INPUT0"}, + {"VA SMIC MUX2", "SWR_MIC1", "VA SWR_INPUT1"}, + {"VA SMIC MUX2", "SWR_MIC2", "VA SWR_INPUT2"}, + {"VA SMIC MUX2", "SWR_MIC3", "VA SWR_INPUT3"}, + {"VA SMIC MUX2", "SWR_MIC4", "VA SWR_INPUT4"}, + {"VA SMIC MUX2", "SWR_MIC5", "VA SWR_INPUT5"}, + {"VA SMIC MUX2", "SWR_MIC6", "VA SWR_INPUT6"}, + {"VA SMIC MUX2", "SWR_MIC7", "VA SWR_INPUT7"}, + + {"VA DEC3 MUX", "SWR_MIC", "VA SMIC MUX3"}, + {"VA SMIC MUX3", "SWR_MIC0", "VA SWR_INPUT0"}, + {"VA SMIC MUX3", "SWR_MIC1", "VA SWR_INPUT1"}, + {"VA SMIC MUX3", "SWR_MIC2", "VA SWR_INPUT2"}, + {"VA SMIC MUX3", "SWR_MIC3", "VA SWR_INPUT3"}, + {"VA SMIC MUX3", "SWR_MIC4", "VA SWR_INPUT4"}, + {"VA SMIC MUX3", "SWR_MIC5", "VA SWR_INPUT5"}, + {"VA SMIC MUX3", "SWR_MIC6", "VA SWR_INPUT6"}, + {"VA SMIC MUX3", "SWR_MIC7", "VA SWR_INPUT7"}, + { "VA DMIC0", NULL, "DMIC0 Pin" }, { "VA DMIC1", NULL, "DMIC1 Pin" }, { "VA DMIC2", NULL, "DMIC2 Pin" }, @@ -1734,7 +1819,7 @@ static void va_macro_set_lpass_codec_version(struct va_macro *va) if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x90 || core_id_2 == 0x91)) version = LPASS_CODEC_VERSION_2_9; if (core_id_0 == 0x04) - version = LPASS_CODEC_VERSION_4_0; + version = LPASS_CODEC_VERSION_4_1; if (version == LPASS_CODEC_VERSION_UNKNOWN) @@ -1761,6 +1846,7 @@ static int va_macro_probe(struct platform_device *pdev) return -ENOMEM; va->dev = dev; + data = of_device_get_match_data(dev); va->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(va->macro)) @@ -1797,21 +1883,17 @@ static int va_macro_probe(struct platform_device *pdev) goto err; } - data = of_device_get_match_data(dev); - va->has_swr_master = data->has_swr_master; - va->has_npl_clk = data->has_npl_clk; - va->bypass_fs_control = data->bypass_fs_control; - va->has_adpt_block = data->has_adpt_block; + dev_set_drvdata(dev, va); va->regmap = devm_regmap_init_mmio(dev, base, - data->regmap_config ? data->regmap_config - : &va_regmap_config); + data->regmap_config ?: &va_regmap_config); if (IS_ERR(va->regmap)) { ret = -EINVAL; goto err; } - dev_set_drvdata(dev, va); + va->has_swr_master = data->has_swr_master; + va->has_npl_clk = data->has_npl_clk; /* mclk rate */ clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); diff --git a/sound/soc/codecs/wsa885x-i2c.c b/sound/soc/codecs/wsa885x.c similarity index 75% rename from sound/soc/codecs/wsa885x-i2c.c rename to sound/soc/codecs/wsa885x.c index a7d8f8d48a21c..1faa8541a872e 100644 --- a/sound/soc/codecs/wsa885x-i2c.c +++ b/sound/soc/codecs/wsa885x.c @@ -3,23 +3,27 @@ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ -/* WSA885X I2C codec driver */ +/* WSA885X codec driver */ -#include #include +#include +#include #include +#include +#include #include -#include #include +#include #include +#include #include +#include #include #include #include -#include #include +#include #include -#include /* Control Registers - Audio Processing */ #define WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S 0x0000 @@ -142,7 +146,6 @@ /* Driver Constants */ #define WSA885X_CLK_RATE_FIXED 73728000 -#define WSA885X_SUPPLIES_NUM 2 #define WSA885X_NUM_REGS 0x03 /* Interrupt Registers */ @@ -194,6 +197,8 @@ #define WSA885X_I2S_TDM_CH_TX_CH1_EN BIT(1) #define WSA885X_I2S_TDM_CH_TX_CH2_EN BIT(2) #define WSA885X_I2S_TDM_CH_TX_CH3_EN BIT(3) +#define WSA885X_I2S_TDM_CH_RX_CH0_EN BIT(0) +#define WSA885X_I2S_TDM_CH_RX_CH3_EN BIT(3) #define WSA885X_I2S_RESET_CTL_RESET_MASK BIT(0) #define WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK BIT(2) #define WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK BIT(3) @@ -230,11 +235,14 @@ #define WSA885X_CHANNEL_MONO_LEFT 0x01 #define WSA885X_CHANNEL_MONO_RIGHT 0x02 +#define WSA885X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) + #define WSA885X_PLL_LOCK_BIT BIT(0) #define WSA885X_FU21_VOL_STEPS 124 #define WSA885X_USAGE_MODE_MAX 8 -#define WSA885X_INIT_TABLE_MAX_ITEMS 256 static const DECLARE_TLV_DB_SCALE(wsa885x_fu21_digital_gain, -8400, 100, 0); static bool wsa885x_is_valid_rx_slot_mask(u32 mask) @@ -281,21 +289,18 @@ enum { WSA885X_IRQ_MAX, }; -struct wsa885x_i2c_priv { +struct wsa885x_priv { struct i2c_client *client; struct regmap *regmap; struct device *dev; struct snd_soc_component *component; - struct regulator_bulk_data supplies[WSA885X_SUPPLIES_NUM]; struct gpio_desc *sd_n; - u32 sample_rate; - u32 *init_table; - u32 init_table_size; + struct reset_control *sd_reset; u32 usage_mode; u32 rx_slot_mask; - struct gpio_desc *intr_pin; u32 batt_conf; int stereo_vol_db; + struct mutex state_lock; /* protects mutable control state */ }; struct wsa885x_reg_update { @@ -390,7 +395,7 @@ static const struct reg_default wsa885x_codec_reg_defaults[] = { {WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05}, {WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00}, {WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00}, - {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, 0x08}, + {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, WSA885X_I2S_TDM_CH_RX_CH3_EN}, {WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89}, {WSA885X_CDC_RX0_RX_PATH_CFG1, 0x64}, {WSA885X_CDC_RX0_RX_PATH_CTL, 0x24}, @@ -414,44 +419,27 @@ static const struct reg_default wsa885x_codec_reg_defaults[] = { {WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05}, }; -static void wsa885x_gpio_set(struct wsa885x_i2c_priv *wsa885x, bool val) -{ - if (!wsa885x || !wsa885x->sd_n) - return; - - gpiod_set_value_cansleep(wsa885x->sd_n, val); -} - static void wsa885x_multi_update_bits(struct regmap *regmap, const struct wsa885x_reg_update *updates, size_t num_updates) { size_t i; - if (!regmap || !updates) - return; - for (i = 0; i < num_updates; i++) regmap_update_bits(regmap, updates[i].reg, updates[i].mask, updates[i].val); } -static void wsa885x_toggle_irq_bit(struct wsa885x_i2c_priv *wsa885x, +static void wsa885x_toggle_irq_bit(struct wsa885x_priv *wsa885x, unsigned int reg, unsigned int mask) { - if (!wsa885x || !wsa885x->regmap) - return; - regmap_update_bits(wsa885x->regmap, reg, mask, 0); regmap_update_bits(wsa885x->regmap, reg, mask, mask); } -static void wsa885x_pulse_irq_bit(struct wsa885x_i2c_priv *wsa885x, +static void wsa885x_pulse_irq_bit(struct wsa885x_priv *wsa885x, unsigned int reg, unsigned int mask) { - if (!wsa885x || !wsa885x->regmap) - return; - regmap_update_bits(wsa885x->regmap, reg, mask, 0); regmap_update_bits(wsa885x->regmap, reg, mask, mask); regmap_update_bits(wsa885x->regmap, reg, mask, 0); @@ -510,14 +498,10 @@ static int wsa885x_reg_update_sequence(struct regmap *regmap, int slots) return 0; } -static int wsa885x_wait_for_pll_lock(struct wsa885x_i2c_priv *wsa885x) +static int wsa885x_wait_for_pll_lock(struct wsa885x_priv *wsa885x) { unsigned int status = 0; - int cnt = 0; - int ret = 0; - - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; + int cnt = 0, ret = 0; do { usleep_range(1000, 1100); @@ -535,7 +519,7 @@ static int wsa885x_wait_for_pll_lock(struct wsa885x_i2c_priv *wsa885x) return -ETIMEDOUT; } -static int wsa885x_2s_conf(struct wsa885x_i2c_priv *wsa885x) +static int wsa885x_2s_conf(struct wsa885x_priv *wsa885x) { static const struct reg_sequence regs[] = { { WSA885X_SPK_TOP_COMMON_TUNE1, 0x26 }, @@ -548,39 +532,64 @@ static int wsa885x_2s_conf(struct wsa885x_i2c_priv *wsa885x) return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); } -static int wsa885x_apply_init_table(struct wsa885x_i2c_priv *wsa885x) -{ - int i; - int ret; - - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; - - if (!wsa885x->init_table_size) - return 0; - - if (!wsa885x->init_table) - return -EINVAL; - - for (i = 0; i < wsa885x->init_table_size / 2; i++) { - u32 reg = wsa885x->init_table[2 * i]; - u32 val = wsa885x->init_table[2 * i + 1]; - - if (wsa885x->batt_conf == WSA885X_BATT_2S && reg == WSA885X_SPK_TOP_LF_CH1_CTRL11) - continue; - - if (wsa885x->batt_conf == WSA885X_BATT_2S && reg == WSA885X_SPK_TOP_LF_CH2_CTRL11) - continue; - - ret = regmap_write(wsa885x->regmap, reg, val); - if (ret) - return ret; - } - - return 0; -} +static const struct reg_sequence wsa885x_reg_init[] = { + { WSA885X_CDC_RX0_RX_PATH_CTL, 0x24 }, + { WSA885X_CDC_RX1_RX_PATH_CTL, 0x24 }, + { WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01 }, + { WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01 }, + { WSA885X_CDC_COMPANDER0_CTL0, 0x01 }, + { WSA885X_CDC_COMPANDER1_CTL0, 0x01 }, + { WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0f }, + { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x4f }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x02 }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00 }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x01 }, + { WSA885X_CDC_RX0_RX_PATH_CFG1, 0x60 }, + { WSA885X_CDC_RX1_RX_PATH_CFG1, 0x60 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa5 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa5 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x85 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0c }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0e }, + { WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x0c }, + { WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01 }, + { WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01 }, + { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x88 }, + { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89 }, + { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x88 }, + { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89 }, + { WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x82 }, + { WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x34 }, + { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x41 }, + { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0x7f }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c }, + { WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d }, + { WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03 }, + { WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05 }, + { WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x20 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0x45 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0x45 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05 }, + { WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x35 }, + { WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x21 }, + { WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc7 }, + { WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x11 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0x80 }, + { WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x08 }, + { WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x47 }, + { WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x47 }, + { WSA885X_CDC_COMPANDER0_CTL7, 0x34 }, + { WSA885X_CDC_COMPANDER1_CTL7, 0x34 }, + { WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x79 }, +}; -static int wsa885x_hw_init(struct wsa885x_i2c_priv *wsa885x) +static int wsa885x_hw_init(struct wsa885x_priv *wsa885x) { static const struct reg_sequence regs[] = { { WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL, 0x2e }, @@ -589,10 +598,8 @@ static int wsa885x_hw_init(struct wsa885x_i2c_priv *wsa885x) }; int ret; - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; - - ret = wsa885x_apply_init_table(wsa885x); + ret = regmap_multi_reg_write(wsa885x->regmap, wsa885x_reg_init, + ARRAY_SIZE(wsa885x_reg_init)); if (ret) return ret; @@ -605,7 +612,7 @@ static int wsa885x_hw_init(struct wsa885x_i2c_priv *wsa885x) return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); } -static int wsa885x_unmask_interrupts(struct wsa885x_i2c_priv *wsa885x) +static int wsa885x_unmask_interrupts(struct wsa885x_priv *wsa885x) { static const struct reg_sequence regs[] = { { WSA885X_INTR_MASK0, 0x00 }, @@ -613,19 +620,13 @@ static int wsa885x_unmask_interrupts(struct wsa885x_i2c_priv *wsa885x) { WSA885X_INTR_MASK0 + 2, 0xf8 }, }; - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; - return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); } -static int wsa885x_wait_for_pde_state(struct wsa885x_i2c_priv *wsa885x, int ps) +static int wsa885x_wait_for_pde_state(struct wsa885x_priv *wsa885x, int ps) { - int act_ps = -1, cnt = 0, clock_valid = -1; - int rc = 0; - - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; + unsigned int act_ps = 0, clock_valid = 0; + int rc = 0, cnt = 0; if (ps < 0 || ps > 3) return -EINVAL; @@ -642,6 +643,7 @@ static int wsa885x_wait_for_pde_state(struct wsa885x_i2c_priv *wsa885x, int ps) if (act_ps == ps) return 0; } while (++cnt < 5); + if (regmap_read(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, &clock_valid)) @@ -656,25 +658,34 @@ static int wsa885x_wait_for_pde_state(struct wsa885x_i2c_priv *wsa885x, int ps) return -ETIMEDOUT; } +static void wsa885x_program_stereo_volume(struct wsa885x_priv *wsa885x, + int stereo_vol_db, bool commit) +{ + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, + (u8)(s8)stereo_vol_db); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, + (u8)(s8)stereo_vol_db); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00); + + if (commit) + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); +} + static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct wsa885x_i2c_priv *wsa885x; + struct wsa885x_priv *wsa885x; u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx; - (void)substream; - - if (!params || !dai || !dai->component) - return -EINVAL; - wsa885x = snd_soc_component_get_drvdata(dai->component); - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; - - wsa885x->sample_rate = params_rate(params); - switch (wsa885x->sample_rate) { + switch (params_rate(params)) { case 8000: pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_8KHZ; cs21_sample_rate_idx = WSA885X_RX_RATE_8000HZ; @@ -688,9 +699,6 @@ static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream, case 32000: pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_32KHZ; cs21_sample_rate_idx = WSA885X_RX_RATE_32000HZ; - /* The VI sensing path has no 32 kHz rate index; use the - * nearest supported rate (48 kHz) for the CS24 clock. - */ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; break; case 44100: @@ -736,14 +744,11 @@ static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream, cs21_sample_rate_idx); regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, cs24_sample_rate_idx); - regmap_write(wsa885x->regmap, - WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, - (s8)wsa885x->stereo_vol_db); - regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00); - regmap_write(wsa885x->regmap, - WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, - (s8)wsa885x->stereo_vol_db); - regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00); + + mutex_lock(&wsa885x->state_lock); + wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); + mutex_unlock(&wsa885x->state_lock); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); return 0; @@ -776,19 +781,12 @@ static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai, { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, }; - struct wsa885x_i2c_priv *wsa885x; + struct wsa885x_priv *wsa885x; unsigned int slot_num_val; + u32 mask; int ret; - (void)tx_slot_mask; - (void)slot_width; - - if (!dai || !dai->component) - return -EINVAL; - wsa885x = snd_soc_component_get_drvdata(dai->component); - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); if (ret) { @@ -797,46 +795,48 @@ static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai, return ret; } - if (rx_slot_mask) { - if (!wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) { - dev_err(wsa885x->dev, - "%s: unsupported rx_slot_mask 0x%x\n", - __func__, rx_slot_mask); - return -EINVAL; - } + if (rx_slot_mask && !wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) { + dev_err(wsa885x->dev, + "%s: unsupported rx_slot_mask 0x%x\n", + __func__, rx_slot_mask); + return -EINVAL; + } + + mutex_lock(&wsa885x->state_lock); + if (rx_slot_mask) wsa885x->rx_slot_mask = rx_slot_mask; - } else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) { + else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; - } + mask = wsa885x->rx_slot_mask; regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, WSA885X_I2S_RESET_CTL_RESET_MASK, WSA885X_I2S_RESET_CTL_RESET_MASK); - if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) { + if (mask == WSA885X_CHANNEL_STEREO) { wsa885x_multi_update_bits(wsa885x->regmap, stereo_updates, ARRAY_SIZE(stereo_updates)); ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); if (ret) - return ret; + goto exit_unlock; regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, WSA885X_I2S_TDM_CH_TX_CH2_EN, WSA885X_I2S_TDM_CH_TX_CH2_EN); regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, WSA885X_I2S_TDM_CH_TX_CH3_EN, WSA885X_I2S_TDM_CH_TX_CH3_EN); - } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) { + } else if (mask == WSA885X_CHANNEL_MONO_LEFT) { wsa885x_multi_update_bits(wsa885x->regmap, mono_left_updates, ARRAY_SIZE(mono_left_updates)); ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); if (ret) - return ret; - } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) { + goto exit_unlock; + } else if (mask == WSA885X_CHANNEL_MONO_RIGHT) { wsa885x_multi_update_bits(wsa885x->regmap, mono_right_updates, ARRAY_SIZE(mono_right_updates)); ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); if (ret) - return ret; + goto exit_unlock; } regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, @@ -845,7 +845,12 @@ static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai, regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, WSA885X_I2S_RESET_CTL_RESET_MASK, 0); - return 0; + ret = 0; + +exit_unlock: + mutex_unlock(&wsa885x->state_lock); + + return ret; } static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, @@ -863,23 +868,11 @@ static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 }, { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 }, }; - struct wsa885x_i2c_priv *wsa885x; + struct wsa885x_priv *wsa885x; u32 pll_div; int ret = 0; - /* - * This device has a single fixed PLL clock source; clk_id and dir - * are not used. The PLL divisor is derived solely from freq. - */ - (void)clk_id; - (void)dir; - - if (!dai || !dai->component) - return -EINVAL; - wsa885x = snd_soc_component_get_drvdata(dai->component); - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; if (!freq) return -EINVAL; @@ -939,21 +932,20 @@ static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stre { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x00 }, { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, }; - struct wsa885x_i2c_priv *wsa885x; + struct wsa885x_priv *wsa885x; int ret = 0, ps0 = 0, ps3 = 3; - if (!dai || !dai->component) - return -EINVAL; - wsa885x = snd_soc_component_get_drvdata(dai->component); - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; if (stream != SNDRV_PCM_STREAM_PLAYBACK) return 0; - if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) - return -EINVAL; + mutex_lock(&wsa885x->state_lock); + + if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { + ret = -EINVAL; + goto exit_unlock; + } if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; @@ -976,33 +968,37 @@ static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stre wsa885x->usage_mode); regmap_multi_reg_write(wsa885x->regmap, unmute_prep_tail_regs, ARRAY_SIZE(unmute_prep_tail_regs)); - regmap_write(wsa885x->regmap, - WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, - (s8)wsa885x->stereo_vol_db); - regmap_write(wsa885x->regmap, - WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, - (s8)wsa885x->stereo_vol_db); + wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); regmap_multi_reg_write(wsa885x->regmap, unmute_volume_regs, ARRAY_SIZE(unmute_volume_regs)); regmap_multi_reg_write(wsa885x->regmap, unmute_commit_regs, ARRAY_SIZE(unmute_commit_regs)); ret = wsa885x_wait_for_pde_state(wsa885x, ps0); if (ret) - goto exit; + goto exit_unlock; if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH0_EN | + WSA885X_I2S_TDM_CH_RX_CH3_EN); regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03); } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH3_EN); regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01); } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH0_EN); regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02); - regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, 0x01); } regmap_multi_reg_write(wsa885x->regmap, unmute_finish_regs, ARRAY_SIZE(unmute_finish_regs)); } -exit: + +exit_unlock: + mutex_unlock(&wsa885x->state_lock); + return ret; } @@ -1010,38 +1006,23 @@ static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { static const struct reg_sequence regs[] = { - { WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00 }, - { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00 }, - { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00 }, - { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05 }, - { WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00 }, - { WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00 }, - { WSA885X_DIG_CTRL1_I2S_CTL0, 0x06 }, - { WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, 0x08 }, { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, - { WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00 }, - { WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 }, - { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 }, - { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 }, }; - struct wsa885x_i2c_priv *wsa885x; - - if (!substream || !dai || !dai->component) - return -EINVAL; + struct wsa885x_priv *wsa885x; wsa885x = snd_soc_component_get_drvdata(dai->component); - if (!wsa885x || !wsa885x->regmap) - return -EINVAL; if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return 0; + mutex_lock(&wsa885x->state_lock); regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); + mutex_unlock(&wsa885x->state_lock); return 0; } -static const struct snd_soc_dai_ops wsa885x_i2c_dai_ops = { +static const struct snd_soc_dai_ops wsa885x_dai_ops = { .hw_params = wsa885x_codec_hw_params, .set_tdm_slot = wsa885x_codec_set_tdm_slot, .set_sysclk = wsa885x_codec_set_sysclk, @@ -1049,31 +1030,54 @@ static const struct snd_soc_dai_ops wsa885x_i2c_dai_ops = { .hw_free = wsa885x_codec_hw_free, }; -static struct snd_soc_dai_driver wsa885x_i2c_dai[] = { +static struct snd_soc_dai_driver wsa885x_dai[] = { { .name = "wsa885x_dai_drv", .playback = { - .stream_name = "WSA885X I2C TDM Playback", + .stream_name = "WSA885X TDM Playback", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000 | - SNDRV_PCM_RATE_352800 | - SNDRV_PCM_RATE_384000, + .rates = WSA885X_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, - .ops = &wsa885x_i2c_dai_ops, + .ops = &wsa885x_dai_ops, }, }; -static void wsa885x_gpio_powerdown(void *data) +static void wsa885x_reset_assert(void *data) { - struct wsa885x_i2c_priv *wsa885x = data; + struct wsa885x_priv *wsa885x = data; - if (!wsa885x) - return; + if (wsa885x->sd_reset) + reset_control_assert(wsa885x->sd_reset); + else + gpiod_direction_output(wsa885x->sd_n, 1); +} + +static void wsa885x_reset_deassert(struct wsa885x_priv *wsa885x) +{ + if (wsa885x->sd_reset) + reset_control_deassert(wsa885x->sd_reset); + else + gpiod_direction_output(wsa885x->sd_n, 0); +} + +static int wsa885x_get_reset(struct device *dev, struct wsa885x_priv *wsa885x) +{ + wsa885x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(wsa885x->sd_reset)) + return dev_err_probe(dev, PTR_ERR(wsa885x->sd_reset), + "Failed to get reset\n"); + else if (wsa885x->sd_reset) + return 0; + + wsa885x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(wsa885x->sd_n)) + return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n), + "Shutdown Control GPIO not found\n"); - wsa885x_gpio_set(wsa885x, true); + return 0; } static bool wsa885x_volatile_register(struct device *dev, unsigned int reg) @@ -1081,6 +1085,7 @@ static bool wsa885x_volatile_register(struct device *dev, unsigned int reg) switch (reg) { case WSA885X_ANA_TOP_PLL_STATUS_0: case WSA885X_ANA_TOP_PLL_STATUS_1: + case WSA885X_DIG_CTRL0_SDCA_COMMIT: case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: case WSA885X_INTR_STATUS0: @@ -1141,13 +1146,10 @@ static const struct regmap_config wsa885x_regmap_cfg = { static int wsa885x_component_probe(struct snd_soc_component *component) { - struct wsa885x_i2c_priv *wsa885x = + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); int ret; - if (!wsa885x || !wsa885x->regmap) - return -ENODEV; - wsa885x->component = component; snd_soc_component_init_regmap(component, wsa885x->regmap); @@ -1155,47 +1157,19 @@ static int wsa885x_component_probe(struct snd_soc_component *component) if (ret) return ret; - /* Restore interrupt masks after reg_defaults programming. */ return wsa885x_unmask_interrupts(wsa885x); } -static void wsa885x_component_remove(struct snd_soc_component *component) -{ - if (!component) - return; - - snd_soc_component_exit_regmap(component); -} - -static void wsa885x_regulator_disable(void *data) -{ - struct wsa885x_i2c_priv *wsa885x = data; - - if (!wsa885x) - return; - - regulator_bulk_disable(WSA885X_SUPPLIES_NUM, wsa885x->supplies); -} - static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component; - struct wsa885x_i2c_priv *wsa885x; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); int val; - if (!kcontrol || !ucontrol) - return -EINVAL; - - component = snd_kcontrol_chip(kcontrol); - if (!component) - return -EINVAL; - - wsa885x = snd_soc_component_get_drvdata(component); - if (!wsa885x) - return -EINVAL; - + mutex_lock(&wsa885x->state_lock); val = wsa885x->stereo_vol_db + 84; + mutex_unlock(&wsa885x->state_lock); if (val < 0 || val > WSA885X_FU21_VOL_STEPS) return -ERANGE; @@ -1206,20 +1180,10 @@ static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol, static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component; - struct wsa885x_i2c_priv *wsa885x; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); long val; - - if (!kcontrol || !ucontrol) - return -EINVAL; - - component = snd_kcontrol_chip(kcontrol); - if (!component) - return -EINVAL; - - wsa885x = snd_soc_component_get_drvdata(component); - if (!wsa885x) - return -EINVAL; + int stereo_vol_db; val = ucontrol->value.integer.value[0]; @@ -1227,82 +1191,72 @@ static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol, dev_err(component->dev, "%s: Invalid range, Val: %ld\n", __func__, val); return -EINVAL; } - wsa885x->stereo_vol_db = (int)val - 84; - return 0; -} -static int wsa885x_i2c_usage_modes_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component; - struct wsa885x_i2c_priv *wsa885x_i2c; + stereo_vol_db = (int)val - 84; - if (!kcontrol || !ucontrol) - return -EINVAL; + mutex_lock(&wsa885x->state_lock); + if (wsa885x->stereo_vol_db == stereo_vol_db) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } - component = snd_kcontrol_chip(kcontrol); - if (!component) - return -EINVAL; + wsa885x_program_stereo_volume(wsa885x, stereo_vol_db, true); + wsa885x->stereo_vol_db = stereo_vol_db; + mutex_unlock(&wsa885x->state_lock); - wsa885x_i2c = snd_soc_component_get_drvdata(component); - if (!wsa885x_i2c) - return -EINVAL; + return 1; +} + +static int wsa885x_usage_modes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); - if (wsa885x_i2c->usage_mode > WSA885X_USAGE_MODE_MAX) + mutex_lock(&wsa885x->state_lock); + if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { + mutex_unlock(&wsa885x->state_lock); return -ERANGE; + } - ucontrol->value.integer.value[0] = wsa885x_i2c->usage_mode; + ucontrol->value.integer.value[0] = wsa885x->usage_mode; + mutex_unlock(&wsa885x->state_lock); return 0; } -static int wsa885x_i2c_usage_modes_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int wsa885x_usage_modes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component; - struct wsa885x_i2c_priv *wsa885x_i2c; - long val; - - if (!kcontrol || !ucontrol) - return -EINVAL; - - component = snd_kcontrol_chip(kcontrol); - if (!component) - return -EINVAL; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 val = ucontrol->value.integer.value[0]; - wsa885x_i2c = snd_soc_component_get_drvdata(component); - if (!wsa885x_i2c) + if (val > WSA885X_USAGE_MODE_MAX) return -EINVAL; - val = ucontrol->value.integer.value[0]; - - if (val < 0 || val > WSA885X_USAGE_MODE_MAX) - return -EINVAL; + mutex_lock(&wsa885x->state_lock); + if (wsa885x->usage_mode == val) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } - wsa885x_i2c->usage_mode = val; + wsa885x->usage_mode = val; + mutex_unlock(&wsa885x->state_lock); - return 0; + return 1; } -static int wsa885x_i2c_rx_slot_mask_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int wsa885x_rx_slot_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component; - struct wsa885x_i2c_priv *wsa885x_i2c; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); u32 mask; - if (!kcontrol || !ucontrol) - return -EINVAL; - - component = snd_kcontrol_chip(kcontrol); - if (!component) - return -EINVAL; - - wsa885x_i2c = snd_soc_component_get_drvdata(component); - if (!wsa885x_i2c) - return -EINVAL; - - mask = wsa885x_i2c->rx_slot_mask; + mutex_lock(&wsa885x->state_lock); + mask = wsa885x->rx_slot_mask; + mutex_unlock(&wsa885x->state_lock); if (!wsa885x_is_valid_rx_slot_mask(mask)) return -ERANGE; @@ -1311,38 +1265,32 @@ static int wsa885x_i2c_rx_slot_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static int wsa885x_i2c_rx_slot_mask_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component; - struct wsa885x_i2c_priv *wsa885x_i2c; - long mask; - - if (!kcontrol || !ucontrol) - return -EINVAL; - - component = snd_kcontrol_chip(kcontrol); - if (!component) - return -EINVAL; - - wsa885x_i2c = snd_soc_component_get_drvdata(component); - if (!wsa885x_i2c) - return -EINVAL; - - mask = ucontrol->value.integer.value[0]; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 mask = ucontrol->value.integer.value[0]; if (!wsa885x_is_valid_rx_slot_mask(mask)) return -EINVAL; - wsa885x_i2c->rx_slot_mask = mask; + mutex_lock(&wsa885x->state_lock); + if (wsa885x->rx_slot_mask == mask) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } - return 0; + wsa885x->rx_slot_mask = mask; + mutex_unlock(&wsa885x->state_lock); + + return 1; } static const struct snd_kcontrol_new wsa885x_snd_controls[] = { SOC_SINGLE_EXT("Usage Mode", SND_SOC_NOPM, 0, WSA885X_USAGE_MODE_MAX, 0, - wsa885x_i2c_usage_modes_get, - wsa885x_i2c_usage_modes_put), + wsa885x_usage_modes_get, + wsa885x_usage_modes_put), SOC_SINGLE_EXT_TLV("Speaker Volume", SND_SOC_NOPM, 0, WSA885X_FU21_VOL_STEPS, 0, @@ -1351,24 +1299,20 @@ static const struct snd_kcontrol_new wsa885x_snd_controls[] = { wsa885x_fu21_digital_gain), SOC_SINGLE_EXT("Rx Slot Mask", SND_SOC_NOPM, 0, 3, 0, - wsa885x_i2c_rx_slot_mask_get, - wsa885x_i2c_rx_slot_mask_put), + wsa885x_rx_slot_mask_get, + wsa885x_rx_slot_mask_put), }; -static const struct snd_soc_component_driver wsa885x_i2c_component = { - .name = "wsa885x-i2c", +static const struct snd_soc_component_driver wsa885x_component = { + .name = "wsa885x", .probe = wsa885x_component_probe, - .remove = wsa885x_component_remove, .controls = wsa885x_snd_controls, .num_controls = ARRAY_SIZE(wsa885x_snd_controls), }; -static irqreturn_t wsa885x_handle_i2c_irq(int irq_idx, void *data) +static irqreturn_t wsa885x_handle_irq(int irq_idx, void *data) { - struct wsa885x_i2c_priv *wsa885x = data; - - if (!wsa885x) - return IRQ_NONE; + struct wsa885x_priv *wsa885x = data; if (irq_idx < 0 || irq_idx >= WSA885X_IRQ_MAX) return IRQ_NONE; @@ -1436,15 +1380,10 @@ static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) WSA885X_INTR_CLEAR0 + 2, }; unsigned int status[WSA885X_NUM_REGS] = { 0 }; - struct wsa885x_i2c_priv *wsa885x = data; + struct wsa885x_priv *wsa885x = data; irqreturn_t handled = IRQ_NONE; irqreturn_t irq_ret; - int i, bit, ret; - int irq_num; - - (void)irq; - if (!wsa885x || !wsa885x->regmap) - return IRQ_NONE; + int i, bit, ret, irq_num; for (i = 0; i < WSA885X_NUM_REGS; i++) { ret = regmap_read(wsa885x->regmap, status_reg[i], &status[i]); @@ -1461,10 +1400,6 @@ static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) for (bit = 0; bit < 8; bit++) { if (status[i] & BIT(bit)) { irq_num = i * 8 + bit; - /* INTR_CLEAR registers are write-only; use regmap_write - * instead of regmap_update_bits to avoid the read-modify-write - * that regmap_update_bits performs on non-readable registers. - */ regmap_write(wsa885x->regmap, clear_reg[i], BIT(bit)); regmap_write(wsa885x->regmap, clear_reg[i], 0); if (irq_num >= WSA885X_IRQ_MAX) { @@ -1474,7 +1409,7 @@ static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) handled = IRQ_HANDLED; continue; } - irq_ret = wsa885x_handle_i2c_irq(irq_num, wsa885x); + irq_ret = wsa885x_handle_irq(irq_num, wsa885x); if (irq_ret == IRQ_HANDLED) handled = IRQ_HANDLED; } @@ -1483,27 +1418,25 @@ static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) return handled; } -static int wsa885x_register_irq(struct wsa885x_i2c_priv *wsa885x) +static int wsa885x_register_irq(struct wsa885x_priv *wsa885x) { - int irq_number; - - irq_number = gpiod_to_irq(wsa885x->intr_pin); - if (irq_number < 0) - return dev_err_probe(wsa885x->dev, irq_number, - "Failed to get interrupt IRQ\n"); + if (!wsa885x->client->irq) + return dev_err_probe(wsa885x->dev, -EINVAL, + "IRQ is not configured\n"); - return devm_request_threaded_irq(wsa885x->dev, irq_number, NULL, + return devm_request_threaded_irq(wsa885x->dev, wsa885x->client->irq, NULL, wsa885x_interrupt_handler, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + IRQF_ONESHOT, dev_name(wsa885x->dev), wsa885x); } -static int wsa885x_i2c_probe(struct i2c_client *client) +static int wsa885x_probe(struct i2c_client *client) { - struct wsa885x_i2c_priv *wsa885x; - const struct snd_soc_component_driver *component_driver = &wsa885x_i2c_component; - const char *init_table_prop = "qcom,wsa885x-init-table"; - int ret, i, count; + struct wsa885x_priv *wsa885x; + const struct snd_soc_component_driver *component_driver = &wsa885x_component; + const char *battery_config; + unsigned int i; + int ret; struct device *dev = &client->dev; wsa885x = devm_kzalloc(dev, sizeof(*wsa885x), GFP_KERNEL); @@ -1514,130 +1447,87 @@ static int wsa885x_i2c_probe(struct i2c_client *client) wsa885x->dev = dev; wsa885x->stereo_vol_db = -84; wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + mutex_init(&wsa885x->state_lock); wsa885x->regmap = devm_regmap_init_i2c(client, &wsa885x_regmap_cfg); if (IS_ERR(wsa885x->regmap)) return PTR_ERR(wsa885x->regmap); - /* - * Use a signed int for the count check: device_property_count_u32() - * returns a negative errno on error. Storing it directly into the - * uint32_t field before checking causes the negative value to wrap to - * a huge positive number, bypassing the <= 0 guard and triggering a - * multi-GB kmalloc that fails with -ENOMEM. - */ - count = device_property_count_u32(dev, init_table_prop); - - if (count > 0) { - if (count % 2) { - dev_err(dev, "%s: Invalid number of elements in %s (%d)\n", - __func__, init_table_prop, count); - return -EINVAL; - } - if (count > WSA885X_INIT_TABLE_MAX_ITEMS) { - dev_err(dev, "%s: %s has too many elements (%d > %u)\n", - __func__, init_table_prop, count, - WSA885X_INIT_TABLE_MAX_ITEMS); - return -EINVAL; - } - wsa885x->init_table_size = count; - - wsa885x->init_table = devm_kcalloc(dev, wsa885x->init_table_size, - sizeof(*wsa885x->init_table), GFP_KERNEL); - if (!wsa885x->init_table) - return -ENOMEM; - - if (device_property_read_u32_array(dev, init_table_prop, - wsa885x->init_table, - wsa885x->init_table_size)) { - dev_err(dev, "%s: Failed to read %s\n", - __func__, init_table_prop); - return -EINVAL; - } - } - - ret = device_property_read_u32(dev, "qcom,battery-config", - &wsa885x->batt_conf); + ret = device_property_read_string(dev, "qcom,battery-config", + &battery_config); if (ret) { wsa885x->batt_conf = WSA885X_BATT_1S; - } else if (wsa885x->batt_conf != WSA885X_BATT_1S && - wsa885x->batt_conf != WSA885X_BATT_2S) { + } else if (!strcmp(battery_config, "1s")) { + wsa885x->batt_conf = WSA885X_BATT_1S; + } else if (!strcmp(battery_config, "2s")) { + wsa885x->batt_conf = WSA885X_BATT_2S; + } else { return dev_err_probe(dev, -EINVAL, - "Invalid battery config %u (expected 1S or 2S)\n", - wsa885x->batt_conf); + "Invalid battery config %s (expected 1s or 2s)\n", + battery_config); } - for (i = 0; i < WSA885X_SUPPLIES_NUM; i++) - wsa885x->supplies[i].supply = wsa885x_supply_name[i]; - - ret = devm_regulator_bulk_get(dev, WSA885X_SUPPLIES_NUM, wsa885x->supplies); - if (ret) - return dev_err_probe(dev, ret, "Failed to get regulators\n"); - - ret = regulator_bulk_enable(WSA885X_SUPPLIES_NUM, wsa885x->supplies); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable regulators\n"); + for (i = 0; i < ARRAY_SIZE(wsa885x_supply_name); i++) { + ret = devm_regulator_get_enable(dev, wsa885x_supply_name[i]); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable regulator %s\n", + wsa885x_supply_name[i]); + } - ret = devm_add_action_or_reset(dev, wsa885x_regulator_disable, wsa885x); + ret = wsa885x_get_reset(dev, wsa885x); if (ret) - return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n"); - - wsa885x->sd_n = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); - if (IS_ERR(wsa885x->sd_n)) - return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n), - "Shutdown Control GPIO not found\n"); + return ret; - wsa885x_gpio_set(wsa885x, false); + wsa885x_reset_deassert(wsa885x); + usleep_range(5000, 5500); - ret = devm_add_action_or_reset(dev, wsa885x_gpio_powerdown, wsa885x); + ret = devm_add_action_or_reset(dev, wsa885x_reset_assert, wsa885x); if (ret) return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n"); i2c_set_clientdata(client, wsa885x); - wsa885x->intr_pin = devm_gpiod_get(dev, "interrupt", GPIOD_IN); - if (IS_ERR(wsa885x->intr_pin)) - return dev_err_probe(dev, PTR_ERR(wsa885x->intr_pin), - "Interrupt GPIO not found\n"); - ret = wsa885x_register_irq(wsa885x); if (ret) return dev_err_probe(dev, ret, "wsa885x irq registration failed\n"); ret = devm_snd_soc_register_component(dev, component_driver, - wsa885x_i2c_dai, - ARRAY_SIZE(wsa885x_i2c_dai)); + wsa885x_dai, + ARRAY_SIZE(wsa885x_dai)); if (ret) return dev_err_probe(dev, ret, "Codec component registration failed\n"); return 0; } -static const struct of_device_id wsa885x_i2c_dt_match[] = { +static const struct of_device_id wsa885x_dt_match[] = { { - .compatible = "qcom,wsa885x-i2c", + .compatible = "qcom,wsa8855", }, {} }; +MODULE_DEVICE_TABLE(of, wsa885x_dt_match); -static const struct i2c_device_id wsa885x_id_i2c[] = { - {"wsa885x_i2c", 0}, +static const struct i2c_device_id wsa885x_id[] = { + { + .name = "wsa885x", + .driver_data = 0, + }, {} }; +MODULE_DEVICE_TABLE(i2c, wsa885x_id); -MODULE_DEVICE_TABLE(i2c, wsa885x_id_i2c); -MODULE_DEVICE_TABLE(of, wsa885x_i2c_dt_match); - -static struct i2c_driver wsa885x_i2c_driver = { +static struct i2c_driver wsa885x_driver = { .driver = { - .name = "wsa885x_i2c", - .of_match_table = wsa885x_i2c_dt_match, + .name = "wsa885x", + .of_match_table = wsa885x_dt_match, }, - .probe = wsa885x_i2c_probe, - .id_table = wsa885x_id_i2c, + .probe = wsa885x_probe, + .id_table = wsa885x_id, }; -module_i2c_driver(wsa885x_i2c_driver); +module_i2c_driver(wsa885x_driver); -MODULE_DESCRIPTION("ASoC WSA885X I2C Smart PA Codec Driver"); +MODULE_DESCRIPTION("ASoC WSA885X Stereo Smart PA Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 8771aaa7913c9..47bd4e1f3061a 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -77,10 +77,9 @@ config SND_SOC_QCOM_QAIF select REGMAP_MMIO help Say Y or M to enable the Qualcomm Audio Interface (QAIF) driver - used on the Shikra audio platform. QAIF is the DMA controller - that moves PCM data between the codec and memory over AIF (MI2S) - and CIF (CDC DMA) paths. Required for audio playback and capture - on Shikra-based platforms. + for the Shikra audio platform. QAIF is a DMA-based audio + subsystem that moves PCM data between memory and external serial + audio interfaces (AIF) and internal codec interfaces (CIF). config SND_SOC_QDSP6_COMMON tristate diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 857bb2a032a2d..cf50b7a24bcfd 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -31,7 +31,6 @@ snd-soc-qcom-common-y := common.o snd-soc-qcom-sdw-y := sdw.o snd-soc-x1e80100-y := x1e80100.o snd-soc-qcom-offload-utils-objs := usb_offload_utils.o -snd-soc-qcom-qaif-y := qaif-cpu.o qaif-platform.o qaif-shikra.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o @@ -45,7 +44,9 @@ obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o obj-$(CONFIG_SND_SOC_X1E80100) += snd-soc-x1e80100.o obj-$(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) += snd-soc-qcom-offload-utils.o -obj-$(CONFIG_SND_SOC_QCOM_QAIF) += snd-soc-qcom-qaif.o #DSP lib obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/ + +snd-soc-qcom-qaif-y := qaif-cpu.o qaif-platform.o qaif-shikra.o +obj-$(CONFIG_SND_SOC_QCOM_QAIF) += snd-soc-qcom-qaif.o diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index fced8eb951c2d..5ca720ecf8431 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -3,7 +3,6 @@ // Copyright (c) 2018, The Linux Foundation. All rights reserved. #include -#include #include #include #include @@ -24,40 +23,6 @@ static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = { SND_SOC_DAPM_SPK("DP7 Jack", NULL), }; -/** - * asoc_qcom_of_xlate_dai_name - Resolve a sound-dai phandle argument to a - * DAI name by searching the DAI driver array. - * @dai_drv: Array of DAI drivers registered by the component. - * @num_dai: Number of entries in @dai_drv. - * @args: Phandle arguments from the sound-dai property; args[0] is the - * DAI ID. - * @dai_name: Output pointer set to the matched DAI name on success. - * - * Returns 0 on success, -EINVAL if args_count != 1 or no match is found. - */ -int asoc_qcom_of_xlate_dai_name(const struct snd_soc_dai_driver *dai_drv, - int num_dai, - const struct of_phandle_args *args, - const char **dai_name) -{ - int id, i; - - if (args->args_count != 1) - return -EINVAL; - - id = args->args[0]; - - for (i = 0; i < num_dai; i++) { - if (dai_drv[i].id == id) { - *dai_name = dai_drv[i].name; - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(asoc_qcom_of_xlate_dai_name); - static struct device_node *qcom_snd_get_link_node(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -431,7 +396,6 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, } switch (cpu_dai->id) { - case QAIF_CDC_DMA_RX0: case TX_CODEC_DMA_TX_0: case TX_CODEC_DMA_TX_1: case TX_CODEC_DMA_TX_2: diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h index f8cc3079b8917..c68fe7fa6527c 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -4,10 +4,11 @@ #ifndef __QCOM_SND_COMMON_H__ #define __QCOM_SND_COMMON_H__ +#include #include #include -#define LPASS_MAX_PORT (LPI_MI2S_TX_6 + 1) +#define LPASS_MAX_PORT (AIF_TDM_TX_12 + 1) struct qcom_snd_tdm_slot_cfg { unsigned int tx_mask; @@ -28,9 +29,4 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_jack *jack, bool *jack_setup); int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_jack *dp_jack, int id); - -int asoc_qcom_of_xlate_dai_name(const struct snd_soc_dai_driver *dai_drv, - int num_dai, - const struct of_phandle_args *args, - const char **dai_name); #endif diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 0c84964bafdcd..61efa45376cd8 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -18,7 +18,6 @@ #include #include "lpass-lpaif-reg.h" #include "lpass.h" -#include "common.h" #define LPASS_CPU_MAX_MI2S_LINES 4 #define LPASS_CPU_I2S_SD0_MASK BIT(0) @@ -459,20 +458,9 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = { }; EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2); -static int lpass_cpu_of_xlate_dai_name(struct snd_soc_component *component, - const struct of_phandle_args *args, - const char **dai_name) -{ - struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); - const struct lpass_variant *variant = drvdata->variant; - - return asoc_qcom_of_xlate_dai_name(variant->dai_driver, - variant->num_dai, args, dai_name); -} - static const struct snd_soc_component_driver lpass_cpu_comp_driver = { .name = "lpass-cpu", - .of_xlate_dai_name = lpass_cpu_of_xlate_dai_name, + .of_xlate_dai_name = snd_soc_of_xlate_dai_name, .legacy_dai_naming = 1, }; diff --git a/sound/soc/qcom/qaif-cpu.c b/sound/soc/qcom/qaif-cpu.c index 0029c31c37dbf..d751abb7a888c 100644 --- a/sound/soc/qcom/qaif-cpu.c +++ b/sound/soc/qcom/qaif-cpu.c @@ -11,199 +11,91 @@ #include #include #include +#include +#include #include #include -#include #include #include #include "qaif-reg.h" #include "qaif.h" -#include "common.h" - -static int qaif_cif_cpu_init_bitfields(struct device *dev, - struct regmap *map) -{ - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - const struct qaif_variant *v = drvdata->variant; - struct qaif_dmactl *rd_dmactl; - struct qaif_dmactl *wr_dmactl; - struct qaif_cdc_intfctl *rd_intfctl; - struct qaif_cdc_intfctl *wr_intfctl; - - rd_dmactl = devm_kzalloc(dev, sizeof(struct qaif_dmactl), GFP_KERNEL); - if (!rd_dmactl) - return -ENOMEM; - - wr_dmactl = devm_kzalloc(dev, sizeof(struct qaif_dmactl), GFP_KERNEL); - if (!wr_dmactl) - return -ENOMEM; - - rd_intfctl = devm_kzalloc(dev, sizeof(struct qaif_cdc_intfctl), GFP_KERNEL); - if (!rd_intfctl) - return -ENOMEM; - - wr_intfctl = devm_kzalloc(dev, sizeof(struct qaif_cdc_intfctl), GFP_KERNEL); - if (!wr_intfctl) - return -ENOMEM; - - /* - * Bulk-allocate CIF RDDMA dmactl fields. - * Order must match struct qaif_dmactl member order: - * enable, reset, num_ot, dma_dyncclk, burst16, burst8, burst4, burst2, burst1, shram_wm - */ - { - const struct reg_field cif_rd_dmactl_fields[] = { - v->cif_rddma_enable, - v->cif_rddma_reset, - v->cif_rddma_num_ot, - v->cif_rddma_dma_dyncclk, - v->cif_rddma_burst16, - v->cif_rddma_burst8, - v->cif_rddma_burst4, - v->cif_rddma_burst2, - v->cif_rddma_burst1, - v->cif_rddma_shram_wm, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &rd_dmactl->enable, - cif_rd_dmactl_fields, - ARRAY_SIZE(cif_rd_dmactl_fields)); - if (ret) { - dev_err(dev, "error allocating CIF RDDMA dmactl regmap fields: %d\n", ret); - return ret; - } - } - - /* - * Bulk-allocate CIF RDDMA intfctl fields. - * Order must match struct qaif_cdc_intfctl member order: - * active_ch_en, fs_sel, fs_delay, fs_out_gate, intf_dyncclk, en_16bit_unpack - */ - { - const struct reg_field cif_rd_intfctl_fields[] = { - v->cif_rddma_active_ch_en, - v->cif_rddma_fs_sel, - v->cif_rddma_fs_delay, - v->cif_rddma_fs_out_gate, - v->cif_rddma_intf_dyncclk, - v->cif_rddma_en_16bit_unpack, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &rd_intfctl->active_ch_en, - cif_rd_intfctl_fields, - ARRAY_SIZE(cif_rd_intfctl_fields)); - if (ret) { - dev_err(dev, "error allocating CIF RDDMA intfctl regmap fields: %d\n", ret); - return ret; - } - } - - /* - * Bulk-allocate CIF WRDMA dmactl fields. - * Order must match struct qaif_dmactl member order: - * enable, reset, num_ot, dma_dyncclk, burst16, burst8, burst4, burst2, burst1, shram_wm - */ - { - const struct reg_field cif_wr_dmactl_fields[] = { - v->cif_wrdma_enable, - v->cif_wrdma_reset, - v->cif_wrdma_num_ot, - v->cif_wrdma_dma_dyncclk, - v->cif_wrdma_burst16, - v->cif_wrdma_burst8, - v->cif_wrdma_burst4, - v->cif_wrdma_burst2, - v->cif_wrdma_burst1, - v->cif_wrdma_shram_wm, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &wr_dmactl->enable, - cif_wr_dmactl_fields, - ARRAY_SIZE(cif_wr_dmactl_fields)); - if (ret) { - dev_err(dev, "error allocating CIF WRDMA dmactl regmap fields: %d\n", ret); - return ret; - } - } - /* - * Bulk-allocate CIF WRDMA intfctl fields. - * Order must match struct qaif_cdc_intfctl member order: - * active_ch_en, fs_sel, fs_delay, fs_out_gate, intf_dyncclk, en_16bit_unpack - */ - { - const struct reg_field cif_wr_intfctl_fields[] = { - v->cif_wrdma_active_ch_en, - v->cif_wrdma_fs_sel, - v->cif_wrdma_fs_delay, - v->cif_wrdma_fs_out_gate, - v->cif_wrdma_intf_dyncclk, - v->cif_wrdma_en_16bit_unpack, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &wr_intfctl->active_ch_en, - cif_wr_intfctl_fields, - ARRAY_SIZE(cif_wr_intfctl_fields)); - if (ret) { - dev_err(dev, "error allocating CIF WRDMA intfctl regmap fields: %d\n", ret); - return ret; - } - } +/* CIF INTF CFG register bit positions */ +#define QAIF_CIF_INTF_16BIT_UNPACK_BIT BIT(0) +#define QAIF_CIF_INTF_DYNCLK_BIT BIT(2) +#define QAIF_CIF_INTF_FS_SEL_MASK GENMASK(7, 4) +#define QAIF_CIF_INTF_ACTIVE_CH_MASK GENMASK(27, 12) +#define QAIF_CIF_INTF_ACTIVE_CH_SHIFT 12 + +/* AIF CTL register (QAIF_AUD_INTF_CTL_REG) bit positions */ +#define QAIF_AIF_CTL_ENABLE_BIT BIT(0) +#define QAIF_AIF_CTL_ENABLE_TX_BIT BIT(4) +#define QAIF_AIF_CTL_ENABLE_RX_BIT BIT(8) + +/* AIF SYNC CFG register (QAIF_AUD_INTF_SYNC_CFG_REG) bit positions */ +#define QAIF_AIF_SYNC_SRC_BIT BIT(0) +#define QAIF_AIF_SYNC_MODE_MASK GENMASK(5, 4) +#define QAIF_AIF_SYNC_MODE_SHIFT 4 +#define QAIF_AIF_SYNC_DELAY_MASK GENMASK(9, 8) +#define QAIF_AIF_SYNC_DELAY_SHIFT 8 +#define QAIF_AIF_SYNC_INV_BIT BIT(12) + +/* SYNC_MODE field values */ +#define QAIF_AIF_SYNC_MODE_SHORT 0 +#define QAIF_AIF_SYNC_MODE_ONE_SLOT 1 +#define QAIF_AIF_SYNC_MODE_LONG 2 + +/* SYNC_DELAY field values */ +#define QAIF_AIF_SYNC_DELAY_SAME 0 +#define QAIF_AIF_SYNC_DELAY_ONE 1 + +/* AIF BIT WIDTH CFG register (QAIF_AUD_INTF_BIT_WIDTH_CFG_REG) bit positions */ +#define QAIF_AIF_SLOT_WIDTH_TX_MASK GENMASK(4, 0) +#define QAIF_AIF_SLOT_WIDTH_RX_MASK GENMASK(12, 8) +#define QAIF_AIF_SLOT_WIDTH_RX_SHIFT 8 +#define QAIF_AIF_SAMPLE_WIDTH_TX_MASK GENMASK(20, 16) +#define QAIF_AIF_SAMPLE_WIDTH_TX_SHIFT 16 +#define QAIF_AIF_SAMPLE_WIDTH_RX_MASK GENMASK(28, 24) +#define QAIF_AIF_SAMPLE_WIDTH_RX_SHIFT 24 - drvdata->cif_rd_dmactl = rd_dmactl; - drvdata->cif_wr_dmactl = wr_dmactl; - drvdata->cif_rddma_intfctl = rd_intfctl; - drvdata->cif_wrdma_intfctl = wr_intfctl; +/* + * slot_width is programmed 0-based into the 5-bit SLOT_WIDTH field and the + * frame length (slots * slot_width) 0-based into the 10-bit BITS_PER_LANE + * field, so these are the largest values the registers can represent. + */ +#define QAIF_AIF_SLOT_WIDTH_MAX 32 +#define QAIF_AIF_FRAME_BITS_MAX 1024 - return 0; -} +/* AIF FRAME CFG register (QAIF_AUD_INTF_FRAME_CFG_REG) bit positions */ +#define QAIF_AIF_BITS_PER_LANE_MASK GENMASK(9, 0) -static struct qaif_cdc_intfctl *qaif_get_cif_intfctl_handle(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); - struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); - const struct qaif_variant *v = drvdata->variant; - unsigned int dai_id = cpu_dai->driver->id; - struct qaif_cdc_intfctl *intfctl = NULL; +/* AIF LANE CFG register (QAIF_AUD_INTF_LANE_CFG_REG) bit positions */ +#define QAIF_AIF_LANE_DIR_MASK GENMASK(7, 0) +#define QAIF_AIF_LANE_EN_MASK GENMASK(15, 8) +#define QAIF_AIF_LANE_EN_SHIFT 8 +#define QAIF_AIF_CTRL_DATA_OE_BIT BIT(16) +#define QAIF_AIF_LOOPBACK_EN_BIT BIT(31) - if (!v) { - dev_err(soc_runtime->dev, "No variant data\n"); - return intfctl; - } +/* AIF MI2S CFG register (QAIF_AUD_INTF_MI2S_CFG_REG) bit positions */ +#define QAIF_AIF_MONO_MODE_TX_BIT BIT(0) +#define QAIF_AIF_MONO_MODE_RX_BIT BIT(1) - switch (dai_id) { - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - intfctl = drvdata->cif_rddma_intfctl; - break; - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - intfctl = drvdata->cif_wrdma_intfctl; - break; - default: - dev_err(soc_runtime->dev, "invalid dai id for dma ctl: %d\n", dai_id); - break; - } - return intfctl; -} +/* AIF CFG register (QAIF_AUD_INTF_CFG_REG) bit positions */ +#define QAIF_AIF_FULL_CYCLE_EN_BIT BIT(0) static int qaif_cif_daiops_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; - struct qaif_cdc_intfctl *intfctl = NULL; - unsigned int dai_id = cpu_dai->driver->id; - int ret; + unsigned int dai_id = dai->driver->id; unsigned int regval; - unsigned int channels = params_channels(params); + u32 reg; int idx; - switch (channels) { + switch (params_channels(params)) { case 1: regval = QAIF_CIF_DMA_INTF_ONE_CHANNEL; break; @@ -220,270 +112,155 @@ static int qaif_cif_daiops_hw_params(struct snd_pcm_substream *substream, regval = QAIF_CIF_DMA_INTF_EIGHT_CHANNEL; break; default: - dev_err(soc_runtime->dev, "invalid PCM config\n"); + dev_dbg(rtd->dev, "unsupported channel count %u\n", + params_channels(params)); return -EINVAL; } - intfctl = qaif_get_cif_intfctl_handle(substream, dai); - if (!intfctl) { - dev_err(soc_runtime->dev, "Invalid intfctl: %d\n", dai_id); - return -EINVAL; - } idx = v->get_dma_idx(dai_id); if (idx < 0) { - dev_err(soc_runtime->dev, "Invalid DMA index: %d\n", idx); + dev_err(rtd->dev, "Invalid DMA index: %d\n", idx); return -EINVAL; } - ret = regmap_fields_write(intfctl->active_ch_en, idx, regval); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to intfctl active_ch_en reg field: %d\n", ret); - return ret; - } - return 0; + reg = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_INTF_CFG_REG(v, idx) : + QAIF_CDC_WRDMA_INTF_CFG_REG(v, idx); + + return regmap_update_bits(drvdata->audio_qaif_map, reg, + QAIF_CIF_INTF_ACTIVE_CH_MASK, + regval << QAIF_CIF_INTF_ACTIVE_CH_SHIFT); } static int qaif_cif_daiops_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; - unsigned int dai_id = cpu_dai->driver->id; - struct qaif_cdc_intfctl *intfctl = NULL; - int ret = 0, idx; + unsigned int dai_id = dai->driver->id; + struct regmap *map = drvdata->audio_qaif_map; + u32 reg; + int idx, ret; - intfctl = qaif_get_cif_intfctl_handle(substream, dai); - if (!intfctl) { - dev_err(soc_runtime->dev, "Invalid intfctl: %d\n", dai_id); - return -EINVAL; - } idx = v->get_dma_idx(dai_id); if (idx < 0) { - dev_err(soc_runtime->dev, "Invalid DMA index: %d\n", idx); + dev_err(rtd->dev, "Invalid DMA index: %d\n", idx); return -EINVAL; } + reg = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_INTF_CFG_REG(v, idx) : + QAIF_CDC_WRDMA_INTF_CFG_REG(v, idx); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = regmap_fields_write(intfctl->intf_dyncclk, idx, QAIF_DMACTL_DYNCLK_ON); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to dmactl intf_dyncclk reg field: %d\n", ret); - return ret; - } - ret = regmap_fields_write(intfctl->fs_sel, idx, QAIF_CIF_DMA_FS_SEL_DEFAULT); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to dmactl codec_fs_sel reg field: %d\n", ret); + ret = regmap_update_bits(map, reg, + QAIF_CIF_INTF_DYNCLK_BIT, + QAIF_CIF_INTF_DYNCLK_BIT); + if (ret) return ret; - } - - ret = regmap_fields_write(intfctl->en_16bit_unpack, idx, - QAIF_CIF_16BIT_UNPACK_ENABLE); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to dmactl en_16bit_unpack reg field: %d\n", ret); + ret = regmap_update_bits(map, reg, QAIF_CIF_INTF_FS_SEL_MASK, 0); + if (ret) return ret; - } - break; + return regmap_update_bits(map, reg, + QAIF_CIF_INTF_16BIT_UNPACK_BIT, + QAIF_CIF_INTF_16BIT_UNPACK_BIT); case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = regmap_fields_write(intfctl->intf_dyncclk, idx, QAIF_DMACTL_DYNCLK_OFF); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to dmactl intf_dyncclk reg field: %d\n", ret); - return ret; - } - ret = regmap_fields_write(intfctl->en_16bit_unpack, idx, - QAIF_CIF_16BIT_UNPACK_DISABLE); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to dmactl en_16bit_unpack reg field: %d\n", ret); + ret = regmap_update_bits(map, reg, QAIF_CIF_INTF_DYNCLK_BIT, 0); + if (ret) return ret; - } - break; + return regmap_update_bits(map, reg, + QAIF_CIF_INTF_16BIT_UNPACK_BIT, 0); default: - ret = -EINVAL; - dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, cmd); - break; + dev_err(rtd->dev, "invalid trigger cmd %d\n", cmd); + return -EINVAL; } - return ret; } -const struct snd_soc_dai_ops asoc_qcom_qaif_cif_dai_ops = { - .hw_params = qaif_cif_daiops_hw_params, - .trigger = qaif_cif_daiops_trigger, -}; -EXPORT_SYMBOL_GPL(asoc_qcom_qaif_cif_dai_ops); - -static int qaif_aif_cfg_cpu_init_bitfields(struct device *dev, - struct regmap *map) +static int qaif_cif_daiops_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - const struct qaif_variant *v = drvdata->variant; - struct qaif_aud_intfctl *aif_intfctl; - - aif_intfctl = devm_kzalloc(dev, sizeof(struct qaif_aud_intfctl), GFP_KERNEL); - if (!aif_intfctl) - return -ENOMEM; + struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; - /* - * Bulk-allocate all AIF intfctl fields in one call. - * Order must match struct qaif_aud_intfctl member order: - * inv_sync, sync_delay, sync_mode, sync_src, - * slot_width_rx, slot_width_tx, sample_width_rx, sample_width_tx, - * mono_mode_rx, mono_mode_tx, - * lane_en, lane_dir, loopback_en, ctrl_data_oe, - * slot_en_rx_mask, slot_en_tx_mask, - * full_cycle_en, bits_per_lane, - * enable, enable_tx, enable_rx, - * reset, reset_tx, reset_rx - */ - { - const struct reg_field aif_intfctl_fields[] = { - v->aif_inv_sync, - v->aif_sync_delay, - v->aif_sync_mode, - v->aif_sync_src, - v->aif_slot_width_rx, - v->aif_slot_width_tx, - v->aif_sample_width_rx, - v->aif_sample_width_tx, - v->aif_mono_mode_rx, - v->aif_mono_mode_tx, - v->aif_lane_en, - v->aif_lane_dir, - v->aif_loopback_en, - v->aif_ctrl_data_oe, - v->aif_slot_en_rx_mask, - v->aif_slot_en_tx_mask, - v->aif_full_cycle_en, - v->aif_bits_per_lane, - v->aif_enable, - v->aif_enable_tx, - v->aif_enable_rx, - v->aif_reset, - v->aif_reset_tx, - v->aif_reset_rx, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &aif_intfctl->inv_sync, - aif_intfctl_fields, - ARRAY_SIZE(aif_intfctl_fields)); - if (ret) { - dev_err(dev, "error allocating AIF interface regmap fields: %d\n", ret); - return ret; - } + ret = clk_prepare_enable(drvdata->aud_dma_clk); + if (ret) { + dev_err(dai->dev, "error enabling aud_dma clk: %d\n", ret); + return ret; } - drvdata->aif_intfctl = aif_intfctl; - + ret = clk_prepare_enable(drvdata->aud_dma_mem_clk); + if (ret) { + dev_err(dai->dev, "error enabling aud_dma_mem clk: %d\n", ret); + clk_disable_unprepare(drvdata->aud_dma_clk); + return ret; + } return 0; } -static int qaif_aif_cpu_init_bitfields(struct device *dev, - struct regmap *map) +static void qaif_cif_daiops_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - const struct qaif_variant *v = drvdata->variant; - struct qaif_dmactl *rd_dmactl; - struct qaif_dmactl *wr_dmactl; - - rd_dmactl = devm_kzalloc(dev, sizeof(struct qaif_dmactl), GFP_KERNEL); - if (!rd_dmactl) - return -ENOMEM; - - wr_dmactl = devm_kzalloc(dev, sizeof(struct qaif_dmactl), GFP_KERNEL); - if (!wr_dmactl) - return -ENOMEM; - - /* - * Bulk-allocate AIF RDDMA dmactl fields. - * Order must match struct qaif_dmactl member order: - * enable, reset, num_ot, dma_dyncclk, burst16, burst8, burst4, burst2, burst1, shram_wm - */ - { - const struct reg_field aif_rd_dmactl_fields[] = { - v->rddma_enable, - v->rddma_reset, - v->rddma_num_ot, - v->rddma_dma_dyncclk, - v->rddma_burst16, - v->rddma_burst8, - v->rddma_burst4, - v->rddma_burst2, - v->rddma_burst1, - v->rddma_shram_wm, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &rd_dmactl->enable, - aif_rd_dmactl_fields, - ARRAY_SIZE(aif_rd_dmactl_fields)); - if (ret) { - dev_err(dev, "error allocating AIF RDDMA dmactl regmap fields: %d\n", ret); - return ret; - } - } - - /* - * Bulk-allocate AIF WRDMA dmactl fields. - * Order must match struct qaif_dmactl member order: - * enable, reset, num_ot, dma_dyncclk, burst16, burst8, burst4, burst2, burst1, shram_wm - */ - { - const struct reg_field aif_wr_dmactl_fields[] = { - v->wrdma_enable, - v->wrdma_reset, - v->wrdma_num_ot, - v->wrdma_dma_dyncclk, - v->wrdma_burst16, - v->wrdma_burst8, - v->wrdma_burst4, - v->wrdma_burst2, - v->wrdma_burst1, - v->wrdma_shram_wm, - }; - int ret = devm_regmap_field_bulk_alloc(dev, map, - &wr_dmactl->enable, - aif_wr_dmactl_fields, - ARRAY_SIZE(aif_wr_dmactl_fields)); - if (ret) { - dev_err(dev, "error allocating AIF WRDMA dmactl regmap fields: %d\n", ret); - return ret; - } - } - - drvdata->aif_rd_dmactl = rd_dmactl; - drvdata->aif_wr_dmactl = wr_dmactl; + struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); - return 0; + clk_disable_unprepare(drvdata->aud_dma_mem_clk); + clk_disable_unprepare(drvdata->aud_dma_clk); } +/* + * asoc_qcom_qaif_cif_dai_ops - DAI ops for QAIF CIF (CDC DMA) paths + * + * Provides startup, shutdown, hw_params and trigger callbacks for the + * Codec Interface DMA (CIF) DAI. startup/shutdown enable and disable the + * audio DMA clocks. Used by Shikra machine drivers for Bolero CDC DMA + * RX, TX and VA TX paths. + */ +const struct snd_soc_dai_ops asoc_qcom_qaif_cif_dai_ops = { + .startup = qaif_cif_daiops_startup, + .shutdown = qaif_cif_daiops_shutdown, + .hw_params = qaif_cif_daiops_hw_params, + .trigger = qaif_cif_daiops_trigger, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_qaif_cif_dai_ops); + static int qaif_aif_cpu_daiops_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; - int idx, ret = 0; + int idx, ret; idx = v->get_dma_idx(dai->driver->id); if (idx < 0) { - dev_err(dai->dev, "%s: Invalid DMA index: %d\n", __func__, idx); + dev_err(dai->dev, "Invalid DMA index: %d\n", idx); return -EINVAL; } - ret = clk_prepare(drvdata->mi2s_bit_clk[idx]); + ret = clk_prepare_enable(drvdata->aud_dma_clk); if (ret) { - dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret); + dev_err(dai->dev, "error enabling aud_dma clk: %d\n", ret); return ret; } - return 0; + + ret = clk_prepare_enable(drvdata->aud_dma_mem_clk); + if (ret) { + dev_err(dai->dev, "error enabling aud_dma_mem clk: %d\n", ret); + clk_disable_unprepare(drvdata->aud_dma_clk); + return ret; + } + + ret = clk_prepare_enable(drvdata->mi2s_bit_clk[idx]); + if (ret) { + dev_err(dai->dev, "error enabling mi2s bit clk: %d\n", ret); + clk_disable_unprepare(drvdata->aud_dma_mem_clk); + clk_disable_unprepare(drvdata->aud_dma_clk); + } + return ret; } static void qaif_aif_cpu_daiops_shutdown(struct snd_pcm_substream *substream, @@ -491,39 +268,32 @@ static void qaif_aif_cpu_daiops_shutdown(struct snd_pcm_substream *substream, { struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; - struct qaif_aud_intfctl *aif_intfctl = drvdata->aif_intfctl; - const struct qaif_aif_config *aif_intf_cfg; + const struct qaif_aif_config *cfg; + unsigned int enable_bit; int idx = v->get_dma_idx(dai->driver->id); + int ret; if (idx < 0) { - dev_err(dai->dev, "%s: Invalid DMA index: %d\n", __func__, idx); + dev_err(dai->dev, "Invalid DMA index: %d\n", idx); return; } - aif_intf_cfg = &drvdata->aif_intf_cfg[idx]; - - if (aif_intf_cfg->loopback_en) - regmap_fields_write(aif_intfctl->enable, idx, QAIF_AIF_CTL_ENABLE_OFF); + cfg = &drvdata->aif_intf_cfg[idx]; + if (cfg->loopback_en) + enable_bit = QAIF_AIF_CTL_ENABLE_BIT; else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - regmap_fields_write(aif_intfctl->enable_tx, idx, QAIF_AIF_CTL_ENABLE_OFF); + enable_bit = QAIF_AIF_CTL_ENABLE_TX_BIT; else - regmap_fields_write(aif_intfctl->enable_rx, idx, QAIF_AIF_CTL_ENABLE_OFF); - - clk_unprepare(drvdata->mi2s_bit_clk[idx]); -} - -static int qaif_aif_cpu_daiops_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); - const struct qaif_variant *v = drvdata->variant; - int idx = v->get_dma_idx(dai->driver->id); + enable_bit = QAIF_AIF_CTL_ENABLE_RX_BIT; - if (idx < 0) - return 0; + ret = regmap_update_bits(drvdata->audio_qaif_map, + QAIF_AUD_INTF_CTL_REG(idx), enable_bit, 0); + if (ret) + dev_err(dai->dev, "error clearing AIF enable bit: %d\n", ret); - clk_disable(drvdata->mi2s_bit_clk[idx]); - return 0; + clk_disable_unprepare(drvdata->mi2s_bit_clk[idx]); + clk_disable_unprepare(drvdata->aud_dma_mem_clk); + clk_disable_unprepare(drvdata->aud_dma_clk); } static int qaif_aif_cpu_daiops_hw_params(struct snd_pcm_substream *substream, @@ -531,196 +301,124 @@ static int qaif_aif_cpu_daiops_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); const struct qaif_variant *v = drvdata->variant; - struct qaif_aud_intfctl *aif_intfctl = drvdata->aif_intfctl; - const struct qaif_aif_config *aif_intf_cfg = NULL; - int idx; + const struct qaif_aif_config *cfg; + struct regmap *map = drvdata->audio_qaif_map; snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); - unsigned int rate = params_rate(params); - unsigned int slot_width = 32; - int bitwidth, ret; - - if (!aif_intfctl) { - dev_err(dai->dev, "AIF interface control not initialized\n"); - return -EINVAL; - } + unsigned int slot_width; + int bitwidth, idx, ret; idx = v->get_dma_idx(dai->driver->id); - if (idx < 0) { - dev_err(dai->dev, "%s: Invalid DMA index: %d\n", __func__, idx); + dev_err(dai->dev, "Invalid DMA index: %d\n", idx); return -EINVAL; } - aif_intf_cfg = &drvdata->aif_intf_cfg[idx]; + cfg = &drvdata->aif_intf_cfg[idx]; - if (!aif_intf_cfg) { - dev_err(dai->dev, "AIF interface config not found\n"); - return -EINVAL; - } bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { dev_err(dai->dev, "invalid bit width given: %d\n", bitwidth); return bitwidth; } - /* SYNC_CFG: write all four sync fields */ - ret = regmap_fields_write(aif_intfctl->inv_sync, idx, aif_intf_cfg->invert_sync); - if (ret) { - dev_err(dai->dev, "Failed to write inv_sync: %d\n", ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->sync_delay, idx, aif_intf_cfg->sync_delay); - if (ret) { - dev_err(dai->dev, "Failed to write sync_delay: %d\n", ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->sync_mode, idx, aif_intf_cfg->sync_mode); - if (ret) { - dev_err(dai->dev, "Failed to write sync_mode: %d\n", ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->sync_src, idx, aif_intf_cfg->sync_src); - if (ret) { - dev_err(dai->dev, "Failed to write sync_src: %d\n", ret); + /* + * The sync, lane and frame configuration and the MI2S bit clock are + * shared by both directions of an AIF. Concurrent playback and + * capture on the same interface are therefore expected to use a + * compatible format, rate and slot configuration. + */ + ret = regmap_update_bits(map, QAIF_AUD_INTF_SYNC_CFG_REG(idx), + QAIF_AIF_SYNC_SRC_BIT | + QAIF_AIF_SYNC_MODE_MASK | + QAIF_AIF_SYNC_DELAY_MASK | + QAIF_AIF_SYNC_INV_BIT, + (cfg->sync_src ? QAIF_AIF_SYNC_SRC_BIT : 0) | + (cfg->sync_mode << QAIF_AIF_SYNC_MODE_SHIFT) | + (cfg->sync_delay << QAIF_AIF_SYNC_DELAY_SHIFT) | + (cfg->invert_sync ? QAIF_AIF_SYNC_INV_BIT : 0)); + if (ret) return ret; - } - /* LANE_CFG: write all four lane fields */ - ret = regmap_fields_write(aif_intfctl->loopback_en, idx, aif_intf_cfg->loopback_en); - if (ret) { - dev_err(dai->dev, "Failed to write loopback_en: %d\n", ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->ctrl_data_oe, idx, aif_intf_cfg->ctrl_data_oe); - if (ret) { - dev_err(dai->dev, "Failed to write ctrl_data_oe: %d\n", ret); + ret = regmap_update_bits(map, QAIF_AUD_INTF_LANE_CFG_REG(idx), + QAIF_AIF_LANE_DIR_MASK | + QAIF_AIF_LANE_EN_MASK | + QAIF_AIF_CTRL_DATA_OE_BIT | + QAIF_AIF_LOOPBACK_EN_BIT, + cfg->lane_dir_mask | + (cfg->lane_en_mask << QAIF_AIF_LANE_EN_SHIFT) | + (cfg->ctrl_data_oe ? QAIF_AIF_CTRL_DATA_OE_BIT : 0) | + (cfg->loopback_en ? QAIF_AIF_LOOPBACK_EN_BIT : 0)); + if (ret) return ret; - } - ret = regmap_fields_write(aif_intfctl->lane_en, idx, aif_intf_cfg->lane_en_mask); - if (ret) { - dev_err(dai->dev, "Failed to write lane_en (mask=0x%02X): %d\n", - aif_intf_cfg->lane_en_mask, ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->lane_dir, idx, aif_intf_cfg->lane_dir_mask); - if (ret) { - dev_err(dai->dev, "Failed to write lane_dir (mask=0x%02X): %d\n", - aif_intf_cfg->lane_dir_mask, ret); - return ret; - } - /* CFG: full_cycle_en */ - ret = regmap_fields_write(aif_intfctl->full_cycle_en, idx, aif_intf_cfg->full_cycle_en); - if (ret) { - dev_err(dai->dev, "Failed to write full_cycle_en: %d\n", ret); + ret = regmap_update_bits(map, QAIF_AUD_INTF_CFG_REG(idx), + QAIF_AIF_FULL_CYCLE_EN_BIT, + cfg->full_cycle_en ? QAIF_AIF_FULL_CYCLE_EN_BIT : 0); + if (ret) return ret; - } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - slot_width = aif_intf_cfg->slot_width_tx; - /* BIT_WIDTH_CFG: TX slot width and sample width */ - ret = regmap_fields_write(aif_intfctl->slot_width_tx, idx, - QAIF_AIF_SLOT_WIDTH(slot_width)); - if (ret) { - dev_err(dai->dev, "Failed to write slot_width_tx: %d\n", ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->sample_width_tx, idx, - QAIF_AIF_SAMPLE_WIDTH(bitwidth)); - if (ret) { - dev_err(dai->dev, "Failed to write sample_width_tx: %d\n", ret); - return ret; - } - /* ACTV_SLOT_EN_TX */ - ret = regmap_fields_write(aif_intfctl->slot_en_tx_mask, idx, - aif_intf_cfg->slot_en_tx_mask); - if (ret) { - dev_err(dai->dev, "Failed to write slot_en_tx_mask (0x%08X): %d\n", - aif_intf_cfg->slot_en_tx_mask, ret); - return ret; + if (qaif_is_aif_mi2s_port(dai->driver->id) && !cfg->slot_width) { + slot_width = bitwidth; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + drvdata->aif_intf_cfg[idx].slot_en_tx_mask = + GENMASK(channels - 1, 0); + else + drvdata->aif_intf_cfg[idx].slot_en_rx_mask = + GENMASK(channels - 1, 0); + drvdata->aif_intf_cfg[idx].slot_num = QAIF_MI2S_SLOTS; + } else { + slot_width = cfg->slot_width; + if (!slot_width || !cfg->slot_num) { + dev_err(dai->dev, "invalid TDM slot config: width=%u num=%u\n", + slot_width, cfg->slot_num); + return -EINVAL; } + } - /* FRAME_CFG: bits_per_lane */ - ret = regmap_fields_write(aif_intfctl->bits_per_lane, idx, - (slot_width * aif_intf_cfg->bits_per_lane) - 1); - if (ret) { - dev_err(dai->dev, "Failed to write bits_per_lane: %d\n", ret); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = regmap_update_bits(map, QAIF_AUD_INTF_BIT_WIDTH_CFG_REG(idx), + QAIF_AIF_SLOT_WIDTH_TX_MASK | + QAIF_AIF_SAMPLE_WIDTH_TX_MASK, + QAIF_AIF_SLOT_WIDTH(slot_width) | + (QAIF_AIF_SAMPLE_WIDTH(bitwidth) << + QAIF_AIF_SAMPLE_WIDTH_TX_SHIFT)); + if (ret) return ret; - } - - /* MI2S_CFG: TX mono mode */ - ret = regmap_fields_write(aif_intfctl->mono_mode_tx, idx, - (channels >= 2) ? QAIF_AUD_INTF_CTL_STEREO - : QAIF_AUD_INTF_CTL_MONO); - if (ret) { - dev_err(dai->dev, "Failed to write mono_mode_tx: %d\n", ret); + ret = regmap_write(map, QAIF_AUD_INTF_ACTV_SLOT_EN_TX_REG(idx), + cfg->slot_en_tx_mask); + if (ret) return ret; - } + ret = regmap_update_bits(map, QAIF_AUD_INTF_MI2S_CFG_REG(idx), + QAIF_AIF_MONO_MODE_TX_BIT, + (channels < 2) ? QAIF_AIF_MONO_MODE_TX_BIT : 0); } else { - slot_width = aif_intf_cfg->slot_width_rx; - /* BIT_WIDTH_CFG: RX slot width and sample width */ - ret = regmap_fields_write(aif_intfctl->slot_width_rx, idx, - QAIF_AIF_SLOT_WIDTH(slot_width)); - if (ret) { - dev_err(dai->dev, "Failed to write slot_width_rx: %d\n", ret); - return ret; - } - ret = regmap_fields_write(aif_intfctl->sample_width_rx, idx, - QAIF_AIF_SAMPLE_WIDTH(bitwidth)); - if (ret) { - dev_err(dai->dev, "Failed to write sample_width_rx: %d\n", ret); - return ret; - } - - /* ACTV_SLOT_EN_RX */ - ret = regmap_fields_write(aif_intfctl->slot_en_rx_mask, idx, - aif_intf_cfg->slot_en_rx_mask); - if (ret) { - dev_err(dai->dev, "Failed to write slot_en_rx_mask (0x%08X): %d\n", - aif_intf_cfg->slot_en_rx_mask, ret); - return ret; - } - - /* FRAME_CFG: bits_per_lane */ - ret = regmap_fields_write(aif_intfctl->bits_per_lane, idx, - (slot_width * aif_intf_cfg->bits_per_lane) - 1); - if (ret) { - dev_err(dai->dev, "Failed to write bits_per_lane: %d\n", ret); + ret = regmap_update_bits(map, QAIF_AUD_INTF_BIT_WIDTH_CFG_REG(idx), + QAIF_AIF_SLOT_WIDTH_RX_MASK | + QAIF_AIF_SAMPLE_WIDTH_RX_MASK, + (QAIF_AIF_SLOT_WIDTH(slot_width) << + QAIF_AIF_SLOT_WIDTH_RX_SHIFT) | + (QAIF_AIF_SAMPLE_WIDTH(bitwidth) << + QAIF_AIF_SAMPLE_WIDTH_RX_SHIFT)); + if (ret) return ret; - } - - /* MI2S_CFG: RX mono mode */ - ret = regmap_fields_write(aif_intfctl->mono_mode_rx, idx, - (channels >= 2) ? QAIF_AUD_INTF_CTL_STEREO - : QAIF_AUD_INTF_CTL_MONO); - if (ret) { - dev_err(dai->dev, "Failed to write mono_mode_rx: %d\n", ret); + ret = regmap_write(map, QAIF_AUD_INTF_ACTV_SLOT_EN_RX_REG(idx), + cfg->slot_en_rx_mask); + if (ret) return ret; - } + ret = regmap_update_bits(map, QAIF_AUD_INTF_MI2S_CFG_REG(idx), + QAIF_AIF_MONO_MODE_RX_BIT, + (channels < 2) ? QAIF_AIF_MONO_MODE_RX_BIT : 0); } - - ret = clk_set_rate(drvdata->mi2s_bit_clk[idx], - rate * slot_width * aif_intf_cfg->bits_per_lane); - if (ret) { - dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n", - rate * slot_width * aif_intf_cfg->bits_per_lane, ret); + if (ret) return ret; - } - dev_dbg(dai->dev, "setting IBIT clock to %u\n", - rate * slot_width * aif_intf_cfg->bits_per_lane); - ret = clk_enable(drvdata->mi2s_bit_clk[idx]); - if (ret) { - dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret); + ret = regmap_update_bits(map, QAIF_AUD_INTF_FRAME_CFG_REG(idx), + QAIF_AIF_BITS_PER_LANE_MASK, + (slot_width * cfg->slot_num) - 1); + if (ret) return ret; - } - snd_soc_dai_set_tdm_slot(codec_dai, 0x0f, 0b11, aif_intf_cfg->bits_per_lane, slot_width); - snd_soc_dai_set_sysclk(codec_dai, 0, rate * aif_intf_cfg->bits_per_lane * slot_width, 0); return 0; } @@ -730,522 +428,181 @@ static int qaif_aif_cpu_daiops_trigger(struct snd_pcm_substream *substream, { struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; - int idx, ret = -EINVAL; - const struct qaif_aif_config *aif_intf_cfg; + const struct qaif_aif_config *cfg; + unsigned int enable_bit; + int idx, ret; idx = v->get_dma_idx(dai->driver->id); if (idx < 0) { - dev_err(dai->dev, "%s: Invalid DMA index: %d\n", __func__, idx); + dev_err(dai->dev, "Invalid DMA index: %d\n", idx); return -EINVAL; } - aif_intf_cfg = &drvdata->aif_intf_cfg[idx]; + cfg = &drvdata->aif_intf_cfg[idx]; + if (cfg->loopback_en) + enable_bit = QAIF_AIF_CTL_ENABLE_BIT; + else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + enable_bit = QAIF_AIF_CTL_ENABLE_TX_BIT; + else + enable_bit = QAIF_AIF_CTL_ENABLE_RX_BIT; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (aif_intf_cfg->loopback_en) - ret = regmap_fields_write(drvdata->aif_intfctl->enable, - idx, QAIF_AIF_CTL_ENABLE_ON); - else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = regmap_fields_write(drvdata->aif_intfctl->enable_tx, - idx, QAIF_AIF_CTL_ENABLE_ON); - else - ret = regmap_fields_write(drvdata->aif_intfctl->enable_rx, - idx, QAIF_AIF_CTL_ENABLE_ON); + ret = regmap_update_bits(drvdata->audio_qaif_map, + QAIF_AUD_INTF_CTL_REG(idx), enable_bit, enable_bit); if (ret) - dev_err(dai->dev, "error writing to AIF CTL reg: %d\n", ret); - - ret = clk_enable(drvdata->mi2s_bit_clk[idx]); - if (ret) { - dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret); - return ret; - } - break; + dev_err(dai->dev, "error setting AIF enable bit: %d\n", ret); + return ret; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - - if (aif_intf_cfg->loopback_en) - ret = regmap_fields_write(drvdata->aif_intfctl->enable, - idx, QAIF_AIF_CTL_ENABLE_OFF); - else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = regmap_fields_write(drvdata->aif_intfctl->enable_tx, - idx, QAIF_AIF_CTL_ENABLE_OFF); - else - ret = regmap_fields_write(drvdata->aif_intfctl->enable_rx, - idx, QAIF_AIF_CTL_ENABLE_OFF); + ret = regmap_update_bits(drvdata->audio_qaif_map, + QAIF_AUD_INTF_CTL_REG(idx), enable_bit, 0); if (ret) - dev_err(dai->dev, "error writing to AIF CTL reg: %d\n", ret); - - clk_disable(drvdata->mi2s_bit_clk[idx]); - - break; + dev_err(dai->dev, "error clearing AIF enable bit: %d\n", ret); + return ret; + default: + dev_err(dai->dev, "invalid trigger cmd %d\n", cmd); + return -EINVAL; } - - return ret; } -const struct snd_soc_dai_ops asoc_qcom_qaif_aif_cpu_dai_ops = { - .startup = qaif_aif_cpu_daiops_startup, - .shutdown = qaif_aif_cpu_daiops_shutdown, - .hw_free = qaif_aif_cpu_daiops_hw_free, - .hw_params = qaif_aif_cpu_daiops_hw_params, - .trigger = qaif_aif_cpu_daiops_trigger, -}; -EXPORT_SYMBOL_GPL(asoc_qcom_qaif_aif_cpu_dai_ops); - -static int qaif_cpu_of_xlate_dai_name(struct snd_soc_component *component, - const struct of_phandle_args *args, - const char **dai_name) +static int qaif_aif_cpu_daiops_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, int slots, + int slot_width) { - struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); + struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; + int idx = v->get_dma_idx(dai->driver->id); + struct qaif_aif_config *cfg; - return asoc_qcom_of_xlate_dai_name(v->dai_driver, - v->num_dai, args, dai_name); -} - -static const struct snd_soc_component_driver qaif_cpu_comp_driver = { - .name = "qaif-cpu", - .of_xlate_dai_name = qaif_cpu_of_xlate_dai_name, -}; - -static bool audio_qaif_regmap_writeable(struct device *dev, unsigned int reg) -{ - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - const struct qaif_variant *v = drvdata->variant; - int i; - - /* EE maps */ - if (reg == QAIF_EE_RDDMA_MAP_REG(v)) - return true; - if (reg == QAIF_EE_WRDMA_MAP_REG(v)) - return true; - if (reg == QAIF_EE_INTF_MAP_REG(v)) - return true; - if (reg == QAIF_EE_CODEC_RDDMA_MAP_REG(v)) - return true; - if (reg == QAIF_EE_CODEC_WRDMA_MAP_REG(v)) - return true; - - /* QXM DMA path mapping */ - if (reg == QAIF_RDDMA_MAP_QXM) - return true; - if (reg == QAIF_WRDMA_MAP_QXM) - return true; - if (reg == QAIF_CODEC_RDDMA_MAP_QXM) - return true; - if (reg == QAIF_CODEC_WRDMA_MAP_QXM) - return true; - - /* SID maps */ - if (reg == QAIF_WRDMA_SID_MAP_REG) - return true; - if (reg == QAIF_CODEC_WRDMA_SID_MAP_REG) - return true; - if (reg == QAIF_RDDMA_SID_MAP_REG) - return true; - if (reg == QAIF_CODEC_RDDMA_SID_MAP_REG) - return true; - - /* SHRAM QXM0 start address and length */ - for (i = 0; i < v->num_rddma; i++) { - if (reg == QAIF_RDDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_RDDMA_QXM0_SHRAM_LEN(i)) - return true; - } - for (i = 0; i < v->num_codec_rddma; i++) { - if (reg == QAIF_CODEC_RDDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_CODEC_RDDMA_QXM0_SHRAM_LEN(i)) - return true; - } - for (i = 0; i < v->num_wrdma; i++) { - if (reg == QAIF_WRDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_WRDMA_QXM0_SHRAM_LEN(i)) - return true; - } - for (i = 0; i < v->num_codec_wrdma; i++) { - if (reg == QAIF_CODEC_WRDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_CODEC_WRDMA_QXM0_SHRAM_LEN(i)) - return true; - } + if (idx < 0) + return -EINVAL; - /* EE IRQ EN and CLR */ - for (i = 0; i < DMA_TYPE_MAX; i++) { - if (reg == QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, i)) - return true; - } + if (slots <= 0 || slot_width <= 0) + return -EINVAL; - /* AUD_INTF control and configuration */ - for (i = 0; i < v->num_intf; i++) { - if (reg == QAIF_AUD_INTF_CTL_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_SYNC_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_BIT_WIDTH_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_FRAME_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_ACTV_SLOT_EN_TX_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_ACTV_SLOT_EN_RX_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_LANE_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_MI2S_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_CFG_REG(i)) - return true; - } + if (slot_width > QAIF_AIF_SLOT_WIDTH_MAX || + slots * slot_width > QAIF_AIF_FRAME_BITS_MAX) + return -EINVAL; - /* RDDMA control and configuration */ - for (i = 0; i < v->num_rddma; i++) { - if (reg == QAIF_RDDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_PERIOD_LEN_REG(v, i)) - return true; - } + cfg = &drvdata->aif_intf_cfg[idx]; + cfg->slot_num = slots; + cfg->slot_width = slot_width; + cfg->slot_en_tx_mask = tx_mask; + cfg->slot_en_rx_mask = rx_mask; - /* CODEC RDDMA control and configuration */ - for (i = 0; i < v->num_codec_rddma; i++) { - if (reg == QAIF_CODEC_RDDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_PERIOD_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_INTF_CFG_REG(v, i)) - return true; - } + return 0; +} - /* WRDMA control and configuration */ - for (i = 0; i < v->num_wrdma; i++) { - if (reg == QAIF_WRDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_PERIOD_LEN_REG(v, i)) - return true; - } +static int qaif_aif_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, + int dir) +{ + struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); + const struct qaif_variant *v = drvdata->variant; + int idx = v->get_dma_idx(dai->driver->id); - /* CODEC WRDMA control and configuration */ - for (i = 0; i < v->num_codec_wrdma; i++) { - if (reg == QAIF_CODEC_WRDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_PERIOD_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_INTF_CFG_REG(v, i)) - return true; - } + if (idx < 0) + return -EINVAL; - return false; + /* + * The bit clock is prepared and enabled for the lifetime of the + * stream by startup()/shutdown(); only the rate is set here. + */ + return clk_set_rate(drvdata->mi2s_bit_clk[idx], freq); } -static bool audio_qaif_regmap_readable(struct device *dev, unsigned int reg) +static int qaif_aif_cpu_daiops_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) { - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); + struct qaif_drv_data *drvdata = snd_soc_dai_get_drvdata(dai); const struct qaif_variant *v = drvdata->variant; - int i; - - /* Summary IRQ status */ - if (reg == QAIF_SUMMARY_IRQSTAT_REG(v)) - return true; - - /* EE maps */ - if (reg == QAIF_EE_RDDMA_MAP_REG(v)) - return true; - if (reg == QAIF_EE_WRDMA_MAP_REG(v)) - return true; - if (reg == QAIF_EE_INTF_MAP_REG(v)) - return true; - if (reg == QAIF_EE_CODEC_RDDMA_MAP_REG(v)) - return true; - if (reg == QAIF_EE_CODEC_WRDMA_MAP_REG(v)) - return true; - - /* QXM DMA path mapping */ - if (reg == QAIF_RDDMA_MAP_QXM) - return true; - if (reg == QAIF_WRDMA_MAP_QXM) - return true; - if (reg == QAIF_CODEC_RDDMA_MAP_QXM) - return true; - if (reg == QAIF_CODEC_WRDMA_MAP_QXM) - return true; - - /* SID maps */ - if (reg == QAIF_WRDMA_SID_MAP_REG) - return true; - if (reg == QAIF_CODEC_WRDMA_SID_MAP_REG) - return true; - if (reg == QAIF_RDDMA_SID_MAP_REG) - return true; - if (reg == QAIF_CODEC_RDDMA_SID_MAP_REG) - return true; - - /* SHRAM QXM0 start address and length */ - for (i = 0; i < v->num_rddma; i++) { - if (reg == QAIF_RDDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_RDDMA_QXM0_SHRAM_LEN(i)) - return true; - } - for (i = 0; i < v->num_codec_rddma; i++) { - if (reg == QAIF_CODEC_RDDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_CODEC_RDDMA_QXM0_SHRAM_LEN(i)) - return true; - } - for (i = 0; i < v->num_wrdma; i++) { - if (reg == QAIF_WRDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_WRDMA_QXM0_SHRAM_LEN(i)) - return true; - } - for (i = 0; i < v->num_codec_wrdma; i++) { - if (reg == QAIF_CODEC_WRDMA_QXM0_SHRAM_ST_ADDR(i)) - return true; - if (reg == QAIF_CODEC_WRDMA_QXM0_SHRAM_LEN(i)) - return true; - } - - /* EE IRQ EN, CLR and STATUS */ - for (i = 0; i < DMA_TYPE_MAX; i++) { - if (reg == QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_UNDERFLOW_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_OVERFLOW_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, i)) - return true; - } + int idx = v->get_dma_idx(dai->driver->id); + struct qaif_aif_config *cfg; - /* AUD_INTF control and configuration */ - for (i = 0; i < v->num_intf; i++) { - if (reg == QAIF_AUD_INTF_CTL_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_SYNC_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_BIT_WIDTH_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_FRAME_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_ACTV_SLOT_EN_TX_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_ACTV_SLOT_EN_RX_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_LANE_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_MI2S_CFG_REG(i)) - return true; - if (reg == QAIF_AUD_INTF_CFG_REG(i)) - return true; - } + if (idx < 0) + return -EINVAL; - /* RDDMA control, configuration and current address */ - for (i = 0; i < v->num_rddma; i++) { - if (reg == QAIF_RDDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_CURR_ADDR_REG(v, i)) - return true; - if (reg == QAIF_RDDMA_PERIOD_LEN_REG(v, i)) - return true; - } + cfg = &drvdata->aif_intf_cfg[idx]; - /* CODEC RDDMA control, configuration and current address */ - for (i = 0; i < v->num_codec_rddma; i++) { - if (reg == QAIF_CODEC_RDDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_CURR_ADDR_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_PERIOD_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_RDDMA_INTF_CFG_REG(v, i)) - return true; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cfg->sync_mode = QAIF_AIF_SYNC_MODE_LONG; + cfg->sync_delay = QAIF_AIF_SYNC_DELAY_ONE; + break; + case SND_SOC_DAIFMT_DSP_A: + cfg->sync_mode = QAIF_AIF_SYNC_MODE_ONE_SLOT; + cfg->sync_delay = QAIF_AIF_SYNC_DELAY_ONE; + break; + case SND_SOC_DAIFMT_DSP_B: + cfg->sync_mode = QAIF_AIF_SYNC_MODE_SHORT; + cfg->sync_delay = QAIF_AIF_SYNC_DELAY_SAME; + break; + default: + dev_err(dai->dev, "unsupported format 0x%x\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; } - /* WRDMA control, configuration and current address */ - for (i = 0; i < v->num_wrdma; i++) { - if (reg == QAIF_WRDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_CURR_ADDR_REG(v, i)) - return true; - if (reg == QAIF_WRDMA_PERIOD_LEN_REG(v, i)) - return true; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + cfg->sync_src = 1; + break; + case SND_SOC_DAIFMT_CBC_CFC: + cfg->sync_src = 0; + break; + default: + dev_err(dai->dev, "unsupported clock provider mode\n"); + return -EINVAL; } - /* CODEC WRDMA control, configuration and current address */ - for (i = 0; i < v->num_codec_wrdma; i++) { - if (reg == QAIF_CODEC_WRDMA_CTL_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_CFG_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_BASE_ADDR_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_BUFF_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_CURR_ADDR_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_PERIOD_LEN_REG(v, i)) - return true; - if (reg == QAIF_CODEC_WRDMA_INTF_CFG_REG(v, i)) - return true; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_NB_IF: + cfg->invert_sync = (fmt & SND_SOC_DAIFMT_INV_MASK) == + SND_SOC_DAIFMT_NB_IF; + break; + default: + dev_err(dai->dev, "bit clock inversion is not supported\n"); + return -EINVAL; } - return false; + return 0; } -static bool audio_qaif_regmap_volatile(struct device *dev, unsigned int reg) -{ - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - const struct qaif_variant *v = drvdata->variant; - int i; - - /* Summary IRQ status - hardware updated on any interrupt */ - if (reg == QAIF_SUMMARY_IRQSTAT_REG(v)) - return true; - - /* EE IRQ status - hardware updated on interrupt */ - for (i = 0; i < DMA_TYPE_MAX; i++) { - if (reg == QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_UNDERFLOW_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_OVERFLOW_IRQ_STAT_REG(v, i)) - return true; - if (reg == QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, i)) - return true; - } - - /* DMA current address - hardware updated during streaming */ - for (i = 0; i < v->num_rddma; i++) { - if (reg == QAIF_RDDMA_CURR_ADDR_REG(v, i)) - return true; - } - for (i = 0; i < v->num_wrdma; i++) { - if (reg == QAIF_WRDMA_CURR_ADDR_REG(v, i)) - return true; - } - for (i = 0; i < v->num_codec_rddma; i++) { - if (reg == QAIF_CODEC_RDDMA_CURR_ADDR_REG(v, i)) - return true; - } - for (i = 0; i < v->num_codec_wrdma; i++) { - if (reg == QAIF_CODEC_WRDMA_CURR_ADDR_REG(v, i)) - return true; - } +/* + * asoc_qcom_qaif_aif_cpu_dai_ops - DAI ops for QAIF AIF (MI2S/TDM/PCM) paths + * + * Provides startup, shutdown, hw_params and trigger callbacks + * for the Unified Audio Interface (AIF) DAI. Used by Shikra machine + * drivers for MI2S, TDM and PCM serial audio paths. + */ +const struct snd_soc_dai_ops asoc_qcom_qaif_aif_cpu_dai_ops = { + .set_fmt = qaif_aif_cpu_daiops_set_fmt, + .set_tdm_slot = qaif_aif_cpu_daiops_set_tdm_slot, + .set_sysclk = qaif_aif_cpu_daiops_set_sysclk, + .startup = qaif_aif_cpu_daiops_startup, + .shutdown = qaif_aif_cpu_daiops_shutdown, + .hw_params = qaif_aif_cpu_daiops_hw_params, + .trigger = qaif_aif_cpu_daiops_trigger, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_qaif_aif_cpu_dai_ops); - return false; -} +static const struct snd_soc_component_driver qaif_cpu_comp_driver = { + .name = "qaif-cpu", + .of_xlate_dai_name = snd_soc_of_xlate_dai_name, +}; static const struct regmap_config audio_qaif_regmap_config = { - .name = "audio_qaif_cpu", - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .writeable_reg = audio_qaif_regmap_writeable, - .readable_reg = audio_qaif_regmap_readable, - .volatile_reg = audio_qaif_regmap_volatile, - .cache_type = REGCACHE_FLAT, + .name = "audio_qaif_cpu", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .cache_type = REGCACHE_NONE, }; static int of_qaif_parse_aif_intf_cfg(struct device *dev, @@ -1255,34 +612,16 @@ static int of_qaif_parse_aif_intf_cfg(struct device *dev, struct device_node *np = dev->of_node; struct device_node *intf_np; struct qaif_aif_config *cfg; - const __be32 *lane_cfg_prop; - int ret, j; - int lane_cfg_len; - u32 dai_id, intf_idx; + int ret; + u32 dai_id; + int intf_idx; int num_interfaces = 0; + u32 val_buf[QAIF_MAX_LANES]; + int j, n; + unsigned long configured_intf_mask = 0; - if (!v) { - dev_err(dev, "No variant data\n"); - return -EINVAL; - } - - /* - * Iterate over all child nodes of qaif_cpu and process only those - * with a recognised AIF interface compatible. The compatible string - * identifies the serial protocol the interface is wired for on the - * board: qcom,qaif-pcm-dai, qcom,qaif-tdm-dai or qcom,qaif-mi2s-dai. - * Other child nodes are silently skipped. - */ for_each_child_of_node(np, intf_np) { - enum qaif_aif_mode mode; - - if (of_device_is_compatible(intf_np, "qcom,qaif-pcm-dai")) - mode = QAIF_AIF_MODE_PCM; - else if (of_device_is_compatible(intf_np, "qcom,qaif-tdm-dai")) - mode = QAIF_AIF_MODE_TDM; - else if (of_device_is_compatible(intf_np, "qcom,qaif-mi2s-dai")) - mode = QAIF_AIF_MODE_MI2S; - else + if (!of_property_present(intf_np, "reg")) continue; if (num_interfaces >= QAIF_MAX_AIF_CFG_CNT) { @@ -1294,319 +633,242 @@ static int of_qaif_parse_aif_intf_cfg(struct device *dev, ret = of_property_read_u32(intf_np, "reg", &dai_id); if (ret) { - dev_err(dev, "Missing reg for interface %d: %s\n", - num_interfaces, intf_np->name); - continue; + dev_err(dev, "Missing reg for interface %pOFn\n", intf_np); + of_node_put(intf_np); + return ret; } - if (v->get_dma_idx) { - intf_idx = v->get_dma_idx(dai_id); - if (intf_idx < 0) { - dev_err(dev, "Invalid DAI ID %d for interface '%s' (node %d)\n", - dai_id, intf_np->name, num_interfaces); - continue; - } - if (intf_idx >= ARRAY_SIZE(data->aif_intf_cfg)) { - dev_err(dev, "DAI ID %d maps to out-of-range intf_idx %d\n", - dai_id, intf_idx); - continue; - } - } else { - dev_err(dev, "can not get intf idx for : %d: %s\n", - num_interfaces, intf_np->name); + intf_idx = v->get_dma_idx(dai_id); + if (intf_idx < 0) { + dev_err(dev, "Invalid DAI ID %d for interface %pOFn\n", + dai_id, intf_np); of_node_put(intf_np); return -EINVAL; } - cfg = &data->aif_intf_cfg[intf_idx]; - cfg->mode = mode; - - /* Parse sync configuration — mode-specific */ - if (mode == QAIF_AIF_MODE_MI2S) { - /* MI2S: sync mode is fixed (long sync = 1, WS-based) */ - cfg->sync_mode = 1; - } else { - /* PCM/TDM: sync mode comes from DT (0=short, 1=long) */ - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-sync-mode", - &cfg->sync_mode); - if (ret) { - dev_err(dev, "Missing sync-mode for interface %d\n", - num_interfaces); - of_node_put(intf_np); - return -EINVAL; - } - } - - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-sync-src", &cfg->sync_src); - if (ret) { - dev_warn(dev, "Missing sync-src for interface %d\n", num_interfaces); - cfg->sync_src = 0; - } - - cfg->invert_sync = of_property_read_bool(intf_np, "qcom,qaif-aif-invert-sync"); - - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-sync-delay", &cfg->sync_delay); - if (ret) { - dev_warn(dev, "Missing sync-delay for interface %d\n", num_interfaces); - cfg->sync_delay = 0; + if (intf_idx >= ARRAY_SIZE(data->aif_intf_cfg)) { + dev_err(dev, "DAI ID %d maps to out-of-range intf_idx %d\n", + dai_id, intf_idx); + of_node_put(intf_np); + return -EINVAL; } - /* Parse slot and sample width configuration */ - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-slot-width-rx", - &cfg->slot_width_rx); - if (ret) { - dev_warn(dev, "Missing slot-width-rx for interface %d\n", num_interfaces); - cfg->slot_width_rx = 0; + if (configured_intf_mask & BIT(intf_idx)) { + dev_err(dev, "Duplicate reg %d for interface %pOFn\n", + dai_id, intf_np); + of_node_put(intf_np); + return -EINVAL; } + configured_intf_mask |= BIT(intf_idx); - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-slot-width-tx", - &cfg->slot_width_tx); - if (ret) { - dev_warn(dev, "Missing slot-width-tx for interface %d\n", num_interfaces); - cfg->slot_width_tx = 0; + cfg = &data->aif_intf_cfg[intf_idx]; + if (v->aif_full_cycle_en) + cfg->full_cycle_en = v->aif_full_cycle_en[intf_idx]; + if (v->aif_ctrl_data_oe) + cfg->ctrl_data_oe = v->aif_ctrl_data_oe[intf_idx]; + if (v->aif_loopback_en) + cfg->loopback_en = v->aif_loopback_en[intf_idx]; + + switch (snd_soc_daifmt_parse_format(intf_np, NULL) & + SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cfg->sync_mode = QAIF_AIF_SYNC_MODE_LONG; + cfg->sync_delay = QAIF_AIF_SYNC_DELAY_ONE; + cfg->invert_sync = true; + break; + case SND_SOC_DAIFMT_DSP_A: + cfg->sync_mode = QAIF_AIF_SYNC_MODE_ONE_SLOT; + cfg->sync_delay = QAIF_AIF_SYNC_DELAY_ONE; + break; + case SND_SOC_DAIFMT_DSP_B: + cfg->sync_mode = QAIF_AIF_SYNC_MODE_SHORT; + cfg->sync_delay = QAIF_AIF_SYNC_DELAY_SAME; + break; + default: + break; } - /* Parse slot enable masks — mode-specific */ - if (mode == QAIF_AIF_MODE_MI2S) { - /* MI2S: always 2 active slots (left + right) */ - cfg->slot_en_rx_mask = 0x3; - cfg->slot_en_tx_mask = 0x3; - } else { - /* PCM/TDM: active slot mask comes from DT */ - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-slot-en-rx-mask", - &cfg->slot_en_rx_mask); - if (ret) { - dev_warn(dev, "Missing slot-en-rx-mask for interface %d\n", - num_interfaces); - cfg->slot_en_rx_mask = 0; - } - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-slot-en-tx-mask", - &cfg->slot_en_tx_mask); - if (ret) { - dev_warn(dev, "Missing slot-en-tx-mask for interface %d\n", - num_interfaces); - cfg->slot_en_tx_mask = 0; + if (!qaif_is_aif_mi2s_port(dai_id)) { + ret = of_property_read_u32(intf_np, "dai-tdm-slot-width", + &cfg->slot_width); + if (ret || !cfg->slot_width) { + dev_err(dev, "Missing/invalid dai-tdm-slot-width for %pOFn\n", + intf_np); + of_node_put(intf_np); + return ret ? ret : -EINVAL; } - } - - /* Parse control configuration */ - cfg->loopback_en = of_property_read_bool(intf_np, "qcom,qaif-aif-loopback"); - - cfg->ctrl_data_oe = of_property_read_bool(intf_np, "qcom,qaif-aif-ctrl-data-oe"); - - /* Parse lane configuration */ - lane_cfg_prop = of_get_property(intf_np, "qcom,qaif-aif-lane-config", - &lane_cfg_len); - if (lane_cfg_prop) { - /* Each lane config has 2 u32 values: enable and direction */ - cfg->num_lanes = lane_cfg_len / (2 * sizeof(u32)); - if (cfg->num_lanes > QAIF_MAX_LANES) { - dev_warn(dev, "Too many lanes (%d), limiting to %d\n", - cfg->num_lanes, QAIF_MAX_LANES); - cfg->num_lanes = QAIF_MAX_LANES; + ret = of_property_read_u32(intf_np, "dai-tdm-slot-num", + &cfg->slot_num); + if (ret || !cfg->slot_num) { + dev_err(dev, "Missing/invalid dai-tdm-slot-num for %pOFn\n", + intf_np); + of_node_put(intf_np); + return ret ? ret : -EINVAL; } - - for (j = 0; j < cfg->num_lanes; j++) { - cfg->lane_cfg[j].enable = be32_to_cpup(lane_cfg_prop + (j * 2)); - if (cfg->lane_cfg[j].enable) - cfg->lane_en_mask |= BIT(j); - - cfg->lane_cfg[j].direction = - be32_to_cpup(lane_cfg_prop + (j * 2 + 1)); - if (cfg->lane_cfg[j].direction) - cfg->lane_dir_mask |= BIT(j); + snd_soc_of_get_slot_mask(intf_np, "dai-tdm-slot-rx-mask", + &cfg->slot_en_rx_mask); + snd_soc_of_get_slot_mask(intf_np, "dai-tdm-slot-tx-mask", + &cfg->slot_en_tx_mask); + if (!cfg->slot_en_rx_mask && !cfg->slot_en_tx_mask) { + dev_err(dev, "No active TDM slots for %pOFn\n", + intf_np); + of_node_put(intf_np); + return -EINVAL; } - - } else { - dev_warn(dev, "Missing lane-config for interface %d\n", num_interfaces); - cfg->num_lanes = 0; } - /* Mono/stereo mode is written directly from params_channels() in hw_params */ - - /* Parse frame configuration */ - cfg->full_cycle_en = of_property_read_bool(intf_np, "qcom,qaif-aif-full-cycle-en"); - - ret = of_property_read_u32(intf_np, "qcom,qaif-aif-bits-per-lane", - &cfg->bits_per_lane); - if (ret) { - dev_warn(dev, "Missing bits-per-lane for interface %d\n", num_interfaces); - cfg->bits_per_lane = 0; + n = of_property_read_variable_u32_array(intf_np, + "qcom,qaif-aif-lane-map", + val_buf, 1, QAIF_MAX_LANES); + if (n < 0) { + dev_err(dev, "Missing qcom,qaif-aif-lane-map for %pOFn\n", + intf_np); + of_node_put(intf_np); + return n; + } + for (j = 0; j < n; j++) { + if (val_buf[j] > 1) { + dev_err(dev, "Invalid lane-map value %u for %pOFn\n", + val_buf[j], intf_np); + of_node_put(intf_np); + return -EINVAL; + } + cfg->lane_en_mask |= BIT(j); + if (val_buf[j]) + cfg->lane_dir_mask |= BIT(j); } num_interfaces++; } - if (num_interfaces == 0) { - dev_err(dev, "No AIF child nodes with qcom,qaif-{pcm,tdm,mi2s}-dai compatible found\n"); - return -EINVAL; - } - - return 0; -} - -static int of_qaif_cdc_dma_clks_parse(struct device *dev, - struct qaif_drv_data *data) -{ - data->aud_dma_clk = devm_clk_get(dev, "aud_dma_clk"); - if (IS_ERR(data->aud_dma_clk)) - return PTR_ERR(data->aud_dma_clk); - - data->aud_dma_mem_clk = devm_clk_get(dev, "aud_dma_mem_clk"); - if (IS_ERR(data->aud_dma_mem_clk)) - return PTR_ERR(data->aud_dma_mem_clk); - return 0; } +/** + * asoc_qcom_qaif_cpu_platform_probe - Probe the QAIF CPU and platform driver + * @pdev: Platform device + * + * Initialises the QAIF regmap, parses DT, sets up clocks and registers + * the CPU DAI component and PCM platform. + * + * Return: 0 on success, negative error code on failure. + */ int asoc_qcom_qaif_cpu_platform_probe(struct platform_device *pdev) { + struct regmap_config regmap_cfg = audio_qaif_regmap_config; struct qaif_drv_data *drvdata; struct resource *res; const struct qaif_variant *variant; struct device *dev = &pdev->dev; const struct of_device_id *match; int ret, i, dai_id, idx; - bool variant_init_done = false; - drvdata = devm_kzalloc(dev, sizeof(struct qaif_drv_data), GFP_KERNEL); + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) - return -ENOMEM; + return dev_err_probe(dev, -ENOMEM, "Failed to allocate driver data\n"); platform_set_drvdata(pdev, drvdata); match = of_match_device(dev->driver->of_match_table, dev); if (!match || !match->data) - return -EINVAL; + return dev_err_probe(dev, -EINVAL, "No matching device data\n"); - drvdata->variant = (const struct qaif_variant *)match->data; + drvdata->variant = match->data; variant = drvdata->variant; - if (!variant) { - dev_err(dev, "No variant data\n"); - return -EINVAL; - } + + if (!variant->get_dma_idx) + return dev_err_probe(dev, -EINVAL, + "variant is missing get_dma_idx callback\n"); ret = of_qaif_parse_aif_intf_cfg(dev, drvdata); - if (ret) { - dev_err(dev, "Failed to parse aif interfaces: %d\n", ret); - return -EINVAL; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to parse aif interfaces\n"); - drvdata->audio_qaif = - devm_platform_ioremap_resource(pdev, 0); + drvdata->audio_qaif = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(drvdata->audio_qaif)) - return PTR_ERR(drvdata->audio_qaif); + return dev_err_probe(dev, PTR_ERR(drvdata->audio_qaif), + "Failed to ioremap QAIF registers\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) - return -EINVAL; - - const struct regmap_config qaif_regmap_cfg = { - .name = audio_qaif_regmap_config.name, - .reg_bits = audio_qaif_regmap_config.reg_bits, - .reg_stride = audio_qaif_regmap_config.reg_stride, - .val_bits = audio_qaif_regmap_config.val_bits, - .writeable_reg = audio_qaif_regmap_config.writeable_reg, - .readable_reg = audio_qaif_regmap_config.readable_reg, - .volatile_reg = audio_qaif_regmap_config.volatile_reg, - .cache_type = audio_qaif_regmap_config.cache_type, - .max_register = resource_size(res), - }; + return dev_err_probe(dev, -EINVAL, "Failed to get MMIO resource\n"); + regmap_cfg.max_register = resource_size(res) - regmap_cfg.reg_stride; drvdata->audio_qaif_map = devm_regmap_init_mmio(dev, drvdata->audio_qaif, - &qaif_regmap_cfg); + ®map_cfg); if (IS_ERR(drvdata->audio_qaif_map)) - return PTR_ERR(drvdata->audio_qaif_map); + return dev_err_probe(dev, PTR_ERR(drvdata->audio_qaif_map), + "Failed to init regmap\n"); - ret = of_qaif_cdc_dma_clks_parse(dev, drvdata); - if (ret) { - dev_err(dev, "failed to get cdc dma clocks %d\n", ret); - return ret; - } + drvdata->aud_dma_clk = devm_clk_get(dev, "aud_dma"); + if (IS_ERR(drvdata->aud_dma_clk)) + return dev_err_probe(dev, PTR_ERR(drvdata->aud_dma_clk), + "Failed to get aud_dma clock\n"); - if (variant->init) { - ret = variant->init(pdev); - if (ret) { - dev_err(dev, "error initializing variant: %d\n", ret); - return ret; - } - variant_init_done = true; - } + drvdata->aud_dma_mem_clk = devm_clk_get(dev, "aud_dma_mem"); + if (IS_ERR(drvdata->aud_dma_mem_clk)) + return dev_err_probe(dev, PTR_ERR(drvdata->aud_dma_mem_clk), + "Failed to get aud_dma_mem clock\n"); for (i = 0; i < variant->num_dai; i++) { dai_id = variant->dai_driver[i].id; - if (is_cif_dma_port(dai_id)) + if (qaif_is_cif_port(dai_id)) continue; idx = variant->get_dma_idx(dai_id); if (idx < 0) continue; - drvdata->mi2s_bit_clk[idx] = devm_clk_get(dev, - variant->dai_bit_clk_names[idx]); - if (IS_ERR(drvdata->mi2s_bit_clk[idx])) { - dev_err(dev, - "error getting %s: %ld\n", - variant->dai_bit_clk_names[idx], - PTR_ERR(drvdata->mi2s_bit_clk[idx])); - ret = PTR_ERR(drvdata->mi2s_bit_clk[idx]); - goto err; - } + drvdata->mi2s_bit_clk[idx] = + devm_clk_get(dev, variant->dai_bit_clk_names[idx]); + if (IS_ERR(drvdata->mi2s_bit_clk[idx])) + return dev_err_probe(dev, PTR_ERR(drvdata->mi2s_bit_clk[idx]), + "Failed to get bit clock %d\n", idx); } - ret = qaif_aif_cpu_init_bitfields(dev, drvdata->audio_qaif_map); - if (ret) { - dev_err(dev, "error init cif bitfield: %d\n", ret); - goto err; - } + drvdata->num_clks = variant->num_clks; + drvdata->clks = devm_kcalloc(dev, drvdata->num_clks, + sizeof(*drvdata->clks), GFP_KERNEL); + if (!drvdata->clks) + return dev_err_probe(dev, -ENOMEM, "Failed to allocate clocks\n"); - ret = qaif_aif_cfg_cpu_init_bitfields(dev, drvdata->audio_qaif_map); - if (ret) { - dev_err(dev, "error init aif_intfctl field: %d\n", ret); - goto err; - } + for (i = 0; i < drvdata->num_clks; i++) + drvdata->clks[i].id = variant->clk_name[i]; - ret = qaif_cif_cpu_init_bitfields(dev, drvdata->audio_qaif_map); - if (ret) { - dev_err(dev, "error init cif bitfield: %d\n", ret); - goto err; - } + ret = devm_clk_bulk_get(dev, drvdata->num_clks, drvdata->clks); + if (ret) + return dev_err_probe(dev, ret, "Failed to get clocks\n"); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); ret = devm_snd_soc_register_component(dev, &qaif_cpu_comp_driver, - variant->dai_driver, - variant->num_dai); - if (ret) { - dev_err(dev, "error registering cpu driver: %d\n", ret); - goto err; - } + variant->dai_driver, variant->num_dai); + if (ret) + return dev_err_probe(dev, ret, "error registering cpu driver\n"); - ret = asoc_qcom_qaif_platform_register(pdev); - if (ret) { - dev_err(dev, "error registering platform driver: %d\n", ret); - goto err; - } - dev_dbg(&pdev->dev, "%s: QAIF CPU-Platform Driver Registered Successfully\n", __func__); -err: - if (ret && variant_init_done && variant->exit) - variant->exit(pdev); - return ret; + return asoc_qcom_qaif_platform_register(pdev); } EXPORT_SYMBOL_GPL(asoc_qcom_qaif_cpu_platform_probe); -void asoc_qcom_qaif_cpu_platform_remove(struct platform_device *pdev) +static int asoc_qcom_qaif_runtime_suspend(struct device *dev) { - struct qaif_drv_data *drvdata = platform_get_drvdata(pdev); + struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - if (drvdata->variant->exit) - drvdata->variant->exit(pdev); + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks); + return 0; } -EXPORT_SYMBOL_GPL(asoc_qcom_qaif_cpu_platform_remove); -void asoc_qcom_qaif_cpu_platform_shutdown(struct platform_device *pdev) +static int asoc_qcom_qaif_runtime_resume(struct device *dev) { - struct qaif_drv_data *drvdata = platform_get_drvdata(pdev); + struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - if (drvdata->variant->exit) - drvdata->variant->exit(pdev); + return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); } -EXPORT_SYMBOL_GPL(asoc_qcom_qaif_cpu_platform_shutdown); + +EXPORT_GPL_DEV_PM_OPS(asoc_qcom_qaif_pm_ops) = { + RUNTIME_PM_OPS(asoc_qcom_qaif_runtime_suspend, + asoc_qcom_qaif_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; MODULE_DESCRIPTION("Qualcomm Audio Interface (QAIF) CPU DAI driver"); MODULE_AUTHOR("Harendra Gautam "); diff --git a/sound/soc/qcom/qaif-platform.c b/sound/soc/qcom/qaif-platform.c index 5b62715d11d28..1da50a834b786 100644 --- a/sound/soc/qcom/qaif-platform.c +++ b/sound/soc/qcom/qaif-platform.c @@ -9,45 +9,36 @@ #include #include #include +#include #include -#include #include +#include #include #include "qaif-reg.h" #include "qaif.h" #define DRV_NAME "qaif-platform" -/* 20 ms period at 48 kHz S16 stereo = 3840 bytes */ -#define QAIF_PLATFORM_BUFFER_MIN_SIZE (960 * 2 * 2) -#define QAIF_PLATFORM_PERIOD_BYTES_MIN (960 * 2 * 2) -#define QAIF_PLATFORM_BUFFER_SIZE (4 * QAIF_PLATFORM_BUFFER_MIN_SIZE) -#define QAIF_PLATFORM_PERIODS_MIN 2 -#define QAIF_PLATFORM_PERIODS_MAX 4 - -static const struct snd_pcm_hardware qaif_platform_aif_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, - .formats = SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_S24 | - SNDRV_PCM_FMTBIT_S32, - .rates = SNDRV_PCM_RATE_8000_192000, - .rate_min = 8000, - .rate_max = 192000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = QAIF_PLATFORM_BUFFER_SIZE, - .period_bytes_min = QAIF_PLATFORM_PERIOD_BYTES_MIN, - .period_bytes_max = QAIF_PLATFORM_BUFFER_SIZE / QAIF_PLATFORM_PERIODS_MIN, - .periods_min = QAIF_PLATFORM_PERIODS_MIN, - .periods_max = QAIF_PLATFORM_PERIODS_MAX, - .fifo_size = 0, -}; - -static const struct snd_pcm_hardware qaif_platform_cif_hardware = { +/* period: 5ms @ 48kHz/1ch/S16 min, 20ms @ 48kHz/8ch/S32 max */ +#define QAIF_PLATFORM_PERIOD_BYTES_MIN (48 * 5 * 1 * 2) /* 480 B */ +#define QAIF_PLATFORM_PERIOD_BYTES_MAX (48 * 20 * 8 * 4) /* 30720 B */ +#define QAIF_PLATFORM_PERIODS_MIN 2 +#define QAIF_PLATFORM_PERIODS_MAX 4 +/* QAIF_PLATFORM_PERIODS_MAX * QAIF_PLATFORM_PERIOD_BYTES_MAX = 122880 B */ +#define QAIF_PLATFORM_BUFFER_BYTES_MAX \ + (QAIF_PLATFORM_PERIODS_MAX * QAIF_PLATFORM_PERIOD_BYTES_MAX) + +/* DMA CFG register bit positions */ +#define QAIF_DMACFG_SHRAM_WM_MASK GENMASK(11, 0) +#define QAIF_DMACFG_BURST4_BIT BIT(18) +#define QAIF_DMACFG_DYNCLK_BIT BIT(24) + +/* DMA CTL register bit positions */ +#define QAIF_DMACTL_ENABLE_BIT BIT(0) +#define QAIF_ALL_CLIENTS_MASK (QAIF_BITMASK_AIF_RDDMA_WRDMA | \ + QAIF_BITMASK_CIF_RDDMA_WRDMA) + +static const struct snd_pcm_hardware qaif_platform_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | @@ -61,148 +52,77 @@ static const struct snd_pcm_hardware qaif_platform_cif_hardware = { .rate_max = 192000, .channels_min = 1, .channels_max = 8, - .buffer_bytes_max = QAIF_PLATFORM_BUFFER_SIZE, + .buffer_bytes_max = QAIF_PLATFORM_BUFFER_BYTES_MAX, .period_bytes_min = QAIF_PLATFORM_PERIOD_BYTES_MIN, - .period_bytes_max = QAIF_PLATFORM_BUFFER_SIZE / QAIF_PLATFORM_PERIODS_MIN, + .period_bytes_max = QAIF_PLATFORM_PERIOD_BYTES_MAX, .periods_min = QAIF_PLATFORM_PERIODS_MIN, .periods_max = QAIF_PLATFORM_PERIODS_MAX, .fifo_size = 0, }; -static struct qaif_dma_mem_info *qaif_mem_alloc_attach(struct snd_soc_component *component, - size_t alloc_size) -{ - struct device *dev = component->dev; - struct qaif_dma_mem_info *dma_mem_info; - - dma_mem_info = kzalloc(sizeof(*dma_mem_info), GFP_KERNEL); - if (!dma_mem_info) - return NULL; - - dma_mem_info->alloc_size = alloc_size; - - dma_mem_info->vaddr = dma_alloc_coherent(dev, alloc_size, - &dma_mem_info->dma_addr, - GFP_KERNEL); - if (!dma_mem_info->vaddr) { - dev_err(dev, "dma_alloc_coherent failed for %zu bytes\n", alloc_size); - kfree(dma_mem_info); - return NULL; - } - - dev_dbg(dev, "%s: dma_addr=%pad vaddr=%p\n", __func__, - &dma_mem_info->dma_addr, - dma_mem_info->vaddr); - return dma_mem_info; -} - -static void qaif_mem_dealloc_detach(struct device *dev, - struct qaif_dma_mem_info *dma_info) -{ - if (!dma_info) - return; - - if (dma_info->vaddr) - dma_free_coherent(dev, dma_info->alloc_size, - dma_info->vaddr, dma_info->dma_addr); - - kfree(dma_info); -} - -static struct qaif_dmactl *qaif_get_dmactl_handle(const struct snd_pcm_substream *substream, - struct snd_soc_component *component) -{ - struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); - struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); - struct qaif_dmactl *dmactl = NULL; - - switch (cpu_dai->driver->id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dmactl = drvdata->aif_rd_dmactl; - else - dmactl = drvdata->aif_wr_dmactl; - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - dmactl = drvdata->cif_rd_dmactl; - break; - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - dmactl = drvdata->cif_wr_dmactl; - break; - } - - return dmactl; -} - static int qaif_map_ee_resource(struct qaif_drv_data *drvdata) { const struct qaif_variant *v = drvdata->variant; struct regmap *map = drvdata->audio_qaif_map; - int ret = 0; - u32 mask; - - mask = GENMASK(v->num_rddma - 1, 0); - ret |= regmap_write(map, QAIF_EE_RDDMA_MAP_REG(v), mask); - - mask = GENMASK(v->num_wrdma - 1, 0); - ret |= regmap_write(map, QAIF_EE_WRDMA_MAP_REG(v), mask); + int ret; + ret = regmap_write(map, QAIF_EE_RDDMA_MAP_REG(v), GENMASK(v->num_rddma - 1, 0)); + if (ret) + return ret; + ret = regmap_write(map, QAIF_EE_WRDMA_MAP_REG(v), GENMASK(v->num_wrdma - 1, 0)); + if (ret) + return ret; if (v->num_intf > 0) { - mask = GENMASK(v->num_intf - 1, 0); - ret |= regmap_write(map, QAIF_EE_INTF_MAP_REG(v), mask); + ret = regmap_write(map, QAIF_EE_INTF_MAP_REG(v), GENMASK(v->num_intf - 1, 0)); + if (ret) + return ret; } - - mask = GENMASK(v->num_codec_rddma - 1, 0); - ret |= regmap_write(map, QAIF_EE_CODEC_RDDMA_MAP_REG(v), mask); - - mask = GENMASK(v->num_codec_wrdma - 1, 0); - ret |= regmap_write(map, QAIF_EE_CODEC_WRDMA_MAP_REG(v), mask); - + ret = regmap_write(map, QAIF_EE_CODEC_RDDMA_MAP_REG(v), + GENMASK(v->num_codec_rddma - 1, 0)); if (ret) return ret; - return 0; + return regmap_write(map, QAIF_EE_CODEC_WRDMA_MAP_REG(v), + GENMASK(v->num_codec_wrdma - 1, 0)); } static int qaif_map_dma_path(struct qaif_drv_data *drvdata) { struct regmap *map = drvdata->audio_qaif_map; - const struct qaif_variant *v = drvdata->variant; - int ret = 0; - int qxm_sel = v->qxm_type; + int ret; - if (qxm_sel != QXM0) { + if (drvdata->variant->qxm_type != QAIF_QXM0) { dev_err(regmap_get_device(map), - "%s: only QXM0 is supported, qxm_type=%d\n", - __func__, qxm_sel); + "only QXM0 is supported, qxm_type=%d\n", + drvdata->variant->qxm_type); return -EINVAL; } - ret |= regmap_write(map, QAIF_RDDMA_MAP_QXM, qxm_sel); - ret |= regmap_write(map, QAIF_WRDMA_MAP_QXM, qxm_sel); - ret |= regmap_write(map, QAIF_CODEC_RDDMA_MAP_QXM, qxm_sel); - ret |= regmap_write(map, QAIF_CODEC_WRDMA_MAP_QXM, qxm_sel); - + ret = regmap_write(map, QAIF_RDDMA_MAP_QXM, QAIF_QXM0); if (ret) return ret; - - return 0; + ret = regmap_write(map, QAIF_WRDMA_MAP_QXM, QAIF_QXM0); + if (ret) + return ret; + ret = regmap_write(map, QAIF_CDC_RDDMA_MAP_QXM, QAIF_QXM0); + if (ret) + return ret; + return regmap_write(map, QAIF_CDC_WRDMA_MAP_QXM, QAIF_QXM0); } static int qaif_config_shram(struct qaif_drv_data *drvdata) { const struct qaif_variant *v = drvdata->variant; - u32 start_addr, shram_len; - int ret = 0, i = 0; struct regmap *map = drvdata->audio_qaif_map; + u32 start_addr, shram_len; + int ret, i; - if (v->qxm_type != QXM0) { + if (v->qxm_type != QAIF_QXM0) { dev_err(regmap_get_device(map), - "%s: only QXM0 is supported, qxm_type=%d\n", - __func__, v->qxm_type); + "only QXM0 is supported, qxm_type=%d\n", + v->qxm_type); return -EINVAL; } + start_addr = v->rddma_shram_start_addr[QAIF_AIF_DMA]; shram_len = v->rddma_shram_len; for (i = 0; i < v->num_rddma; i++) { @@ -214,6 +134,7 @@ static int qaif_config_shram(struct qaif_drv_data *drvdata) if (ret) return ret; } + start_addr = v->wrdma_shram_start_addr[QAIF_AIF_DMA]; shram_len = v->wrdma_shram_len; for (i = 0; i < v->num_wrdma; i++) { @@ -225,26 +146,27 @@ static int qaif_config_shram(struct qaif_drv_data *drvdata) if (ret) return ret; } + start_addr = v->rddma_shram_start_addr[QAIF_CIF_DMA]; shram_len = v->rddma_shram_len; for (i = 0; i < v->num_codec_rddma; i++) { - ret = regmap_write(map, QAIF_CODEC_RDDMA_QXM0_SHRAM_ST_ADDR(i), + ret = regmap_write(map, QAIF_CDC_RDDMA_QXM0_SHRAM_ST_ADDR(i), start_addr + (shram_len * i)); if (ret) return ret; - ret = regmap_write(map, QAIF_CODEC_RDDMA_QXM0_SHRAM_LEN(i), shram_len); + ret = regmap_write(map, QAIF_CDC_RDDMA_QXM0_SHRAM_LEN(i), shram_len); if (ret) return ret; } + start_addr = v->wrdma_shram_start_addr[QAIF_CIF_DMA]; shram_len = v->wrdma_shram_len; for (i = 0; i < v->num_codec_wrdma; i++) { - ret = regmap_write(map, QAIF_CODEC_WRDMA_QXM0_SHRAM_ST_ADDR(i), + ret = regmap_write(map, QAIF_CDC_WRDMA_QXM0_SHRAM_ST_ADDR(i), start_addr + (shram_len * i)); if (ret) return ret; - ret = regmap_write(map, QAIF_CODEC_WRDMA_QXM0_SHRAM_LEN(i), shram_len); - + ret = regmap_write(map, QAIF_CDC_WRDMA_QXM0_SHRAM_LEN(i), shram_len); if (ret) return ret; } @@ -254,35 +176,28 @@ static int qaif_config_shram(struct qaif_drv_data *drvdata) static int qaif_init(struct snd_soc_component *component) { struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); - int ret = 0; + int ret; - if (drvdata->qaif_init_ref_cnt) { - dev_dbg(component->dev, - "%s: QAIF init is done already: ref cnt: %d\n", - __func__, drvdata->qaif_init_ref_cnt); + if (drvdata->qaif_hw_configured) return 0; - } ret = qaif_config_shram(drvdata); if (ret) { - dev_err(component->dev, "QAIF: Failed to config shram: %d\n", ret); + dev_err(component->dev, "failed to config shram: %d\n", ret); return ret; } ret = qaif_map_ee_resource(drvdata); if (ret) { - dev_err(component->dev, "QAIF: Failed to map EE resources: %d\n", ret); + dev_err(component->dev, "failed to map EE resources: %d\n", ret); return ret; } ret = qaif_map_dma_path(drvdata); - if (ret) { - dev_err(component->dev, "QAIF: Failed to map DMA path: %d\n", ret); + if (ret) return ret; - } - dev_dbg(component->dev, - "%s: QAIF init is done ref cnt: %d\n", - __func__, drvdata->qaif_init_ref_cnt); + + drvdata->qaif_hw_configured = true; return 0; } @@ -292,179 +207,147 @@ static int qaif_platform_pcmops_open(struct snd_soc_component *component, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); - struct snd_dma_buffer *buf; struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; - int ret, stream_dma_idx, dir = substream->stream; - struct qaif_pcm_data *data; - struct qaif_dmactl *dmactl; - struct qaif_dma_mem_info *dma_mem_info; - struct regmap *map; unsigned int dai_id = cpu_dai->driver->id; + struct snd_dma_buffer *buf = &substream->dma_buffer; + struct qaif_dma_mem_info *dma_mem_info; + struct qaif_pcm_data *data; + int ret, stream_dma_idx, dma_reg_idx, dir = substream->stream; - if (v->alloc_stream_dma_idx) - stream_dma_idx = v->alloc_stream_dma_idx(drvdata, dir, dai_id); - else - return -EINVAL; + dma_reg_idx = v->get_dma_idx(dai_id); + if (dma_reg_idx < 0) { + dev_err(component->dev, "invalid DMA register index for DAI %u: %d\n", + dai_id, dma_reg_idx); + return dma_reg_idx; + } - if (stream_dma_idx < 0) - return stream_dma_idx; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); + if (!data) return -ENOMEM; - } - - data->stream_dma_idx = stream_dma_idx; - runtime->private_data = data; - map = drvdata->audio_qaif_map; - dmactl = qaif_get_dmactl_handle(substream, component); - if (!dmactl) { - kfree(data); - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); - return -EINVAL; - } - buf = &substream->dma_buffer; + buf->dev.dev = component->dev; buf->private_data = NULL; - buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS; + buf->dev.type = SNDRV_DMA_TYPE_DEV; - dma_mem_info = qaif_mem_alloc_attach(component, - qaif_platform_aif_hardware.buffer_bytes_max); + dma_mem_info = kzalloc(sizeof(*dma_mem_info), GFP_KERNEL); if (!dma_mem_info) { - kfree(data); - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); - return -ENOMEM; - } - - ret = clk_prepare_enable(drvdata->aud_dma_clk); - if (ret) { - dev_err(soc_runtime->dev, "failed to enable aud_dma_clk: %d\n", ret); - qaif_mem_dealloc_detach(component->dev, dma_mem_info); - kfree(data); - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); - return ret; + ret = -ENOMEM; + goto err_free_data; } - ret = clk_prepare_enable(drvdata->aud_dma_mem_clk); - if (ret) { - dev_err(soc_runtime->dev, "failed to enable aud_dma_mem_clk: %d\n", ret); - clk_disable_unprepare(drvdata->aud_dma_clk); - qaif_mem_dealloc_detach(component->dev, dma_mem_info); - kfree(data); - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); - return ret; + dma_mem_info->alloc_size = qaif_platform_hardware.buffer_bytes_max; + dma_mem_info->vaddr = dma_alloc_coherent(component->dev, + dma_mem_info->alloc_size, + &dma_mem_info->dma_addr, + GFP_KERNEL); + if (!dma_mem_info->vaddr) { + ret = -ENOMEM; + goto err_free_mem_info; } - ret = qaif_init(component); - if (ret) { - dev_err(soc_runtime->dev, "qaif_init failed: %d\n", ret); - clk_disable_unprepare(drvdata->aud_dma_mem_clk); - clk_disable_unprepare(drvdata->aud_dma_clk); - qaif_mem_dealloc_detach(component->dev, dma_mem_info); - kfree(data); - return -EINVAL; + mutex_lock(&drvdata->stream_lock); + stream_dma_idx = v->alloc_stream_dma_idx(drvdata, dir, dai_id); + mutex_unlock(&drvdata->stream_lock); + if (stream_dma_idx < 0) { + ret = stream_dma_idx; + goto err_free_dma; } - drvdata->qaif_init_ref_cnt++; - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - drvdata->aif_substream[stream_dma_idx] = substream; - drvdata->aif_dma_heap[stream_dma_idx] = dma_mem_info; - buf->bytes = qaif_platform_aif_hardware.buffer_bytes_max; - buf->addr = drvdata->aif_dma_heap[stream_dma_idx]->dma_addr; - buf->area = (unsigned char *)drvdata->aif_dma_heap[stream_dma_idx]->vaddr; + data->stream_dma_idx = stream_dma_idx; + data->dma_reg_idx = dma_reg_idx; - snd_soc_set_runtime_hwparams(substream, &qaif_platform_aif_hardware); - runtime->dma_bytes = qaif_platform_aif_hardware.buffer_bytes_max; - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - drvdata->cif_substream[stream_dma_idx] = substream; - drvdata->cif_dma_heap[stream_dma_idx] = dma_mem_info; - buf->bytes = qaif_platform_cif_hardware.buffer_bytes_max; - buf->addr = drvdata->cif_dma_heap[stream_dma_idx]->dma_addr; - buf->area = (unsigned char *)drvdata->cif_dma_heap[stream_dma_idx]->vaddr; + buf->bytes = qaif_platform_hardware.buffer_bytes_max; + buf->addr = dma_mem_info->dma_addr; + buf->area = (unsigned char *)dma_mem_info->vaddr; - snd_soc_set_runtime_hwparams(substream, &qaif_platform_cif_hardware); - runtime->dma_bytes = qaif_platform_cif_hardware.buffer_bytes_max; - break; - default: - break; + if (qaif_is_cif_port(dai_id)) { + WRITE_ONCE(drvdata->cif_substream[stream_dma_idx], substream); + drvdata->cif_dma_heap[stream_dma_idx] = dma_mem_info; + } else { + WRITE_ONCE(drvdata->aif_substream[stream_dma_idx], substream); + drvdata->aif_dma_heap[stream_dma_idx] = dma_mem_info; } - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + snd_soc_set_runtime_hwparams(substream, &qaif_platform_hardware); + runtime->dma_bytes = qaif_platform_hardware.buffer_bytes_max; + snd_pcm_set_runtime_buffer(substream, buf); + + /* + * The DMA buffer/period length registers are programmed in 64-bit + * (8-byte) words, so constrain buffer and period sizes to that step + * to keep the ALSA and hardware sizes identical. + */ + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + BIT(QAIF_DMA_BYTES_TO_WORDS_SHIFT)); + if (ret >= 0) + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + BIT(QAIF_DMA_BYTES_TO_WORDS_SHIFT)); + if (ret >= 0) + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) { dev_err(soc_runtime->dev, "setting constraints failed: %d\n", ret); - if (is_cif_dma_port(dai_id)) { - drvdata->cif_substream[stream_dma_idx] = NULL; + if (qaif_is_cif_port(dai_id)) { + WRITE_ONCE(drvdata->cif_substream[stream_dma_idx], NULL); drvdata->cif_dma_heap[stream_dma_idx] = NULL; } else { - drvdata->aif_substream[stream_dma_idx] = NULL; + WRITE_ONCE(drvdata->aif_substream[stream_dma_idx], NULL); drvdata->aif_dma_heap[stream_dma_idx] = NULL; } - drvdata->qaif_init_ref_cnt--; - clk_disable_unprepare(drvdata->aud_dma_mem_clk); - clk_disable_unprepare(drvdata->aud_dma_clk); - qaif_mem_dealloc_detach(component->dev, dma_mem_info); - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); - kfree(data); - return ret; + mutex_lock(&drvdata->stream_lock); + v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id); + mutex_unlock(&drvdata->stream_lock); + goto err_free_dma; } - return 0; + +err_free_dma: + dma_free_coherent(component->dev, dma_mem_info->alloc_size, + dma_mem_info->vaddr, dma_mem_info->dma_addr); +err_free_mem_info: + kfree(dma_mem_info); +err_free_data: + kfree(data); + return ret; } static int qaif_platform_pcmops_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; - struct qaif_pcm_data *data; + struct qaif_pcm_data *data = substream->runtime->private_data; + struct qaif_dma_mem_info *dma_mem_info; unsigned int dai_id = cpu_dai->driver->id; - data = runtime->private_data; - - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - drvdata->aif_substream[data->stream_dma_idx] = NULL; - qaif_mem_dealloc_detach(component->dev, - drvdata->aif_dma_heap[data->stream_dma_idx]); - drvdata->aif_dma_heap[data->stream_dma_idx] = NULL; - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - drvdata->cif_substream[data->stream_dma_idx] = NULL; - qaif_mem_dealloc_detach(component->dev, - drvdata->cif_dma_heap[data->stream_dma_idx]); + if (qaif_is_cif_port(dai_id)) { + WRITE_ONCE(drvdata->cif_substream[data->stream_dma_idx], NULL); + dma_mem_info = drvdata->cif_dma_heap[data->stream_dma_idx]; drvdata->cif_dma_heap[data->stream_dma_idx] = NULL; - break; - default: - break; + } else { + WRITE_ONCE(drvdata->aif_substream[data->stream_dma_idx], NULL); + dma_mem_info = drvdata->aif_dma_heap[data->stream_dma_idx]; + drvdata->aif_dma_heap[data->stream_dma_idx] = NULL; } - if (drvdata->qaif_init_ref_cnt > 0) - drvdata->qaif_init_ref_cnt--; - else - dev_dbg(component->dev, "%s: QAIF init ref cnt: %d, skipping decrement\n", - __func__, drvdata->qaif_init_ref_cnt); + mutex_lock(&drvdata->stream_lock); + v->free_stream_dma_idx(drvdata, data->stream_dma_idx, dai_id); + mutex_unlock(&drvdata->stream_lock); + + if (dma_mem_info) { + dma_free_coherent(component->dev, dma_mem_info->alloc_size, + dma_mem_info->vaddr, dma_mem_info->dma_addr); + kfree(dma_mem_info); + } + + snd_pcm_set_runtime_buffer(substream, NULL); + substream->runtime->private_data = NULL; - if (v->free_stream_dma_idx) - v->free_stream_dma_idx(drvdata, data->stream_dma_idx, dai_id); - clk_disable_unprepare(drvdata->aud_dma_clk); - clk_disable_unprepare(drvdata->aud_dma_mem_clk); kfree(data); return 0; } @@ -477,34 +360,26 @@ static int qaif_platform_pcmops_hw_params(struct snd_soc_component *component, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; - struct qaif_dmactl *dmactl; + struct qaif_pcm_data *data = substream->runtime->private_data; unsigned int dai_id = cpu_dai->driver->id; - int idx; + int idx = data->dma_reg_idx; int ret; - dmactl = qaif_get_dmactl_handle(substream, component); - if (!dmactl) - return -EINVAL; - idx = v->get_dma_idx(dai_id); - - if (idx < 0) { - dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx); - return -EINVAL; - } - - ret = regmap_fields_write(dmactl->burst4, idx, QAIF_DMACTL_BURSTEN); - if (ret) { - dev_err(soc_runtime->dev, "error updating burst4 field: %d\n", ret); - return ret; - } - - ret = regmap_fields_write(dmactl->shram_wm, idx, QAIF_DMACTL_WM_5); + mutex_lock(&drvdata->stream_lock); + ret = qaif_init(component); + mutex_unlock(&drvdata->stream_lock); if (ret) { - dev_err(soc_runtime->dev, "error updating shram_wm field: %d\n", ret); + dev_err(soc_runtime->dev, "qaif_init failed: %d\n", ret); return ret; } - return 0; + ret = regmap_update_bits(drvdata->audio_qaif_map, + qaif_dmacfg_reg(v, idx, substream->stream, dai_id), + QAIF_DMACFG_BURST4_BIT | QAIF_DMACFG_SHRAM_WM_MASK, + QAIF_DMACFG_BURST4_BIT | QAIF_DMACTL_WM_5); + if (ret) + dev_err(soc_runtime->dev, "error updating DMA CFG: %d\n", ret); + return ret; } static int qaif_platform_pcmops_hw_free(struct snd_soc_component *component, @@ -514,31 +389,23 @@ static int qaif_platform_pcmops_hw_free(struct snd_soc_component *component, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; - unsigned int reg; - int ret, idx; + struct qaif_pcm_data *data = substream->runtime->private_data; unsigned int dai_id = cpu_dai->driver->id; - struct regmap *map = drvdata->audio_qaif_map; - struct qaif_dmactl *dmactl; - - dmactl = qaif_get_dmactl_handle(substream, component); - if (!dmactl) - return -EINVAL; - idx = v->get_dma_idx(dai_id); + int idx = data->dma_reg_idx; + int ret; - if (idx < 0) { - dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx); - return -EINVAL; + ret = regmap_update_bits(drvdata->audio_qaif_map, + qaif_dmactl_reg(v, idx, substream->stream, dai_id), + QAIF_DMACTL_ENABLE_BIT, 0); + if (ret) { + dev_err(soc_runtime->dev, "error disabling DMA: %d\n", ret); + return ret; } - ret = regmap_fields_write(dmactl->enable, idx, QAIF_DMACTL_ENABLE_OFF); - if (ret) - dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret); - - reg = QAIF_DMACFG_REG(v, idx, substream->stream, dai_id); - ret = regmap_write(map, reg, 0); + ret = regmap_write(drvdata->audio_qaif_map, + qaif_dmacfg_reg(v, idx, substream->stream, dai_id), 0); if (ret) - dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret); - + dev_err(soc_runtime->dev, "error clearing DMA CFG: %d\n", ret); return ret; } @@ -550,155 +417,168 @@ static int qaif_platform_pcmops_prepare(struct snd_soc_component *component, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; - struct qaif_dmactl *dmactl; - struct regmap *map; - int bitwidth = QAIF_DMA_DEFAULT_BIT_WIDTH; - unsigned int channels = runtime->channels; - unsigned int rate = runtime->rate; - int ret, idx, dir = substream->stream; + struct regmap *map = drvdata->audio_qaif_map; + struct qaif_pcm_data *data = runtime->private_data; unsigned int dai_id = cpu_dai->driver->id; + int idx = data->dma_reg_idx; + int ret, dir = substream->stream; - dmactl = qaif_get_dmactl_handle(substream, component); - if (!dmactl) - return -EINVAL; - idx = v->get_dma_idx(dai_id); - map = drvdata->audio_qaif_map; - - if (idx < 0) { - dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx); - return -EINVAL; + ret = clk_set_rate(drvdata->aud_dma_clk, QAIF_DMA_CLOCK_FREQ); + if (ret) { + dev_err(soc_runtime->dev, "error setting aud_dma_clk rate: %d\n", ret); + return ret; } - - clk_set_rate(drvdata->aud_dma_clk, - rate * bitwidth * channels * QAIF_DMA_CLK_RATE_MULTIPLIER); - clk_set_rate(drvdata->aud_dma_mem_clk, - rate * bitwidth * channels * QAIF_DMA_CLK_RATE_MULTIPLIER); - - ret = regmap_write(map, QAIF_SID_MAP_REG(dir, dai_id), - drvdata->smmu_csid_bits); + ret = clk_set_rate(drvdata->aud_dma_mem_clk, QAIF_DMA_CLOCK_FREQ); if (ret) { - dev_err(soc_runtime->dev, "error writing to SID MAP reg: %d\n", - ret); + dev_err(soc_runtime->dev, "error setting aud_dma_mem_clk rate: %d\n", ret); return ret; } - ret = regmap_write(map, QAIF_DMABASE_REG(v, idx, dir, dai_id), - runtime->dma_addr); + ret = regmap_write(map, qaif_sid_map_reg(dir, dai_id), drvdata->smmu_csid_bits); if (ret) { - dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n", - ret); + dev_err(soc_runtime->dev, "error writing to SID MAP reg: %d\n", ret); return ret; } - ret = regmap_write(map, QAIF_DMABUFF_REG(v, idx, dir, dai_id), - (snd_pcm_lib_buffer_bytes(substream) >> - QAIF_DMA_BYTES_TO_WORDS_SHIFT) - 1); + ret = regmap_write(map, qaif_dmabase_reg(v, idx, dir, dai_id), + lower_32_bits(runtime->dma_addr)); if (ret) { - dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n", - ret); + dev_err(soc_runtime->dev, "error writing to dma base reg: %d\n", ret); return ret; } - ret = regmap_write(map, QAIF_DMAPER_LEN_REG(v, idx, dir, dai_id), - (snd_pcm_lib_period_bytes(substream) >> - QAIF_DMA_BYTES_TO_WORDS_SHIFT) - 1); + ret = regmap_write(map, qaif_dmabuff_reg(v, idx, dir, dai_id), + (snd_pcm_lib_buffer_bytes(substream) >> + QAIF_DMA_BYTES_TO_WORDS_SHIFT) - 1); if (ret) { - dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n", - ret); + dev_err(soc_runtime->dev, "error writing to dma buf reg: %d\n", ret); return ret; } - return 0; + ret = regmap_write(map, qaif_dmaper_len_reg(v, idx, dir, dai_id), + (snd_pcm_lib_period_bytes(substream) >> + QAIF_DMA_BYTES_TO_WORDS_SHIFT) - 1); + if (ret) + dev_err(soc_runtime->dev, "error writing to dma period reg: %d\n", ret); + return ret; } -static int qaif_platform_irq_clear(struct qaif_drv_data *drvdata, - int dir, enum qaif_irq_type irq_type, int idx) +static snd_pcm_uframes_t qaif_platform_pcmops_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - int ret = 0; + struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; struct regmap *map = drvdata->audio_qaif_map; - unsigned int val_irqclr = BIT(idx); + struct qaif_pcm_data *data = substream->runtime->private_data; + unsigned int dai_id = cpu_dai->driver->id; + unsigned int base_addr, curr_addr; + int idx = data->dma_reg_idx; + int ret, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - ret |= regmap_write(map, - QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, irq_type), val_irqclr); - ret |= regmap_write(map, - QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, irq_type), val_irqclr); - ret |= regmap_write(map, - QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, irq_type), val_irqclr); - } else { - ret |= regmap_write(map, - QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, irq_type), val_irqclr); - ret |= regmap_write(map, - QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, irq_type), val_irqclr); - ret |= regmap_write(map, - QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, irq_type), val_irqclr); + ret = regmap_read(map, qaif_dmabase_reg(v, idx, dir, dai_id), &base_addr); + if (ret) { + dev_err(soc_runtime->dev, "error reading from rdmabase reg: %d\n", ret); + return SNDRV_PCM_POS_XRUN; } - return ret; + + ret = regmap_read(map, qaif_dmacurr_reg(v, idx, dir, dai_id), &curr_addr); + if (ret) { + dev_err(soc_runtime->dev, "error reading from rdmacurr reg: %d\n", ret); + return SNDRV_PCM_POS_XRUN; + } + + return bytes_to_frames(substream->runtime, + (curr_addr - base_addr) % + snd_pcm_lib_buffer_bytes(substream)); } -static int qaif_platform_irq_enable(struct qaif_drv_data *drvdata, - int dir, enum qaif_irq_type irq_type, int idx) +static int qaif_platform_pcmops_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { - int ret = 0; - const struct qaif_variant *v = drvdata->variant; - struct regmap *map = drvdata->audio_qaif_map; - unsigned int val_irqen = BIT(idx); + struct snd_pcm_runtime *runtime = substream->runtime; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - ret |= regmap_write_bits(map, - QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, irq_type), - val_irqen, val_irqen); - ret |= regmap_write_bits(map, - QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, irq_type), - val_irqen, val_irqen); - ret |= regmap_write_bits(map, - QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, irq_type), - val_irqen, val_irqen); - } else { - ret |= regmap_write_bits(map, - QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, irq_type), - val_irqen, val_irqen); - ret |= regmap_write_bits(map, - QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, irq_type), - val_irqen, val_irqen); - ret |= regmap_write_bits(map, - QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, irq_type), - val_irqen, val_irqen); - } - return ret; + return dma_mmap_coherent(component->dev, vma, + runtime->dma_area, runtime->dma_addr, + runtime->dma_bytes); +} + +static int qaif_platform_copy(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int channel, unsigned long pos, + struct iov_iter *buf, unsigned long bytes) +{ + struct snd_pcm_runtime *rt = substream->runtime; + size_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + size_t channel_bytes = buffer_bytes / rt->channels; + unsigned long offset; + void *dma_buf; + size_t copied; + + if (channel < 0 || channel >= rt->channels) + return -EINVAL; + + /* Absolute byte offset into the configured (not the max) buffer. */ + offset = pos + channel * channel_bytes; + if (offset > buffer_bytes || bytes > buffer_bytes - offset) + return -EINVAL; + + dma_buf = rt->dma_area + offset; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + copied = copy_from_iter(dma_buf, bytes, buf); + else + copied = copy_to_iter(dma_buf, bytes, buf); + + return (copied != bytes) ? -EFAULT : 0; } -static int qaif_platform_irq_disable(struct qaif_drv_data *drvdata, - int dir, enum qaif_irq_type irq_type, int idx) +static int qaif_platform_irq_op(struct qaif_drv_data *drvdata, int dir, + enum qaif_irq_type irq_type, int idx, + enum qaif_irq_op op) { - int ret = 0; const struct qaif_variant *v = drvdata->variant; struct regmap *map = drvdata->audio_qaif_map; - unsigned int val_irq_disable = BIT(idx); + unsigned int bit = BIT(idx); + unsigned int val = op == QAIF_IRQ_ENABLE ? bit : 0; + u32 per_reg, err_reg, xrun_reg; + int ret; if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - ret |= regmap_write_bits(map, - QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, irq_type), - val_irq_disable, 0); - ret |= regmap_write_bits(map, - QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, irq_type), - val_irq_disable, 0); - ret |= regmap_write_bits(map, - QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, irq_type), - val_irq_disable, 0); + per_reg = op == QAIF_IRQ_CLEAR ? QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, irq_type) + : QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, irq_type); + xrun_reg = op == QAIF_IRQ_CLEAR ? QAIF_EE_RDDMA_UF_IRQ_CLR_REG(v, irq_type) + : QAIF_EE_RDDMA_UF_IRQ_EN_REG(v, irq_type); + err_reg = op == QAIF_IRQ_CLEAR ? QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, irq_type) + : QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, irq_type); } else { - ret |= regmap_write_bits(map, - QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, irq_type), - val_irq_disable, 0); - ret |= regmap_write_bits(map, - QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, irq_type), - val_irq_disable, 0); - ret |= regmap_write_bits(map, - QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, irq_type), - val_irq_disable, 0); + per_reg = op == QAIF_IRQ_CLEAR ? QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, irq_type) + : QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, irq_type); + xrun_reg = op == QAIF_IRQ_CLEAR ? QAIF_EE_WRDMA_OF_IRQ_CLR_REG(v, irq_type) + : QAIF_EE_WRDMA_OF_IRQ_EN_REG(v, irq_type); + err_reg = op == QAIF_IRQ_CLEAR ? QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, irq_type) + : QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, irq_type); } - return ret; + + if (op == QAIF_IRQ_CLEAR) { + ret = regmap_write(map, per_reg, bit); + if (ret) + return ret; + ret = regmap_write(map, xrun_reg, bit); + if (ret) + return ret; + return regmap_write(map, err_reg, bit); + } + + ret = regmap_write_bits(map, per_reg, bit, val); + if (ret) + return ret; + ret = regmap_write_bits(map, xrun_reg, bit, val); + if (ret) + return ret; + return regmap_write_bits(map, err_reg, bit, val); } static int qaif_platform_pcmops_trigger(struct snd_soc_component *component, @@ -709,349 +589,243 @@ static int qaif_platform_pcmops_trigger(struct snd_soc_component *component, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); const struct qaif_variant *v = drvdata->variant; - struct qaif_dmactl *dmactl; - struct regmap *map; - int ret, idx; + struct qaif_pcm_data *data = substream->runtime->private_data; unsigned int dai_id = cpu_dai->driver->id; - - dmactl = qaif_get_dmactl_handle(substream, component); - if (!dmactl) - return -EINVAL; - idx = v->get_dma_idx(dai_id); - map = drvdata->audio_qaif_map; - - if (idx < 0) { - dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx); - return -EINVAL; - } + enum qaif_irq_type irq_type = qaif_is_cif_port(dai_id) ? QAIF_CIF_IRQ : QAIF_AIF_IRQ; + struct regmap *map = drvdata->audio_qaif_map; + int idx = data->dma_reg_idx; + int ret; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = regmap_fields_write(dmactl->dma_dyncclk, idx, QAIF_DMACTL_DYNCLK_ON); + ret = qaif_platform_irq_op(drvdata, substream->stream, irq_type, + idx, QAIF_IRQ_CLEAR); if (ret) { - dev_err(soc_runtime->dev, - "error writing to dma_dyncclk reg field: %d\n", ret); + dev_err(soc_runtime->dev, "error clearing irq regs: %d\n", ret); return ret; } - ret = regmap_fields_write(dmactl->enable, idx, QAIF_DMACTL_ENABLE_ON); + ret = regmap_update_bits(map, + qaif_dmacfg_reg(v, idx, substream->stream, dai_id), + QAIF_DMACFG_DYNCLK_BIT, QAIF_DMACFG_DYNCLK_BIT); if (ret) { - dev_err(soc_runtime->dev, - "error writing to dma enable reg: %d\n", ret); + dev_err(soc_runtime->dev, "error enabling dma_dynclk: %d\n", ret); return ret; } - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - ret = qaif_platform_irq_clear(drvdata, - substream->stream, QAIF_AIF_IRQ, idx); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to clear irq reg: %d\n", ret); - return ret; - } - ret = qaif_platform_irq_enable(drvdata, - substream->stream, QAIF_AIF_IRQ, idx); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to enable irq reg: %d\n", ret); - return ret; - } - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - ret = qaif_platform_irq_clear(drvdata, - substream->stream, QAIF_CIF_IRQ, idx); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to clear irq reg: %d\n", ret); - return ret; - } - ret = qaif_platform_irq_enable(drvdata, - substream->stream, QAIF_CIF_IRQ, idx); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to enable irq reg: %d\n", ret); - return ret; - } - break; - default: - dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); - return -EINVAL; + ret = regmap_update_bits(map, + qaif_dmactl_reg(v, idx, substream->stream, dai_id), + QAIF_DMACTL_ENABLE_BIT, QAIF_DMACTL_ENABLE_BIT); + if (ret) { + dev_err(soc_runtime->dev, "error enabling DMA: %d\n", ret); + return ret; } + ret = qaif_platform_irq_op(drvdata, substream->stream, irq_type, + idx, QAIF_IRQ_ENABLE); + if (ret) + dev_err(soc_runtime->dev, "error enabling irq regs: %d\n", ret); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = regmap_fields_write(dmactl->dma_dyncclk, idx, QAIF_DMACTL_DYNCLK_OFF); + ret = regmap_update_bits(map, + qaif_dmactl_reg(v, idx, substream->stream, dai_id), + QAIF_DMACTL_ENABLE_BIT, 0); if (ret) { - dev_err(soc_runtime->dev, - "error writing to dma_dyncclk reg field: %d\n", ret); + dev_err(soc_runtime->dev, "error disabling DMA: %d\n", ret); return ret; } - ret = regmap_fields_write(dmactl->enable, idx, QAIF_DMACTL_ENABLE_OFF); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to dma enable reg: %d\n", ret); - return ret; - } - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - ret = qaif_platform_irq_disable(drvdata, - substream->stream, QAIF_AIF_IRQ, idx); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to enable irq reg: %d\n", ret); - return ret; - } - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - ret = qaif_platform_irq_disable(drvdata, - substream->stream, QAIF_CIF_IRQ, idx); - if (ret) { - dev_err(soc_runtime->dev, - "error writing to enable irq reg: %d\n", ret); - return ret; - } - break; - default: - dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id); - return -EINVAL; - } + ret = regmap_update_bits(map, + qaif_dmacfg_reg(v, idx, substream->stream, dai_id), + QAIF_DMACFG_DYNCLK_BIT, 0); + if (ret) + dev_err(soc_runtime->dev, "error disabling dma_dynclk: %d\n", ret); + ret = qaif_platform_irq_op(drvdata, substream->stream, irq_type, + idx, QAIF_IRQ_DISABLE); + if (ret) + dev_err(soc_runtime->dev, "error disabling irq regs: %d\n", ret); break; default: return -EINVAL; } - return 0; + return ret; } -static snd_pcm_uframes_t qaif_platform_pcmops_pointer(struct snd_soc_component *component, - struct snd_pcm_substream *substream) +static int qaif_platform_pcmops_sync_stop(struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); - const struct qaif_variant *v = drvdata->variant; - unsigned int base_addr, curr_addr; - int ret, idx, dir = substream->stream; - struct regmap *map; - unsigned int dai_id = cpu_dai->driver->id; - - map = drvdata->audio_qaif_map; - idx = v->get_dma_idx(dai_id); - - if (idx < 0) { - dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx); - return -EINVAL; - } - - ret = regmap_read(map, QAIF_DMABASE_REG(v, idx, dir, dai_id), &base_addr); - if (ret) { - dev_err(soc_runtime->dev, - "error reading from rdmabase reg: %d\n", ret); - return ret; - } - - ret = regmap_read(map, QAIF_DMACURR_REG(v, idx, dir, dai_id), &curr_addr); - if (ret) { - dev_err(soc_runtime->dev, - "error reading from rdmacurr reg: %d\n", ret); - return ret; - } - - return bytes_to_frames(substream->runtime, curr_addr - base_addr); -} - -static int qaif_platform_cdc_dma_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_coherent(substream->pcm->card->dev, vma, - runtime->dma_area, runtime->dma_addr, - runtime->dma_bytes); -} - -static int qaif_platform_pcmops_mmap(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + struct qaif_pcm_data *data = substream->runtime->private_data; unsigned int dai_id = cpu_dai->driver->id; + enum qaif_irq_type irq_type = qaif_is_cif_port(dai_id) ? QAIF_CIF_IRQ : QAIF_AIF_IRQ; + int idx = data->dma_reg_idx; + int ret; - if (is_cif_dma_port(dai_id)) - return qaif_platform_cdc_dma_mmap(substream, vma); - - return snd_pcm_lib_default_mmap(substream, vma); + synchronize_irq(drvdata->audio_qaif_irq); + ret = qaif_platform_irq_op(drvdata, substream->stream, irq_type, + idx, QAIF_IRQ_CLEAR); + if (ret) + dev_err(soc_runtime->dev, "error clearing irq regs: %d\n", ret); + return ret; } static irqreturn_t qaif_process_dma_irq(struct qaif_drv_data *drvdata, u32 stat_reg_addr, u32 clr_reg_addr, enum qaif_irq_type irq_type, - enum dma_type dma_type, + enum qaif_dma_dir dma_type, enum qaif_irq irq, struct snd_pcm_substream **substream) { const struct qaif_variant *v = drvdata->variant; - struct snd_pcm_substream *stream = NULL; unsigned int reg = 0; - int dma_idx, stream_dma_idx, rv, num_dma = 0; - int stream_offset; - irqreturn_t ret = IRQ_NONE; - u32 mask = 0; - - if (dma_type == DMA_TYPE_WRDMA) - stream_offset = (irq_type == QAIF_AIF_IRQ) ? v->wrdma_start - : v->codec_wrdma_start; - else - stream_offset = 0; + int dma_idx, stream_dma_idx, rv, num_dma, stream_offset, array_size; + u32 mask; + struct snd_pcm_substream *ss; + + stream_offset = (dma_type == QAIF_DMA_WRDMA) ? + ((irq_type == QAIF_AIF_IRQ) ? v->wrdma_start : v->codec_wrdma_start) : 0; + num_dma = (dma_type == QAIF_DMA_WRDMA) ? + ((irq_type == QAIF_AIF_IRQ) ? v->num_wrdma : v->num_codec_wrdma) : + ((irq_type == QAIF_AIF_IRQ) ? v->num_rddma : v->num_codec_rddma); + if (!num_dma) + return IRQ_NONE; - if (dma_type == DMA_TYPE_WRDMA) - num_dma = (irq_type == QAIF_AIF_IRQ) ? v->num_wrdma : v->num_codec_wrdma; - else - num_dma = (irq_type == QAIF_AIF_IRQ) ? v->num_rddma : v->num_codec_rddma; + array_size = (irq_type == QAIF_AIF_IRQ) ? + QAIF_MAX_AIF_DMA_IDX : QAIF_MAX_CIF_DMA_IDX; + if (stream_offset + num_dma > array_size) { + dev_err(regmap_get_device(drvdata->audio_qaif_map), + "DMA index range %d+%d exceeds substream table %d\n", + stream_offset, num_dma, array_size); + return IRQ_NONE; + } mask = GENMASK(num_dma - 1, 0); + rv = regmap_read(drvdata->audio_qaif_map, stat_reg_addr, ®); if (rv) { - dev_err(regmap_get_device(drvdata->audio_qaif_map), - "error reading stat reg 0x%x: %d\n", stat_reg_addr, rv); + dev_err_ratelimited(regmap_get_device(drvdata->audio_qaif_map), + "error reading stat reg 0x%x: %d\n", stat_reg_addr, rv); return IRQ_NONE; } - regmap_write(drvdata->audio_qaif_map, clr_reg_addr, reg & mask); + if (!(reg & mask)) { + dev_warn_ratelimited(regmap_get_device(drvdata->audio_qaif_map), + "spurious IRQ: stat reg 0x%x status 0x%x mask 0x%x\n", + stat_reg_addr, reg, mask); + return IRQ_NONE; + } + + if (regmap_write(drvdata->audio_qaif_map, clr_reg_addr, reg & mask)) + return IRQ_NONE; for (dma_idx = 0; dma_idx < num_dma; dma_idx++) { stream_dma_idx = dma_idx + stream_offset; - if ((reg & BIT(dma_idx)) && substream[stream_dma_idx]) { - stream = substream[stream_dma_idx]; - switch (irq) { - case QAIF_IRQ_PERIOD: - snd_pcm_period_elapsed(stream); - ret = IRQ_HANDLED; - break; - - case QAIF_IRQ_OVERFLOW: - case QAIF_IRQ_UNDERFLOW: - dev_warn_ratelimited(regmap_get_device(drvdata->audio_qaif_map), - "QAIF DMA xRun\n"); - ret = IRQ_HANDLED; - break; - - case QAIF_IRQ_ERROR: - snd_pcm_stop(stream, SNDRV_PCM_STATE_DISCONNECTED); - dev_err(regmap_get_device(drvdata->audio_qaif_map), - "QAIF bus error\n"); - ret = IRQ_HANDLED; - break; - } + ss = READ_ONCE(substream[stream_dma_idx]); + if (!(reg & BIT(dma_idx)) || !ss) + continue; + switch (irq) { + case QAIF_IRQ_PERIOD: + snd_pcm_period_elapsed(ss); + break; + case QAIF_IRQ_OVERFLOW: + case QAIF_IRQ_UNDERFLOW: + dev_warn_ratelimited(regmap_get_device(drvdata->audio_qaif_map), + "QAIF DMA xRun\n"); + snd_pcm_stop_xrun(ss); + break; + case QAIF_IRQ_ERROR: + snd_pcm_stop_xrun(ss); + dev_err_ratelimited(regmap_get_device(drvdata->audio_qaif_map), + "QAIF bus error\n"); + break; } } - return ret; + return IRQ_HANDLED; } -static irqreturn_t qaif_aif_irq_handler(struct qaif_drv_data *drvdata, u32 summary_irq_status) +static irqreturn_t qaif_aif_irq_handler(struct qaif_drv_data *drvdata, u32 status) { const struct qaif_variant *v = drvdata->variant; + struct snd_pcm_substream **ss = drvdata->aif_substream; irqreturn_t ret = IRQ_NONE; - struct snd_pcm_substream **substream = drvdata->aif_substream; - if (summary_irq_status & QAIF_SUMMARY_BITMASK_AIF_PERIOD_RDDMA) { + if (status & QAIF_SUMMARY_BITMASK_AIF_PERIOD_RDDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, QAIF_AIF_IRQ), - QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, QAIF_AIF_IRQ), - QAIF_AIF_IRQ, DMA_TYPE_RDDMA, QAIF_IRQ_PERIOD, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_AIF_PERIOD_WRDMA) { + QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, QAIF_AIF_IRQ), + QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, QAIF_AIF_IRQ), + QAIF_AIF_IRQ, QAIF_DMA_RDDMA, QAIF_IRQ_PERIOD, ss); + if (status & QAIF_SUMMARY_BITMASK_AIF_PERIOD_WRDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, QAIF_AIF_IRQ), - QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, QAIF_AIF_IRQ), - QAIF_AIF_IRQ, DMA_TYPE_WRDMA, QAIF_IRQ_PERIOD, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_AIF_OVERFLOW_WRDMA) { + QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, QAIF_AIF_IRQ), + QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, QAIF_AIF_IRQ), + QAIF_AIF_IRQ, QAIF_DMA_WRDMA, QAIF_IRQ_PERIOD, ss); + if (status & QAIF_SUMMARY_BITMASK_AIF_OVERFLOW_WRDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_WRDMA_OVERFLOW_IRQ_STAT_REG(v, QAIF_AIF_IRQ), - QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, QAIF_AIF_IRQ), - QAIF_AIF_IRQ, DMA_TYPE_WRDMA, QAIF_IRQ_OVERFLOW, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_AIF_UNDERFLOW_RDDMA) { + QAIF_EE_WRDMA_OF_IRQ_STAT_REG(v, QAIF_AIF_IRQ), + QAIF_EE_WRDMA_OF_IRQ_CLR_REG(v, QAIF_AIF_IRQ), + QAIF_AIF_IRQ, QAIF_DMA_WRDMA, QAIF_IRQ_OVERFLOW, ss); + if (status & QAIF_SUMMARY_BITMASK_AIF_UNDERFLOW_RDDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_RDDMA_UNDERFLOW_IRQ_STAT_REG(v, QAIF_AIF_IRQ), - QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, QAIF_AIF_IRQ), - QAIF_AIF_IRQ, DMA_TYPE_RDDMA, QAIF_IRQ_UNDERFLOW, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_AIF_ERR_RSP_RDDMA) { + QAIF_EE_RDDMA_UF_IRQ_STAT_REG(v, QAIF_AIF_IRQ), + QAIF_EE_RDDMA_UF_IRQ_CLR_REG(v, QAIF_AIF_IRQ), + QAIF_AIF_IRQ, QAIF_DMA_RDDMA, QAIF_IRQ_UNDERFLOW, ss); + if (status & QAIF_SUMMARY_BITMASK_AIF_ERR_RSP_RDDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_AIF_IRQ), - QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_AIF_IRQ), - QAIF_AIF_IRQ, DMA_TYPE_RDDMA, QAIF_IRQ_ERROR, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_AIF_ERR_RSP_WRDMA) { + QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_AIF_IRQ), + QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_AIF_IRQ), + QAIF_AIF_IRQ, QAIF_DMA_RDDMA, QAIF_IRQ_ERROR, ss); + if (status & QAIF_SUMMARY_BITMASK_AIF_ERR_RSP_WRDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_AIF_IRQ), - QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_AIF_IRQ), - QAIF_AIF_IRQ, DMA_TYPE_WRDMA, QAIF_IRQ_ERROR, substream); - } + QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_AIF_IRQ), + QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_AIF_IRQ), + QAIF_AIF_IRQ, QAIF_DMA_WRDMA, QAIF_IRQ_ERROR, ss); return ret; } -static irqreturn_t qaif_cif_irq_handler(struct qaif_drv_data *drvdata, u32 summary_irq_status) +static irqreturn_t qaif_cif_irq_handler(struct qaif_drv_data *drvdata, u32 status) { const struct qaif_variant *v = drvdata->variant; + struct snd_pcm_substream **ss = drvdata->cif_substream; irqreturn_t ret = IRQ_NONE; - struct snd_pcm_substream **substream = drvdata->cif_substream; - if (summary_irq_status & QAIF_SUMMARY_BITMASK_CIF_PERIOD_RDDMA) { + if (status & QAIF_SUMMARY_BITMASK_CIF_PERIOD_RDDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, QAIF_CIF_IRQ), - QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, QAIF_CIF_IRQ), - QAIF_CIF_IRQ, DMA_TYPE_RDDMA, QAIF_IRQ_PERIOD, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_CIF_PERIOD_WRDMA) { + QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, QAIF_CIF_IRQ), + QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, QAIF_CIF_IRQ), + QAIF_CIF_IRQ, QAIF_DMA_RDDMA, QAIF_IRQ_PERIOD, ss); + if (status & QAIF_SUMMARY_BITMASK_CIF_PERIOD_WRDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, QAIF_CIF_IRQ), - QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, QAIF_CIF_IRQ), - QAIF_CIF_IRQ, DMA_TYPE_WRDMA, QAIF_IRQ_PERIOD, substream); - } - - if (summary_irq_status & QAIF_SUMMARY_BITMASK_CIF_OVERFLOW_WRDMA) { + QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, QAIF_CIF_IRQ), + QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, QAIF_CIF_IRQ), + QAIF_CIF_IRQ, QAIF_DMA_WRDMA, QAIF_IRQ_PERIOD, ss); + if (status & QAIF_SUMMARY_BITMASK_CIF_OVERFLOW_WRDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_WRDMA_OVERFLOW_IRQ_STAT_REG(v, QAIF_CIF_IRQ), - QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, QAIF_CIF_IRQ), - QAIF_CIF_IRQ, DMA_TYPE_WRDMA, QAIF_IRQ_OVERFLOW, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_CIF_UNDERFLOW_RDDMA) { + QAIF_EE_WRDMA_OF_IRQ_STAT_REG(v, QAIF_CIF_IRQ), + QAIF_EE_WRDMA_OF_IRQ_CLR_REG(v, QAIF_CIF_IRQ), + QAIF_CIF_IRQ, QAIF_DMA_WRDMA, QAIF_IRQ_OVERFLOW, ss); + if (status & QAIF_SUMMARY_BITMASK_CIF_UNDERFLOW_RDDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_RDDMA_UNDERFLOW_IRQ_STAT_REG(v, QAIF_CIF_IRQ), - QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, QAIF_CIF_IRQ), - QAIF_CIF_IRQ, DMA_TYPE_RDDMA, QAIF_IRQ_UNDERFLOW, substream); - } - - if (summary_irq_status & QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_RDDMA) { + QAIF_EE_RDDMA_UF_IRQ_STAT_REG(v, QAIF_CIF_IRQ), + QAIF_EE_RDDMA_UF_IRQ_CLR_REG(v, QAIF_CIF_IRQ), + QAIF_CIF_IRQ, QAIF_DMA_RDDMA, QAIF_IRQ_UNDERFLOW, ss); + if (status & QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_RDDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_CIF_IRQ), - QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_CIF_IRQ), - QAIF_CIF_IRQ, DMA_TYPE_RDDMA, QAIF_IRQ_ERROR, substream); - } - if (summary_irq_status & QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_WRDMA) { + QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_CIF_IRQ), + QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_CIF_IRQ), + QAIF_CIF_IRQ, QAIF_DMA_RDDMA, QAIF_IRQ_ERROR, ss); + if (status & QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_WRDMA) ret |= qaif_process_dma_irq(drvdata, - QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_CIF_IRQ), - QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_CIF_IRQ), - QAIF_CIF_IRQ, DMA_TYPE_WRDMA, QAIF_IRQ_ERROR, substream); - } - + QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, QAIF_CIF_IRQ), + QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, QAIF_CIF_IRQ), + QAIF_CIF_IRQ, QAIF_DMA_WRDMA, QAIF_IRQ_ERROR, ss); return ret; } -#define QAIF_ALL_CLIENTS_MASK (QAIF_BITMASK_AIF_RDDMA_WRDMA | QAIF_BITMASK_CIF_RDDMA_WRDMA) - static const struct qaif_irq_map qaif_irq_clients[] = { - { QAIF_CLIENT_ID_AIF_DMA, QAIF_BITMASK_AIF_RDDMA_WRDMA, qaif_aif_irq_handler}, - { QAIF_CLIENT_ID_CIF_DMA, QAIF_BITMASK_CIF_RDDMA_WRDMA, qaif_cif_irq_handler}, + { QAIF_CLIENT_ID_AIF_DMA, QAIF_BITMASK_AIF_RDDMA_WRDMA, qaif_aif_irq_handler }, + { QAIF_CLIENT_ID_CIF_DMA, QAIF_BITMASK_CIF_RDDMA_WRDMA, qaif_cif_irq_handler }, }; static irqreturn_t asoc_platform_qaif_irq(int irq, void *data) @@ -1062,15 +836,17 @@ static irqreturn_t asoc_platform_qaif_irq(int irq, void *data) int rv, client; irqreturn_t ret = IRQ_NONE; - rv = regmap_read(drvdata->audio_qaif_map, - QAIF_SUMMARY_IRQSTAT_REG(v), &summary_irq_status); + rv = regmap_read(drvdata->audio_qaif_map, QAIF_SUMMARY_IRQSTAT_REG(v), + &summary_irq_status); if (rv) { dev_err(regmap_get_device(drvdata->audio_qaif_map), "error reading from irqstat reg: %d\n", rv); return IRQ_NONE; } + if (!(summary_irq_status & QAIF_ALL_CLIENTS_MASK)) return IRQ_NONE; + for (client = 0; client < ARRAY_SIZE(qaif_irq_clients); client++) { if (summary_irq_status & qaif_irq_clients[client].mask) ret |= qaif_irq_clients[client].client_irq_handler(drvdata, @@ -1079,67 +855,6 @@ static irqreturn_t asoc_platform_qaif_irq(int irq, void *data) return ret; } -static int qaif_platform_pcmops_suspend(struct snd_soc_component *component) -{ - struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); - struct regmap *map; - - map = drvdata->audio_qaif_map; - - regcache_cache_only(map, true); - regcache_mark_dirty(map); - if (drvdata->qaif_init_ref_cnt > 0) { - clk_disable(drvdata->aud_dma_clk); - clk_disable(drvdata->aud_dma_mem_clk); - } - return 0; -} - -static int qaif_platform_pcmops_resume(struct snd_soc_component *component) -{ - struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component); - struct regmap *map = drvdata->audio_qaif_map; - int ret; - - if (drvdata->qaif_init_ref_cnt > 0) { - ret = clk_enable(drvdata->aud_dma_clk); - if (ret) - return ret; - ret = clk_enable(drvdata->aud_dma_mem_clk); - if (ret) { - clk_disable(drvdata->aud_dma_clk); - return ret; - } - } - regcache_cache_only(map, false); - return regcache_sync(map); -} - -static int qaif_platform_copy(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int channel, - unsigned long pos, struct iov_iter *buf, - unsigned long bytes) -{ - struct snd_pcm_runtime *rt = substream->runtime; - size_t copied; - void *dma_buf; - - dma_buf = (void *)(rt->dma_area + pos + - channel * (rt->dma_bytes / rt->channels)); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - copied = copy_from_iter(dma_buf, bytes, buf); - if (copied != bytes) - return -EFAULT; - } else { - copied = copy_to_iter(dma_buf, bytes, buf); - if (copied != bytes) - return -EFAULT; - } - - return 0; -} - static const struct snd_soc_component_driver qaif_component_driver = { .name = DRV_NAME, .open = qaif_platform_pcmops_open, @@ -1148,60 +863,63 @@ static const struct snd_soc_component_driver qaif_component_driver = { .hw_free = qaif_platform_pcmops_hw_free, .prepare = qaif_platform_pcmops_prepare, .trigger = qaif_platform_pcmops_trigger, + .sync_stop = qaif_platform_pcmops_sync_stop, .pointer = qaif_platform_pcmops_pointer, .mmap = qaif_platform_pcmops_mmap, - .suspend = qaif_platform_pcmops_suspend, - .resume = qaif_platform_pcmops_resume, .copy = qaif_platform_copy, }; -static int qaif_parse_smmu_sid(struct platform_device *pdev, - struct qaif_drv_data *drvdata) -{ - struct device_node *np = pdev->dev.of_node; - int ret; - u32 sid; - - ret = of_property_read_u32_index(np, "iommus", 1, &sid); - if (ret) { - dev_err(&pdev->dev, "failed to read SMMU SID from iommus property: %d\n", ret); - return ret; - } - - drvdata->smmu_csid_bits = sid & 0x1; - dev_dbg(&pdev->dev, "sid=0x%x csid=0x%x\n", sid, drvdata->smmu_csid_bits); - return 0; -} - int asoc_qcom_qaif_platform_register(struct platform_device *pdev) { struct qaif_drv_data *drvdata = platform_get_drvdata(pdev); - int ret = 0; + struct of_phandle_args iommu_spec; + u32 sid; + int ret; - if (!drvdata || !drvdata->variant) { - dev_err(&pdev->dev, "Invalid drvdata or variant\n"); - return -EINVAL; - } + if (!drvdata->variant->alloc_stream_dma_idx || + !drvdata->variant->free_stream_dma_idx) + return dev_err_probe(&pdev->dev, -EINVAL, + "Variant missing mandatory callbacks\n"); - ret = qaif_parse_smmu_sid(pdev, drvdata); + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "iommus", 2, 0, + &iommu_spec); if (ret) - return ret; + return dev_err_probe(&pdev->dev, ret, + "failed to parse iommus property\n"); + sid = iommu_spec.args[0]; + of_node_put(iommu_spec.np); + drvdata->smmu_csid_bits = sid & QAIF_CSID_MASK; + + /* + * The DMA base register only holds the low 32 bits of the buffer + * address, so the coherent buffer must come from the low 32-bit + * address space. + */ + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to set 32-bit DMA mask\n"); drvdata->audio_qaif_irq = platform_get_irq(pdev, 0); if (drvdata->audio_qaif_irq < 0) - return drvdata->audio_qaif_irq; + return dev_err_probe(&pdev->dev, drvdata->audio_qaif_irq, + "Failed to get IRQ\n"); + + drvdata->qaif_hw_configured = false; + mutex_init(&drvdata->stream_lock); ret = devm_request_irq(&pdev->dev, drvdata->audio_qaif_irq, - asoc_platform_qaif_irq, IRQF_TRIGGER_HIGH, + asoc_platform_qaif_irq, 0, "qaif-irq-audio-core", drvdata); - if (ret) { - dev_err(&pdev->dev, "irq request failed: %d\n", ret); - return ret; - } - drvdata->qaif_init_ref_cnt = 0; - dev_dbg(&pdev->dev, "%s: Register QAIF Platform\n", __func__); - return devm_snd_soc_register_component(&pdev->dev, - &qaif_component_driver, NULL, 0); + if (ret) + return dev_err_probe(&pdev->dev, ret, "irq request failed\n"); + + ret = devm_snd_soc_register_component(&pdev->dev, &qaif_component_driver, NULL, 0); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to register platform component\n"); + return 0; } EXPORT_SYMBOL_GPL(asoc_qcom_qaif_platform_register); diff --git a/sound/soc/qcom/qaif-reg.h b/sound/soc/qcom/qaif-reg.h index 3a240f80cbc2a..84a9c0285289e 100644 --- a/sound/soc/qcom/qaif-reg.h +++ b/sound/soc/qcom/qaif-reg.h @@ -2,472 +2,457 @@ /* * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * - * qaif-reg.h -- ALSA SoC CPU-Platform DAI driver register header file for QTi QAIF + * qaif-reg.h -- QAIF ALSA SoC CPU-Platform DAI driver register header */ -#ifndef __QAIF_REG_H__ -#define __QAIF_REG_H__ +#ifndef SND_SOC_QCOM_QAIF_REG_H +#define SND_SOC_QCOM_QAIF_REG_H #include "qaif.h" -#define QAIF_SUMMARY_IRQSTAT_REG(v) (0x19188 + (0x1000 * ((v)->ee))) +#define QAIF_SUMMARY_IRQSTAT_REG(v) (0x19188 + (0x1000 * ((v)->ee))) /* Core HW info */ -#define QAIF_HW_VERSION_REG (0x0000) -#define QAIF_HW_INFO_REG (0x0004) -#define QAIF_HW_INFO2_REG (0x0008) +#define QAIF_HW_VERSION_REG (0x0000) +#define QAIF_HW_INFO_REG (0x0004) +#define QAIF_HW_INFO2_REG (0x0008) /* Interface lane and channel info */ -#define QAIF_AUD_INTF_LANE_INFO_REG (0x0020) -#define QAIF_AUD_INTF_LANE_INFO2_REG (0x0024) -#define QAIF_CODEC_TX_INTF_CH_INFO_REG(n) (0x0028 + (0x4 * (n))) -#define QAIF_CODEC_RX_INTF_CH_INFO_REG(n) (0x0068 + (0x4 * (n))) -#define QAIF_QXM1_SHRAM_LENGTH_INFO_REG (0x0088) -#define QAIF_QXM0_SHRAM_LENGTH_INFO_REG (0x008C) -#define QAIF_NUM_AUD_INTF_TO_RAIL_INFO_REG (0x0090) +#define QAIF_AUD_INTF_LANE_INFO_REG (0x0020) +#define QAIF_AUD_INTF_LANE_INFO2_REG (0x0024) +#define QAIF_CDC_TX_INTF_CH_INFO_REG(n) (0x0028 + (0x4 * (n))) +#define QAIF_CDC_RX_INTF_CH_INFO_REG(n) (0x0068 + (0x4 * (n))) +#define QAIF_QXM1_SHRAM_LENGTH_INFO_REG (0x0088) +#define QAIF_QXM0_SHRAM_LENGTH_INFO_REG (0x008C) +#define QAIF_NUM_AUD_INTF_TO_RAIL_INFO_REG (0x0090) /* Debug/control and status */ -#define QAIF_DEBUG_CTL_REG (0x0200) -#define QAIF_WRDMA_LOOPBACK_EN_REG (0x0204) -#define QAIF_WRDMA_LOOPBACK_SEL_REG (0x0208) -#define QAIF_SHRAM_DYNAMIC_CLK_GATING_EN_REG (0x0300) -#define QAIF_AXI_STATUS_REG (0x0304) -#define QAIF_QSB_DYNAMIC_CLK_GATING_EN_REG (0x0308) -#define QAIF_START_STOP_CTRL_BYPASS_EN_REG (0x030C) -#define QAIF_QXM0_AXI_ATTR_CFG_REG (0x040C) +#define QAIF_DEBUG_CTL_REG (0x0200) +#define QAIF_WRDMA_LOOPBACK_EN_REG (0x0204) +#define QAIF_WRDMA_LOOPBACK_SEL_REG (0x0208) +#define QAIF_SHRAM_DYNAMIC_CLK_GATING_EN_REG (0x0300) +#define QAIF_AXI_STATUS_REG (0x0304) +#define QAIF_QSB_DYNAMIC_CLK_GATING_EN_REG (0x0308) +#define QAIF_START_STOP_CTRL_BYPASS_EN_REG (0x030C) +#define QAIF_QXM0_AXI_ATTR_CFG_REG (0x040C) /* QXM request/grant debug */ -#define QAIF_QXM0_AUD_WR_REQ_GNT_DBG_STAT_REG (0x0500) -#define QAIF_QXM1_AUD_WR_REQ_GNT_DBG_STAT_REG (0x0504) -#define QAIF_QXM0_CODEC_RX_WR_REQ_DBG_STAT_REG (0x0508) -#define QAIF_QXM0_CODEC_RX_WR_GNT_DBG_STAT_REG (0x050C) -#define QAIF_QXM1_CODEC_RX_WR_REQ_DBG_STAT_REG (0x0510) -#define QAIF_QXM1_CODEC_RX_WR_GNT_DBG_STAT_REG (0x0514) -#define QAIF_QXM0_AUD_RD_REQ_GNT_DBG_STAT_REG (0x0518) -#define QAIF_QXM1_AUD_RD_REQ_GNT_DBG_STAT_REG (0x051C) -#define QAIF_QXM0_CODEC_TX_RD_REQ_DBG_STAT_REG (0x0520) -#define QAIF_QXM0_CODEC_TX_RD_GNT_DBG_STAT_REG (0x0524) -#define QAIF_QXM1_CODEC_TX_RD_REQ_DBG_STAT_REG (0x0528) -#define QAIF_QXM1_CODEC_TX_RD_GNT_DBG_STAT_REG (0x052C) -#define QAIF_QXM0_EXT_RDDMA_RD_REQ_GNT_DBG_STAT_REG (0x0530) -#define QAIF_QXM1_EXT_RDDMA_RD_REQ_GNT_DBG_STAT_REG (0x0534) +#define QAIF_QXM0_AUD_WR_REQ_GNT_DBG_STAT_REG (0x0500) +#define QAIF_QXM1_AUD_WR_REQ_GNT_DBG_STAT_REG (0x0504) +#define QAIF_QXM0_CODEC_RX_WR_REQ_DBG_STAT_REG (0x0508) +#define QAIF_QXM0_CODEC_RX_WR_GNT_DBG_STAT_REG (0x050C) +#define QAIF_QXM1_CODEC_RX_WR_REQ_DBG_STAT_REG (0x0510) +#define QAIF_QXM1_CODEC_RX_WR_GNT_DBG_STAT_REG (0x0514) +#define QAIF_QXM0_AUD_RD_REQ_GNT_DBG_STAT_REG (0x0518) +#define QAIF_QXM1_AUD_RD_REQ_GNT_DBG_STAT_REG (0x051C) +#define QAIF_QXM0_CODEC_TX_RD_REQ_DBG_STAT_REG (0x0520) +#define QAIF_QXM0_CODEC_TX_RD_GNT_DBG_STAT_REG (0x0524) +#define QAIF_QXM1_CODEC_TX_RD_REQ_DBG_STAT_REG (0x0528) +#define QAIF_QXM1_CODEC_TX_RD_GNT_DBG_STAT_REG (0x052C) +#define QAIF_QXM0_EXT_RDDMA_RD_REQ_GNT_DBG_STAT_REG (0x0530) +#define QAIF_QXM1_EXT_RDDMA_RD_REQ_GNT_DBG_STAT_REG (0x0534) /* QSB transaction debug */ -#define QAIF_QSB_AUD_WR_TXN_DBG_STAT_REG (0x0538) -#define QAIF_QSB_CODEC_RX_WR_TXN_ERR_DBG_STAT_REG (0x053C) -#define QAIF_QSB_CODEC_RX_WR_TXN_OKAY_DBG_STAT_REG (0x0540) -#define QAIF_QSB_AUD_ADDR_SENT_DBG_STAT_REG (0x0544) -#define QAIF_QSB_CODEC_TX_RD_ADDR_SENT_DBG_STAT_REG (0x0548) -#define QAIF_QSB_EXT_RDDMA_RD_ADDR_SENT_DBG_STAT_REG (0x054C) -#define QAIF_QSB_CODEC_RX_WR_ADDR_SENT_DBG_STAT_REG (0x0550) -#define QAIF_QSB_AUD_RD_TXN_DBG_STAT_REG (0x0554) -#define QAIF_QSB_CODEC_TX_RD_TXN_ERR_DBG_STAT_REG (0x0558) -#define QAIF_QSB_CODEC_TX_RD_TXN_RCVD_DBG_STAT_REG (0x055C) -#define QAIF_QSB_EXT_RDDMA_RD_TXN_DBG_STAT_REG (0x0560) -#define QAIF_QSB_MISC_DBG_STATUS_REG (0x0564) +#define QAIF_QSB_AUD_WR_TXN_DBG_STAT_REG (0x0538) +#define QAIF_QSB_CODEC_RX_WR_TXN_ERR_DBG_STAT_REG (0x053C) +#define QAIF_QSB_CODEC_RX_WR_TXN_OKAY_DBG_STAT_REG (0x0540) +#define QAIF_QSB_AUD_ADDR_SENT_DBG_STAT_REG (0x0544) +#define QAIF_QSB_CODEC_TX_RD_ADDR_SENT_DBG_STAT_REG (0x0548) +#define QAIF_QSB_EXT_RDDMA_RD_ADDR_SENT_DBG_STAT_REG (0x054C) +#define QAIF_QSB_CODEC_RX_WR_ADDR_SENT_DBG_STAT_REG (0x0550) +#define QAIF_QSB_AUD_RD_TXN_DBG_STAT_REG (0x0554) +#define QAIF_QSB_CODEC_TX_RD_TXN_ERR_DBG_STAT_REG (0x0558) +#define QAIF_QSB_CODEC_TX_RD_TXN_RCVD_DBG_STAT_REG (0x055C) +#define QAIF_QSB_EXT_RDDMA_RD_TXN_DBG_STAT_REG (0x0560) +#define QAIF_QSB_MISC_DBG_STATUS_REG (0x0564) /* Global spare and HWE */ -#define QAIF_GLOBAL_SPARE_IN_REG (0x0B00) -#define QAIF_GLOBAL_SPARE_OUT_REG (0x0B04) -#define QAIF_HWE_CFG_REG (0x0B08) +#define QAIF_GLOBAL_SPARE_IN_REG (0x0B00) +#define QAIF_GLOBAL_SPARE_OUT_REG (0x0B04) +#define QAIF_HWE_CFG_REG (0x0B08) /* SID maps */ -#define QAIF_WRDMA_SID_MAP_REG (0x1B00) -#define QAIF_CODEC_WRDMA_SID_MAP_REG (0x1B40) -#define QAIF_RDDMA_SID_MAP_REG (0x1C00) -#define QAIF_CODEC_RDDMA_SID_MAP_REG (0x1C40) +#define QAIF_WRDMA_SID_MAP_REG (0x1B00) +#define QAIF_CDC_WRDMA_SID_MAP_REG (0x1B40) +#define QAIF_RDDMA_SID_MAP_REG (0x1C00) +#define QAIF_CDC_RDDMA_SID_MAP_REG (0x1C40) /* EE overlap interrupts */ -#define QAIF_EE_OVERLAP_IRQ_EN_REG (0x1D00) -#define QAIF_EE_OVERLAP_IRQ_RAW_STATUS_REG (0x1D04) -#define QAIF_EE_OVERLAP_IRQ_CLEAR_REG (0x1D08) -#define QAIF_EE_OVERLAP_IRQ_FORCE_REG (0x1D0C) - -/* EE assignments and maps */ -#define QAIF_EE_RDDMA_ASSIGNMENT_REG(v) (0x19148 + (0x1000 * ((v)->ee))) -#define QAIF_EE_WRDMA_ASSIGNMENT_REG(v) (0x19150 + (0x1000 * ((v)->ee))) -#define QAIF_EE_INTF_ASSIGNMENT_REG(v) (0x19158 + (0x1000 * ((v)->ee))) -#define QAIF_EE_CODEC_RDDMA_ASSIGNMENT_REG(v) (0x19308 + (0x1000 * ((v)->ee))) -#define QAIF_EE_CODEC_WRDMA_ASSIGNMENT_REG(v) (0x19318 + (0x1000 * ((v)->ee))) -#define QAIF_EE_RDDMA_MAP_REG(v) (0x1920 + (0x1000 * ((v)->ee))) -#define QAIF_EE_WRDMA_MAP_REG(v) (0x1940 + (0x1000 * ((v)->ee))) -#define QAIF_EE_INTF_MAP_REG(v) (0x1960 + (0x1000 * ((v)->ee))) -#define QAIF_EE_CODEC_RDDMA_MAP_REG(v) (0x1980 + (0x1000 * ((v)->ee))) -#define QAIF_EE_CODEC_WRDMA_MAP_REG(v) (0x1A00 + (0x1000 * ((v)->ee))) +#define QAIF_EE_OVERLAP_IRQ_EN_REG (0x1D00) +#define QAIF_EE_OVERLAP_IRQ_RAW_STATUS_REG (0x1D04) +#define QAIF_EE_OVERLAP_IRQ_CLEAR_REG (0x1D08) +#define QAIF_EE_OVERLAP_IRQ_FORCE_REG (0x1D0C) + +/* + * EE (Execution Engine) assignment and map registers. + * + * The EE offset (v->ee) is an address/index offset relative to the + * platform-defined QAIF/EE base and lets the hardware route the AIF + * operation to the correct EE context. It is hardware/platform-specific and + * must match the mapping defined for the selected QAIF AIF/lane in the + * hardware programming guide. It is not a runtime data offset and must not + * be changed based on the stream configuration. + */ +#define QAIF_EE_RDDMA_ASSIGNMENT_REG(v) (0x19148 + (0x1000 * ((v)->ee))) +#define QAIF_EE_WRDMA_ASSIGNMENT_REG(v) (0x19150 + (0x1000 * ((v)->ee))) +#define QAIF_EE_INTF_ASSIGNMENT_REG(v) (0x19158 + (0x1000 * ((v)->ee))) +#define QAIF_EE_CODEC_RDDMA_ASSIGN_REG(v) (0x19308 + (0x1000 * ((v)->ee))) +#define QAIF_EE_CODEC_WRDMA_ASSIGN_REG(v) (0x19318 + (0x1000 * ((v)->ee))) +#define QAIF_EE_RDDMA_MAP_REG(v) (0x1920 + (0x1000 * ((v)->ee))) +#define QAIF_EE_WRDMA_MAP_REG(v) (0x1940 + (0x1000 * ((v)->ee))) +#define QAIF_EE_INTF_MAP_REG(v) (0x1960 + (0x1000 * ((v)->ee))) +#define QAIF_EE_CODEC_RDDMA_MAP_REG(v) (0x1980 + (0x1000 * ((v)->ee))) +#define QAIF_EE_CODEC_WRDMA_MAP_REG(v) (0x1A00 + (0x1000 * ((v)->ee))) /* EE rate-detection and VFR interrupts */ -#define QAIF_EE_RATE_DET_IRQ_EN_REG(v) (0x190F0 + (0x1000 * ((v)->ee))) -#define QAIF_EE_RATE_DET_IRQ_STATUS_REG(v) (0x190F4 + (0x1000 * ((v)->ee))) -#define QAIF_EE_RATE_DET_IRQ_RAW_STATUS_REG(v) (0x190F8 + (0x1000 * ((v)->ee))) -#define QAIF_EE_RATE_DET_IRQ_CLEAR_REG(v) (0x190FC + (0x1000 * ((v)->ee))) -#define QAIF_EE_RATE_DET_IRQ_FORCE_REG(v) (0x19100 + (0x1000 * ((v)->ee))) - -#define QAIF_EE_VFR_IRQ_EN_REG(v) (0x19104 + (0x1000 * ((v)->ee))) -#define QAIF_EE_VFR_IRQ_STATUS_REG(v) (0x19108 + (0x1000 * ((v)->ee))) -#define QAIF_EE_VFR_IRQ_RAW_STATUS_REG(v) (0x1910C + (0x1000 * ((v)->ee))) -#define QAIF_EE_VFR_IRQ_CLEAR_REG(v) (0x19110 + (0x1000 * ((v)->ee))) -#define QAIF_EE_VFR_IRQ_FORCE_REG(v) (0x19114 + (0x1000 * ((v)->ee))) +#define QAIF_EE_RATE_DET_IRQ_EN_REG(v) (0x190F0 + (0x1000 * ((v)->ee))) +#define QAIF_EE_RATE_DET_IRQ_STAT_REG(v) (0x190F4 + (0x1000 * ((v)->ee))) +#define QAIF_EE_RATE_DET_IRQ_RAW_STAT_REG(v) (0x190F8 + (0x1000 * ((v)->ee))) +#define QAIF_EE_RATE_DET_IRQ_CLEAR_REG(v) (0x190FC + (0x1000 * ((v)->ee))) +#define QAIF_EE_RATE_DET_IRQ_FORCE_REG(v) (0x19100 + (0x1000 * ((v)->ee))) + +#define QAIF_EE_VFR_IRQ_EN_REG(v) (0x19104 + (0x1000 * ((v)->ee))) +#define QAIF_EE_VFR_IRQ_STATUS_REG(v) (0x19108 + (0x1000 * ((v)->ee))) +#define QAIF_EE_VFR_IRQ_RAW_STATUS_REG(v) (0x1910C + (0x1000 * ((v)->ee))) +#define QAIF_EE_VFR_IRQ_CLEAR_REG(v) (0x19110 + (0x1000 * ((v)->ee))) +#define QAIF_EE_VFR_IRQ_FORCE_REG(v) (0x19114 + (0x1000 * ((v)->ee))) /* EE AUD_INTF underflow/overflow interrupts */ -#define QAIF_EE_AUD_INTF_UNDERFLOW_IRQ_EN_REG(v) (0x19160 + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_UNDERFLOW_IRQ_STATUS_REG(v) (0x19164 + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_UNDERFLOW_IRQ_RAW_STATUS_REG(v) \ - (0x19168 + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_UNDERFLOW_IRQ_CLEAR_REG(v) (0x1916C + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_UNDERFLOW_IRQ_FORCE_REG(v) (0x19170 + (0x1000 * ((v)->ee))) - -#define QAIF_EE_AUD_INTF_OVERFLOW_IRQ_EN_REG(v) (0x19174 + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_OVERFLOW_IRQ_STATUS_REG(v) (0x19178 + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_OVERFLOW_IRQ_RAW_STATUS_REG(v) \ - (0x1917C + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_OVERFLOW_IRQ_CLEAR_REG(v) (0x19180 + (0x1000 * ((v)->ee))) -#define QAIF_EE_AUD_INTF_OVERFLOW_IRQ_FORCE_REG(v) (0x19184 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_UF_IRQ_EN_REG(v) (0x19160 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_UF_IRQ_STAT_REG(v) (0x19164 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_UF_IRQ_RAW_STAT_REG(v) (0x19168 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_UF_IRQ_CLEAR_REG(v) (0x1916C + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_UF_IRQ_FORCE_REG(v) (0x19170 + (0x1000 * ((v)->ee))) + +#define QAIF_EE_AUD_INTF_OF_IRQ_EN_REG(v) (0x19174 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_OF_IRQ_STAT_REG(v) (0x19178 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_OF_IRQ_RAW_STAT_REG(v) (0x1917C + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_OF_IRQ_CLEAR_REG(v) (0x19180 + (0x1000 * ((v)->ee))) +#define QAIF_EE_AUD_INTF_OF_IRQ_FORCE_REG(v) (0x19184 + (0x1000 * ((v)->ee))) /* EE L2 Period IRQ mux selection */ #define QAIF_EE_L2_PERIOD_IRQ_0_3_MUX_SEL_REG(v) (0x19F00 + (0x1000 * ((v)->ee))) #define QAIF_EE_L2_PERIOD_IRQ_4_7_MUX_SEL_REG(v) (0x19F04 + (0x1000 * ((v)->ee))) /* AUD_INTF block (per interface, stride 0x1000 starting at 0x4000) */ -#define QAIF_AUD_INTF_REG_ADDR(offset, intf) (0x4000 + (offset) + (0x1000 * (intf))) - -#define QAIF_AUD_INTF_CTL_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0000, (intf)) -#define QAIF_AUD_INTF_SYNC_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0004, (intf)) -#define QAIF_AUD_INTF_BIT_WIDTH_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0008, (intf)) -#define QAIF_AUD_INTF_FRAME_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x000C, (intf)) -#define QAIF_AUD_INTF_ACTV_SLOT_EN_TX_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0010, (intf)) -#define QAIF_AUD_INTF_ACTV_SLOT_EN_RX_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0030, (intf)) -#define QAIF_AUD_INTF_LANE_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0050, (intf)) -#define QAIF_AUD_INTF_MI2S_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0054, (intf)) -#define QAIF_AUD_INTF_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0058, (intf)) -#define QAIF_AUD_INTF_CHAR_CTL_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x005C, (intf)) -#define QAIF_AUD_INTF_CHAR_CFG_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0060, (intf)) -#define QAIF_AUD_INTF_CHAR_DATA_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0064, (intf)) -#define QAIF_AUD_INTF_CHAR_DATA_EXT_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0068, (intf)) -#define QAIF_AUD_INTF_CHAR_SYNC_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x006C, (intf)) -#define QAIF_AUD_INTF_INIT_DBG_STATUS_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0FF0, (intf)) -#define QAIF_AUD_INTF_TX_DBG_STATUS_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0FF4, (intf)) -#define QAIF_AUD_INTF_RX_DBG_STATUS_REG(intf) QAIF_AUD_INTF_REG_ADDR(0x0FF8, (intf)) +#define QAIF_AUD_INTF_REG_ADDR(offset, i) (0x4000 + (offset) + (0x1000 * (i))) + +#define QAIF_AUD_INTF_CTL_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0000, (i)) +#define QAIF_AUD_INTF_SYNC_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0004, (i)) +#define QAIF_AUD_INTF_BIT_WIDTH_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0008, (i)) +#define QAIF_AUD_INTF_FRAME_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x000C, (i)) +#define QAIF_AUD_INTF_ACTV_SLOT_EN_TX_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0010, (i)) +#define QAIF_AUD_INTF_ACTV_SLOT_EN_RX_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0030, (i)) +#define QAIF_AUD_INTF_LANE_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0050, (i)) +#define QAIF_AUD_INTF_MI2S_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0054, (i)) +#define QAIF_AUD_INTF_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0058, (i)) +#define QAIF_AUD_INTF_CHAR_CTL_REG(i) QAIF_AUD_INTF_REG_ADDR(0x005C, (i)) +#define QAIF_AUD_INTF_CHAR_CFG_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0060, (i)) +#define QAIF_AUD_INTF_CHAR_DATA_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0064, (i)) +#define QAIF_AUD_INTF_CHAR_DATA_EXT_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0068, (i)) +#define QAIF_AUD_INTF_CHAR_SYNC_REG(i) QAIF_AUD_INTF_REG_ADDR(0x006C, (i)) +#define QAIF_AUD_INTF_INIT_DBG_STATUS_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0FF0, (i)) +#define QAIF_AUD_INTF_TX_DBG_STATUS_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0FF4, (i)) +#define QAIF_AUD_INTF_RX_DBG_STATUS_REG(i) QAIF_AUD_INTF_REG_ADDR(0x0FF8, (i)) /* RATE_DET block (per detector, stride 0x1000 starting at 0x1E000) */ -#define QAIF_RATE_DET_REG_ADDR(offset, det) (0x1E000 + (offset) + (0x1000 * (det))) - -#define QAIF_RATE_DET_CONFIG_REG(det) QAIF_RATE_DET_REG_ADDR(0x0000, (det)) -#define QAIF_RATE_DET_TARGET1_CONFIG_REG(det) QAIF_RATE_DET_REG_ADDR(0x0004, (det)) -#define QAIF_RATE_DET_TARGET2_CONFIG_REG(det) QAIF_RATE_DET_REG_ADDR(0x0008, (det)) -#define QAIF_RATE_DET_BIN_REG(det) QAIF_RATE_DET_REG_ADDR(0x000C, (det)) -#define QAIF_RATE_DET_STC_DIFF_REG(det) QAIF_RATE_DET_REG_ADDR(0x0010, (det)) -#define QAIF_RATE_DET_SEL_REG(det) QAIF_RATE_DET_REG_ADDR(0x0014, (det)) -#define QAIF_RATE_DET_TIMEOUT_CFG_REG(det) QAIF_RATE_DET_REG_ADDR(0x0018, (det)) - -#define QAIF_WRDMA_MAP_QXM (0X1000) -#define QAIF_CODEC_WRDMA_MAP_QXM (0X1004) -#define QAIF_RDDMA_MAP_QXM (0X1010) -#define QAIF_CODEC_RDDMA_MAP_QXM (0X1014) -#define QAIF_RDDMA_QXM1_SHRAM_ST_ADDR(i) (0X1100 + (0x4 * (i))) -#define QAIF_CODEC_RDDMA_QXM1_SHRAM_ST_ADDR(i) (0X1140 + (0x4 * (i))) -#define QAIF_RDDMA_QXM0_SHRAM_ST_ADDR(i) (0X1200 + (0x4 * (i))) -#define QAIF_CODEC_RDDMA_QXM0_SHRAM_ST_ADDR(i) (0X1240 + (0x4 * (i))) -#define QAIF_RDDMA_QXM1_SHRAM_LEN(i) (0x1300 + (0x4 * (i))) -#define QAIF_CODEC_RDDMA_QXM1_SHRAM_LEN(i) (0x1340 + (0x4 * (i))) -#define QAIF_RDDMA_QXM0_SHRAM_LEN(i) (0x1400 + (0x4 * (i))) -#define QAIF_CODEC_RDDMA_QXM0_SHRAM_LEN(i) (0x1440 + (0x4 * (i))) -#define QAIF_WRDMA_QXM1_SHRAM_ST_ADDR(i) (0x1500 + (0x4 * (i))) -#define QAIF_CODEC_WRDMA_QXM1_SHRAM_ST_ADDR(i) (0x1540 + (0x4 * (i))) -#define QAIF_WRDMA_QXM0_SHRAM_ST_ADDR(i) (0x1600 + (0x4 * (i))) -#define QAIF_CODEC_WRDMA_QXM0_SHRAM_ST_ADDR(i) (0x1640 + (0x4 * (i))) -#define QAIF_WRDMA_QXM1_SHRAM_LEN(i) (0x1700 + (0x4 * (i))) -#define QAIF_CODEC_WRDMA_QXM1_SHRAM_LEN(i) (0x1740 + (0x4 * (i))) -#define QAIF_WRDMA_QXM0_SHRAM_LEN(i) (0x1800 + (0x4 * (i))) -#define QAIF_CODEC_WRDMA_QXM0_SHRAM_LEN(i) (0x1840 + (0x4 * (i))) - -/* RDDMA - * v : ptr to qaif_variant - */ -#define QAIF_RDDMA_REG_ADDR(v, offset, chan) \ - ((v)->rddma_reg_base + (offset) + (v)->rddma_stride * (chan)) -#define QAIF_RDDMA_CTL_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x00, (chan)) -#define QAIF_RDDMA_CFG_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x04, (chan)) -#define QAIF_RDDMA_BASE_ADDR_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x08, (chan)) -#define QAIF_RDDMA_BUFF_LEN_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x10, (chan)) -#define QAIF_RDDMA_CURR_ADDR_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x14, (chan)) -#define QAIF_RDDMA_PERIOD_LEN_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x1C, (chan)) -#define QAIF_RDDMA_PERIOD_CNT_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x20, (chan)) -#define QAIF_RDDMA_SHRAM_WORDCNT_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x24, (chan)) -#define QAIF_RDDMA_FRAME_STATUS_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x28, (chan)) -#define QAIF_RDDMA_FRAME_STATUS_EXTN_REG(v, chan) \ - QAIF_RDDMA_REG_ADDR(v, 0x2C, (chan)) -#define QAIF_RDDMA_FRAME_STATUS_CLR_REG(v, chan) \ - QAIF_RDDMA_REG_ADDR(v, 0x30, (chan)) -#define QAIF_RDDMA_SET_BUFF_CNT_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x34, (chan)) -#define QAIF_RDDMA_SET_PERIOD_CNT_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x38, (chan)) -#define QAIF_RDDMA_STC_LSB_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x3C, (chan)) -#define QAIF_RDDMA_STC_MSB_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x40, (chan)) -#define QAIF_RDDMA_PERIOD_DET_STAT_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x44, (chan)) -#define QAIF_RDDMA_PERIOD_DET_CLR_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x48, (chan)) -#define QAIF_RDDMA_FORMAT_ERR_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x4C, (chan)) -#define QAIF_RDDMA_AHB_BYPASS_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x50, (chan)) -#define QAIF_RDDMA_SHUTDOWN_STAT_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x54, (chan)) -#define QAIF_RDDMA_PADDING_CFG_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x58, (chan)) -#define QAIF_RDDMA_STATUS_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0x60, (chan)) -#define QAIF_RDDMA_DBG_STATUS_REG(v, chan) QAIF_RDDMA_REG_ADDR(v, 0xFF0, (chan)) - -#define QAIF_CODEC_RDDMA_REG_ADDR(v, offset, chan) \ - ((v)->codec_rddma_reg_base + (offset) + (v)->codec_rddma_stride * (chan)) -#define QAIF_CODEC_RDDMA_CTL_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x00, (chan)) -#define QAIF_CODEC_RDDMA_CFG_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x04, (chan)) -#define QAIF_CODEC_RDDMA_BASE_ADDR_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x08, (chan)) -#define QAIF_CODEC_RDDMA_BUFF_LEN_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x10, (chan)) -#define QAIF_CODEC_RDDMA_CURR_ADDR_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x14, (chan)) -#define QAIF_CODEC_RDDMA_PERIOD_LEN_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x1C, (chan)) -#define QAIF_CODEC_RDDMA_PERIOD_CNT_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x20, (chan)) -#define QAIF_CODEC_RDDMA_SHRAM_WORDCNT_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x24, (chan)) -#define QAIF_CODEC_RDDMA_FRAME_STATUS_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x28, (chan)) -#define QAIF_CODEC_RDDMA_FRAME_STATUS_EXTN_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x2C, (chan)) -#define QAIF_CODEC_RDDMA_FRAME_STATUS_CLR_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x30, (chan)) -#define QAIF_CODEC_RDDMA_SET_BUFF_CNT_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x34, (chan)) -#define QAIF_CODEC_RDDMA_SET_PERIOD_CNT_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x38, (chan)) -#define QAIF_CODEC_RDDMA_STC_LSB_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x3C, (chan)) -#define QAIF_CODEC_RDDMA_STC_MSB_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x40, (chan)) -#define QAIF_CODEC_RDDMA_PERIOD_DET_STAT_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x44, (chan)) -#define QAIF_CODEC_RDDMA_PERIOD_DET_CLR_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x48, (chan)) -#define QAIF_CODEC_RDDMA_FORMAT_ERR_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x4C, (chan)) -#define QAIF_CODEC_RDDMA_AHB_BYPASS_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x50, (chan)) -#define QAIF_CODEC_RDDMA_SHUTDOWN_STAT_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x54, (chan)) -#define QAIF_CODEC_RDDMA_PADDING_CFG_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0x58, (chan)) -#define QAIF_CODEC_RDDMA_INTF_CFG_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x5C, (chan)) -#define QAIF_CODEC_RDDMA_STATUS_REG(v, chan) QAIF_CODEC_RDDMA_REG_ADDR(v, 0x60, (chan)) -#define QAIF_CODEC_RDDMA_DBG_STATUS_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0xFF0, (chan)) -#define QAIF_CODEC_RDDMA_INTF_DBG_STATUS_REG(v, chan) \ - QAIF_CODEC_RDDMA_REG_ADDR(v, 0xFF4, (chan)) - -/* WRDMA - * v : ptr to qaif_variant - */ -#define QAIF_WRDMA_REG_ADDR(v, offset, chan) \ - ((v)->wrdma_reg_base + (offset) + (v)->wrdma_stride * (chan)) -#define QAIF_WRDMA_CTL_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x00, (chan)) -#define QAIF_WRDMA_CFG_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x04, (chan)) -#define QAIF_WRDMA_BASE_ADDR_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x08, (chan)) -#define QAIF_WRDMA_BUFF_LEN_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x10, (chan)) -#define QAIF_WRDMA_CURR_ADDR_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x14, (chan)) -#define QAIF_WRDMA_PERIOD_LEN_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x1C, (chan)) -#define QAIF_WRDMA_PERIOD_CNT_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x20, (chan)) -#define QAIF_WRDMA_SHRAM_WORDCNT_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x24, (chan)) -#define QAIF_WRDMA_FRAME_STATUS_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x28, (chan)) -#define QAIF_WRDMA_FRAME_STATUS_EXTN_REG(v, chan) \ - QAIF_WRDMA_REG_ADDR(v, 0x2C, (chan)) -#define QAIF_WRDMA_FRAME_STATUS_CLR_REG(v, chan) \ - QAIF_WRDMA_REG_ADDR(v, 0x30, (chan)) -#define QAIF_WRDMA_SET_BUFF_CNT_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x34, (chan)) -#define QAIF_WRDMA_SET_PERIOD_CNT_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x38, (chan)) -#define QAIF_WRDMA_STC_LSB_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x3C, (chan)) -#define QAIF_WRDMA_STC_MSB_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x40, (chan)) -#define QAIF_WRDMA_PERIOD_DET_STAT_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x44, (chan)) -#define QAIF_WRDMA_PERIOD_DET_CLR_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x48, (chan)) -#define QAIF_WRDMA_FORMAT_ERR_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x4C, (chan)) -#define QAIF_WRDMA_AHB_BYPASS_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x50, (chan)) -#define QAIF_WRDMA_SHUTDOWN_STAT_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0x54, (chan)) -#define QAIF_WRDMA_DBG_STATUS_REG(v, chan) QAIF_WRDMA_REG_ADDR(v, 0xFF0, (chan)) - -#define QAIF_CODEC_WRDMA_REG_ADDR(v, offset, chan) \ - ((v)->codec_wrdma_reg_base + (offset) + (v)->codec_wrdma_stride * (chan)) -#define QAIF_CODEC_WRDMA_CTL_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x00, (chan)) -#define QAIF_CODEC_WRDMA_CFG_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x04, (chan)) -#define QAIF_CODEC_WRDMA_BASE_ADDR_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x08, (chan)) -#define QAIF_CODEC_WRDMA_BUFF_LEN_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x10, (chan)) -#define QAIF_CODEC_WRDMA_CURR_ADDR_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x14, (chan)) -#define QAIF_CODEC_WRDMA_PERIOD_LEN_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x1C, (chan)) -#define QAIF_CODEC_WRDMA_PERIOD_CNT_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x20, (chan)) -#define QAIF_CODEC_WRDMA_SHRAM_WORDCNT_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x24, (chan)) -#define QAIF_CODEC_WRDMA_FRAME_STATUS_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x28, (chan)) -#define QAIF_CODEC_WRDMA_FRAME_STATUS_EXTN_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x2C, (chan)) -#define QAIF_CODEC_WRDMA_FRAME_STATUS_CLR_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x30, (chan)) -#define QAIF_CODEC_WRDMA_SET_BUFF_CNT_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x34, (chan)) -#define QAIF_CODEC_WRDMA_SET_PERIOD_CNT_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x38, (chan)) -#define QAIF_CODEC_WRDMA_STC_LSB_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x3C, (chan)) -#define QAIF_CODEC_WRDMA_STC_MSB_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x40, (chan)) -#define QAIF_CODEC_WRDMA_PERIOD_DET_STAT_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x44, (chan)) -#define QAIF_CODEC_WRDMA_PERIOD_DET_CLR_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x48, (chan)) -#define QAIF_CODEC_WRDMA_FORMAT_ERR_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x4C, (chan)) -#define QAIF_CODEC_WRDMA_AHB_BYPASS_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x50, (chan)) -#define QAIF_CODEC_WRDMA_SHUTDOWN_STAT_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0x54, (chan)) -#define QAIF_CODEC_WRDMA_INTF_CFG_REG(v, chan) QAIF_CODEC_WRDMA_REG_ADDR(v, 0x58, (chan)) -#define QAIF_CODEC_WRDMA_DBG_STATUS_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0xFF0, (chan)) -#define QAIF_CODEC_WRDMA_INTF_DBG_STATUS_REG(v, chan) \ - QAIF_CODEC_WRDMA_REG_ADDR(v, 0xFF4, (chan)) - -#define QAIF_EE_RDDMA_IRQ_REG_ADDR(v, dma_type, offset) \ - ((dma_type) == QAIF_AIF_IRQ ? \ - ((v)->rddma_irq_reg_base + (offset) + (v)->rddma_irq_stride * ((v)->ee)) : \ - ((v)->codec_rddma_irq_reg_base + (offset) + \ - (v)->codec_rddma_irq_stride * ((v)->ee))) +#define QAIF_RATE_DET_REG_ADDR(offset, det) (0x1E000 + (offset) + (0x1000 * (det))) + +#define QAIF_RATE_DET_CONFIG_REG(det) QAIF_RATE_DET_REG_ADDR(0x0000, (det)) +#define QAIF_RATE_DET_TARGET1_CONF_REG(det) QAIF_RATE_DET_REG_ADDR(0x0004, (det)) +#define QAIF_RATE_DET_TARGET2_CONF_REG(det) QAIF_RATE_DET_REG_ADDR(0x0008, (det)) +#define QAIF_RATE_DET_BIN_REG(det) QAIF_RATE_DET_REG_ADDR(0x000C, (det)) +#define QAIF_RATE_DET_STC_DIFF_REG(det) QAIF_RATE_DET_REG_ADDR(0x0010, (det)) +#define QAIF_RATE_DET_SEL_REG(det) QAIF_RATE_DET_REG_ADDR(0x0014, (det)) +#define QAIF_RATE_DET_TIMEOUT_CFG_REG(det) QAIF_RATE_DET_REG_ADDR(0x0018, (det)) + +#define QAIF_WRDMA_MAP_QXM (0x1000) +#define QAIF_CDC_WRDMA_MAP_QXM (0x1004) +#define QAIF_RDDMA_MAP_QXM (0x1010) +#define QAIF_CDC_RDDMA_MAP_QXM (0x1014) +#define QAIF_RDDMA_QXM1_SHRAM_ST_ADDR(i) (0x1100 + (0x4 * (i))) +#define QAIF_CDC_RDDMA_QXM1_SHRAM_ST_ADDR(i) (0x1140 + (0x4 * (i))) +#define QAIF_RDDMA_QXM0_SHRAM_ST_ADDR(i) (0x1200 + (0x4 * (i))) +#define QAIF_CDC_RDDMA_QXM0_SHRAM_ST_ADDR(i) (0x1240 + (0x4 * (i))) +#define QAIF_RDDMA_QXM1_SHRAM_LEN(i) (0x1300 + (0x4 * (i))) +#define QAIF_CDC_RDDMA_QXM1_SHRAM_LEN(i) (0x1340 + (0x4 * (i))) +#define QAIF_RDDMA_QXM0_SHRAM_LEN(i) (0x1400 + (0x4 * (i))) +#define QAIF_CDC_RDDMA_QXM0_SHRAM_LEN(i) (0x1440 + (0x4 * (i))) +#define QAIF_WRDMA_QXM1_SHRAM_ST_ADDR(i) (0x1500 + (0x4 * (i))) +#define QAIF_CDC_WRDMA_QXM1_SHRAM_ST_ADDR(i) (0x1540 + (0x4 * (i))) +#define QAIF_WRDMA_QXM0_SHRAM_ST_ADDR(i) (0x1600 + (0x4 * (i))) +#define QAIF_CDC_WRDMA_QXM0_SHRAM_ST_ADDR(i) (0x1640 + (0x4 * (i))) +#define QAIF_WRDMA_QXM1_SHRAM_LEN(i) (0x1700 + (0x4 * (i))) +#define QAIF_CDC_WRDMA_QXM1_SHRAM_LEN(i) (0x1740 + (0x4 * (i))) +#define QAIF_WRDMA_QXM0_SHRAM_LEN(i) (0x1800 + (0x4 * (i))) +#define QAIF_CDC_WRDMA_QXM0_SHRAM_LEN(i) (0x1840 + (0x4 * (i))) + +/* RDDMA */ +static inline u32 qaif_rddma_reg_addr(const struct qaif_variant *v, + u32 offset, u32 i) +{ + return v->rddma_reg_base + offset + v->rddma_stride * i; +} + +#define QAIF_RDDMA_CTL_REG(v, i) qaif_rddma_reg_addr(v, 0x00, (i)) +#define QAIF_RDDMA_CFG_REG(v, i) qaif_rddma_reg_addr(v, 0x04, (i)) +#define QAIF_RDDMA_BASE_ADDR_REG(v, i) qaif_rddma_reg_addr(v, 0x08, (i)) +#define QAIF_RDDMA_BUFF_LEN_REG(v, i) qaif_rddma_reg_addr(v, 0x10, (i)) +#define QAIF_RDDMA_CURR_ADDR_REG(v, i) qaif_rddma_reg_addr(v, 0x14, (i)) +#define QAIF_RDDMA_PERIOD_LEN_REG(v, i) qaif_rddma_reg_addr(v, 0x1C, (i)) +#define QAIF_RDDMA_PERIOD_CNT_REG(v, i) qaif_rddma_reg_addr(v, 0x20, (i)) +#define QAIF_RDDMA_SHRAM_WORDCNT_REG(v, i) qaif_rddma_reg_addr(v, 0x24, (i)) +#define QAIF_RDDMA_FRAME_STATUS_REG(v, i) qaif_rddma_reg_addr(v, 0x28, (i)) +#define QAIF_RDDMA_FRAME_STATUS_EXTN_REG(v, i) qaif_rddma_reg_addr(v, 0x2C, (i)) +#define QAIF_RDDMA_FRAME_STATUS_CLR_REG(v, i) qaif_rddma_reg_addr(v, 0x30, (i)) +#define QAIF_RDDMA_SET_BUFF_CNT_REG(v, i) qaif_rddma_reg_addr(v, 0x34, (i)) +#define QAIF_RDDMA_SET_PERIOD_CNT_REG(v, i) qaif_rddma_reg_addr(v, 0x38, (i)) +#define QAIF_RDDMA_STC_LSB_REG(v, i) qaif_rddma_reg_addr(v, 0x3C, (i)) +#define QAIF_RDDMA_STC_MSB_REG(v, i) qaif_rddma_reg_addr(v, 0x40, (i)) +#define QAIF_RDDMA_PERIOD_DET_STAT_REG(v, i) qaif_rddma_reg_addr(v, 0x44, (i)) +#define QAIF_RDDMA_PERIOD_DET_CLR_REG(v, i) qaif_rddma_reg_addr(v, 0x48, (i)) +#define QAIF_RDDMA_FORMAT_ERR_REG(v, i) qaif_rddma_reg_addr(v, 0x4C, (i)) +#define QAIF_RDDMA_AHB_BYPASS_REG(v, i) qaif_rddma_reg_addr(v, 0x50, (i)) +#define QAIF_RDDMA_SHUTDOWN_STAT_REG(v, i) qaif_rddma_reg_addr(v, 0x54, (i)) +#define QAIF_RDDMA_PADDING_CFG_REG(v, i) qaif_rddma_reg_addr(v, 0x58, (i)) +#define QAIF_RDDMA_STATUS_REG(v, i) qaif_rddma_reg_addr(v, 0x60, (i)) +#define QAIF_RDDMA_DBG_STATUS_REG(v, i) qaif_rddma_reg_addr(v, 0xFF0, (i)) + +static inline u32 qaif_codec_rddma_reg_addr(const struct qaif_variant *v, + u32 offset, u32 i) +{ + return v->codec_rddma_reg_base + offset + v->codec_rddma_stride * i; +} + +#define QAIF_CDC_RDDMA_CTL_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x00, (i)) +#define QAIF_CDC_RDDMA_CFG_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x04, (i)) +#define QAIF_CDC_RDDMA_BASE_ADDR_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x08, (i)) +#define QAIF_CDC_RDDMA_BUFF_LEN_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x10, (i)) +#define QAIF_CDC_RDDMA_CURR_ADDR_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x14, (i)) +#define QAIF_CDC_RDDMA_PERIOD_LEN_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x1C, (i)) +#define QAIF_CDC_RDDMA_PERIOD_CNT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x20, (i)) +#define QAIF_CDC_RDDMA_SHRAM_WORDCNT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x24, (i)) +#define QAIF_CDC_RDDMA_FRAME_STAT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x28, (i)) +#define QAIF_CDC_RDDMA_FRAME_STAT_EXTN_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x2C, (i)) +#define QAIF_CDC_RDDMA_FRAME_STAT_CLR_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x30, (i)) +#define QAIF_CDC_RDDMA_SET_BUFF_CNT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x34, (i)) +#define QAIF_CDC_RDDMA_SET_PERIOD_CNT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x38, (i)) +#define QAIF_CDC_RDDMA_STC_LSB_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x3C, (i)) +#define QAIF_CDC_RDDMA_STC_MSB_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x40, (i)) +#define QAIF_CDC_RDDMA_PERIOD_DET_STAT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x44, (i)) +#define QAIF_CDC_RDDMA_PERIOD_DET_CLR_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x48, (i)) +#define QAIF_CDC_RDDMA_FORMAT_ERR_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x4C, (i)) +#define QAIF_CDC_RDDMA_AHB_BYPASS_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x50, (i)) +#define QAIF_CDC_RDDMA_SHUTDOWN_STAT_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x54, (i)) +#define QAIF_CDC_RDDMA_PADDING_CFG_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x58, (i)) +#define QAIF_CDC_RDDMA_INTF_CFG_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x5C, (i)) +#define QAIF_CDC_RDDMA_STATUS_REG(v, i) qaif_codec_rddma_reg_addr(v, 0x60, (i)) +#define QAIF_CDC_RDDMA_DBG_STATUS_REG(v, i) qaif_codec_rddma_reg_addr(v, 0xFF0, (i)) +#define QAIF_CDC_RDDMA_INTF_DBG_STATUS_REG(v, i) qaif_codec_rddma_reg_addr(v, 0xFF4, (i)) + +/* WRDMA */ +static inline u32 qaif_wrdma_reg_addr(const struct qaif_variant *v, + u32 offset, u32 i) +{ + return v->wrdma_reg_base + offset + v->wrdma_stride * i; +} + +#define QAIF_WRDMA_CTL_REG(v, i) qaif_wrdma_reg_addr(v, 0x00, (i)) +#define QAIF_WRDMA_CFG_REG(v, i) qaif_wrdma_reg_addr(v, 0x04, (i)) +#define QAIF_WRDMA_BASE_ADDR_REG(v, i) qaif_wrdma_reg_addr(v, 0x08, (i)) +#define QAIF_WRDMA_BUFF_LEN_REG(v, i) qaif_wrdma_reg_addr(v, 0x10, (i)) +#define QAIF_WRDMA_CURR_ADDR_REG(v, i) qaif_wrdma_reg_addr(v, 0x14, (i)) +#define QAIF_WRDMA_PERIOD_LEN_REG(v, i) qaif_wrdma_reg_addr(v, 0x1C, (i)) +#define QAIF_WRDMA_PERIOD_CNT_REG(v, i) qaif_wrdma_reg_addr(v, 0x20, (i)) +#define QAIF_WRDMA_SHRAM_WORDCNT_REG(v, i) qaif_wrdma_reg_addr(v, 0x24, (i)) +#define QAIF_WRDMA_FRAME_STATUS_REG(v, i) qaif_wrdma_reg_addr(v, 0x28, (i)) +#define QAIF_WRDMA_FRAME_STATUS_EXTN_REG(v, i) qaif_wrdma_reg_addr(v, 0x2C, (i)) +#define QAIF_WRDMA_FRAME_STATUS_CLR_REG(v, i) qaif_wrdma_reg_addr(v, 0x30, (i)) +#define QAIF_WRDMA_SET_BUFF_CNT_REG(v, i) qaif_wrdma_reg_addr(v, 0x34, (i)) +#define QAIF_WRDMA_SET_PERIOD_CNT_REG(v, i) qaif_wrdma_reg_addr(v, 0x38, (i)) +#define QAIF_WRDMA_STC_LSB_REG(v, i) qaif_wrdma_reg_addr(v, 0x3C, (i)) +#define QAIF_WRDMA_STC_MSB_REG(v, i) qaif_wrdma_reg_addr(v, 0x40, (i)) +#define QAIF_WRDMA_PERIOD_DET_STAT_REG(v, i) qaif_wrdma_reg_addr(v, 0x44, (i)) +#define QAIF_WRDMA_PERIOD_DET_CLR_REG(v, i) qaif_wrdma_reg_addr(v, 0x48, (i)) +#define QAIF_WRDMA_FORMAT_ERR_REG(v, i) qaif_wrdma_reg_addr(v, 0x4C, (i)) +#define QAIF_WRDMA_AHB_BYPASS_REG(v, i) qaif_wrdma_reg_addr(v, 0x50, (i)) +#define QAIF_WRDMA_SHUTDOWN_STAT_REG(v, i) qaif_wrdma_reg_addr(v, 0x54, (i)) +#define QAIF_WRDMA_DBG_STATUS_REG(v, i) qaif_wrdma_reg_addr(v, 0xFF0, (i)) + +static inline u32 qaif_codec_wrdma_reg_addr(const struct qaif_variant *v, + u32 offset, u32 i) +{ + return v->codec_wrdma_reg_base + offset + v->codec_wrdma_stride * i; +} + +#define QAIF_CDC_WRDMA_CTL_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x00, (i)) +#define QAIF_CDC_WRDMA_CFG_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x04, (i)) +#define QAIF_CDC_WRDMA_BASE_ADDR_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x08, (i)) +#define QAIF_CDC_WRDMA_BUFF_LEN_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x10, (i)) +#define QAIF_CDC_WRDMA_CURR_ADDR_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x14, (i)) +#define QAIF_CDC_WRDMA_PERIOD_LEN_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x1C, (i)) +#define QAIF_CDC_WRDMA_PERIOD_CNT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x20, (i)) +#define QAIF_CDC_WRDMA_SHRAM_WORDCNT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x24, (i)) +#define QAIF_CDC_WRDMA_FRAME_STAT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x28, (i)) +#define QAIF_CDC_WRDMA_FRAME_STAT_EXTN_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x2C, (i)) +#define QAIF_CDC_WRDMA_FRAME_STAT_CLR_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x30, (i)) +#define QAIF_CDC_WRDMA_SET_BUFF_CNT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x34, (i)) +#define QAIF_CDC_WRDMA_SET_PERIOD_CNT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x38, (i)) +#define QAIF_CDC_WRDMA_STC_LSB_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x3C, (i)) +#define QAIF_CDC_WRDMA_STC_MSB_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x40, (i)) +#define QAIF_CDC_WRDMA_PERIOD_DET_STAT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x44, (i)) +#define QAIF_CDC_WRDMA_PERIOD_DET_CLR_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x48, (i)) +#define QAIF_CDC_WRDMA_FORMAT_ERR_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x4C, (i)) +#define QAIF_CDC_WRDMA_AHB_BYPASS_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x50, (i)) +#define QAIF_CDC_WRDMA_SHUTDOWN_STAT_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x54, (i)) +#define QAIF_CDC_WRDMA_INTF_CFG_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0x58, (i)) +#define QAIF_CDC_WRDMA_DBG_STATUS_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0xFF0, (i)) +#define QAIF_CDC_WRDMA_INTF_DBG_STATUS_REG(v, i) qaif_codec_wrdma_reg_addr(v, 0xFF4, (i)) + +static inline u32 qaif_rddma_irq_reg_addr(const struct qaif_variant *v, + enum qaif_irq_type dma_type, + u32 offset) +{ + if (dma_type == QAIF_AIF_IRQ) + return v->rddma_irq_reg_base + offset + + v->rddma_irq_stride * v->ee; + return v->codec_rddma_irq_reg_base + offset + + v->codec_rddma_irq_stride * v->ee; +} /* RDDMA Period Interrupts */ -#define QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x00) -#define QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x08) -#define QAIF_EE_RDDMA_PERIOD_IRQ_RAW_STAT_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x10) -#define QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x18) -#define QAIF_EE_RDDMA_PERIOD_IRQ_FORCE_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x20) +#define QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x00) +#define QAIF_EE_RDDMA_PERIOD_IRQ_STAT_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x08) +#define QAIF_EE_RDDMA_PERIOD_IRQ_RAW_STAT_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x10) +#define QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x18) +#define QAIF_EE_RDDMA_PERIOD_IRQ_FORCE_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x20) /* RDDMA Underflow Interrupts */ -#define QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x28) -#define QAIF_EE_RDDMA_UNDERFLOW_IRQ_STAT_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x30) -#define QAIF_EE_RDDMA_UNDERFLOW_IRQ_RAW_STAT_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x38) -#define QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x40) -#define QAIF_EE_RDDMA_UNDERFLOW_IRQ_FORCE_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x48) +#define QAIF_EE_RDDMA_UF_IRQ_EN_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x28) +#define QAIF_EE_RDDMA_UF_IRQ_STAT_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x30) +#define QAIF_EE_RDDMA_UF_IRQ_RAW_STAT_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x38) +#define QAIF_EE_RDDMA_UF_IRQ_CLR_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x40) +#define QAIF_EE_RDDMA_UF_IRQ_FORCE_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x48) /* RDDMA Error Response Interrupts */ -#define QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x50) -#define QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x58) -#define QAIF_EE_RDDMA_ERR_RSP_IRQ_RAW_STAT_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x60) -#define QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x68) -#define QAIF_EE_RDDMA_ERR_RSP_IRQ_FORCE_REG(v, i) \ - QAIF_EE_RDDMA_IRQ_REG_ADDR(v, i, 0x70) - -#define QAIF_EE_WRDMA_IRQ_REG_ADDR(v, dma_type, offset) \ - ((dma_type) == QAIF_AIF_IRQ ? \ - ((v)->wrdma_irq_reg_base + (offset) + (v)->wrdma_irq_stride * ((v)->ee)) : \ - ((v)->codec_wrdma_irq_reg_base + (offset) + \ - (v)->codec_wrdma_irq_stride * ((v)->ee))) +#define QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x50) +#define QAIF_EE_RDDMA_ERR_RSP_IRQ_STAT_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x58) +#define QAIF_EE_RDDMA_ERR_RSP_IRQ_RAW_STAT(v, i) qaif_rddma_irq_reg_addr(v, i, 0x60) +#define QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x68) +#define QAIF_EE_RDDMA_ERR_RSP_IRQ_FORCE_REG(v, i) qaif_rddma_irq_reg_addr(v, i, 0x70) + +static inline u32 qaif_wrdma_irq_reg_addr(const struct qaif_variant *v, + enum qaif_irq_type dma_type, + u32 offset) +{ + if (dma_type == QAIF_AIF_IRQ) + return v->wrdma_irq_reg_base + offset + + v->wrdma_irq_stride * v->ee; + return v->codec_wrdma_irq_reg_base + offset + + v->codec_wrdma_irq_stride * v->ee; +} /* WRDMA Period Interrupts */ -#define QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x00) -#define QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x08) -#define QAIF_EE_WRDMA_PERIOD_IRQ_RAW_STAT_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x10) -#define QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x18) -#define QAIF_EE_WRDMA_PERIOD_IRQ_FORCE_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x20) +#define QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x00) +#define QAIF_EE_WRDMA_PERIOD_IRQ_STAT_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x08) +#define QAIF_EE_WRDMA_PERIOD_IRQ_RAW_STAT_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x10) +#define QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x18) +#define QAIF_EE_WRDMA_PERIOD_IRQ_FORCE_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x20) /* WRDMA Overflow Interrupts */ -#define QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x28) -#define QAIF_EE_WRDMA_OVERFLOW_IRQ_STAT_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x30) -#define QAIF_EE_WRDMA_OVERFLOW_IRQ_RAW_STAT_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x38) -#define QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x40) -#define QAIF_EE_WRDMA_OVERFLOW_IRQ_FORCE_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x48) +#define QAIF_EE_WRDMA_OF_IRQ_EN_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x28) +#define QAIF_EE_WRDMA_OF_IRQ_STAT_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x30) +#define QAIF_EE_WRDMA_OF_IRQ_RAW_STAT_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x38) +#define QAIF_EE_WRDMA_OF_IRQ_CLR_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x40) +#define QAIF_EE_WRDMA_OF_IRQ_FORCE_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x48) /* WRDMA Error Response Interrupts */ -#define QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x50) -#define QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x58) -#define QAIF_EE_WRDMA_ERR_RSP_IRQ_RAW_STAT_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x60) -#define QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x68) -#define QAIF_EE_WRDMA_ERR_RSP_IRQ_FORCE_REG(v, i) \ - QAIF_EE_WRDMA_IRQ_REG_ADDR(v, i, 0x70) - -#define QAIF_DMACFG_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, CFG) : \ - __QAIF_DMA_REG(v, chan, dir, CFG)) - -#define QAIF_DMACTL_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, CTL) : \ - __QAIF_DMA_REG(v, chan, dir, CTL)) - -#define QAIF_DMABUFF_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, BUFF_LEN) : \ - __QAIF_DMA_REG(v, chan, dir, BUFF_LEN)) - -#define QAIF_DMACURR_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, CURR_ADDR) : \ - __QAIF_DMA_REG(v, chan, dir, CURR_ADDR)) - -#define QAIF_DMAPER_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, PERIOD_CNT) : \ - __QAIF_DMA_REG(v, chan, dir, PERIOD_CNT)) - -#define QAIF_DMAPER_LEN_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, PERIOD_LEN) : \ - __QAIF_DMA_REG(v, chan, dir, PERIOD_LEN)) - -#define QAIF_DMABASE_REG(v, chan, dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_DMA_REG(v, chan, dir, BASE_ADDR) : \ - __QAIF_DMA_REG(v, chan, dir, BASE_ADDR)) - -#define __QAIF_CDC_DMA_REG(v, chan, dir, reg) \ - (((dir) == SNDRV_PCM_STREAM_PLAYBACK) ? \ - __QAIF_CDC_RDDMA_REG(v, chan, reg) : \ - __QAIF_CDC_WRDMA_REG(v, chan, reg)) - -#define __QAIF_DMA_REG(v, chan, dir, reg) \ - (((dir) == SNDRV_PCM_STREAM_PLAYBACK) ? \ - (QAIF_RDDMA_##reg##_REG(v, chan)) : \ - QAIF_WRDMA_##reg##_REG(v, chan)) - -#define __QAIF_CDC_RDDMA_REG(v, chan, reg) \ - QAIF_CODEC_RDDMA_##reg##_REG(v, chan) - -#define __QAIF_CDC_WRDMA_REG(v, chan, reg) \ - QAIF_CODEC_WRDMA_##reg##_REG(v, chan) - -#define QAIF_SID_MAP_REG(dir, dai_id) \ - (is_cif_dma_port(dai_id) ? \ - __QAIF_CDC_SID_MAP_REG(dir) : \ - __QAIF_SID_MAP_REG(dir)) - -#define __QAIF_SID_MAP_REG(dir) \ - (((dir) == SNDRV_PCM_STREAM_PLAYBACK) ? \ - QAIF_RDDMA_SID_MAP_REG : \ - QAIF_WRDMA_SID_MAP_REG) - -#define __QAIF_CDC_SID_MAP_REG(dir) \ - (((dir) == SNDRV_PCM_STREAM_PLAYBACK) ? \ - QAIF_CODEC_RDDMA_SID_MAP_REG : \ - QAIF_CODEC_WRDMA_SID_MAP_REG) - -#endif /* __QAIF_REG_H__ */ +#define QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x50) +#define QAIF_EE_WRDMA_ERR_RSP_IRQ_STAT_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x58) +#define QAIF_EE_WRDMA_ERR_RSP_IRQ_RAW_STAT(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x60) +#define QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x68) +#define QAIF_EE_WRDMA_ERR_RSP_IRQ_FORCE_REG(v, i) qaif_wrdma_irq_reg_addr(v, i, 0x70) + +static inline u32 qaif_dmacfg_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_CFG_REG(v, i) : + QAIF_CDC_WRDMA_CFG_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_CFG_REG(v, i) : QAIF_WRDMA_CFG_REG(v, i); +} + +static inline u32 qaif_dmactl_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_CTL_REG(v, i) : + QAIF_CDC_WRDMA_CTL_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_CTL_REG(v, i) : QAIF_WRDMA_CTL_REG(v, i); +} + +static inline u32 qaif_dmabuff_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_BUFF_LEN_REG(v, i) : + QAIF_CDC_WRDMA_BUFF_LEN_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_BUFF_LEN_REG(v, i) : QAIF_WRDMA_BUFF_LEN_REG(v, i); +} + +static inline u32 qaif_dmacurr_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_CURR_ADDR_REG(v, i) : + QAIF_CDC_WRDMA_CURR_ADDR_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_CURR_ADDR_REG(v, i) : QAIF_WRDMA_CURR_ADDR_REG(v, i); +} + +static inline u32 qaif_dmaper_cnt_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_PERIOD_CNT_REG(v, i) : + QAIF_CDC_WRDMA_PERIOD_CNT_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_PERIOD_CNT_REG(v, i) : QAIF_WRDMA_PERIOD_CNT_REG(v, i); +} + +static inline u32 qaif_dmaper_len_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_PERIOD_LEN_REG(v, i) : + QAIF_CDC_WRDMA_PERIOD_LEN_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_PERIOD_LEN_REG(v, i) : QAIF_WRDMA_PERIOD_LEN_REG(v, i); +} + +static inline u32 qaif_dmabase_reg(const struct qaif_variant *v, + u32 i, int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_BASE_ADDR_REG(v, i) : + QAIF_CDC_WRDMA_BASE_ADDR_REG(v, i); + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_BASE_ADDR_REG(v, i) : QAIF_WRDMA_BASE_ADDR_REG(v, i); +} + +static inline u32 qaif_sid_map_reg(int dir, unsigned int dai_id) +{ + if (qaif_is_cif_port(dai_id)) + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_CDC_RDDMA_SID_MAP_REG : + QAIF_CDC_WRDMA_SID_MAP_REG; + return dir == SNDRV_PCM_STREAM_PLAYBACK ? + QAIF_RDDMA_SID_MAP_REG : QAIF_WRDMA_SID_MAP_REG; +} + +#endif /* SND_SOC_QCOM_QAIF_REG_H */ diff --git a/sound/soc/qcom/qaif-shikra.c b/sound/soc/qcom/qaif-shikra.c index 3a055496b6969..0d5c2baade28f 100644 --- a/sound/soc/qcom/qaif-shikra.c +++ b/sound/soc/qcom/qaif-shikra.c @@ -6,137 +6,246 @@ */ #include +#include #include #include -#include #include "qaif.h" -struct qaif_dmaidx_dai_map shikra_aif_dma_dai_map[] = { - { QAIF_MI2S_TDM_AIF0 }, - { QAIF_MI2S_TDM_AIF1 }, - { QAIF_MI2S_TDM_AIF2 }, - { QAIF_MI2S_TDM_AIF3 } +static const struct qaif_dmaidx_dai_map shikra_mi2s_dma_dai_map[] = { + { AIF_MI2S_RX_0, QAIF_DMA_IDX0 }, + { AIF_MI2S_RX_1, QAIF_DMA_IDX1 }, + { AIF_MI2S_RX_2, QAIF_DMA_IDX2 }, + { AIF_MI2S_RX_3, QAIF_DMA_IDX3 }, + { AIF_MI2S_TX_0, QAIF_DMA_IDX0 }, + { AIF_MI2S_TX_1, QAIF_DMA_IDX1 }, + { AIF_MI2S_TX_2, QAIF_DMA_IDX2 }, + { AIF_MI2S_TX_3, QAIF_DMA_IDX3 }, }; -struct qaif_dmaidx_dai_map shikra_cif_rx_dma_dai_map[] = { - { QAIF_CDC_DMA_RX0 }, - { QAIF_CDC_DMA_RX1 }, - { QAIF_CDC_DMA_RX2 }, - { QAIF_CDC_DMA_RX3 } +static const struct qaif_dmaidx_dai_map shikra_tdm_dma_dai_map[] = { + { AIF_TDM_RX_0, QAIF_DMA_IDX0 }, + { AIF_TDM_RX_1, QAIF_DMA_IDX1 }, + { AIF_TDM_RX_2, QAIF_DMA_IDX2 }, + { AIF_TDM_RX_3, QAIF_DMA_IDX3 }, + { AIF_TDM_TX_0, QAIF_DMA_IDX0 }, + { AIF_TDM_TX_1, QAIF_DMA_IDX1 }, + { AIF_TDM_TX_2, QAIF_DMA_IDX2 }, + { AIF_TDM_TX_3, QAIF_DMA_IDX3 }, }; -struct qaif_dmaidx_dai_map shikra_cif_tx_dma_dai_map[] = { - { QAIF_CDC_DMA_TX0 }, - { QAIF_CDC_DMA_TX1 }, - { QAIF_CDC_DMA_TX2 }, - { QAIF_CDC_DMA_TX3 } -}; - -struct qaif_dmaidx_dai_map shikra_cif_va_dma_dai_map[] = { - { QAIF_CDC_DMA_VA_TX0 }, - { QAIF_CDC_DMA_VA_TX1 }, - { QAIF_CDC_DMA_VA_TX2 }, - { QAIF_CDC_DMA_VA_TX3 } +static const struct qaif_dmaidx_dai_map shikra_cif_dma_dai_map[] = { + { RX_CODEC_DMA_RX_0, QAIF_DMA_IDX0 }, + { RX_CODEC_DMA_RX_1, QAIF_DMA_IDX1 }, + { VA_CODEC_DMA_TX_0, QAIF_DMA_IDX0 }, + { VA_CODEC_DMA_TX_1, QAIF_DMA_IDX1 }, }; static struct snd_soc_dai_driver shikra_qaif_cpu_dai_driver[] = { { - .id = QAIF_MI2S_TDM_AIF0, - .name = "Audio Interface Zero", + .id = AIF_MI2S_RX_0, + .name = "MI2S AIF RX Zero", .playback = { - .stream_name = "AIF Zero Playback", - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "MI2S AIF RX Zero Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_TX_0, + .name = "MI2S AIF TX Zero", .capture = { - .stream_name = "AIF Zero Capture", - .formats = SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_S32, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "MI2S AIF TX Zero Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, }, { - .id = QAIF_MI2S_TDM_AIF1, - .name = "Audio Interface One", + .id = AIF_TDM_RX_0, + .name = "TDM AIF RX Zero", .playback = { - .stream_name = "AIF One Playback", - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "TDM AIF RX Zero Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_TDM_TX_0, + .name = "TDM AIF TX Zero", + .capture = { + .stream_name = "TDM AIF TX Zero Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_RX_1, + .name = "MI2S AIF RX One", + .playback = { + .stream_name = "MI2S AIF RX One Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_TX_1, + .name = "MI2S AIF TX One", .capture = { - .stream_name = "AIF One Capture", - .formats = SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_S32, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "MI2S AIF TX One Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, }, { - .id = QAIF_MI2S_TDM_AIF2, - .name = "Audio Interface Two", + .id = AIF_TDM_RX_1, + .name = "TDM AIF RX One", .playback = { - .stream_name = "AIF Two Playback", - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "TDM AIF RX One Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_TDM_TX_1, + .name = "TDM AIF TX One", + .capture = { + .stream_name = "TDM AIF TX One Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_RX_2, + .name = "MI2S AIF RX Two", + .playback = { + .stream_name = "MI2S AIF RX Two Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_TX_2, + .name = "MI2S AIF TX Two", .capture = { - .stream_name = "AIF Two Capture", - .formats = SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_S32, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "MI2S AIF TX Two Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, }, { - .id = QAIF_MI2S_TDM_AIF3, - .name = "Audio Interface Three", + .id = AIF_TDM_RX_2, + .name = "TDM AIF RX Two", .playback = { - .stream_name = "AIF Three Playback", - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "TDM AIF RX Two Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_TDM_TX_2, + .name = "TDM AIF TX Two", + .capture = { + .stream_name = "TDM AIF TX Two Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_RX_3, + .name = "MI2S AIF RX Three", + .playback = { + .stream_name = "MI2S AIF RX Three Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_MI2S_TX_3, + .name = "MI2S AIF TX Three", .capture = { - .stream_name = "AIF Three Capture", - .formats = SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_S32, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, + .stream_name = "MI2S AIF TX Three Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, .channels_max = 2, }, .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, }, { - .id = QAIF_CDC_DMA_RX0, - .name = "CDC DMA RX0", + .id = AIF_TDM_RX_3, + .name = "TDM AIF RX Three", .playback = { - .stream_name = "WCD Playback0", + .stream_name = "TDM AIF RX Three Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = AIF_TDM_TX_3, + .name = "TDM AIF TX Three", + .capture = { + .stream_name = "TDM AIF TX Three Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &asoc_qcom_qaif_aif_cpu_dai_ops, + }, { + .id = RX_CODEC_DMA_RX_0, + .name = "RX CDC DMA RX0", + .playback = { + .stream_name = "RX CDC DMA RX0 Playback", .formats = SNDRV_PCM_FMTBIT_S16, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, @@ -146,10 +255,10 @@ static struct snd_soc_dai_driver shikra_qaif_cpu_dai_driver[] = { }, .ops = &asoc_qcom_qaif_cif_dai_ops, }, { - .id = QAIF_CDC_DMA_RX1, - .name = "CDC DMA RX1", + .id = RX_CODEC_DMA_RX_1, + .name = "RX CDC DMA RX1", .playback = { - .stream_name = "WCD Playback1", + .stream_name = "RX CDC DMA RX1 Playback", .formats = SNDRV_PCM_FMTBIT_S16, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, @@ -159,10 +268,10 @@ static struct snd_soc_dai_driver shikra_qaif_cpu_dai_driver[] = { }, .ops = &asoc_qcom_qaif_cif_dai_ops, }, { - .id = QAIF_CDC_DMA_VA_TX0, - .name = "CDC DMA VA0", + .id = VA_CODEC_DMA_TX_0, + .name = "VA CDC DMA TX0", .capture = { - .stream_name = "DMIC Capture0", + .stream_name = "VA CDC DMA TX0 Capture", .formats = SNDRV_PCM_FMTBIT_S16, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, @@ -172,10 +281,10 @@ static struct snd_soc_dai_driver shikra_qaif_cpu_dai_driver[] = { }, .ops = &asoc_qcom_qaif_cif_dai_ops, }, { - .id = QAIF_CDC_DMA_VA_TX1, - .name = "CDC DMA VA1", + .id = VA_CODEC_DMA_TX_1, + .name = "VA CDC DMA TX1", .capture = { - .stream_name = "DMIC Capture1", + .stream_name = "VA CDC DMA TX1 Capture", .formats = SNDRV_PCM_FMTBIT_S16, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, @@ -189,94 +298,53 @@ static struct snd_soc_dai_driver shikra_qaif_cpu_dai_driver[] = { static int shikra_qaif_get_dma_idx(unsigned int dai_id) { - int i; - - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - for (i = 0; i < ARRAY_SIZE(shikra_aif_dma_dai_map); i++) { - if (shikra_aif_dma_dai_map[i].dai_id == dai_id) - return i; - } - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - for (i = 0; i < ARRAY_SIZE(shikra_cif_rx_dma_dai_map); i++) { - if (shikra_cif_rx_dma_dai_map[i].dai_id == dai_id) - return i; - } - break; - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - for (i = 0; i < ARRAY_SIZE(shikra_cif_tx_dma_dai_map); i++) { - if (shikra_cif_tx_dma_dai_map[i].dai_id == dai_id) - return i; - } - break; - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - for (i = 0; i < ARRAY_SIZE(shikra_cif_va_dma_dai_map); i++) { - if (shikra_cif_va_dma_dai_map[i].dai_id == dai_id) - return i; - } - break; - default: - pr_debug("DAI ID not Supported\n"); - break; + const struct qaif_dmaidx_dai_map *map; + int i, size; + + if (dai_id >= AIF_MI2S_RX_0 && dai_id <= AIF_MI2S_TX_12) { + map = shikra_mi2s_dma_dai_map; + size = ARRAY_SIZE(shikra_mi2s_dma_dai_map); + } else if (dai_id >= AIF_TDM_RX_0 && dai_id <= AIF_TDM_TX_12) { + map = shikra_tdm_dma_dai_map; + size = ARRAY_SIZE(shikra_tdm_dma_dai_map); + } else { + map = shikra_cif_dma_dai_map; + size = ARRAY_SIZE(shikra_cif_dma_dai_map); } - pr_debug("DAI ID %u not found in map\n", dai_id); + for (i = 0; i < size; i++) { + if (map[i].dai_id == dai_id) + return map[i].dma_idx; + } return -EINVAL; } static int shikra_qaif_alloc_stream_dma_idx(struct qaif_drv_data *drvdata, - int direction, unsigned int dai_id) + int direction, + unsigned int dai_id) { const struct qaif_variant *v = drvdata->variant; - int dma_idx; - int index = 0; - - if (!v) - return -EINVAL; - - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: - dma_idx = shikra_qaif_get_dma_idx(dai_id); - if (dma_idx < 0) - return dma_idx; - - if (direction == SNDRV_PCM_STREAM_PLAYBACK) { - index = dma_idx; - if (index >= v->num_rddma) - return -EBUSY; - } else { - index = v->wrdma_start + dma_idx; - if (index >= v->wrdma_start + v->num_wrdma) - return -EBUSY; - } - if (test_bit(index, &drvdata->aif_dma_idx_bit_map)) + int dma_idx, index; + + dma_idx = shikra_qaif_get_dma_idx(dai_id); + if (dma_idx < 0) + return dma_idx; + + if (qaif_is_aif_port(dai_id)) { + index = (direction == SNDRV_PCM_STREAM_PLAYBACK) ? + dma_idx : v->wrdma_start + dma_idx; + if (index >= QAIF_MAX_AIF_DMA_IDX) + return -EINVAL; + if (test_and_set_bit(index, &drvdata->aif_dma_idx_bit_map)) return -EBUSY; - - set_bit(index, &drvdata->aif_dma_idx_bit_map); - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - dma_idx = shikra_qaif_get_dma_idx(dai_id); - if (dma_idx < 0) - return dma_idx; - - if (direction == SNDRV_PCM_STREAM_PLAYBACK) { - index = dma_idx; - if (index >= v->num_codec_rddma) - return -EBUSY; - } else { - index = v->codec_wrdma_start + dma_idx; - if (index >= v->codec_wrdma_start + v->num_codec_wrdma) - return -EBUSY; - } - if (test_bit(index, &drvdata->cif_dma_idx_bit_map)) + } else if (qaif_is_cif_port(dai_id)) { + index = (direction == SNDRV_PCM_STREAM_PLAYBACK) ? + dma_idx : v->codec_wrdma_start + dma_idx; + if (index >= QAIF_MAX_CIF_DMA_IDX) + return -EINVAL; + if (test_and_set_bit(index, &drvdata->cif_dma_idx_bit_map)) return -EBUSY; - - set_bit(index, &drvdata->cif_dma_idx_bit_map); - break; - default: + } else { return -EINVAL; } @@ -284,106 +352,18 @@ static int shikra_qaif_alloc_stream_dma_idx(struct qaif_drv_data *drvdata, } static int shikra_qaif_free_stream_dma_idx(struct qaif_drv_data *drvdata, - int index, unsigned int dai_id) + int index, + unsigned int dai_id) { - switch (dai_id) { - case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12: + if (qaif_is_aif_port(dai_id)) clear_bit(index, &drvdata->aif_dma_idx_bit_map); - break; - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: + else clear_bit(index, &drvdata->cif_dma_idx_bit_map); - break; - default: - break; - } - return 0; } -static int shikra_qaif_init(struct platform_device *pdev) -{ - struct qaif_drv_data *drvdata = platform_get_drvdata(pdev); - const struct qaif_variant *v = drvdata->variant; - struct device *dev = &pdev->dev; - int ret, i; - - if (!v) { - dev_err(dev, "No variant data\n"); - return -EINVAL; - } - if (v->num_clks == 0 || v->num_clks > QAIF_MAX_VARIANT_CLKS) { - dev_err(dev, "Invalid clock count: %d\n", v->num_clks); - return -EINVAL; - } - drvdata->clks = devm_kcalloc(dev, v->num_clks, - sizeof(*drvdata->clks), GFP_KERNEL); - if (!drvdata->clks) - return -ENOMEM; - - drvdata->num_clks = v->num_clks; - - for (i = 0; i < drvdata->num_clks; i++) - drvdata->clks[i].id = v->clk_name[i]; - - ret = devm_clk_bulk_get(dev, drvdata->num_clks, drvdata->clks); - if (ret) { - dev_err(dev, "Failed to get clocks %d\n", ret); - return ret; - } - - ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); - if (ret) { - dev_err(dev, "shikra clk_enable failed\n"); - return ret; - } - - return 0; -} - -static int shikra_qaif_exit(struct platform_device *pdev) -{ - struct qaif_drv_data *drvdata = platform_get_drvdata(pdev); - - if (!drvdata || !drvdata->clks) - return -EINVAL; - - clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks); - return 0; -} - -static int __maybe_unused shikra_qaif_dev_resume(struct device *dev) -{ - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - - if (!drvdata || !drvdata->clks) { - dev_err(dev, "Invalid drvdata in resume\n"); - return -EINVAL; - } - return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); -} - -static int __maybe_unused shikra_qaif_dev_suspend(struct device *dev) -{ - struct qaif_drv_data *drvdata = dev_get_drvdata(dev); - - if (!drvdata || !drvdata->clks) { - dev_err(dev, "Invalid drvdata in suspend\n"); - return -EINVAL; - } - clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks); - return 0; -} - -static const struct dev_pm_ops shikra_qaif_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(shikra_qaif_dev_suspend, - shikra_qaif_dev_resume) -}; - static const struct qaif_variant shikra_qaif_data = { .ee = 0, - .qaif_type = QAIF, .num_rddma = 4, .num_wrdma = 4, @@ -396,7 +376,7 @@ static const struct qaif_variant shikra_qaif_data = { .rddma_reg_base = 0x8000, .rddma_stride = 0x1000, - .codec_rddma_reg_base = 0xC000, + .codec_rddma_reg_base = 0xc000, .codec_rddma_stride = 0x1000, .wrdma_reg_base = 0x11000, @@ -414,7 +394,7 @@ static const struct qaif_variant shikra_qaif_data = { .codec_wrdma_irq_reg_base = 0x19290, .codec_wrdma_irq_stride = 0x1000, - .qxm_type = QXM0, + .qxm_type = QAIF_QXM0, .rd_len = 512, .rddma_shram_len = 64, .rddma_shram_start_addr = {0, 256}, @@ -422,148 +402,32 @@ static const struct qaif_variant shikra_qaif_data = { .wrdma_shram_len = 64, .wrdma_shram_start_addr = {0, 256}, - /* AUDIO_CORE_QAIF_RDDMAa_CTL (0x8000 + 0x1000*a) */ - .rddma_enable = REG_FIELD_ID(0x8000, 0, 0, 4, 0x1000), - .rddma_reset = REG_FIELD_ID(0x8000, 4, 4, 4, 0x1000), - - /* AUDIO_CORE_QAIF_RDDMAa_CFG (0x8004 + 0x1000*a) */ - .rddma_shram_wm = REG_FIELD_ID(0x8004, 0, 11, 4, 0x1000), - .rddma_burst1 = REG_FIELD_ID(0x8004, 16, 16, 4, 0x1000), - .rddma_burst2 = REG_FIELD_ID(0x8004, 17, 17, 4, 0x1000), - .rddma_burst4 = REG_FIELD_ID(0x8004, 18, 18, 4, 0x1000), - .rddma_burst8 = REG_FIELD_ID(0x8004, 19, 19, 4, 0x1000), - .rddma_burst16 = REG_FIELD_ID(0x8004, 20, 20, 4, 0x1000), - .rddma_dma_dyncclk = REG_FIELD_ID(0x8004, 24, 24, 4, 0x1000), - .rddma_num_ot = REG_FIELD_ID(0x8004, 28, 29, 4, 0x1000), - - /* AUDIO_CORE_QAIF_WRDMAa_CTL (0x11000 + 0x1000*a) */ - .wrdma_enable = REG_FIELD_ID(0x11000, 0, 0, 4, 0x1000), - .wrdma_reset = REG_FIELD_ID(0x11000, 4, 4, 4, 0x1000), - - /* AUDIO_CORE_QAIF_WRDMAa_CFG (0x11004 + 0x1000*a) */ - .wrdma_shram_wm = REG_FIELD_ID(0x11004, 0, 11, 4, 0x1000), - .wrdma_burst1 = REG_FIELD_ID(0x11004, 16, 16, 4, 0x1000), - .wrdma_burst2 = REG_FIELD_ID(0x11004, 17, 17, 4, 0x1000), - .wrdma_burst4 = REG_FIELD_ID(0x11004, 18, 18, 4, 0x1000), - .wrdma_burst8 = REG_FIELD_ID(0x11004, 19, 19, 4, 0x1000), - .wrdma_burst16 = REG_FIELD_ID(0x11004, 20, 20, 4, 0x1000), - .wrdma_dma_dyncclk = REG_FIELD_ID(0x11004, 24, 24, 4, 0x1000), - .wrdma_num_ot = REG_FIELD_ID(0x11004, 28, 29, 4, 0x1000), - - /* AUDIO_CORE_QAIF_CODEC_RDDMAa_CTL (0xC000 + 0x1000*a) */ - .cif_rddma_enable = REG_FIELD_ID(0xC000, 0, 0, 4, 0x1000), - .cif_rddma_reset = REG_FIELD_ID(0xC000, 4, 4, 4, 0x1000), - - /* AUDIO_CORE_QAIF_CODEC_RDDMAa_CFG (0xC004 + 0x1000*a) */ - .cif_rddma_shram_wm = REG_FIELD_ID(0xC004, 0, 11, 4, 0x1000), - .cif_rddma_burst1 = REG_FIELD_ID(0xC004, 16, 16, 4, 0x1000), - .cif_rddma_burst2 = REG_FIELD_ID(0xC004, 17, 17, 4, 0x1000), - .cif_rddma_burst4 = REG_FIELD_ID(0xC004, 18, 18, 4, 0x1000), - .cif_rddma_burst8 = REG_FIELD_ID(0xC004, 19, 19, 4, 0x1000), - .cif_rddma_burst16 = REG_FIELD_ID(0xC004, 20, 20, 4, 0x1000), - .cif_rddma_dma_dyncclk = REG_FIELD_ID(0xC004, 24, 24, 4, 0x1000), - .cif_rddma_num_ot = REG_FIELD_ID(0xC004, 28, 29, 4, 0x1000), - - /* AUDIO_CORE_QAIF_CODEC_RDDMAa_INTF_CFG (0xC05C + 0x1000*a) */ - .cif_rddma_en_16bit_unpack = REG_FIELD_ID(0xC05C, 0, 0, 4, 0x1000), - .cif_rddma_intf_dyncclk = REG_FIELD_ID(0xC05C, 2, 2, 4, 0x1000), - .cif_rddma_fs_out_gate = REG_FIELD_ID(0xC05C, 3, 3, 4, 0x1000), - .cif_rddma_fs_sel = REG_FIELD_ID(0xC05C, 4, 7, 4, 0x1000), - .cif_rddma_fs_delay = REG_FIELD_ID(0xC05C, 8, 11, 4, 0x1000), - .cif_rddma_active_ch_en = REG_FIELD_ID(0xC05C, 12, 27, 4, 0x1000), - - /* AUDIO_CORE_QAIF_CODEC_WRDMAa_CTL (0x15000 + 0x1000*a) */ - .cif_wrdma_enable = REG_FIELD_ID(0x15000, 0, 0, 4, 0x1000), - .cif_wrdma_reset = REG_FIELD_ID(0x15000, 4, 4, 4, 0x1000), - - /* AUDIO_CORE_QAIF_CODEC_WRDMAa_CFG (0x15004 + 0x1000*a) */ - .cif_wrdma_shram_wm = REG_FIELD_ID(0x15004, 0, 11, 4, 0x1000), - .cif_wrdma_burst1 = REG_FIELD_ID(0x15004, 16, 16, 4, 0x1000), - .cif_wrdma_burst2 = REG_FIELD_ID(0x15004, 17, 17, 4, 0x1000), - .cif_wrdma_burst4 = REG_FIELD_ID(0x15004, 18, 18, 4, 0x1000), - .cif_wrdma_burst8 = REG_FIELD_ID(0x15004, 19, 19, 4, 0x1000), - .cif_wrdma_burst16 = REG_FIELD_ID(0x15004, 20, 20, 4, 0x1000), - .cif_wrdma_dma_dyncclk = REG_FIELD_ID(0x15004, 24, 24, 4, 0x1000), - .cif_wrdma_num_ot = REG_FIELD_ID(0x15004, 28, 29, 4, 0x1000), - - /* AUDIO_CORE_QAIF_CODEC_WRDMAa_INTF_CFG (0x15058 + 0x1000*a) */ - .cif_wrdma_en_16bit_unpack = REG_FIELD_ID(0x15058, 0, 0, 4, 0x1000), - .cif_wrdma_intf_dyncclk = REG_FIELD_ID(0x15058, 2, 2, 4, 0x1000), - .cif_wrdma_fs_out_gate = REG_FIELD_ID(0x15058, 3, 3, 4, 0x1000), - .cif_wrdma_fs_sel = REG_FIELD_ID(0x15058, 4, 7, 4, 0x1000), - .cif_wrdma_fs_delay = REG_FIELD_ID(0x15058, 8, 11, 4, 0x1000), - .cif_wrdma_active_ch_en = REG_FIELD_ID(0x15058, 12, 27, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_CTL (0x4000 + 0x1000*a) */ - .aif_enable = REG_FIELD_ID(0x4000, 0, 0, 4, 0x1000), - .aif_enable_tx = REG_FIELD_ID(0x4000, 4, 4, 4, 0x1000), - .aif_enable_rx = REG_FIELD_ID(0x4000, 8, 8, 4, 0x1000), - .aif_reset = REG_FIELD_ID(0x4000, 12, 12, 4, 0x1000), - .aif_reset_tx = REG_FIELD_ID(0x4000, 16, 16, 4, 0x1000), - .aif_reset_rx = REG_FIELD_ID(0x4000, 20, 20, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_SYNC_CFG (0x4004 + 0x1000*a) */ - .aif_inv_sync = REG_FIELD_ID(0x4004, 12, 12, 4, 0x1000), - .aif_sync_delay = REG_FIELD_ID(0x4004, 8, 9, 4, 0x1000), - .aif_sync_mode = REG_FIELD_ID(0x4004, 4, 5, 4, 0x1000), - .aif_sync_src = REG_FIELD_ID(0x4004, 0, 0, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_BIT_WIDTH_CFG (0x4008 + 0x1000*a) */ - .aif_sample_width_rx = REG_FIELD_ID(0x4008, 24, 28, 4, 0x1000), - .aif_sample_width_tx = REG_FIELD_ID(0x4008, 16, 20, 4, 0x1000), - .aif_slot_width_rx = REG_FIELD_ID(0x4008, 8, 12, 4, 0x1000), - .aif_slot_width_tx = REG_FIELD_ID(0x4008, 0, 4, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_FRAME_CFG (0x400C + 0x1000*a) */ - .aif_bits_per_lane = REG_FIELD_ID(0x400C, 0, 9, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_ACTV_SLOT_EN_TX (0x4010 + 0x1000*a) */ - .aif_slot_en_tx_mask = REG_FIELD_ID(0x4010, 0, 31, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_ACTV_SLOT_EN_RX (0x4030 + 0x1000*a) */ - .aif_slot_en_rx_mask = REG_FIELD_ID(0x4030, 0, 31, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_LANE_CFG (0x4050 + 0x1000*a) */ - .aif_loopback_en = REG_FIELD_ID(0x4050, 31, 31, 4, 0x1000), - .aif_ctrl_data_oe = REG_FIELD_ID(0x4050, 16, 16, 4, 0x1000), - .aif_lane_en = REG_FIELD_ID(0x4050, 8, 15, 4, 0x1000), - .aif_lane_dir = REG_FIELD_ID(0x4050, 0, 7, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_MI2S_CFG (0x4054 + 0x1000*a) */ - .aif_mono_mode_rx = REG_FIELD_ID(0x4054, 1, 1, 4, 0x1000), - .aif_mono_mode_tx = REG_FIELD_ID(0x4054, 0, 0, 4, 0x1000), - - /* AUDIO_CORE_QAIF_AUD_INTFa_CFG (0x4058 + 0x1000*a) */ - .aif_full_cycle_en = REG_FIELD_ID(0x4058, 0, 0, 4, 0x1000), - - .clk_name = (const char*[]) { - "lpass_config_clk", - "lpass_core_axim_clk", - "bus_clk" - }, - .num_clks = 3, - - .dai_driver = shikra_qaif_cpu_dai_driver, - .num_dai = ARRAY_SIZE(shikra_qaif_cpu_dai_driver), - - .dai_osr_clk_names = (const char *[]) { - "null" - }, - .dai_bit_clk_names = (const char *[]) { - "aif_if0_ibit_clk", - "aif_if1_ibit_clk", - "aif_if2_ibit_clk", - "aif_if3_ibit_clk" - }, - .init = shikra_qaif_init, - .exit = shikra_qaif_exit, + .clk_name = (const char * const []) { + "lpass_config", + "lpass_core_axim", + "bus", + }, + .num_clks = 3, + + .dai_driver = shikra_qaif_cpu_dai_driver, + .num_dai = ARRAY_SIZE(shikra_qaif_cpu_dai_driver), + + .dai_bit_clk_names = (const char * const []) { + "aif_if0_ibit", + "aif_if1_ibit", + "aif_if2_ibit", + "aif_if3_ibit", + }, + .aif_full_cycle_en = (const bool []) { false, false, false, false }, + .aif_ctrl_data_oe = (const bool []) { false, false, false, false }, + .aif_loopback_en = (const bool []) { false, false, false, false }, .alloc_stream_dma_idx = shikra_qaif_alloc_stream_dma_idx, .free_stream_dma_idx = shikra_qaif_free_stream_dma_idx, - .get_dma_idx = shikra_qaif_get_dma_idx, + .get_dma_idx = shikra_qaif_get_dma_idx, }; static const struct of_device_id shikra_qaif_cpu_device_id[] = { - {.compatible = "qcom,shikra-qaif-cpu", .data = &shikra_qaif_data}, + { .compatible = "qcom,shikra-qaif-cpu", .data = &shikra_qaif_data }, {} }; MODULE_DEVICE_TABLE(of, shikra_qaif_cpu_device_id); @@ -571,12 +435,10 @@ MODULE_DEVICE_TABLE(of, shikra_qaif_cpu_device_id); static struct platform_driver shikra_qaif_cpu_platform_driver = { .driver = { .name = "shikra-qaif-cpu", - .of_match_table = of_match_ptr(shikra_qaif_cpu_device_id), - .pm = &shikra_qaif_pm_ops, + .of_match_table = shikra_qaif_cpu_device_id, + .pm = pm_ptr(&asoc_qcom_qaif_pm_ops), }, .probe = asoc_qcom_qaif_cpu_platform_probe, - .remove = asoc_qcom_qaif_cpu_platform_remove, - .shutdown = asoc_qcom_qaif_cpu_platform_shutdown, }; module_platform_driver(shikra_qaif_cpu_platform_driver); diff --git a/sound/soc/qcom/qaif.h b/sound/soc/qcom/qaif.h index 0ccb26ff66977..ba02784771a25 100644 --- a/sound/soc/qcom/qaif.h +++ b/sound/soc/qcom/qaif.h @@ -1,281 +1,171 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * - * qaif.h -- Shared data structures and definitions for the Qualcomm Audio Interface (QAIF) */ -#ifndef __QAIF_H__ -#define __QAIF_H__ -#include -#include -#include -#include -#include - -#define LPASS_MAX_MI2S_PORTS (8) -#define LPASS_MAX_AIF_DMA_IDX (8) -#define LPASS_MAX_CIF_DMA_IDX (8) -#define QAIF_CIF_DMA_INTF_ONE_CHANNEL (0x01) -#define QAIF_CIF_DMA_INTF_TWO_CHANNEL (0x03) -#define QAIF_CIF_DMA_INTF_FOUR_CHANNEL (0x0F) -#define QAIF_CIF_DMA_INTF_SIX_CHANNEL (0x3F) -#define QAIF_CIF_DMA_INTF_EIGHT_CHANNEL (0xFF) - -#define QAIF_DMACTL_ENABLE_ON 1 -#define QAIF_DMACTL_ENABLE_OFF 0 - -#define QAIF_DMACTL_DYNCLK_ON 1 -#define QAIF_DMACTL_DYNCLK_OFF 0 +#ifndef SND_SOC_QCOM_QAIF_H +#define SND_SOC_QCOM_QAIF_H -#define QAIF_AIF_CTL_ENABLE_ON 1 -#define QAIF_AIF_CTL_ENABLE_OFF 0 - -#define QAIF_CIF_16BIT_UNPACK_ENABLE 1 -#define QAIF_CIF_16BIT_UNPACK_DISABLE 0 +#include +#include +#include +#include +#include +#include +#include +#include -#define QAIF_CIF_DMA_FS_SEL_DEFAULT 0 +struct snd_pcm_substream; +struct snd_soc_dai_driver; +struct snd_soc_dai_ops; +struct platform_device; -#define QAIF_DMA_DEFAULT_BIT_WIDTH 32 +#define QAIF_CIF_DMA_INTF_ONE_CHANNEL 0x01 +#define QAIF_CIF_DMA_INTF_TWO_CHANNEL 0x03 +#define QAIF_CIF_DMA_INTF_FOUR_CHANNEL 0x0f +#define QAIF_CIF_DMA_INTF_SIX_CHANNEL 0x3f +#define QAIF_CIF_DMA_INTF_EIGHT_CHANNEL 0xff -#define QAIF_DMA_BYTES_TO_WORDS_SHIFT 3 +#define QAIF_AIF_SLOT_WIDTH(bits) ((bits) - 1) +#define QAIF_AIF_SAMPLE_WIDTH(bits) ((bits) - 1) -#define QAIF_MAX_VARIANT_CLKS 32 +/* Watermark level 5 encoded as N-1: hardware field value = watermark - 1 */ +#define QAIF_DMACTL_WM_5 4 -#define QAIF_DMA_CLK_RATE_MULTIPLIER 100 +#define QAIF_DMA_BYTES_TO_WORDS_SHIFT 3 +#define QAIF_DMA_CLOCK_FREQ 38400000 -#define QAIF_MAX_AIF_CFG_CNT (LPASS_MAX_AIF_DMA_IDX / 2) +#define QAIF_MAX_AIF_CFG_CNT 4 +#define QAIF_MAX_LANES 8 -#define QAIF_AUD_INTF_CTL_MONO 1 /* Mono Mode True */ -#define QAIF_AUD_INTF_CTL_STEREO 0 /* Mono Mode False */ +#define QAIF_MAX_MI2S_PORTS 8 +#define QAIF_MI2S_SLOTS 2 +#define QAIF_MAX_AIF_DMA_IDX 8 +#define QAIF_MAX_CIF_DMA_IDX 8 -#define QAIF_AIF_SAMPLE_WIDTH(bits) ((bits) - 1) -#define QAIF_AIF_SLOT_WIDTH(bits) ((bits) - 1) +/* SID map register CSID field (WRDMA_SID/RDDMA_SID), bits [4:0] */ +#define QAIF_CSID_MASK GENMASK(4, 0) -#define QAIF_DMACTL_WM_5 4 -#define QAIF_DMACTL_WM_8 7 -#define QAIF_DMACTL_BURSTEN 1 +static inline bool qaif_is_aif_mi2s_port(unsigned int dai_id) +{ + return (dai_id >= AIF_MI2S_RX_0 && dai_id <= AIF_MI2S_RX_12) || + (dai_id >= AIF_MI2S_TX_0 && dai_id <= AIF_MI2S_TX_12); +} -#define QAIF_MAX_LANES 8 +static inline bool qaif_is_aif_tdm_port(unsigned int dai_id) +{ + return (dai_id >= AIF_TDM_RX_0 && dai_id <= AIF_TDM_RX_12) || + (dai_id >= AIF_TDM_TX_0 && dai_id <= AIF_TDM_TX_12); +} -enum qxm_sel { - QXM0 = 0, - QXM1 = 1, - MAX_QXM_TYPE, -}; +static inline bool qaif_is_aif_port(unsigned int dai_id) +{ + return qaif_is_aif_mi2s_port(dai_id) || qaif_is_aif_tdm_port(dai_id); +} -static inline bool is_cif_dma_port(int dai_id) +static inline bool qaif_is_cif_port(unsigned int dai_id) { - switch (dai_id) { - case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9: - case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9: - case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9: - return true; - } - return false; + return (dai_id >= WSA_CODEC_DMA_RX_0 && dai_id <= RX_CODEC_DMA_RX_7); } -enum qaif_type_t { - QAIF_INVALID = -1, - QAIF = 0, - QAIF_VA, - QAIF_MAX_TYPES +enum qxm_sel { + QAIF_QXM0 = 0, + QAIF_QXM1 = 1, }; enum qaif_irq_type { QAIF_AIF_IRQ = 0, QAIF_CIF_IRQ = 1, - QAIF_AUD_INTF_IRQ = 2, - QAIF_IRQ_MAX = 3 + QAIF_IRQ_TYPE_MAX, }; enum qaif_dma_type { QAIF_AIF_DMA = 0, QAIF_CIF_DMA = 1, - DMA_TYPE_MAX -}; - -struct qaif_dmactl { - /* AUDIO_CORE_QAIF_CODEC_xDMAa_CTL */ - struct regmap_field *enable; - struct regmap_field *reset; - - /* AUDIO_CORE_QAIF_CODEC_xDMAa_CFG */ - struct regmap_field *num_ot; /* outstanding transactions */ - struct regmap_field *dma_dyncclk; - struct regmap_field *burst16; - struct regmap_field *burst8; - struct regmap_field *burst4; - struct regmap_field *burst2; - struct regmap_field *burst1; - struct regmap_field *shram_wm; /* SHRAM watermark */ - -}; - -struct qaif_cdc_intfctl { - /* AUDIO_CORE_QAIF_CODEC_xDMAa_INTF_CFG */ - struct regmap_field *active_ch_en; - struct regmap_field *fs_sel; - struct regmap_field *fs_delay; - struct regmap_field *fs_out_gate; - struct regmap_field *intf_dyncclk; - struct regmap_field *en_16bit_unpack; -}; - -struct qaif_aud_intfctl { - /* AUDIO_CORE_QAIF_AUD_INTFa_SYNC_CFG */ - struct regmap_field *inv_sync; - struct regmap_field *sync_delay; - struct regmap_field *sync_mode; - struct regmap_field *sync_src; - - /* AUDIO_CORE_QAIF_AUD_INTFa_BIT_WIDTH_CFG */ - struct regmap_field *slot_width_rx; - struct regmap_field *slot_width_tx; - struct regmap_field *sample_width_rx; - struct regmap_field *sample_width_tx; - - /* AUDIO_CORE_QAIF_AUD_INTFa_MI2S_CFG */ - struct regmap_field *mono_mode_rx; - struct regmap_field *mono_mode_tx; - - /* AUDIO_CORE_QAIF_AUD_INTFa_LANE_CFG */ - struct regmap_field *lane_en; /* Lane enable mask (bits 8-15) */ - struct regmap_field *lane_dir; /* Lane direction mask (bits 0-7, 0=TX, 1=RX) */ - struct regmap_field *loopback_en; - struct regmap_field *ctrl_data_oe; - - /* AUDIO_CORE_QAIF_AUD_INTFa_ACTV_SLOT_EN_RX */ - struct regmap_field *slot_en_rx_mask; - - /* AUDIO_CORE_QAIF_AUD_INTFa_ACTV_SLOT_EN_TX */ - struct regmap_field *slot_en_tx_mask; - - /* AUDIO_CORE_QAIF_AUD_INTFa_CFG */ - struct regmap_field *full_cycle_en; - /* AUDIO_CORE_QAIF_AUD_INTFa_FRAME_CFG */ - struct regmap_field *bits_per_lane; - - /* AUDIO_CORE_QAIF_AUD_INTFa_CTL */ - struct regmap_field *enable; - struct regmap_field *enable_tx; - struct regmap_field *enable_rx; - struct regmap_field *reset; - struct regmap_field *reset_tx; - struct regmap_field *reset_rx; -}; - -/* Lane configuration structure */ -struct qaif_lane_config { - u32 enable; /* 1 = enabled, 0 = disabled */ - u32 direction; /* 0 = TX_SPKR, 1 = RX_MIC */ }; -/* - * AIF interface protocol mode — set by the DT compatible string and - * used to select mode-specific register defaults and property parsing. - */ -enum qaif_aif_mode { - QAIF_AIF_MODE_PCM, - QAIF_AIF_MODE_TDM, - QAIF_AIF_MODE_MI2S, -}; - -/* QAIF Audio Interface Configuration Structure */ struct qaif_aif_config { - /* Interface protocol mode derived from DT compatible */ - enum qaif_aif_mode mode; - /* Sync configuration */ u32 sync_mode; u32 sync_src; - u32 invert_sync; + bool invert_sync; u32 sync_delay; - /* Slot and sample width configuration */ - u32 slot_width_rx; - u32 slot_width_tx; - u32 sample_width_rx; - u32 sample_width_tx; - /* Slot enable masks (32-bit masks for 32 slots) */ + u32 slot_width; u32 slot_en_rx_mask; u32 slot_en_tx_mask; - /* Control configuration */ - u32 loopback_en; - u32 ctrl_data_oe; - /* Lane configuration */ - u32 num_lanes; /* Number of lanes configured */ - struct qaif_lane_config lane_cfg[QAIF_MAX_LANES]; + bool loopback_en; + bool ctrl_data_oe; u32 lane_en_mask; u32 lane_dir_mask; - /* Frame configuration */ - u32 full_cycle_en; - u32 bits_per_lane; + bool full_cycle_en; + u32 slot_num; }; struct qaif_pcm_data { + /* Flat slot in aif_substream[]/aif_dma_heap[] (or cif_*) used to track + * this stream. Direction-encoded: playback uses the raw DMA channel + * number (0..num_rddma-1), capture adds wrdma_start so playback and + * capture of the same DAI occupy distinct slots. + * Set by alloc_stream_dma_idx(); bounded by QAIF_MAX_AIF/CIF_DMA_IDX. + */ int stream_dma_idx; + /* Hardware channel number (0-based within its DMA bank) passed to + * register address helpers (e.g. QAIF_RDDMA_CFG_REG(v, chan)). + * Direction-agnostic: the register helpers select RDDMA or WRDMA bank + * based on stream direction, so both directions of the same DAI share + * the same value. Set by get_dma_idx(). + */ + int dma_reg_idx; }; -struct qaif_dma_mem_info { - dma_addr_t dma_addr; - size_t alloc_size; - void *vaddr; +/* Named 0-based DMA channel indices used as the dma_idx of a + * qaif_dmaidx_dai_map entry, so board tables reference channels by name. + */ +enum qaif_dma_idx { + QAIF_DMA_IDX0 = 0, + QAIF_DMA_IDX1, + QAIF_DMA_IDX2, + QAIF_DMA_IDX3, + QAIF_DMA_IDX4, + QAIF_DMA_IDX5, + QAIF_DMA_IDX6, + QAIF_DMA_IDX7, }; +/* Associates a DAI ID with its physical DMA channel index on a given + * board/variant. @dai_id is the DAI to match; @dma_idx (a qaif_dma_idx value) + * is the 0-based hardware channel that get_dma_idx() returns for it. + */ struct qaif_dmaidx_dai_map { unsigned int dai_id; + int dma_idx; }; -/* Both the CPU DAI and platform drivers will access this data */ -struct qaif_drv_data { - /* MI2S bit clock (derived from system clock by a divider) */ - struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS]; +struct qaif_dma_mem_info { + dma_addr_t dma_addr; + size_t alloc_size; + void *vaddr; +}; - /* SOC specific clock list */ +struct qaif_drv_data { + struct clk *mi2s_bit_clk[QAIF_MAX_MI2S_PORTS]; struct clk_bulk_data *clks; int num_clks; - struct clk *aud_dma_clk; struct clk *aud_dma_mem_clk; - - /* Qualcomm audio interface (QAIF) registers */ void __iomem *audio_qaif; - - /* regmap backed by the Qualcomm audio interface (QAIF) registers */ struct regmap *audio_qaif_map; - - /* interrupts from the Qualcomm audio interface (QAIF) */ int audio_qaif_irq; - - /* QAIF init config refcount*/ - unsigned int qaif_init_ref_cnt; - - /* SOC specific variations in the QAIF IP integration */ + struct mutex stream_lock; /* serializes stream open/close */ + bool qaif_hw_configured; const struct qaif_variant *variant; - - /* Runtime-allocated regmap field handles (populated at probe) */ - struct qaif_dmactl *aif_rd_dmactl; - struct qaif_dmactl *aif_wr_dmactl; - struct qaif_dmactl *cif_rd_dmactl; - struct qaif_dmactl *cif_wr_dmactl; - struct qaif_aud_intfctl *aif_intfctl; - struct qaif_cdc_intfctl *cif_rddma_intfctl; - struct qaif_cdc_intfctl *cif_wrdma_intfctl; struct qaif_aif_config aif_intf_cfg[QAIF_MAX_AIF_CFG_CNT]; - - /* bit map to keep track of dma idx allocations */ unsigned long aif_dma_idx_bit_map; unsigned long cif_dma_idx_bit_map; - - /* used it for handling interrupt per dma channel */ - struct snd_pcm_substream *aif_substream[LPASS_MAX_AIF_DMA_IDX]; - struct snd_pcm_substream *cif_substream[LPASS_MAX_CIF_DMA_IDX]; - - u32 smmu_csid_bits; - - /* DMA info handle per stream/dma idx */ - struct qaif_dma_mem_info *aif_dma_heap[LPASS_MAX_AIF_DMA_IDX]; - struct qaif_dma_mem_info *cif_dma_heap[LPASS_MAX_CIF_DMA_IDX]; - + struct snd_pcm_substream *aif_substream[QAIF_MAX_AIF_DMA_IDX]; + struct snd_pcm_substream *cif_substream[QAIF_MAX_CIF_DMA_IDX]; + u32 smmu_csid_bits; /* SMMU stream ID bits from DT iommus cell */ + struct qaif_dma_mem_info *aif_dma_heap[QAIF_MAX_AIF_DMA_IDX]; + struct qaif_dma_mem_info *cif_dma_heap[QAIF_MAX_CIF_DMA_IDX]; }; enum qaif_summary_irq_bitmask { @@ -285,74 +175,60 @@ enum qaif_summary_irq_bitmask { QAIF_SUMMARY_BITMASK_AIF_PERIOD_WRDMA = BIT(3), QAIF_SUMMARY_BITMASK_AIF_OVERFLOW_WRDMA = BIT(4), QAIF_SUMMARY_BITMASK_AIF_ERR_RSP_WRDMA = BIT(5), - - QAIF_SUMMARY_BITMASK_AUD_OVERFLOW = BIT(6), - QAIF_SUMMARY_BITMASK_AUD_UNDERFLOW = BIT(7), - - QAIF_SUMMARY_BITMASK_RATE_DET = BIT(8), - QAIF_SUMMARY_BITMASK_VFR = BIT(9), - QAIF_SUMMARY_BITMASK_GRP = BIT(10), - QAIF_SUMMARY_BITMASK_RDDMA_OVERLAP = BIT(11), - QAIF_SUMMARY_BITMASK_WRDMA_OVERLAP = BIT(12), - QAIF_SUMMARY_BITMASK_INTF_OVERLAP = BIT(13), - QAIF_SUMMARY_BITMASK_GRP_OVERLAP = BIT(14), - - QAIF_SUMMARY_BITMASK_CIF_OVERLAP_RDDMA = BIT(15), - QAIF_SUMMARY_BITMASK_CIF_OVERLAP_WRDMA = BIT(17), QAIF_SUMMARY_BITMASK_CIF_PERIOD_RDDMA = BIT(18), QAIF_SUMMARY_BITMASK_CIF_UNDERFLOW_RDDMA = BIT(19), QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_RDDMA = BIT(20), QAIF_SUMMARY_BITMASK_CIF_PERIOD_WRDMA = BIT(24), QAIF_SUMMARY_BITMASK_CIF_OVERFLOW_WRDMA = BIT(25), - QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_WRDMA = BIT(26) - + QAIF_SUMMARY_BITMASK_CIF_ERR_RSP_WRDMA = BIT(26), }; enum qaif_client_status_register_bitmask_info { - QAIF_BITMASK_GROUP_INF = 0x400, - QAIF_BITMASK_AIF_RDDMA_WRDMA = 0x3F, - QAIF_BITMASK_CIF_RDDMA_WRDMA = 0x71c0000, - QAIF_BITMASK_DP_RDDMA = 0xe00000, - QAIF_BITMASK_AUD_INF = 0xC0, + QAIF_BITMASK_AIF_RDDMA_WRDMA = GENMASK(5, 0), + QAIF_BITMASK_CIF_RDDMA_WRDMA = GENMASK(26, 18), }; struct qaif_irq_map { - int client_id; + u32 client_id; u32 mask; - irqreturn_t (*client_irq_handler)(struct qaif_drv_data *drvdata, u32 irq_status); + /* + * Called from the hard IRQ handler (asoc_platform_qaif_irq()) with + * @status holding the summary interrupt status. Must not sleep. + */ + irqreturn_t (*client_irq_handler)(struct qaif_drv_data *drvdata, u32 status); }; -enum dma_type { - DMA_TYPE_RDDMA, - DMA_TYPE_WRDMA +enum qaif_dma_dir { + QAIF_DMA_RDDMA = 0, + QAIF_DMA_WRDMA = 1, }; enum qaif_irq { - QAIF_IRQ_PERIOD, + QAIF_IRQ_PERIOD = 0, QAIF_IRQ_OVERFLOW, QAIF_IRQ_UNDERFLOW, - QAIF_IRQ_ERROR + QAIF_IRQ_ERROR, +}; + +enum qaif_irq_op { + QAIF_IRQ_CLEAR = 0, + QAIF_IRQ_ENABLE, + QAIF_IRQ_DISABLE, }; enum qaif_client_info { - QAIF_CLIENT_ID_GROUP_INF = 0, - QAIF_CLIENT_ID_AIF_DMA = 1, - QAIF_CLIENT_ID_CIF_DMA = 2, - QAIF_CLIENT_ID_DP_DMA = 3, - QAIF_CLIENT_ID_AUD_INF = 4, - QAIF_CLIENT_ID_MAX + QAIF_CLIENT_ID_AIF_DMA = 0, + QAIF_CLIENT_ID_CIF_DMA, }; struct qaif_variant { - u32 ee; - u32 qaif_type; + u32 ee; /* Hardware EE index assigned to this driver instance */ u32 num_rddma; u32 num_wrdma; u32 wrdma_start; - - u32 num_codec_rddma; /* RX */ - u32 num_codec_wrdma; /* TX */ + u32 num_codec_rddma; + u32 num_codec_wrdma; u32 codec_wrdma_start; u32 num_intf; @@ -360,7 +236,6 @@ struct qaif_variant { u32 rddma_stride; u32 codec_rddma_reg_base; u32 codec_rddma_stride; - u32 wrdma_reg_base; u32 wrdma_stride; u32 codec_wrdma_reg_base; @@ -370,133 +245,58 @@ struct qaif_variant { u32 rddma_irq_stride; u32 codec_rddma_irq_reg_base; u32 codec_rddma_irq_stride; - u32 wrdma_irq_reg_base; u32 wrdma_irq_stride; u32 codec_wrdma_irq_reg_base; u32 codec_wrdma_irq_stride; - u32 qxm_type; + /* QSB master port selector; only QAIF_QXM0 is supported today */ + enum qxm_sel qxm_type; + /* All *_len values below are SHRAM sizes in 64-bit words */ u32 rd_len; u32 rddma_shram_len; - u32 rddma_shram_start_addr[DMA_TYPE_MAX]; + /* SHRAM start offsets (in 64-bit words), indexed by enum qaif_dma_type */ + u32 rddma_shram_start_addr[2]; u32 wr_len; u32 wrdma_shram_len; - u32 wrdma_shram_start_addr[DMA_TYPE_MAX]; - - /* AIF RDDMA register fields */ - const struct reg_field rddma_enable; - const struct reg_field rddma_reset; - const struct reg_field rddma_num_ot; - const struct reg_field rddma_dma_dyncclk; - const struct reg_field rddma_burst16; - const struct reg_field rddma_burst8; - const struct reg_field rddma_burst4; - const struct reg_field rddma_burst2; - const struct reg_field rddma_burst1; - const struct reg_field rddma_shram_wm; - - /* AIF WRDMA register fields */ - const struct reg_field wrdma_enable; - const struct reg_field wrdma_reset; - const struct reg_field wrdma_num_ot; - const struct reg_field wrdma_dma_dyncclk; - const struct reg_field wrdma_burst16; - const struct reg_field wrdma_burst8; - const struct reg_field wrdma_burst4; - const struct reg_field wrdma_burst2; - const struct reg_field wrdma_burst1; - const struct reg_field wrdma_shram_wm; - - /* CODEC RDDMA register fields */ - const struct reg_field cif_rddma_enable; - const struct reg_field cif_rddma_reset; - const struct reg_field cif_rddma_num_ot; - const struct reg_field cif_rddma_dma_dyncclk; - const struct reg_field cif_rddma_burst16; - const struct reg_field cif_rddma_burst8; - const struct reg_field cif_rddma_burst4; - const struct reg_field cif_rddma_burst2; - const struct reg_field cif_rddma_burst1; - const struct reg_field cif_rddma_shram_wm; - const struct reg_field cif_rddma_active_ch_en; - const struct reg_field cif_rddma_fs_sel; - const struct reg_field cif_rddma_fs_delay; - const struct reg_field cif_rddma_fs_out_gate; - const struct reg_field cif_rddma_intf_dyncclk; - const struct reg_field cif_rddma_en_16bit_unpack; - - /* CODEC WRDMA register fields */ - const struct reg_field cif_wrdma_enable; - const struct reg_field cif_wrdma_reset; - const struct reg_field cif_wrdma_num_ot; - const struct reg_field cif_wrdma_dma_dyncclk; - const struct reg_field cif_wrdma_burst16; - const struct reg_field cif_wrdma_burst8; - const struct reg_field cif_wrdma_burst4; - const struct reg_field cif_wrdma_burst2; - const struct reg_field cif_wrdma_burst1; - const struct reg_field cif_wrdma_shram_wm; - const struct reg_field cif_wrdma_active_ch_en; - const struct reg_field cif_wrdma_fs_sel; - const struct reg_field cif_wrdma_fs_delay; - const struct reg_field cif_wrdma_fs_out_gate; - const struct reg_field cif_wrdma_intf_dyncclk; - const struct reg_field cif_wrdma_en_16bit_unpack; - - /* Regmap fields of AIF interface registers bitfields */ - const struct reg_field aif_inv_sync; - const struct reg_field aif_sync_delay; - const struct reg_field aif_sync_mode; - const struct reg_field aif_sync_src; - const struct reg_field aif_sample_width_rx; - const struct reg_field aif_sample_width_tx; - const struct reg_field aif_slot_width_rx; - const struct reg_field aif_slot_width_tx; - const struct reg_field aif_bits_per_lane; - const struct reg_field aif_slot_en_tx_mask; - const struct reg_field aif_slot_en_rx_mask; - const struct reg_field aif_loopback_en; - const struct reg_field aif_ctrl_data_oe; - const struct reg_field aif_lane_en; - const struct reg_field aif_lane_dir; - const struct reg_field aif_mono_mode_rx; - const struct reg_field aif_mono_mode_tx; - const struct reg_field aif_full_cycle_en; - - /* AUDIO_CORE_QAIF_AUD_INTFa_CTL bitfields */ - const struct reg_field aif_enable; - const struct reg_field aif_enable_tx; - const struct reg_field aif_enable_rx; - const struct reg_field aif_reset; - const struct reg_field aif_reset_tx; - const struct reg_field aif_reset_rx; - - /* Platform-specific data */ - const char **clk_name; + u32 wrdma_shram_start_addr[2]; + + const char * const *clk_name; int num_clks; struct snd_soc_dai_driver *dai_driver; int num_dai; - const char **dai_osr_clk_names; - const char **dai_bit_clk_names; - - /* Platform-specific function pointers */ - int (*init)(struct platform_device *pdev); - int (*exit)(struct platform_device *pdev); - int (*alloc_stream_dma_idx)(struct qaif_drv_data *data, int direction, unsigned int dai_id); - int (*free_stream_dma_idx)(struct qaif_drv_data *data, int chan, unsigned int dai_id); + const char * const *dai_bit_clk_names; + /* + * Optional per-AIF configuration tables, indexed by AIF interface + * index (0..num_intf-1). NULL if the variant does not use them. + */ + const bool *aif_full_cycle_en; + const bool *aif_ctrl_data_oe; + const bool *aif_loopback_en; + + /* Returns a direction-encoded flat slot index for use in + * aif_substream[]/cif_substream[] and the dma_idx_bit_map. + * Playback returns the raw channel number; capture adds wrdma_start (or + * codec_wrdma_start) so both directions of the same DAI get distinct + * slots. Sets the corresponding bit atomically; returns -EBUSY if + * already open, -EINVAL if @dai_id or the computed index is out of range. + */ + int (*alloc_stream_dma_idx)(struct qaif_drv_data *data, int direction, + unsigned int dai_id); + /* Clears the bit set by alloc_stream_dma_idx. */ + int (*free_stream_dma_idx)(struct qaif_drv_data *data, int chan, + unsigned int dai_id); + /* Returns the hardware channel number (0-based within its DMA bank) + * for @dai_id, direction-agnostic. Used as dma_reg_idx. + */ int (*get_dma_idx)(unsigned int dai_id); - }; -/* External DAI ops structures defined in qaif-cpu.c */ extern const struct snd_soc_dai_ops asoc_qcom_qaif_cif_dai_ops; extern const struct snd_soc_dai_ops asoc_qcom_qaif_aif_cpu_dai_ops; -/* Platform driver functions defined in qaif-cpu.c */ int asoc_qcom_qaif_cpu_platform_probe(struct platform_device *pdev); int asoc_qcom_qaif_platform_register(struct platform_device *pdev); -void asoc_qcom_qaif_cpu_platform_remove(struct platform_device *pdev); -void asoc_qcom_qaif_cpu_platform_shutdown(struct platform_device *pdev); +extern const struct dev_pm_ops asoc_qcom_qaif_pm_ops; -#endif /* __QAIF_H__ */ +#endif /* SND_SOC_QCOM_QAIF_H */ diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 6d60e09fbb8d0..fdfd71232165f 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -57,25 +57,6 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), }; -static struct snd_soc_dapm_widget shikra_cqm_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -static const struct snd_soc_dapm_widget shikra_iqs_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_kcontrol_new shikra_iqs_controls[] = { - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Int Mic"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - static const struct snd_soc_dapm_widget talos_lyra_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic12", NULL), @@ -109,6 +90,25 @@ static const struct snd_kcontrol_new talos_lyra_max98090_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), }; +static const struct snd_soc_dapm_widget shikra_cqm_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static const struct snd_soc_dapm_widget shikra_iqs_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_kcontrol_new shikra_iqs_controls[] = { + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + struct snd_soc_common { const char *driver_name; const struct snd_soc_dapm_widget *dapm_widgets; @@ -118,10 +118,10 @@ struct snd_soc_common { const struct snd_kcontrol_new *controls; int num_controls; unsigned int codec_dai_fmt; + unsigned int cpu_dai_fmt; bool codec_sysclk_set; bool mi2s_mclk_enable; bool mi2s_bclk_enable; - bool dsp_bypass; }; struct sc8280xp_snd_data { @@ -177,9 +177,15 @@ static int sc8280xp_tdm_hw_params(struct snd_pcm_substream *substream, if (!cpu_cfg.slots) return 0; - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); - if (ret) - return ret; + if (data->snd_soc_common_priv->cpu_dai_fmt) { + ret = snd_soc_dai_set_fmt(cpu_dai, data->snd_soc_common_priv->cpu_dai_fmt); + if (ret) + return ret; + } else { + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + if (ret) + return ret; + } ret = qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg); if (ret) @@ -284,6 +290,7 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, case TX_CODEC_DMA_TX_1: case TX_CODEC_DMA_TX_2: case TX_CODEC_DMA_TX_3: + case VA_CODEC_DMA_TX_1: channels->min = 1; break; default: @@ -303,16 +310,23 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); int mclk_freq = sc8280xp_get_mclk_freq(params); int bclk_freq = sc8280xp_get_bclk_freq(params); - - /* Skip DSP configuration when operating in CPU-only (bypass) mode */ - if (pdata->snd_soc_common_priv->dsp_bypass) - return 0; + int ret = 0; switch (cpu_dai->id) { case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + case AIF_MI2S_RX_0 ... AIF_MI2S_TX_12: + if (pdata->snd_soc_common_priv->cpu_dai_fmt) { + ret = snd_soc_dai_set_fmt(cpu_dai, + pdata->snd_soc_common_priv->cpu_dai_fmt); + if (ret) + return ret; + } else { + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + if (ret) + return ret; + } if (pdata->snd_soc_common_priv->codec_dai_fmt) snd_soc_dai_set_fmt(codec_dai, @@ -334,6 +348,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, SND_SOC_CLOCK_IN); break; case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: + case AIF_TDM_RX_0 ... AIF_TDM_TX_12: return sc8280xp_tdm_hw_params(substream, params); default: break; @@ -483,7 +498,9 @@ static const struct snd_soc_common shikra_cqm_priv_data = { .driver_name = "shikra", .dapm_widgets = shikra_cqm_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(shikra_cqm_dapm_widgets), - .dsp_bypass = true, + .cpu_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP, + .mi2s_bclk_enable = true, + .codec_sysclk_set = true, }; static const struct snd_soc_common shikra_cqs_priv_data = { diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index e3286cc34aa65..93a355a36ccab 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include "sdw.h" @@ -31,6 +30,7 @@ static bool qcom_snd_is_sdw_dai(int id) case TX_CODEC_DMA_TX_5: case RX_CODEC_DMA_RX_6: case RX_CODEC_DMA_RX_7: + case VA_CODEC_DMA_TX_1: case SLIMBUS_0_RX...SLIMBUS_6_TX: return true; default: @@ -42,8 +42,6 @@ static bool qcom_snd_is_sdw_dai(int id) switch (id) { case LPASS_CDC_DMA_TX3: case LPASS_CDC_DMA_RX0: - case QAIF_CDC_DMA_VA_TX0: - case QAIF_CDC_DMA_RX0: return true; default: break; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index feecf3e4e38b4..619321179297e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3180,6 +3180,39 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); +/** + * snd_soc_of_xlate_dai_name - Resolve a sound-dai phandle argument to a + * DAI name by searching the component DAI list. + * @component: ASoC component to search. + * @args: Phandle arguments from the sound-dai property; args[0] is the + * DAI ID. + * @dai_name: Output pointer set to the matched DAI name on success. + * + * Return: 0 on success, -EINVAL if args_count != 1 or no match is found. + */ +int snd_soc_of_xlate_dai_name(struct snd_soc_component *component, + const struct of_phandle_args *args, + const char **dai_name) +{ + struct snd_soc_dai *dai; + int id; + + if (args->args_count != 1) + return -EINVAL; + + id = args->args[0]; + + for_each_component_dais(component, dai) { + if (dai->driver->id == id) { + *dai_name = snd_soc_dai_name_get(dai); + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_of_xlate_dai_name); + void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, struct snd_soc_dai_link_component *cpus) {