diff --git a/Documentation/devicetree/bindings/arm/qcom-soc.yaml b/Documentation/devicetree/bindings/arm/qcom-soc.yaml index 27261039d56f6..5c7b2351c38a5 100644 --- a/Documentation/devicetree/bindings/arm/qcom-soc.yaml +++ b/Documentation/devicetree/bindings/arm/qcom-soc.yaml @@ -11,10 +11,10 @@ maintainers: description: | Guidelines for new compatibles for SoC blocks/components. - When adding new compatibles in new bindings, use the format:: + When adding new compatibles in new bindings, use the format: qcom,SoC-IP - For example:: + For example: qcom,sdm845-llcc-bwmon When adding new compatibles to existing bindings, use the format in the @@ -25,7 +25,7 @@ select: compatible: oneOf: - pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sar|sc|sd[amx]|sm|x1[ep])[0-9]+.*$" - - pattern: "^qcom,.*(glymur|milos).*$" + - pattern: "^qcom,.*(eliza|kaanapali|glymur|hawi|mahua|maili|milos|nord|shikra).*$" required: - compatible @@ -36,7 +36,7 @@ properties: - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1[ep])[0-9]+(pro)?-.*$" - pattern: "^qcom,sar[0-9]+[a-z]?-.*$" - pattern: "^qcom,(sa|sc)8[0-9]+[a-z][a-z]?-.*$" - - pattern: "^qcom,(glymur|milos)-.*$" + - pattern: "^qcom,(eliza|kaanapali|glymur|hawi|mahua|maili|milos|nord|shikra)-.*$" # Legacy namings - variations of existing patterns/compatibles are OK, # but do not add completely new entries to these: @@ -67,4 +67,8 @@ properties: - qcom,ipq806x-usb-phy-ss - qcom,ipq806x-usb-phy-hs + # In general non-SoC Qualcomm devices do not need to be listed here, + # however in a few cases they got selected by patterns in "select": + - pattern: "^qcom,wsa[0-9]+$" + additionalProperties: true diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index b3491b382f283..08c1fd1285728 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -1158,7 +1158,7 @@ properties: items: items: - description: | - MSM chipset ID - an exact match value consisting of two bitfields:: + MSM chipset ID - an exact match value consisting of two bitfields: - bits 0-15 - The unique MSM chipset ID - bits 16-31 - Reserved; should be 0 - description: | @@ -1184,7 +1184,7 @@ properties: - items: - items: - description: | - Board ID consisting of three bitfields:: + Board ID consisting of three bitfields: - bits 31-24 - Unused - bits 23-16 - Platform Version Major - bits 15-8 - Platform Version Minor diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml index 653f859976434..ab000befe76da 100644 --- a/Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml +++ b/Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml @@ -11,10 +11,10 @@ maintainers: description: | Guidelines for new compatibles for SoC blocks/components. - When adding new compatibles in new bindings, use the format:: + When adding new compatibles in new bindings, use the format: samsung,SoC-IP - For example:: + For example: samsung,exynos5433-cmu-isp select: diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index 85d4ae72f925a..0f3dc77706511 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -70,16 +70,16 @@ properties: clocks: description: | - Several clocks are used, depending on the variant. Typical ones are:: - - bus:: Display AHB clock. - - byte:: Display byte clock. - - byte_intf:: Display byte interface clock. - - core:: Display core clock. - - core_mss:: Core MultiMedia SubSystem clock. - - iface:: Display AXI clock. - - mdp_core:: MDP Core clock. - - mnoc:: MNOC clock - - pixel:: Display pixel clock. + Several clocks are used, depending on the variant. Typical ones are: + - bus: Display AHB clock. + - byte: Display byte clock. + - byte_intf: Display byte interface clock. + - core: Display core clock. + - core_mss: Core MultiMedia SubSystem clock. + - iface: Display AXI clock. + - mdp_core: MDP Core clock. + - mnoc: MNOC clock + - pixel: Display pixel clock. minItems: 3 maxItems: 12 diff --git a/Documentation/devicetree/bindings/display/samsung/samsung,fimd.yaml b/Documentation/devicetree/bindings/display/samsung/samsung,fimd.yaml index ff685031bb2cf..729705f419bb8 100644 --- a/Documentation/devicetree/bindings/display/samsung/samsung,fimd.yaml +++ b/Documentation/devicetree/bindings/display/samsung/samsung,fimd.yaml @@ -41,7 +41,7 @@ properties: additionalProperties: false description: | Timing configuration for lcd i80 interface support. - The parameters are defined as:: + The parameters are defined as: VCLK(internal) __|??????|_____|??????|_____|??????|_____|??????|_____|?? : : : : : Address Output --:. The GPIO + The order of the GPIOs should be the following: . The GPIO specifier depends on the gpio controller. Required in all cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output lines are permanently wired to the respective client. diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml index c4c7a3e3827b0..3c446b62d0942 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml @@ -13,7 +13,7 @@ description: | Bandwidth Monitor measures current throughput on buses between various NoC fabrics and provides information when it crosses configured thresholds. - Certain SoCs might have more than one Bandwidth Monitors, for example on SDM845:: + Certain SoCs might have more than one Bandwidth Monitors, for example on SDM845: - Measuring the bandwidth between CPUs and Last Level Cache Controller - called just BWMON, - Measuring the bandwidth between Last Level Cache Controller and memory diff --git a/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml b/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml index 5e26e48c7217d..0203959c89958 100644 --- a/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml +++ b/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml @@ -23,7 +23,7 @@ description: | The each AXI bus has the owned source clock but, has not the only owned power line. The power line might be shared among one more sub-blocks. So, we can divide into two type of device as the role of each sub-block. There are two - type of bus devices as following:: + type of bus devices as following: - parent bus device - passive bus device @@ -44,8 +44,8 @@ description: | able to support the bus frequency for all Exynos SoCs. Detailed correlation between sub-blocks and power line according - to Exynos SoC:: - - In case of Exynos3250, there are two power line as following:: + to Exynos SoC: + - In case of Exynos3250, there are two power line as following: VDD_MIF |--- DMC (Dynamic Memory Controller) VDD_INT |--- LEFTBUS (parent device) @@ -89,7 +89,7 @@ description: | |L5 |200000 |200000 |400000 |300000 | ||1000000 | ---------------------------------------------------------- - - In case of Exynos4210, there is one power line as following:: + - In case of Exynos4210, there is one power line as following: VDD_INT |--- DMC (parent device, Dynamic Memory Controller) |--- LEFTBUS |--- PERIL @@ -106,7 +106,7 @@ description: | |--- LCD0 |--- LCD1 - - In case of Exynos4x12, there are two power line as following:: + - In case of Exynos4x12, there are two power line as following: VDD_MIF |--- DMC (Dynamic Memory Controller) VDD_INT |--- LEFTBUS (parent device) @@ -124,7 +124,7 @@ description: | |--- LCD0 |--- ISP - - In case of Exynos5422, there are two power line as following:: + - In case of Exynos5422, there are two power line as following: VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller) |--- DREX 1 @@ -143,7 +143,7 @@ description: | |--- FSYS |--- FSYS2 - - In case of Exynos5433, there is VDD_INT power line as following:: + - In case of Exynos5433, there is VDD_INT power line as following: VDD_INT |--- G2D (parent device) |--- MSCL |--- GSCL diff --git a/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml b/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml index fa03e73622d48..2e7725cf1100b 100644 --- a/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml +++ b/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml @@ -10,10 +10,10 @@ maintainers: - Krzysztof Kozlowski description: | - The Qualcomm PM8058 contains an LED block for up to six LEDs:: three normal + The Qualcomm PM8058 contains an LED block for up to six LEDs: three normal LEDs, two "flash" LEDs and one "keypad backlight" LED. The names are quoted because sometimes these LED drivers are used for wildly different things than - flash or keypad backlight:: their names are more of a suggestion than a + flash or keypad backlight: their names are more of a suggestion than a hard-wired usecase. Hardware-wise the different LEDs support slightly different output currents. diff --git a/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml b/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml index a6aaa92dbccd9..65576dfdca110 100644 --- a/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml +++ b/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml @@ -11,7 +11,7 @@ maintainers: - Krzysztof Kozlowski description: | - The device is controlled through two pins:: FL_EN and EN_SET. The pins when, + The device is controlled through two pins: FL_EN and EN_SET. The pins when, asserted high, enable flash strobe and movie mode (max 1/2 of flash current) respectively. In order to add a capability of selecting the strobe signal source (e.g. CPU or camera sensor) there is an additional switch required, @@ -39,11 +39,11 @@ properties: flash-max-microamp: description: | Maximum flash LED supply current can be calculated using following - formula:: I = 1A * 162 kOhm / Rset. + formula: I = 1A * 162 kOhm / Rset. flash-max-timeout-us: description: | - Maximum flash timeout can be calculated using following formula:: + Maximum flash timeout can be calculated using following formula: T = 8.82 * 10^9 * Ct. required: diff --git a/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml index 582c6c9cae48d..21118e4bae0f1 100644 --- a/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml +++ b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml @@ -14,7 +14,7 @@ description: | hooked up to a pull-up GPIO line and - optionally - the HPD line is hooked up to another GPIO line. - Please note:: the maximum voltage for the CEC line is 3.63V, for the HPD and + Please note: the maximum voltage for the CEC line is 3.63V, for the HPD and 5V lines it is 5.3V. So you may need some sort of level conversion circuitry when connecting them to a GPIO line. diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index 946e1361a5334..e57ced1559672 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -142,7 +142,9 @@ patternProperties: "^audio-codec@[0-9a-f]+$": type: object - $ref: /schemas/sound/qcom,pm8916-wcd-analog-codec.yaml# + oneOf: + - $ref: /schemas/sound/qcom,pm4125-codec.yaml# + - $ref: /schemas/sound/qcom,pm8916-wcd-analog-codec.yaml# "^battery@[0-9a-f]+$": type: object diff --git a/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml index 27c4060f2f917..223fcc9f651fb 100644 --- a/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml @@ -85,7 +85,7 @@ properties: description: | The value of CIU TX and RX clock phase shift value for HS400 mode operation. - Valid values for SDR and DDR CIU clock timing:: + Valid values for SDR and DDR CIU clock timing: - valid value for tx phase shift and rx phase shift is 0 to 7. - when CIU clock divider value is set to 3, all possible 8 phase shift values can be used. diff --git a/Documentation/devicetree/bindings/phy/samsung,mipi-video-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,mipi-video-phy.yaml index 16967ef8e9ecc..87b6a35b2626a 100644 --- a/Documentation/devicetree/bindings/phy/samsung,mipi-video-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,mipi-video-phy.yaml @@ -13,14 +13,14 @@ maintainers: description: | For samsung,s5pv210-mipi-video-phy compatible PHYs the second cell in the - PHY specifier identifies the PHY and its meaning is as follows:: + PHY specifier identifies the PHY and its meaning is as follows: 0 - MIPI CSIS 0, 1 - MIPI DSIM 0, 2 - MIPI CSIS 1, 3 - MIPI DSIM 1. samsung,exynos5420-mipi-video-phy and samsung,exynos5433-mipi-video-phy - support additional fifth PHY:: + support additional fifth PHY: 4 - MIPI CSIS 2. properties: diff --git a/Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml index d9f22a801cbf7..7db7605a82e21 100644 --- a/Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml @@ -14,7 +14,7 @@ maintainers: description: | The first phandle argument in the PHY specifier identifies the PHY, its meaning is compatible dependent. For the currently supported SoCs (Exynos4210 - and Exynos4212) it is as follows:: + and Exynos4212) it is as follows: 0 - USB device ("device"), 1 - USB host ("host"), 2 - HSIC0 ("hsic0"), diff --git a/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml index ea1135c91fb74..5ac139c943eb1 100644 --- a/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml @@ -14,7 +14,7 @@ maintainers: description: | For samsung,exynos5250-usbdrd-phy and samsung,exynos5420-usbdrd-phy compatible PHYs, the second cell in the PHY specifier identifies the - PHY id, which is interpreted as follows:: + PHY id, which is interpreted as follows: 0 - UTMI+ type phy, 1 - PIPE3 type phy. diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml index f1094d65e8460..bf6a65782c601 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml @@ -18,7 +18,7 @@ description: | All the pin controller nodes should be represented in the aliases node using the following format 'pinctrl{n}' where n is a unique number for the alias. - The controller supports three types of interrupts:: + The controller supports three types of interrupts: - External GPIO interrupts (see interrupts property in pin controller node); - External wake-up interrupts - multiplexed (capable of waking up the system diff --git a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml index 347571e2545a8..b67aa170b2c1e 100644 --- a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml +++ b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml @@ -13,7 +13,7 @@ maintainers: description: | The R-Car (RZ/G) System Controller provides power management for the CPU cores and various coprocessors. - The power domain IDs for consumers are defined in header files:: + The power domain IDs for consumers are defined in header files: include/dt-bindings/power/r8*-sysc.h properties: diff --git a/Documentation/devicetree/bindings/power/reset/restart-handler.yaml b/Documentation/devicetree/bindings/power/reset/restart-handler.yaml index 965a834a3dbe8..00c00ec5ec814 100644 --- a/Documentation/devicetree/bindings/power/reset/restart-handler.yaml +++ b/Documentation/devicetree/bindings/power/reset/restart-handler.yaml @@ -18,12 +18,12 @@ properties: priority: $ref: /schemas/types.yaml#/definitions/uint32 description: | - A priority ranging from 0 to 255 according to the following guidelines:: - 0:: Restart handler of last resort, with limited restart capabilities. - 128:: Typical, default restart handler; use if no other restart handler + A priority ranging from 0 to 255 according to the following guidelines: + 0: Restart handler of last resort, with limited restart capabilities. + 128: Typical, default restart handler; use if no other restart handler is expected to be available, and/or if restart functionality is sufficient to restart the entire system. - 255:: Highest priority restart handler, will preempt all other restart handlers. + 255: Highest priority restart handler, will preempt all other restart handlers. minimum: 0 maximum: 255 diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml index b704f05ea4542..b886495c1396e 100644 --- a/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml +++ b/Documentation/devicetree/bindings/regulator/maxim,max77802.yaml @@ -22,13 +22,13 @@ description: | Certain regulators support "regulator-initial-mode" and "regulator-mode". The valid modes list is defined in the dt-bindings/regulator/maxim,max77802.h - and their meaning is:: + and their meaning is: 1 - Normal regulator voltage output mode. 3 - Low Power which reduces the quiescent current down to only 1uA The standard "regulator-mode" property can only be used for regulators that support changing their mode to Low Power Mode during suspend. These - regulators are:: bucks 2-4 and LDOs 1-35. Also, it only takes effect if the + regulators are: bucks 2-4 and LDOs 1-35. Also, it only takes effect if the regulator has been enabled for the given suspend state using "regulator-on-in-suspend" and has not been disabled for that state using "regulator-off-in-suspend". diff --git a/Documentation/devicetree/bindings/regulator/richtek,rtq2208.yaml b/Documentation/devicetree/bindings/regulator/richtek,rtq2208.yaml index 022c1f1973646..b0aa38edf8c22 100644 --- a/Documentation/devicetree/bindings/regulator/richtek,rtq2208.yaml +++ b/Documentation/devicetree/bindings/regulator/richtek,rtq2208.yaml @@ -21,7 +21,7 @@ description: | conduction mode (FCCM). The definition of modes is in the datasheet which is available in below link - and their meaning is:: + and their meaning is: 0 - Auto mode for power saving, which reducing the switching frequency at light load condition to maintain high frequency. 1 - FCCM to meet the strict voltage regulation accuracy, which keeping constant switching frequency. diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml index e0fa363ad7e2e..084ddc4962f70 100644 --- a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml +++ b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml @@ -17,7 +17,7 @@ description: | software perspective it's mostly compatible with the MSM serial UART except that it supports reading and writing multiple characters at a time. - Note:: Aliases may be defined to ensure the correct ordering of the UARTs. + Note: Aliases may be defined to ensure the correct ordering of the UARTs. The alias serialN will result in the UART being assigned port N. If any serialN alias exists, then an alias must exist for each enabled UART. The serialN aliases should be in a .dts file instead of in a .dtsi file. diff --git a/Documentation/devicetree/bindings/slimbus/slimbus.yaml b/Documentation/devicetree/bindings/slimbus/slimbus.yaml index 5a941610ce4ed..3910327c8ded1 100644 --- a/Documentation/devicetree/bindings/slimbus/slimbus.yaml +++ b/Documentation/devicetree/bindings/slimbus/slimbus.yaml @@ -29,7 +29,7 @@ patternProperties: description: | Every SLIMbus controller node can contain zero or more child nodes representing slave devices on the bus. Every SLIMbus slave device is - uniquely determined by the enumeration address containing 4 fields:: + uniquely determined by the enumeration address containing 4 fields: Manufacturer ID, Product code, Device index, and Instance value for the device. @@ -48,7 +48,7 @@ patternProperties: reg: maxItems: 1 description: | - Pair of (device index, instande ID), where:: + Pair of (device index, instande ID), where: - Device index, which uniquely identifies multiple devices within a single component. - Instance ID, can be used for the cases where multiple devices of diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml index bdf482db32aac..b663be3ea5a17 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml @@ -40,7 +40,7 @@ properties: $ref: /schemas/types.yaml#/definitions/string-array description: | Protection domain service name and path for APR service (if supported). - Possible values are:: + Possible values are: "avs/audio", "msm/adsp/audio_pd". "kernel/elf_loader", "msm/modem/wlan_pd". "tms/servreg", "msm/adsp/audio_pd". diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml index 26d9bc773ec5c..1889139a3f7af 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml @@ -23,7 +23,7 @@ description: | with a few variations that are captured by the properties here. A TCS may be triggered from Linux or triggered by the F/W after all the CPUs - have powered off to facilitate idle power saving. TCS could be classified as:: + have powered off to facilitate idle power saving. TCS could be classified as: ACTIVE - Triggered by Linux SLEEP - Triggered by F/W WAKE - Triggered by F/W @@ -76,7 +76,7 @@ properties: items: items: - description: | - TCS type:: + TCS type: - ACTIVE_TCS - SLEEP_TCS - WAKE_TCS @@ -152,7 +152,7 @@ examples: - | // For a TCS whose RSC base address is 0x179C0000 and is at a DRV id of // 2, the register offsets for DRV2 start at 0D00, the register - // calculations are like this:: + // calculations are like this: // DRV0: 0x179C0000 // DRV2: 0x179C0000 + 0x10000 = 0x179D0000 // DRV2: 0x179C0000 + 0x10000 * 2 = 0x179E0000 @@ -182,7 +182,7 @@ examples: - | // For a TCS whose RSC base address is 0xAF20000 and is at DRV id of 0, the // register offsets for DRV0 start at 01C00, the register calculations are - // like this:: + // like this: // DRV0: 0xAF20000 // TCS-OFFSET: 0x1C00 #include diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml index 4fcae6bedfffa..72a7f8cb09bad 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml @@ -28,7 +28,7 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: | Reference to a node specifying the wcnss "ccu" and "dxe" register blocks. - The node must be compatible with one of the following:: + The node must be compatible with one of the following: - qcom,riva" - qcom,pronto" diff --git a/Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml b/Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml index 5ddd31f30f267..57c9d3c570212 100644 --- a/Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml +++ b/Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml @@ -12,10 +12,10 @@ maintainers: description: | Guidelines for new compatibles for SoC blocks/components. - When adding new compatibles in new bindings, use the format:: + When adding new compatibles in new bindings, use the format: renesas,SoC-IP - For example:: + For example: renesas,r8a77965-csi2 When adding new compatibles to existing bindings, use the format in the 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,q6asm-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml index ce811942a9f17..f1e991494c9be 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml @@ -45,7 +45,7 @@ patternProperties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2] description: | - The direction of the dai stream:: + The direction of the dai stream: - Q6ASM_DAI_TX_RX (0) for both tx and rx - Q6ASM_DAI_TX (1) for only tx (Capture/Encode) - Q6ASM_DAI_RX (2) for only rx (Playback/Decode) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml index 3b03e2acd67e0..63f53837bd9fb 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml @@ -108,10 +108,15 @@ patternProperties: properties: reg: contains: - # TDM DAI ID range from PRIMARY_TDM_RX_0 - QUINARY_TDM_TX_7 + # TDM DAI ID range from PRIMARY_TDM_RX_0 - QUINARY_TDM_TX_7 and + # AIF_TDM_RX_0 - AIF_TDM_TX_12 items: - minimum: 24 - maximum: 103 + oneOf: + - minimum: 24 + maximum: 103 + - minimum: 179 + maximum: 204 + then: required: - qcom,tdm-sync-mode @@ -127,7 +132,8 @@ patternProperties: contains: # MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and # QUINARY_MI2S_RX - QUINARY_MI2S_TX and - # LPI_MI2S_RX_0 - LPI_MI2S_TX_6 + # LPI_MI2S_RX_0 - LPI_MI2S_TX_6 and + # AIF_MI2S_RX_0 - AIF_MI2S_TX_12 items: oneOf: - minimum: 16 @@ -136,6 +142,8 @@ patternProperties: maximum: 128 - minimum: 137 maximum: 152 + - minimum: 153 + maximum: 178 then: required: - qcom,sd-lines 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,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 540115fc96a19..576816a851daf 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -92,6 +92,19 @@ patternProperties: sound-dai: maxItems: 1 + dai-tdm-slot-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Number of slots in use + + dai-tdm-slot-width: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Width, in bits, of each slot + + patternProperties: + '^dai-tdm-slot-[rt]x-mask$': + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Slot mask for active TDM slots + platform: description: Holds subnode which indicates platform dai. type: object @@ -111,6 +124,19 @@ patternProperties: minItems: 1 maxItems: 8 + dai-tdm-slot-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Number of slots in use + + dai-tdm-slot-width: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Width, in bits, of each slot + + patternProperties: + '^dai-tdm-slot-[rt]x-mask$': + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Slot mask for active TDM slots + required: - link-name - cpu 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/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml b/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml index 29a08b0729eee..3f333db72a711 100644 --- a/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml @@ -40,7 +40,7 @@ properties: description: | The Exynos TMU supports generating interrupts when reaching given temperature thresholds. Number of supported thermal trip points depends - on the SoC (only first trip points defined in DT will be configured):: + on the SoC (only first trip points defined in DT will be configured): - most of SoC: 4 - samsung,exynos5433-tmu: 8 - samsung,exynos7-tmu: 8 @@ -52,7 +52,7 @@ properties: - description: | Shared TMU registers. - Note:: On Exynos5420, the TRIMINFO register is misplaced for TMU + Note: On Exynos5420, the TRIMINFO register is misplaced for TMU channels 2, 3 and 4 Use "samsung,exynos5420-tmu-ext-triminfo" in cases, there is a misplaced register, also provide clock to access that base. diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index a792434c59db2..b686baf0cd3eb 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -92,14 +92,14 @@ properties: clocks: description: | - Several clocks are used, depending on the variant. Typical ones are:: - - cfg_noc:: System Config NOC clock. - - core:: Master/Core clock, has to be >= 125 MHz for SS operation and >= + Several clocks are used, depending on the variant. Typical ones are: + - cfg_noc: System Config NOC clock. + - core: Master/Core clock, has to be >= 125 MHz for SS operation and >= 60MHz for HS operation. - - iface:: System bus AXI clock. - - sleep:: Sleep clock, used for wakeup when USB3 core goes into low + - iface: System bus AXI clock. + - sleep: Sleep clock, used for wakeup when USB3 core goes into low power mode (U3). - - mock_utmi:: Mock utmi clock needed for ITP/SOF generation in host + - mock_utmi: Mock utmi clock needed for ITP/SOF generation in host mode. Its frequency should be 19.2MHz. minItems: 1 maxItems: 9 diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml index 27369c73b5662..c85c231f24938 100644 --- a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml @@ -84,14 +84,14 @@ properties: clocks: description: | - Several clocks are used, depending on the variant. Typical ones are:: - - cfg_noc:: System Config NOC clock. - - core:: Master/Core clock, has to be >= 125 MHz for SS operation and >= + Several clocks are used, depending on the variant. Typical ones are: + - cfg_noc: System Config NOC clock. + - core: Master/Core clock, has to be >= 125 MHz for SS operation and >= 60MHz for HS operation. - - iface:: System bus AXI clock. - - sleep:: Sleep clock, used for wakeup when USB3 core goes into low + - iface: System bus AXI clock. + - sleep: Sleep clock, used for wakeup when USB3 core goes into low power mode (U3). - - mock_utmi:: Mock utmi clock needed for ITP/SOF generation in host + - mock_utmi: Mock utmi clock needed for ITP/SOF generation in host mode. Its frequency should be 19.2MHz. minItems: 1 maxItems: 9 diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts index 142c712dfebd5..5ca81aaeb0f51 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_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "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>; }; }; }; @@ -270,47 +280,20 @@ &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>; }; }; @@ -473,22 +456,14 @@ &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>; + aif@b5 { + reg = ; + 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>; }; }; @@ -511,10 +486,6 @@ status = "okay"; }; -&rxmacro { - status = "okay"; -}; - &i2c3 { status = "okay"; @@ -560,6 +531,10 @@ remote-endpoint = <&usb_qmpphy_out>; }; +&rxmacro { + status = "okay"; +}; + &sdhc_1 { vmmc-supply = <&pm4125_l20>; vqmmc-supply = <&pm4125_l14>; @@ -631,7 +606,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>; }; }; @@ -745,7 +720,7 @@ line-name = "vbus-boost-5v"; }; - 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; @@ -820,7 +795,7 @@ }; &vamacro { - pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&tx_swr_active>; + pinctrl-0 = <&dmic01_default>, <&dmic23_default>; pinctrl-names = "default"; qcom,dmic-sample-rate = <4800000>; diff --git a/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts index e74e8ef0dfb6f..2c6f083611c8e 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_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "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,14 +114,14 @@ 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>; }; cpu { - sound-dai = <&q6apmbedai SECONDARY_TDM_RX_0>; + sound-dai = <&q6apmbedai AIF_TDM_RX_2>; 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>; }; @@ -454,10 +468,9 @@ &q6apmbedai { #address-cells = <1>; #size-cells = <0>; - dai@40 { - reg = ; - clocks = <&q6prmcc LPASS_CLK_ID_AUD_INTF2_IBIT - LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + dai@183 { + reg = ; + clocks = <&q6prmcc LPASS_CLK_ID_AUD_INTF2_IBIT LPASS_CLK_ATTRIBUTE_COUPLE_NO>; clock-names = "bclk"; }; }; @@ -526,6 +539,18 @@ remote-endpoint = <&usb_qmpphy_out>; }; +&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>; @@ -667,7 +692,7 @@ line-name = "vbus-boost-5v"; }; - 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>; @@ -686,6 +711,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"; @@ -743,7 +811,7 @@ }; &vamacro { - pinctrl-0 = <&dmic01_default>, <&dmic23_default>, <&tx_swr_active>; + pinctrl-0 = <&dmic01_default>, <&dmic23_default>; pinctrl-names = "default"; clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, diff --git a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts index ed43a2c055e29..181010854f6d6 100644 --- a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts @@ -67,7 +67,7 @@ }; cpu { - sound-dai = <&q6apmbedai PRIMARY_MI2S_RX>; + sound-dai = <&q6apmbedai AIF_MI2S_RX_0>; }; platform { @@ -83,7 +83,7 @@ }; cpu { - sound-dai = <&q6apmbedai PRIMARY_MI2S_TX>; + sound-dai = <&q6apmbedai AIF_MI2S_TX_0>; }; platform { @@ -582,8 +582,8 @@ #address-cells = <1>; #size-cells = <0>; - dai@16 { - reg = ; + dai@153 { + reg = ; clocks = <&q6prmcc LPASS_CLK_ID_AUD_INTF0_IBIT LPASS_CLK_ATTRIBUTE_COUPLE_NO>; clock-names = "bclk"; }; @@ -883,20 +883,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>; @@ -946,3 +932,17 @@ &usb_qmpphy_out { remote-endpoint = <&ucsi_ccg_port_1_ss>; }; + +&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 23dd13b0aa458..aacd3aa4a5e68 100644 --- a/arch/arm64/boot/dts/qcom/shikra.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi @@ -737,6 +737,38 @@ bias-pull-down; }; + dmic01_default: dmic01-default-state { + clk-pins { + pins = "gpio96"; + function = "dmic"; + drive-strength = <8>; + output-high; + }; + + data-pins { + pins = "gpio97"; + function = "dmic"; + drive-strength = <8>; + bias-disable; + }; + }; + + dmic23_default: dmic23-default-state { + clk-pins { + pins = "gpio98"; + function = "dmic"; + drive-strength = <8>; + output-high; + }; + + data-pins { + pins = "gpio99"; + function = "dmic"; + drive-strength = <8>; + bias-disable; + }; + }; + mclk0_default: mclk0-default-state { pins = "gpio34"; function = "cam_mclk"; @@ -1026,6 +1058,22 @@ bias-disable; }; + rx_swr_active: rx-swr-active-state { + clk-pins { + pins = "gpio107"; + function = "swr0_rx"; + drive-strength = <8>; + bias-disable; + }; + + data-pins { + pins = "gpio108", "gpio109"; + function = "swr0_rx"; + drive-strength = <8>; + bias-bus-hold; + }; + }; + sdc1_state_on: sdc1-on-state { clk-pins { pins = "sdc1_clk"; @@ -1123,38 +1171,6 @@ bias-pull-up; }; - dmic01_default: dmic01-default-state { - clk-pins { - pins = "gpio96"; - function = "dmic"; - drive-strength = <8>; - output-high; - }; - - data-pins { - pins = "gpio97"; - function = "dmic"; - drive-strength = <8>; - bias-disable; - }; - }; - - dmic23_default: dmic23-default-state { - clk-pins { - pins = "gpio98"; - function = "dmic"; - drive-strength = <8>; - output-high; - }; - - data-pins { - pins = "gpio99"; - function = "dmic"; - drive-strength = <8>; - bias-disable; - }; - }; - tx_swr_active: tx-swr-active-state { clk-pins { pins = "gpio105"; @@ -1170,22 +1186,6 @@ bias-bus-hold; }; }; - - rx_swr_active: rx-swr-active-state { - clk-pins { - pins = "gpio107"; - function = "swr0_rx"; - drive-strength = <8>; - bias-disable; - }; - - data-pins { - pins = "gpio108", "gpio109"; - function = "swr0_rx"; - drive-strength = <8>; - bias-bus-hold; - }; - }; }; pmu@c91000 { @@ -3461,159 +3461,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>, @@ -4942,6 +4789,148 @@ label = "cti_apss_2"; }; + 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 3882bf0cb2895..81ede34ac4d50 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1140,7 +1140,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..83e2a207be777 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_TX_0 154 +#define AIF_MI2S_RX_1 155 +#define AIF_MI2S_TX_1 156 +#define AIF_MI2S_RX_2 157 +#define AIF_MI2S_TX_2 158 +#define AIF_MI2S_RX_3 159 +#define AIF_MI2S_TX_3 160 +#define AIF_MI2S_RX_4 161 +#define AIF_MI2S_TX_4 162 +#define AIF_MI2S_RX_5 163 +#define AIF_MI2S_TX_5 164 +#define AIF_MI2S_RX_6 165 +#define AIF_MI2S_TX_6 166 +#define AIF_MI2S_RX_7 167 +#define AIF_MI2S_TX_7 168 +#define AIF_MI2S_RX_8 169 +#define AIF_MI2S_TX_8 170 +#define AIF_MI2S_RX_9 171 +#define AIF_MI2S_TX_9 172 +#define AIF_MI2S_RX_10 173 +#define AIF_MI2S_TX_10 174 +#define AIF_MI2S_RX_11 175 +#define AIF_MI2S_TX_11 176 +#define AIF_MI2S_RX_12 177 +#define AIF_MI2S_TX_12 178 +#define AIF_TDM_RX_0 179 +#define AIF_TDM_TX_0 180 +#define AIF_TDM_RX_1 181 +#define AIF_TDM_TX_1 182 +#define AIF_TDM_RX_2 183 +#define AIF_TDM_TX_2 184 +#define AIF_TDM_RX_3 185 +#define AIF_TDM_TX_3 186 +#define AIF_TDM_RX_4 187 +#define AIF_TDM_TX_4 188 +#define AIF_TDM_RX_5 189 +#define AIF_TDM_TX_5 190 +#define AIF_TDM_RX_6 191 +#define AIF_TDM_TX_6 192 +#define AIF_TDM_RX_7 193 +#define AIF_TDM_TX_7 194 +#define AIF_TDM_RX_8 195 +#define AIF_TDM_TX_8 196 +#define AIF_TDM_RX_9 197 +#define AIF_TDM_TX_9 198 +#define AIF_TDM_RX_10 199 +#define AIF_TDM_TX_10 200 +#define AIF_TDM_RX_11 201 +#define AIF_TDM_TX_11 202 +#define AIF_TDM_RX_12 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 cd4b3a21a8cb3..0985bcdb81dee 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,12 +647,12 @@ 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; bool hph_pwr_mode; bool hph_hd2_mode; + bool fs_cnt_bypass; struct snd_soc_component *component; unsigned long active_ch_mask[RX_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[RX_MACRO_MAX_DAIS]; @@ -1660,7 +1661,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; @@ -2097,10 +2098,10 @@ 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); + if (rx->fs_cnt_bypass) + 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); @@ -3709,7 +3710,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; @@ -3869,7 +3870,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) { @@ -3892,9 +3892,10 @@ 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; + rx->fs_cnt_bypass = (rx->codec_version == LPASS_CODEC_VERSION_4_1); def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults); reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL); if (!reg_defaults) @@ -3996,8 +3997,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 79fee3dc56247..e0d91b063e3a3 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -24,6 +24,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) @@ -147,57 +148,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 |\ @@ -251,9 +249,8 @@ struct va_macro { u16 dmic_clk_div; bool has_swr_master; bool has_npl_clk; - bool bypass_fs_control; - bool has_adpt_block; - + bool fs_cnt_bypass; + bool has_adpt; int dec_mode[VA_MACRO_NUM_DECIMATORS]; struct regmap *regmap; struct clk *mclk; @@ -319,12 +316,31 @@ static int va_macro_enable_clocks(struct va_macro *va) 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) { @@ -422,117 +438,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}, @@ -610,49 +516,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}, @@ -661,48 +559,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_MAPLE, + .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) @@ -713,14 +698,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 (va->fs_cnt_bypass) + 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); @@ -805,10 +790,22 @@ 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) { + /* + * SMIC enums use shift 0 (lower nibble of CFG0), + * DMIC enums use shift 4 (upper nibble of CFG0). + * Use e->shift_l to distinguish them without relying + * on widget name comparisons. + */ + if (e->shift_l == 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_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); } @@ -991,6 +988,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) { @@ -998,9 +1005,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; @@ -1013,8 +1019,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: @@ -1024,15 +1029,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 (va->has_adpt) + 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) & @@ -1058,7 +1066,6 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, 0x0); } - usleep_range(1000, 1010); snd_soc_component_update_bits(comp, hpf_gate_reg, CDC_VA_TX_HPF_ZERO_GATE_MASK, @@ -1258,6 +1265,39 @@ static const char * const adc_mux_text[] = { "VA_DMIC", "SWR_MIC" }; +static const char * const smic_mux_text[] = { + "ZERO", "ADC0", "ADC1", "ADC2", "ADC3", "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, @@ -1393,6 +1433,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"), @@ -1537,6 +1582,62 @@ 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", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX0", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX0", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX0", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX0", "SWR_MIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX0", "SWR_MIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX0", "SWR_MIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX0", "SWR_MIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX0", "SWR_MIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX0", "SWR_MIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX0", "SWR_MIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX0", "SWR_MIC7", "VA SWR_MIC7"}, + + {"VA DEC1 MUX", "SWR_MIC", "VA SMIC MUX1"}, + {"VA SMIC MUX1", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX1", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX1", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX1", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX1", "SWR_MIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX1", "SWR_MIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX1", "SWR_MIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX1", "SWR_MIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX1", "SWR_MIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX1", "SWR_MIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX1", "SWR_MIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX1", "SWR_MIC7", "VA SWR_MIC7"}, + + {"VA DEC2 MUX", "SWR_MIC", "VA SMIC MUX2"}, + {"VA SMIC MUX2", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX2", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX2", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX2", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX2", "SWR_MIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX2", "SWR_MIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX2", "SWR_MIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX2", "SWR_MIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX2", "SWR_MIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX2", "SWR_MIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX2", "SWR_MIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX2", "SWR_MIC7", "VA SWR_MIC7"}, + + {"VA DEC3 MUX", "SWR_MIC", "VA SMIC MUX3"}, + {"VA SMIC MUX3", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX3", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX3", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX3", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX3", "SWR_MIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX3", "SWR_MIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX3", "SWR_MIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX3", "SWR_MIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX3", "SWR_MIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX3", "SWR_MIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX3", "SWR_MIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX3", "SWR_MIC7", "VA SWR_MIC7"}, + { "VA DMIC0", NULL, "DMIC0 Pin" }, { "VA DMIC1", NULL, "DMIC1 Pin" }, { "VA DMIC2", NULL, "DMIC2 Pin" }, @@ -1758,7 +1859,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) @@ -1785,6 +1886,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)) @@ -1821,21 +1923,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 */ ret = clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); @@ -1872,6 +1970,8 @@ static int va_macro_probe(struct platform_device *pdev) lpass_macro_set_codec_version(data->version); else /* read version from register */ va_macro_set_lpass_codec_version(va); + va->fs_cnt_bypass = (lpass_macro_get_codec_version() == LPASS_CODEC_VERSION_4_1); + va->has_adpt = (lpass_macro_get_codec_version() == LPASS_CODEC_VERSION_4_1); if (va->has_swr_master) { /* Set default CLK div to 1 */ diff --git a/sound/soc/codecs/wsa885x-i2c.c b/sound/soc/codecs/wsa885x.c similarity index 76% rename from sound/soc/codecs/wsa885x-i2c.c rename to sound/soc/codecs/wsa885x.c index a7d8f8d48a21c..5ffbf9e89fd93 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; @@ -903,7 +896,6 @@ static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00); regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x01); - regmap_write(wsa885x->regmap, WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00); return 0; } @@ -939,21 +931,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 +967,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; } @@ -1018,30 +1013,25 @@ static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream, { 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 }, + { WSA885X_DIG_CTRL0_PA_FSM_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 +1039,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 +1094,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 +1155,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 +1166,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 +1189,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 +1200,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 +1274,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 +1308,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 +1389,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 +1409,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 +1418,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 +1427,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 +1456,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..42b4b15481039 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -7,7 +7,7 @@ #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 +28,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/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 59223c64a15ff..e3a6684fd8197 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -372,6 +372,7 @@ static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai, switch (dai->id) { case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: + case AIF_TDM_RX_0 ... AIF_TDM_TX_12: cfg->nslots_per_frame = slots; cfg->slot_width = slot_width; cfg->slot_mask = ((dai->id & 0x1) ? tx_mask : rx_mask) & cap_mask; @@ -454,6 +455,7 @@ static int of_q6apm_parse_dai_data(struct device *dev, case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: + case AIF_MI2S_RX_0 ... AIF_TDM_TX_12: priv = &data->priv[id]; priv->mclk = of_clk_get_by_name(node, "mclk"); if (IS_ERR(priv->mclk)) { diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index cc247a0813a20..304722a763652 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -516,6 +516,32 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { .id = QUINARY_MI2S_TX, .name = "QUIN_MI2S_TX", }, + Q6AFE_MI2S_RX_DAI("AIF RX0", AIF_MI2S_RX_0), + Q6AFE_MI2S_RX_DAI("AIF RX1", AIF_MI2S_RX_1), + Q6AFE_MI2S_RX_DAI("AIF RX2", AIF_MI2S_RX_2), + Q6AFE_MI2S_RX_DAI("AIF RX3", AIF_MI2S_RX_3), + Q6AFE_MI2S_RX_DAI("AIF RX4", AIF_MI2S_RX_4), + Q6AFE_MI2S_RX_DAI("AIF RX5", AIF_MI2S_RX_5), + Q6AFE_MI2S_RX_DAI("AIF RX6", AIF_MI2S_RX_6), + Q6AFE_MI2S_RX_DAI("AIF RX7", AIF_MI2S_RX_7), + Q6AFE_MI2S_RX_DAI("AIF RX8", AIF_MI2S_RX_8), + Q6AFE_MI2S_RX_DAI("AIF RX9", AIF_MI2S_RX_9), + Q6AFE_MI2S_RX_DAI("AIF RX10", AIF_MI2S_RX_10), + Q6AFE_MI2S_RX_DAI("AIF RX11", AIF_MI2S_RX_11), + Q6AFE_MI2S_RX_DAI("AIF RX12", AIF_MI2S_RX_12), + Q6AFE_MI2S_TX_DAI("AIF TX0", AIF_MI2S_TX_0), + Q6AFE_MI2S_TX_DAI("AIF TX1", AIF_MI2S_TX_1), + Q6AFE_MI2S_TX_DAI("AIF TX2", AIF_MI2S_TX_2), + Q6AFE_MI2S_TX_DAI("AIF TX3", AIF_MI2S_TX_3), + Q6AFE_MI2S_TX_DAI("AIF TX4", AIF_MI2S_TX_4), + Q6AFE_MI2S_TX_DAI("AIF TX5", AIF_MI2S_TX_5), + Q6AFE_MI2S_TX_DAI("AIF TX6", AIF_MI2S_TX_6), + Q6AFE_MI2S_TX_DAI("AIF TX7", AIF_MI2S_TX_7), + Q6AFE_MI2S_TX_DAI("AIF TX8", AIF_MI2S_TX_8), + Q6AFE_MI2S_TX_DAI("AIF TX9", AIF_MI2S_TX_9), + Q6AFE_MI2S_TX_DAI("AIF TX10", AIF_MI2S_TX_10), + Q6AFE_MI2S_TX_DAI("AIF TX11", AIF_MI2S_TX_11), + Q6AFE_MI2S_TX_DAI("AIF TX12", AIF_MI2S_TX_12), Q6AFE_MI2S_RX_DAI("LPI RX0", LPI_MI2S_RX_0), Q6AFE_MI2S_RX_DAI("LPI RX1", LPI_MI2S_RX_1), Q6AFE_MI2S_RX_DAI("LPI RX2", LPI_MI2S_RX_2), @@ -530,6 +556,32 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { Q6AFE_MI2S_TX_DAI("LPI TX4", LPI_MI2S_TX_4), Q6AFE_MI2S_TX_DAI("LPI TX5", LPI_MI2S_TX_5), Q6AFE_MI2S_TX_DAI("LPI TX6", LPI_MI2S_TX_6), + Q6AFE_TDM_PB_DAI("AIF RX0", 0, AIF_TDM_RX_0), + Q6AFE_TDM_PB_DAI("AIF RX1", 1, AIF_TDM_RX_1), + Q6AFE_TDM_PB_DAI("AIF RX2", 2, AIF_TDM_RX_2), + Q6AFE_TDM_PB_DAI("AIF RX3", 3, AIF_TDM_RX_3), + Q6AFE_TDM_PB_DAI("AIF RX4", 4, AIF_TDM_RX_4), + Q6AFE_TDM_PB_DAI("AIF RX5", 5, AIF_TDM_RX_5), + Q6AFE_TDM_PB_DAI("AIF RX6", 6, AIF_TDM_RX_6), + Q6AFE_TDM_PB_DAI("AIF RX7", 7, AIF_TDM_RX_7), + Q6AFE_TDM_PB_DAI("AIF RX8", 8, AIF_TDM_RX_8), + Q6AFE_TDM_PB_DAI("AIF RX9", 9, AIF_TDM_RX_9), + Q6AFE_TDM_PB_DAI("AIF RX10", 10, AIF_TDM_RX_10), + Q6AFE_TDM_PB_DAI("AIF RX11", 11, AIF_TDM_RX_11), + Q6AFE_TDM_PB_DAI("AIF RX12", 12, AIF_TDM_RX_12), + Q6AFE_TDM_CAP_DAI("AIF TX0", 0, AIF_TDM_TX_0), + Q6AFE_TDM_CAP_DAI("AIF TX1", 1, AIF_TDM_TX_1), + Q6AFE_TDM_CAP_DAI("AIF TX2", 2, AIF_TDM_TX_2), + Q6AFE_TDM_CAP_DAI("AIF TX3", 3, AIF_TDM_TX_3), + Q6AFE_TDM_CAP_DAI("AIF TX4", 4, AIF_TDM_TX_4), + Q6AFE_TDM_CAP_DAI("AIF TX5", 5, AIF_TDM_TX_5), + Q6AFE_TDM_CAP_DAI("AIF TX6", 6, AIF_TDM_TX_6), + Q6AFE_TDM_CAP_DAI("AIF TX7", 7, AIF_TDM_TX_7), + Q6AFE_TDM_CAP_DAI("AIF TX8", 8, AIF_TDM_TX_8), + Q6AFE_TDM_CAP_DAI("AIF TX9", 9, AIF_TDM_TX_9), + Q6AFE_TDM_CAP_DAI("AIF TX10", 10, AIF_TDM_TX_10), + Q6AFE_TDM_CAP_DAI("AIF TX11", 11, AIF_TDM_TX_11), + Q6AFE_TDM_CAP_DAI("AIF TX12", 12, AIF_TDM_TX_12), Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0), Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1), Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2), @@ -684,9 +736,11 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: + case AIF_MI2S_RX_0 ... AIF_MI2S_TX_12: q6dsp_audio_fe_dais[i].ops = cfg->q6i2s_ops; break; case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: + case AIF_TDM_RX_0 ... AIF_TDM_TX_12: q6dsp_audio_fe_dais[i].ops = cfg->q6tdm_ops; break; case WSA_CODEC_DMA_RX_0 ... RX_CODEC_DMA_RX_7: diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 6d60e09fbb8d0..c8bf217f2f83b 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; 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) {