diff options
47 files changed, 8743 insertions, 127 deletions
diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt deleted file mode 100644 index 641edf75e184..000000000000 --- a/Documentation/devicetree/bindings/sound/bt-sco.txt +++ /dev/null @@ -1,13 +0,0 @@ -Bluetooth-SCO audio CODEC - -This device support generic Bluetooth SCO link. - -Required properties: - - - compatible : "delta,dfbmcs320" or "linux,bt-sco" - -Example: - -codec: bt_sco { - compatible = "delta,dfbmcs320"; -}; diff --git a/Documentation/devicetree/bindings/sound/cs35l41.yaml b/Documentation/devicetree/bindings/sound/cs35l41.yaml new file mode 100644 index 000000000000..fde78c850286 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs35l41.yaml @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cs35l41.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS35L41 Speaker Amplifier + +maintainers: + +description: | + CS35L41 is a boosted mono Class D amplifier with DSP + speaker protection and equalization + +properties: + compatible: + enum: + - cirrus,cs35l40 + - cirrus,cs35l41 + + reg: + maxItems: 1 + + '#sound-dai-cells': + description: + The first cell indicating the audio interface. + const: 1 + + reset-gpios: + maxItems: 1 + + VA-supply: + description: voltage regulator phandle for the VA supply + + VP-supply: + description: voltage regulator phandle for the VP supply + + cirrus,boost-peak-milliamp: + description: + Boost-converter peak current limit in mA. + Configures the peak current by monitoring the current through the boost FET. + Range starts at 1600 mA and goes to a maximum of 4500 mA with increments + of 50 mA. See section 4.3.6 of the datasheet for details. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 1600 + maximum: 4500 + default: 4500 + + cirrus,boost-ind-nanohenry: + description: + Boost inductor value, expressed in nH. Valid + values include 1000, 1200, 1500 and 2200. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 1000 + maximum: 2200 + + cirrus,boost-cap-microfarad: + description: + Total equivalent boost capacitance on the VBST + and VAMP pins, derated at 11 volts DC. The value must be rounded to the + nearest integer and expressed in uF. + $ref: "/schemas/types.yaml#/definitions/uint32" + + cirrus,asp-sdout-hiz: + description: + Audio serial port SDOUT Hi-Z control. Sets the Hi-Z + configuration for SDOUT pin of amplifier. + 0 = Logic 0 during unused slots, and while all transmit channels disabled + 1 = Hi-Z during unused slots but logic 0 while all transmit channels disabled + 2 = (Default) Logic 0 during unused slots, but Hi-Z while all transmit channels disabled + 3 = Hi-Z during unused slots and while all transmit channels disabled + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 3 + default: 2 + + cirrus,gpio1-polarity-invert: + description: + Boolean which specifies whether the GPIO1 + level is inverted. If this property is not present the level is not inverted. + type: boolean + + cirrus,gpio1-output-enable: + description: + Boolean which specifies whether the GPIO1 pin + is configured as an output. If this property is not present the + pin will be configured as an input. + type: boolean + + cirrus,gpio1-src-select: + description: + Configures the function of the GPIO1 pin. + Note that the options are different from the GPIO2 pin + 0 = High Impedance (Default) + 1 = GPIO + 2 = Sync + 3 = MCLK input + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 3 + + cirrus,gpio2-polarity-invert: + description: + Boolean which specifies whether the GPIO2 + level is inverted. If this property is not present the level is not inverted. + type: boolean + + cirrus,gpio2-output-enable: + description: + Boolean which specifies whether the GPIO2 pin + is configured as an output. If this property is not present the + pin will be configured as an input. + type: boolean + + cirrus,gpio2-src-select: + description: + Configures the function of the GPIO2 pin. + Note that the options are different from the GPIO1 pin. + 0 = High Impedance (Default) + 1 = GPIO + 2 = Open Drain INTB + 3 = MCLK input + 4 = Push-pull INTB (active low) + 5 = Push-pull INT (active high) + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 5 + +required: + - compatible + - reg + - "#sound-dai-cells" + - cirrus,boost-peak-milliamp + - cirrus,boost-ind-nanohenry + - cirrus,boost-cap-microfarad + +unevaluatedProperties: false + +examples: + - | + cs35l41: cs35l41@2 { + compatible = "cirrus,cs35l41"; + reg = <2>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + reset-gpios = <&gpio 110 0>; + cirrus,boost-peak-milliamp = <4500>; + cirrus,boost-ind-nanohenry = <1000>; + cirrus,boost-cap-microfarad = <15>; + };
\ No newline at end of file diff --git a/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml b/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml new file mode 100644 index 000000000000..e3a1f485f664 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/linux,bt-sco.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bluetooth SCO Audio Codec Device Tree Bindings + +maintainers: + - Mark Brown <[email protected]> + +properties: + '#sound-dai-cells': + enum: + - 0 + + # For Wideband PCM + - 1 + + compatible: + enum: + - delta,dfbmcs320 + - linux,bt-sco + +required: + - '#sound-dai-cells' + - compatible + +additionalProperties: false + +examples: + - | + codec { + #sound-dai-cells = <0>; + compatible = "linux,bt-sco"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml new file mode 100644 index 000000000000..c6b070e1d014 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/linux,spdif-dit.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dummy SPDIF Transmitter Device Tree Bindings + +maintainers: + - Mark Brown <[email protected]> + +properties: + compatible: + const: linux,spdif-dit + + "#sound-dai-cells": + const: 0 + +required: + - "#sound-dai-cells" + - compatible + +additionalProperties: false + +examples: + - | + spdif-out { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/name-prefix.txt b/Documentation/devicetree/bindings/sound/name-prefix.txt deleted file mode 100644 index 645775908657..000000000000 --- a/Documentation/devicetree/bindings/sound/name-prefix.txt +++ /dev/null @@ -1,24 +0,0 @@ -Name prefix: - -Card implementing the routing property define the connection between -audio components as list of string pair. Component using the same -sink/source names may use the name prefix property to prepend the -name of their sinks/sources with the provided string. - -Optional name prefix property: -- sound-name-prefix : string using as prefix for the sink/source names of - the component. - -Example: Two instances of the same component. - -amp0: analog-amplifier@0 { - compatible = "simple-audio-amplifier"; - enable-gpios = <&gpio GPIOH_3 0>; - sound-name-prefix = "FRONT"; -}; - -amp1: analog-amplifier@1 { - compatible = "simple-audio-amplifier"; - enable-gpios = <&gpio GPIOH_4 0>; - sound-name-prefix = "BACK"; -}; diff --git a/Documentation/devicetree/bindings/sound/name-prefix.yaml b/Documentation/devicetree/bindings/sound/name-prefix.yaml new file mode 100644 index 000000000000..2fe57f87ac52 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/name-prefix.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/name-prefix.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Component sound name prefix + +maintainers: + - Jerome Brunet <[email protected]> + +properties: + sound-name-prefix: + $ref: /schemas/types.yaml#/definitions/string + description: | + Card implementing the routing property define the connection between + audio components as list of string pair. Component using the same + sink/source names may use this property to prepend the name of their + sinks/sources with the provided string. + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml index 5f6b37c251a8..0912d3e3fd8e 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml @@ -17,6 +17,9 @@ maintainers: - Jon Hunter <[email protected]> - Sameer Pujar <[email protected]> +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^dspk@[0-9a-f]*$" @@ -48,12 +51,6 @@ properties: sound-name-prefix: pattern: "^DSPK[1-9]$" - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - The name can be "DSPK1" or "DSPKx", where x depends on the maximum - available instances on a Tegra SoC. ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml index fd275a575055..62db982bb01d 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml @@ -16,6 +16,9 @@ maintainers: - Jon Hunter <[email protected]> - Sameer Pujar <[email protected]> +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^dmic@[0-9a-f]*$" @@ -49,12 +52,6 @@ properties: sound-name-prefix: pattern: "^DMIC[1-9]$" - $ref: /schemas/types.yaml#/definitions/string - description: - used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends - on the maximum available instances on a Tegra SoC. ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml index 63370709c768..f954be636697 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml @@ -16,6 +16,9 @@ maintainers: - Jon Hunter <[email protected]> - Sameer Pujar <[email protected]> +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^i2s@[0-9a-f]*$" @@ -65,12 +68,6 @@ properties: sound-name-prefix: pattern: "^I2S[1-9]$" - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends - on the maximum available instances on a Tegra SoC. ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml index ffb8fcfeb629..68e5ad2a2acc 100644 --- a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml +++ b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml @@ -9,6 +9,9 @@ title: NXP/Goodix TFA989X (TFA1) Audio Amplifiers maintainers: - Stephan Gerhold <[email protected]> +allOf: + - $ref: name-prefix.yaml# + properties: compatible: enum: @@ -21,12 +24,6 @@ properties: '#sound-dai-cells': const: 0 - sound-name-prefix: - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - vddd-supply: description: regulator phandle for the VDDD power supply. diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml new file mode 100644 index 000000000000..fbf23696f1a7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5682s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek rt5682s codec devicetree bindings + +maintainers: + - Derek Fang <[email protected]> + +description: | + Rt5682s(ALC5682I-VS) is a rt5682i variant which supports I2C only. + +properties: + compatible: + const: realtek,rt5682s + + reg: + maxItems: 1 + description: I2C address of the device. + + interrupts: + description: The CODEC's interrupt output. + + realtek,dmic1-data-pin: + enum: + - 0 # dmic1 data is not used + - 1 # using GPIO2 pin as dmic1 data pin + - 2 # using GPIO5 pin as dmic1 data pin + + realtek,dmic1-clk-pin: + enum: + - 0 # dmic1 clk is not used + - 1 # using GPIO1 pin as dmic1 clock pin + - 2 # using GPIO3 pin as dmic1 clock pin + + realtek,jd-src: + enum: + - 0 # No JD is used + - 1 # using JD1 as JD source + + realtek,ldo1-en-gpios: + description: | + The GPIO that controls the CODEC's LDO1_EN pin. + + realtek,dmic-clk-rate-hz: + description: | + Set the clock rate (hz) for the requirement of the particular DMIC. + + realtek,dmic-delay-ms: + description: | + Set the delay time (ms) for the requirement of the particular DMIC. + + realtek,dmic-clk-driving-high: + type: boolean + description: | + Set the high driving of the DMIC clock out. + + clocks: + items: + - description: phandle and clock specifier for codec MCLK. + + clock-names: + items: + const: mclk + + "#clock-cells": + const: 1 + + clock-output-names: + items: + - description: Name given for DAI word clock output. + - description: Name given for DAI bit clock output. + +additionalProperties: false + +required: + - compatible + - reg + +example: + - | + rt5682s { + compatible = "realtek,rt5682s"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <TEGRA_GPIO(U, 6) IRQ_TYPE_LEVEL_HIGH>; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + realtek,dmic1-data-pin = <1>; + realtek,dmic1-clk-pin = <1>; + realtek,jd-src = <1>; + + #clock-cells = <1>; + clock-output-names = "rt5682-dai-wclk", "rt5682-dai-bclk"; + + clocks = <&osc>; + clock-names = "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt index c473df5c878c..013f534fa059 100644 --- a/Documentation/devicetree/bindings/sound/rt5659.txt +++ b/Documentation/devicetree/bindings/sound/rt5659.txt @@ -42,7 +42,7 @@ Optional properties: - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. - realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin. -- sound-name-prefix: Please refer to name-prefix.txt +- sound-name-prefix: Please refer to name-prefix.yaml - ports: A Codec may have a single or multiple I2S interfaces. These interfaces on Codec side can be described under 'ports' or 'port'. diff --git a/Documentation/devicetree/bindings/sound/simple-amplifier.txt b/Documentation/devicetree/bindings/sound/simple-amplifier.txt deleted file mode 100644 index b1b097cc9b68..000000000000 --- a/Documentation/devicetree/bindings/sound/simple-amplifier.txt +++ /dev/null @@ -1,17 +0,0 @@ -Simple Amplifier Audio Driver - -Required properties: -- compatible : "dioo,dio2125" or "simple-audio-amplifier" - -Optional properties: -- enable-gpios : the gpio connected to the enable pin of the simple amplifier -- VCC-supply : power supply for the device, as covered - in Documentation/devicetree/bindings/regulator/regulator.txt - -Example: - -amp: analog-amplifier { - compatible = "simple-audio-amplifier"; - VCC-supply = <®ulator>; - enable-gpios = <&gpio GPIOH_3 0>; -}; diff --git a/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml new file mode 100644 index 000000000000..26379377a7ac --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/simple-audio-amplifier.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Simple Audio Amplifier Device Tree Bindings + +maintainers: + - Jerome Brunet <[email protected]> + +properties: + compatible: + enum: + - dioo,dio2125 + - simple-audio-amplifier + + enable-gpios: + maxItems: 1 + + VCC-supply: + description: > + power supply for the device + + sound-name-prefix: + $ref: /schemas/types.yaml#/definitions/string + description: > + See ./name-prefix.txt + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/meson8-gpio.h> + + analog-amplifier { + compatible = "simple-audio-amplifier"; + VCC-supply = <®ulator>; + enable-gpios = <&gpio GPIOH_3 0>; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml index 5986d1fcbb54..c597d9dfb001 100644 --- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml +++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml @@ -13,6 +13,9 @@ description: | Simple audio multiplexers are driven using gpios, allowing to select which of their input line is connected to the output line. +allOf: + - $ref: name-prefix.yaml# + properties: compatible: const: simple-audio-mux @@ -21,12 +24,6 @@ properties: description: | GPIOs used to select the input line. - sound-name-prefix: - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - required: - compatible - mux-gpios diff --git a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt b/Documentation/devicetree/bindings/sound/spdif-transmitter.txt deleted file mode 100644 index 55a85841dd85..000000000000 --- a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt +++ /dev/null @@ -1,10 +0,0 @@ -Device-Tree bindings for dummy spdif transmitter - -Required properties: - - compatible: should be "linux,spdif-dit". - -Example node: - - codec: spdif-transmitter { - compatible = "linux,spdif-dit"; - }; diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml new file mode 100644 index 000000000000..944e5859c962 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/wlf,wm8978.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wolfson WM8978 Codec Device Tree Bindings + +maintainers: + +properties: + '#sound-dai-cells': + const: 0 + + compatible: + const: wlf,wm8978 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 526000 + +required: + - '#sound-dai-cells' + - compatible + - reg + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + codec@0 { + #sound-dai-cells = <0>; + compatible = "wlf,wm8978"; + reg = <0>; + spi-max-frequency = <500000>; + }; + }; + + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@0 { + #sound-dai-cells = <0>; + compatible = "wlf,wm8978"; + reg = <0>; + }; + }; + +... diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index ebd27f883033..8ce840c7ecc8 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -204,9 +204,6 @@ struct tegra_slink_data { struct dma_async_tx_descriptor *tx_dma_desc; }; -static int tegra_slink_runtime_suspend(struct device *dev); -static int tegra_slink_runtime_resume(struct device *dev); - static inline u32 tegra_slink_readl(struct tegra_slink_data *tspi, unsigned long reg) { @@ -1185,6 +1182,7 @@ static int tegra_slink_resume(struct device *dev) } #endif +#ifdef CONFIG_PM static int tegra_slink_runtime_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); @@ -1210,6 +1208,7 @@ static int tegra_slink_runtime_resume(struct device *dev) } return 0; } +#endif /* CONFIG_PM */ static const struct dev_pm_ops slink_pm_ops = { SET_RUNTIME_PM_OPS(tegra_slink_runtime_suspend, diff --git a/include/dt-bindings/sound/qcom,lpass.h b/include/dt-bindings/sound/qcom,lpass.h index 7b0b80b38699..187af4591cd8 100644 --- a/include/dt-bindings/sound/qcom,lpass.h +++ b/include/dt-bindings/sound/qcom,lpass.h @@ -10,6 +10,11 @@ #define LPASS_DP_RX 5 +#define LPASS_CDC_DMA_RX0 6 +#define LPASS_CDC_DMA_TX3 7 +#define LPASS_CDC_DMA_VA0 8 +#define LPASS_MAX_PORTS 9 + #define LPASS_MCLK0 0 #endif /* __DT_QCOM_LPASS_H */ diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h new file mode 100644 index 000000000000..1f1e3c6c9be1 --- /dev/null +++ b/include/sound/cs35l41.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * linux/sound/cs35l41.h -- Platform data for CS35L41 + * + * Copyright (c) 2017-2021 Cirrus Logic Inc. + * + * Author: David Rhodes <[email protected]> + */ + +#ifndef __CS35L41_H +#define __CS35L41_H + +enum cs35l41_clk_ids { + CS35L41_CLKID_SCLK = 0, + CS35L41_CLKID_LRCLK = 1, + CS35L41_CLKID_MCLK = 4, +}; + +struct cs35l41_irq_cfg { + bool irq_pol_inv; + bool irq_out_en; + int irq_src_sel; +}; + +struct cs35l41_platform_data { + int bst_ind; + int bst_ipk; + int bst_cap; + int dout_hiz; + struct cs35l41_irq_cfg irq_config1; + struct cs35l41_irq_cfg irq_config2; +}; + +#endif /* __CS35L41_H */ diff --git a/include/sound/rt5682s.h b/include/sound/rt5682s.h new file mode 100644 index 000000000000..accfbc2dcdd2 --- /dev/null +++ b/include/sound/rt5682s.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/sound/rt5682s.h -- Platform data for RT5682I-VS + * + * Copyright 2021 Realtek Microelectronics + */ + +#ifndef __LINUX_SND_RT5682S_H +#define __LINUX_SND_RT5682S_H + +enum rt5682s_dmic1_data_pin { + RT5682S_DMIC1_DATA_NULL, + RT5682S_DMIC1_DATA_GPIO2, + RT5682S_DMIC1_DATA_GPIO5, +}; + +enum rt5682s_dmic1_clk_pin { + RT5682S_DMIC1_CLK_NULL, + RT5682S_DMIC1_CLK_GPIO1, + RT5682S_DMIC1_CLK_GPIO3, +}; + +enum rt5682s_jd_src { + RT5682S_JD_NULL, + RT5682S_JD1, +}; + +enum rt5682s_dai_clks { + RT5682S_DAI_WCLK_IDX, + RT5682S_DAI_BCLK_IDX, + RT5682S_DAI_NUM_CLKS, +}; + +struct rt5682s_platform_data { + + int ldo1_en; /* GPIO for LDO1_EN */ + + enum rt5682s_dmic1_data_pin dmic1_data_pin; + enum rt5682s_dmic1_clk_pin dmic1_clk_pin; + enum rt5682s_jd_src jd_src; + unsigned int dmic_clk_rate; + unsigned int dmic_delay; + bool dmic_clk_driving_high; + + const char *dai_clk_names[RT5682S_DAI_NUM_CLKS]; +}; + +#endif diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index b3df98a9f9f3..b2065f3fe42c 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -33,7 +33,7 @@ static struct clk *da7219_dai_wclk; static struct clk *da7219_dai_bclk; static struct clk *rt5682_dai_wclk; static struct clk *rt5682_dai_bclk; -extern bool bt_uart_enable; + void *acp_soc_is_rltk_max(struct device *dev); static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) @@ -760,8 +760,8 @@ static int cz_probe(struct platform_device *pdev) "devm_snd_soc_register_card(%s) failed\n", card->name); } - bt_uart_enable = !device_property_read_bool(&pdev->dev, - "bt-pad-enable"); + acp_bt_uart_enable = !device_property_read_bool(&pdev->dev, + "bt-pad-enable"); return 0; } diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 11b3c4f39eba..1f322accd9ea 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -36,8 +36,8 @@ #define ST_MIN_BUFFER ST_MAX_BUFFER #define DRV_NAME "acp_audio_dma" -bool bt_uart_enable = true; -EXPORT_SYMBOL(bt_uart_enable); +bool acp_bt_uart_enable = true; +EXPORT_SYMBOL(acp_bt_uart_enable); static const struct snd_pcm_hardware acp_pcm_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | @@ -596,7 +596,7 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type) acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); /* For BT instance change pins from UART to BT */ - if (!bt_uart_enable) { + if (!acp_bt_uart_enable) { val = acp_reg_read(acp_mmio, mmACP_BT_UART_PAD_SEL); val |= ACP_BT_UART_PAD_SELECT_MASK; acp_reg_write(val, acp_mmio, mmACP_BT_UART_PAD_SEL); diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index e5ab6c6040a6..85529ed7e5f5 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -204,4 +204,6 @@ typedef struct acp_dma_dscr_transfer { u32 reserved; } acp_dma_dscr_transfer_t; +extern bool acp_bt_uart_enable; + #endif /*__ACP_HW_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 82ee233a269d..ab7ac5e0bd68 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -61,6 +61,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS35L34 imply SND_SOC_CS35L35 imply SND_SOC_CS35L36 + imply SND_SOC_CS35L41_SPI + imply SND_SOC_CS35L41_I2C imply SND_SOC_CS42L42 imply SND_SOC_CS42L51_I2C imply SND_SOC_CS42L52 @@ -180,6 +182,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT5677 imply SND_SOC_RT5682_I2C imply SND_SOC_RT5682_SDW + imply SND_SOC_RT5682S imply SND_SOC_RT700_SDW imply SND_SOC_RT711_SDW imply SND_SOC_RT711_SDCA_SDW @@ -602,6 +605,16 @@ config SND_SOC_CS35L36 tristate "Cirrus Logic CS35L36 CODEC" depends on I2C +config SND_SOC_CS35L41_SPI + tristate "Cirrus Logic CS35L41 CODEC (SPI)" + depends on SPI_MASTER + select REGMAP_SPI + +config SND_SOC_CS35L41_I2C + tristate "Cirrus Logic CS35L41 CODEC (I2C)" + depends on I2C + select REGMAP_I2C + config SND_SOC_CS42L42 tristate "Cirrus Logic CS42L42 CODEC" depends on I2C @@ -1249,6 +1262,10 @@ config SND_SOC_RT5682_SDW select SND_SOC_RT5682 select REGMAP_SOUNDWIRE +config SND_SOC_RT5682S + tristate + depends on I2C + config SND_SOC_RT700 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8dcea2c4604a..4cf939d0d3fb 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -54,6 +54,8 @@ snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs35l35-objs := cs35l35.o snd-soc-cs35l36-objs := cs35l36.o +snd-soc-cs35l41-spi-objs := cs35l41-spi.o cs35l41.o cs35l41-tables.o +snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o cs35l41.o cs35l41-tables.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o @@ -198,6 +200,7 @@ snd-soc-rt5677-spi-objs := rt5677-spi.o snd-soc-rt5682-objs := rt5682.o snd-soc-rt5682-sdw-objs := rt5682-sdw.o snd-soc-rt5682-i2c-objs := rt5682-i2c.o +snd-soc-rt5682s-objs := rt5682s.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt711-objs := rt711.o rt711-sdw.o snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o @@ -385,6 +388,8 @@ obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o +obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o +obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o @@ -526,6 +531,7 @@ obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o obj-$(CONFIG_SND_SOC_RT5682_I2C) += snd-soc-rt5682-i2c.o obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o +obj-$(CONFIG_SND_SOC_RT5682S) += snd-soc-rt5682s.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c new file mode 100644 index 000000000000..dc9da78df412 --- /dev/null +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-i2c.c -- CS35l41 I2C driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <[email protected]> + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <sound/cs35l41.h> +#include "cs35l41.h" + +static struct regmap_config cs35l41_regmap_i2c = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct i2c_device_id cs35l41_id_i2c[] = { + { "cs35l40", 0 }, + { "cs35l41", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c); + +static int cs35l41_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs35l41_private *cs35l41; + struct device *dev = &client->dev; + struct cs35l41_platform_data *pdata = dev_get_platdata(dev); + const struct regmap_config *regmap_config = &cs35l41_regmap_i2c; + int ret; + + cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL); + + if (!cs35l41) + return -ENOMEM; + + cs35l41->dev = dev; + cs35l41->irq = client->irq; + + i2c_set_clientdata(client, cs35l41); + cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(cs35l41->regmap)) { + ret = PTR_ERR(cs35l41->regmap); + dev_err(cs35l41->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + return cs35l41_probe(cs35l41, pdata); +} + +static int cs35l41_i2c_remove(struct i2c_client *client) +{ + struct cs35l41_private *cs35l41 = i2c_get_clientdata(client); + + return cs35l41_remove(cs35l41); +} + +#ifdef CONFIG_OF +static const struct of_device_id cs35l41_of_match[] = { + { .compatible = "cirrus,cs35l40" }, + { .compatible = "cirrus,cs35l41" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l41_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l41_acpi_match[] = { + { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); +#endif + +static struct i2c_driver cs35l41_i2c_driver = { + .driver = { + .name = "cs35l41", + .of_match_table = of_match_ptr(cs35l41_of_match), + .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), + }, + .id_table = cs35l41_id_i2c, + .probe = cs35l41_i2c_probe, + .remove = cs35l41_i2c_remove, +}; + +module_i2c_driver(cs35l41_i2c_driver); + +MODULE_DESCRIPTION("I2C CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c new file mode 100644 index 000000000000..e253c6d82ce8 --- /dev/null +++ b/sound/soc/codecs/cs35l41-spi.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-spi.c -- CS35l41 SPI driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <[email protected]> + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> + +#include <sound/cs35l41.h> +#include "cs35l41.h" + +static struct regmap_config cs35l41_regmap_spi = { + .reg_bits = 32, + .val_bits = 32, + .pad_bits = 16, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct spi_device_id cs35l41_id_spi[] = { + { "cs35l40", 0 }, + { "cs35l41", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(spi, cs35l41_id_spi); + +static void cs35l41_spi_otp_setup(struct cs35l41_private *cs35l41, + bool is_pre_setup, unsigned int *freq) +{ + struct spi_device *spi; + u32 orig_spi_freq; + + spi = to_spi_device(cs35l41->dev); + + if (!spi) { + dev_err(cs35l41->dev, "%s: No SPI device\n", __func__); + return; + } + + if (is_pre_setup) { + orig_spi_freq = spi->max_speed_hz; + if (orig_spi_freq > CS35L41_SPI_MAX_FREQ_OTP) { + spi->max_speed_hz = CS35L41_SPI_MAX_FREQ_OTP; + spi_setup(spi); + } + *freq = orig_spi_freq; + } else { + if (spi->max_speed_hz != *freq) { + spi->max_speed_hz = *freq; + spi_setup(spi); + } + } +} + +static int cs35l41_spi_probe(struct spi_device *spi) +{ + const struct regmap_config *regmap_config = &cs35l41_regmap_spi; + struct cs35l41_platform_data *pdata = + dev_get_platdata(&spi->dev); + struct cs35l41_private *cs35l41; + int ret; + + cs35l41 = devm_kzalloc(&spi->dev, + sizeof(struct cs35l41_private), + GFP_KERNEL); + if (!cs35l41) + return -ENOMEM; + + + spi_set_drvdata(spi, cs35l41); + cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config); + if (IS_ERR(cs35l41->regmap)) { + ret = PTR_ERR(cs35l41->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + cs35l41->dev = &spi->dev; + cs35l41->irq = spi->irq; + cs35l41->otp_setup = cs35l41_spi_otp_setup; + + return cs35l41_probe(cs35l41, pdata); +} + +static int cs35l41_spi_remove(struct spi_device *spi) +{ + struct cs35l41_private *cs35l41 = spi_get_drvdata(spi); + + return cs35l41_remove(cs35l41); +} + +#ifdef CONFIG_OF +static const struct of_device_id cs35l41_of_match[] = { + { .compatible = "cirrus,cs35l40" }, + { .compatible = "cirrus,cs35l41" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l41_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l41_acpi_match[] = { + { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); +#endif + +static struct spi_driver cs35l41_spi_driver = { + .driver = { + .name = "cs35l41", + .of_match_table = of_match_ptr(cs35l41_of_match), + .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), + }, + .id_table = cs35l41_id_spi, + .probe = cs35l41_spi_probe, + .remove = cs35l41_spi_remove, +}; + +module_spi_driver(cs35l41_spi_driver); + +MODULE_DESCRIPTION("SPI CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-tables.c new file mode 100644 index 000000000000..155db0e6e3d8 --- /dev/null +++ b/sound/soc/codecs/cs35l41-tables.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-tables.c -- CS35L41 ALSA SoC audio driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <[email protected]> + +#include "cs35l41.h" + +const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = { + {CS35L41_PWR_CTRL1, 0x00000000}, + {CS35L41_PWR_CTRL3, 0x01000010}, + {CS35L41_GPIO_PAD_CONTROL, 0x00000000}, + {CS35L41_SP_ENABLES, 0x00000000}, + {CS35L41_SP_RATE_CTRL, 0x00000028}, + {CS35L41_SP_FORMAT, 0x18180200}, + {CS35L41_SP_HIZ_CTRL, 0x00000002}, + {CS35L41_SP_FRAME_TX_SLOT, 0x03020100}, + {CS35L41_SP_FRAME_RX_SLOT, 0x00000100}, + {CS35L41_SP_TX_WL, 0x00000018}, + {CS35L41_SP_RX_WL, 0x00000018}, + {CS35L41_DAC_PCM1_SRC, 0x00000008}, + {CS35L41_ASP_TX1_SRC, 0x00000018}, + {CS35L41_ASP_TX2_SRC, 0x00000019}, + {CS35L41_ASP_TX3_SRC, 0x00000020}, + {CS35L41_ASP_TX4_SRC, 0x00000021}, + {CS35L41_DSP1_RX1_SRC, 0x00000008}, + {CS35L41_DSP1_RX2_SRC, 0x00000009}, + {CS35L41_DSP1_RX3_SRC, 0x00000018}, + {CS35L41_DSP1_RX4_SRC, 0x00000019}, + {CS35L41_DSP1_RX5_SRC, 0x00000020}, + {CS35L41_DSP1_RX6_SRC, 0x00000021}, + {CS35L41_DSP1_RX7_SRC, 0x0000003A}, + {CS35L41_DSP1_RX8_SRC, 0x00000001}, + {CS35L41_NGATE1_SRC, 0x00000008}, + {CS35L41_NGATE2_SRC, 0x00000009}, + {CS35L41_AMP_DIG_VOL_CTRL, 0x00008000}, + {CS35L41_CLASSH_CFG, 0x000B0405}, + {CS35L41_WKFET_CFG, 0x00000111}, + {CS35L41_NG_CFG, 0x00000033}, + {CS35L41_AMP_GAIN_CTRL, 0x00000273}, + {CS35L41_GPIO1_CTRL1, 0xE1000001}, + {CS35L41_GPIO2_CTRL1, 0xE1000001}, + {CS35L41_MIXER_NGATE_CFG, 0x00000000}, + {CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303}, + {CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303}, +}; + +bool cs35l41_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_REVID: + case CS35L41_FABID: + case CS35L41_RELID: + case CS35L41_OTPID: + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: + case CS35L41_OTP_CTRL0: + case CS35L41_OTP_CTRL3: + case CS35L41_OTP_CTRL4: + case CS35L41_OTP_CTRL5: + case CS35L41_OTP_CTRL6: + case CS35L41_OTP_CTRL7: + case CS35L41_OTP_CTRL8: + case CS35L41_PWR_CTRL1: + case CS35L41_PWR_CTRL2: + case CS35L41_PWR_CTRL3: + case CS35L41_CTRL_OVRRIDE: + case CS35L41_AMP_OUT_MUTE: + case CS35L41_PROTECT_REL_ERR_IGN: + case CS35L41_GPIO_PAD_CONTROL: + case CS35L41_JTAG_CONTROL: + case CS35L41_PLL_CLK_CTRL: + case CS35L41_DSP_CLK_CTRL: + case CS35L41_GLOBAL_CLK_CTRL: + case CS35L41_DATA_FS_SEL: + case CS35L41_MDSYNC_EN: + case CS35L41_MDSYNC_TX_ID: + case CS35L41_MDSYNC_PWR_CTRL: + case CS35L41_MDSYNC_DATA_TX: + case CS35L41_MDSYNC_TX_STATUS: + case CS35L41_MDSYNC_DATA_RX: + case CS35L41_MDSYNC_RX_STATUS: + case CS35L41_MDSYNC_ERR_STATUS: + case CS35L41_MDSYNC_SYNC_PTE2: + case CS35L41_MDSYNC_SYNC_PTE3: + case CS35L41_MDSYNC_SYNC_MSM_STATUS: + case CS35L41_BSTCVRT_VCTRL1: + case CS35L41_BSTCVRT_VCTRL2: + case CS35L41_BSTCVRT_PEAK_CUR: + case CS35L41_BSTCVRT_SFT_RAMP: + case CS35L41_BSTCVRT_COEFF: + case CS35L41_BSTCVRT_SLOPE_LBST: + case CS35L41_BSTCVRT_SW_FREQ: + case CS35L41_BSTCVRT_DCM_CTRL: + case CS35L41_BSTCVRT_DCM_MODE_FORCE: + case CS35L41_BSTCVRT_OVERVOLT_CTRL: + case CS35L41_VI_VOL_POL: + case CS35L41_DTEMP_WARN_THLD: + case CS35L41_DTEMP_CFG: + case CS35L41_DTEMP_EN: + case CS35L41_VPVBST_FS_SEL: + case CS35L41_SP_ENABLES: + case CS35L41_SP_RATE_CTRL: + case CS35L41_SP_FORMAT: + case CS35L41_SP_HIZ_CTRL: + case CS35L41_SP_FRAME_TX_SLOT: + case CS35L41_SP_FRAME_RX_SLOT: + case CS35L41_SP_TX_WL: + case CS35L41_SP_RX_WL: + case CS35L41_DAC_PCM1_SRC: + case CS35L41_ASP_TX1_SRC: + case CS35L41_ASP_TX2_SRC: + case CS35L41_ASP_TX3_SRC: + case CS35L41_ASP_TX4_SRC: + case CS35L41_DSP1_RX1_SRC: + case CS35L41_DSP1_RX2_SRC: + case CS35L41_DSP1_RX3_SRC: + case CS35L41_DSP1_RX4_SRC: + case CS35L41_DSP1_RX5_SRC: + case CS35L41_DSP1_RX6_SRC: + case CS35L41_DSP1_RX7_SRC: + case CS35L41_DSP1_RX8_SRC: + case CS35L41_NGATE1_SRC: + case CS35L41_NGATE2_SRC: + case CS35L41_AMP_DIG_VOL_CTRL: + case CS35L41_VPBR_CFG: + case CS35L41_VBBR_CFG: + case CS35L41_VPBR_STATUS: + case CS35L41_VBBR_STATUS: + case CS35L41_OVERTEMP_CFG: + case CS35L41_AMP_ERR_VOL: + case CS35L41_VOL_STATUS_TO_DSP: + case CS35L41_CLASSH_CFG: + case CS35L41_WKFET_CFG: + case CS35L41_NG_CFG: + case CS35L41_AMP_GAIN_CTRL: + case CS35L41_DAC_MSM_CFG: + case CS35L41_IRQ1_CFG: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_MASK1: + case CS35L41_IRQ1_MASK2: + case CS35L41_IRQ1_MASK3: + case CS35L41_IRQ1_MASK4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_CFG: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_MASK1: + case CS35L41_IRQ2_MASK2: + case CS35L41_IRQ2_MASK3: + case CS35L41_IRQ2_MASK4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_GPIO1_CTRL1: + case CS35L41_GPIO2_CTRL1: + case CS35L41_MIXER_NGATE_CFG: + case CS35L41_MIXER_NGATE_CH1_CFG: + case CS35L41_MIXER_NGATE_CH2_CFG: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_CLOCK_DETECT_1: + case CS35L41_DIE_STS1: + case CS35L41_DIE_STS2: + case CS35L41_TEMP_CAL1: + case CS35L41_TEMP_CAL2: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + /*test regs*/ + case CS35L41_PLL_OVR: + case CS35L41_BST_TEST_DUTY: + case CS35L41_DIGPWM_IOCTRL: + return true; + default: + return false; + } +} + +bool cs35l41_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_SFT_RESET: + case CS35L41_FABID: + case CS35L41_REVID: + case CS35L41_DTEMP_EN: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +static const struct cs35l41_otp_packed_element_t + otp_map_1[CS35L41_NUM_OTP_ELEM] = { + /* addr shift size */ + {0x00002030, 0, 4}, /*TRIM_OSC_FREQ_TRIM*/ + {0x00002030, 7, 1}, /*TRIM_OSC_TRIM_DONE*/ + {0x0000208c, 24, 6}, /*TST_DIGREG_VREF_TRIM*/ + {0x00002090, 14, 4}, /*TST_REF_TRIM*/ + {0x00002090, 10, 4}, /*TST_REF_TEMPCO_TRIM*/ + {0x0000300C, 11, 4}, /*PLL_LDOA_TST_VREF_TRIM*/ + {0x0000394C, 23, 2}, /*BST_ATEST_CM_VOFF*/ + {0x00003950, 0, 7}, /*BST_ATRIM_IADC_OFFSET*/ + {0x00003950, 8, 7}, /*BST_ATRIM_IADC_GAIN1*/ + {0x00003950, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + {0x00003950, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN1*/ + {0x00003954, 0, 7}, /*BST_ATRIM_IADC_OFFSET2*/ + {0x00003954, 8, 7}, /*BST_ATRIM_IADC_GAIN2*/ + {0x00003954, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + {0x00003954, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN2*/ + {0x00003958, 0, 7}, /*BST_ATRIM_IADC_OFFSET3*/ + {0x00003958, 8, 7}, /*BST_ATRIM_IADC_GAIN3*/ + {0x00003958, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + {0x00003958, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN3*/ + {0x0000395C, 0, 7}, /*BST_ATRIM_IADC_OFFSET4*/ + {0x0000395C, 8, 7}, /*BST_ATRIM_IADC_GAIN4*/ + {0x0000395C, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + {0x0000395C, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN4*/ + {0x0000416C, 0, 8}, /*VMON_GAIN_OTP_VAL*/ + {0x00004160, 0, 7}, /*VMON_OFFSET_OTP_VAL*/ + {0x0000416C, 8, 8}, /*IMON_GAIN_OTP_VAL*/ + {0x00004160, 16, 10}, /*IMON_OFFSET_OTP_VAL*/ + {0x0000416C, 16, 12}, /*VMON_CM_GAIN_OTP_VAL*/ + {0x0000416C, 28, 1}, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + {0x00004170, 0, 6}, /*IMON_CAL_TEMPCO_OTP_VAL*/ + {0x00004170, 6, 1}, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + {0x00004170, 8, 6}, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + {0x00004170, 14, 1}, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + {0x00004170, 16, 9}, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + {0x00004360, 0, 5}, /*TEMP_GAIN_OTP_VAL*/ + {0x00004360, 6, 9}, /*TEMP_OFFSET_OTP_VAL*/ + {0x00004448, 0, 8}, /*VP_SARADC_OFFSET*/ + {0x00004448, 8, 8}, /*VP_GAIN_INDEX*/ + {0x00004448, 16, 8}, /*VBST_SARADC_OFFSET*/ + {0x00004448, 24, 8}, /*VBST_GAIN_INDEX*/ + {0x0000444C, 0, 3}, /*ANA_SELINVREF*/ + {0x00006E30, 0, 5}, /*GAIN_ERR_COEFF_0*/ + {0x00006E30, 8, 5}, /*GAIN_ERR_COEFF_1*/ + {0x00006E30, 16, 5}, /*GAIN_ERR_COEFF_2*/ + {0x00006E30, 24, 5}, /*GAIN_ERR_COEFF_3*/ + {0x00006E34, 0, 5}, /*GAIN_ERR_COEFF_4*/ + {0x00006E34, 8, 5}, /*GAIN_ERR_COEFF_5*/ + {0x00006E34, 16, 5}, /*GAIN_ERR_COEFF_6*/ + {0x00006E34, 24, 5}, /*GAIN_ERR_COEFF_7*/ + {0x00006E38, 0, 5}, /*GAIN_ERR_COEFF_8*/ + {0x00006E38, 8, 5}, /*GAIN_ERR_COEFF_9*/ + {0x00006E38, 16, 5}, /*GAIN_ERR_COEFF_10*/ + {0x00006E38, 24, 5}, /*GAIN_ERR_COEFF_11*/ + {0x00006E3C, 0, 5}, /*GAIN_ERR_COEFF_12*/ + {0x00006E3C, 8, 5}, /*GAIN_ERR_COEFF_13*/ + {0x00006E3C, 16, 5}, /*GAIN_ERR_COEFF_14*/ + {0x00006E3C, 24, 5}, /*GAIN_ERR_COEFF_15*/ + {0x00006E40, 0, 5}, /*GAIN_ERR_COEFF_16*/ + {0x00006E40, 8, 5}, /*GAIN_ERR_COEFF_17*/ + {0x00006E40, 16, 5}, /*GAIN_ERR_COEFF_18*/ + {0x00006E40, 24, 5}, /*GAIN_ERR_COEFF_19*/ + {0x00006E44, 0, 5}, /*GAIN_ERR_COEFF_20*/ + {0x00006E48, 0, 10}, /*VOFF_GAIN_0*/ + {0x00006E48, 10, 10}, /*VOFF_GAIN_1*/ + {0x00006E48, 20, 10}, /*VOFF_GAIN_2*/ + {0x00006E4C, 0, 10}, /*VOFF_GAIN_3*/ + {0x00006E4C, 10, 10}, /*VOFF_GAIN_4*/ + {0x00006E4C, 20, 10}, /*VOFF_GAIN_5*/ + {0x00006E50, 0, 10}, /*VOFF_GAIN_6*/ + {0x00006E50, 10, 10}, /*VOFF_GAIN_7*/ + {0x00006E50, 20, 10}, /*VOFF_GAIN_8*/ + {0x00006E54, 0, 10}, /*VOFF_GAIN_9*/ + {0x00006E54, 10, 10}, /*VOFF_GAIN_10*/ + {0x00006E54, 20, 10}, /*VOFF_GAIN_11*/ + {0x00006E58, 0, 10}, /*VOFF_GAIN_12*/ + {0x00006E58, 10, 10}, /*VOFF_GAIN_13*/ + {0x00006E58, 20, 10}, /*VOFF_GAIN_14*/ + {0x00006E5C, 0, 10}, /*VOFF_GAIN_15*/ + {0x00006E5C, 10, 10}, /*VOFF_GAIN_16*/ + {0x00006E5C, 20, 10}, /*VOFF_GAIN_17*/ + {0x00006E60, 0, 10}, /*VOFF_GAIN_18*/ + {0x00006E60, 10, 10}, /*VOFF_GAIN_19*/ + {0x00006E60, 20, 10}, /*VOFF_GAIN_20*/ + {0x00006E64, 0, 10}, /*VOFF_INT1*/ + {0x00007418, 7, 5}, /*DS_SPK_INT1_CAP_TRIM*/ + {0x0000741C, 0, 5}, /*DS_SPK_INT2_CAP_TRIM*/ + {0x0000741C, 11, 4}, /*DS_SPK_LPF_CAP_TRIM*/ + {0x0000741C, 19, 4}, /*DS_SPK_QUAN_CAP_TRIM*/ + {0x00007434, 17, 1}, /*FORCE_CAL*/ + {0x00007434, 18, 7}, /*CAL_OVERRIDE*/ + {0x00007068, 0, 9}, /*MODIX*/ + {0x0000410C, 7, 1}, /*VIMON_DLY_NOT_COMB*/ + {0x0000400C, 0, 7}, /*VIMON_DLY*/ + {0x00000000, 0, 1}, /*extra bit*/ + {0x00017040, 0, 8}, /*X_COORDINATE*/ + {0x00017040, 8, 8}, /*Y_COORDINATE*/ + {0x00017040, 16, 8}, /*WAFER_ID*/ + {0x00017040, 24, 8}, /*DVS*/ + {0x00017044, 0, 24}, /*LOT_NUMBER*/ +}; + +static const struct cs35l41_otp_packed_element_t + otp_map_2[CS35L41_NUM_OTP_ELEM] = { + /* addr shift size */ + {0x00002030, 0, 4}, /*TRIM_OSC_FREQ_TRIM*/ + {0x00002030, 7, 1}, /*TRIM_OSC_TRIM_DONE*/ + {0x0000208c, 24, 6}, /*TST_DIGREG_VREF_TRIM*/ + {0x00002090, 14, 4}, /*TST_REF_TRIM*/ + {0x00002090, 10, 4}, /*TST_REF_TEMPCO_TRIM*/ + {0x0000300C, 11, 4}, /*PLL_LDOA_TST_VREF_TRIM*/ + {0x0000394C, 23, 2}, /*BST_ATEST_CM_VOFF*/ + {0x00003950, 0, 7}, /*BST_ATRIM_IADC_OFFSET*/ + {0x00003950, 8, 7}, /*BST_ATRIM_IADC_GAIN1*/ + {0x00003950, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + {0x00003950, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN1*/ + {0x00003954, 0, 7}, /*BST_ATRIM_IADC_OFFSET2*/ + {0x00003954, 8, 7}, /*BST_ATRIM_IADC_GAIN2*/ + {0x00003954, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + {0x00003954, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN2*/ + {0x00003958, 0, 7}, /*BST_ATRIM_IADC_OFFSET3*/ + {0x00003958, 8, 7}, /*BST_ATRIM_IADC_GAIN3*/ + {0x00003958, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + {0x00003958, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN3*/ + {0x0000395C, 0, 7}, /*BST_ATRIM_IADC_OFFSET4*/ + {0x0000395C, 8, 7}, /*BST_ATRIM_IADC_GAIN4*/ + {0x0000395C, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + {0x0000395C, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN4*/ + {0x0000416C, 0, 8}, /*VMON_GAIN_OTP_VAL*/ + {0x00004160, 0, 7}, /*VMON_OFFSET_OTP_VAL*/ + {0x0000416C, 8, 8}, /*IMON_GAIN_OTP_VAL*/ + {0x00004160, 16, 10}, /*IMON_OFFSET_OTP_VAL*/ + {0x0000416C, 16, 12}, /*VMON_CM_GAIN_OTP_VAL*/ + {0x0000416C, 28, 1}, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + {0x00004170, 0, 6}, /*IMON_CAL_TEMPCO_OTP_VAL*/ + {0x00004170, 6, 1}, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + {0x00004170, 8, 6}, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + {0x00004170, 14, 1}, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + {0x00004170, 16, 9}, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + {0x00004360, 0, 5}, /*TEMP_GAIN_OTP_VAL*/ + {0x00004360, 6, 9}, /*TEMP_OFFSET_OTP_VAL*/ + {0x00004448, 0, 8}, /*VP_SARADC_OFFSET*/ + {0x00004448, 8, 8}, /*VP_GAIN_INDEX*/ + {0x00004448, 16, 8}, /*VBST_SARADC_OFFSET*/ + {0x00004448, 24, 8}, /*VBST_GAIN_INDEX*/ + {0x0000444C, 0, 3}, /*ANA_SELINVREF*/ + {0x00006E30, 0, 5}, /*GAIN_ERR_COEFF_0*/ + {0x00006E30, 8, 5}, /*GAIN_ERR_COEFF_1*/ + {0x00006E30, 16, 5}, /*GAIN_ERR_COEFF_2*/ + {0x00006E30, 24, 5}, /*GAIN_ERR_COEFF_3*/ + {0x00006E34, 0, 5}, /*GAIN_ERR_COEFF_4*/ + {0x00006E34, 8, 5}, /*GAIN_ERR_COEFF_5*/ + {0x00006E34, 16, 5}, /*GAIN_ERR_COEFF_6*/ + {0x00006E34, 24, 5}, /*GAIN_ERR_COEFF_7*/ + {0x00006E38, 0, 5}, /*GAIN_ERR_COEFF_8*/ + {0x00006E38, 8, 5}, /*GAIN_ERR_COEFF_9*/ + {0x00006E38, 16, 5}, /*GAIN_ERR_COEFF_10*/ + {0x00006E38, 24, 5}, /*GAIN_ERR_COEFF_11*/ + {0x00006E3C, 0, 5}, /*GAIN_ERR_COEFF_12*/ + {0x00006E3C, 8, 5}, /*GAIN_ERR_COEFF_13*/ + {0x00006E3C, 16, 5}, /*GAIN_ERR_COEFF_14*/ + {0x00006E3C, 24, 5}, /*GAIN_ERR_COEFF_15*/ + {0x00006E40, 0, 5}, /*GAIN_ERR_COEFF_16*/ + {0x00006E40, 8, 5}, /*GAIN_ERR_COEFF_17*/ + {0x00006E40, 16, 5}, /*GAIN_ERR_COEFF_18*/ + {0x00006E40, 24, 5}, /*GAIN_ERR_COEFF_19*/ + {0x00006E44, 0, 5}, /*GAIN_ERR_COEFF_20*/ + {0x00006E48, 0, 10}, /*VOFF_GAIN_0*/ + {0x00006E48, 10, 10}, /*VOFF_GAIN_1*/ + {0x00006E48, 20, 10}, /*VOFF_GAIN_2*/ + {0x00006E4C, 0, 10}, /*VOFF_GAIN_3*/ + {0x00006E4C, 10, 10}, /*VOFF_GAIN_4*/ + {0x00006E4C, 20, 10}, /*VOFF_GAIN_5*/ + {0x00006E50, 0, 10}, /*VOFF_GAIN_6*/ + {0x00006E50, 10, 10}, /*VOFF_GAIN_7*/ + {0x00006E50, 20, 10}, /*VOFF_GAIN_8*/ + {0x00006E54, 0, 10}, /*VOFF_GAIN_9*/ + {0x00006E54, 10, 10}, /*VOFF_GAIN_10*/ + {0x00006E54, 20, 10}, /*VOFF_GAIN_11*/ + {0x00006E58, 0, 10}, /*VOFF_GAIN_12*/ + {0x00006E58, 10, 10}, /*VOFF_GAIN_13*/ + {0x00006E58, 20, 10}, /*VOFF_GAIN_14*/ + {0x00006E5C, 0, 10}, /*VOFF_GAIN_15*/ + {0x00006E5C, 10, 10}, /*VOFF_GAIN_16*/ + {0x00006E5C, 20, 10}, /*VOFF_GAIN_17*/ + {0x00006E60, 0, 10}, /*VOFF_GAIN_18*/ + {0x00006E60, 10, 10}, /*VOFF_GAIN_19*/ + {0x00006E60, 20, 10}, /*VOFF_GAIN_20*/ + {0x00006E64, 0, 10}, /*VOFF_INT1*/ + {0x00007418, 7, 5}, /*DS_SPK_INT1_CAP_TRIM*/ + {0x0000741C, 0, 5}, /*DS_SPK_INT2_CAP_TRIM*/ + {0x0000741C, 11, 4}, /*DS_SPK_LPF_CAP_TRIM*/ + {0x0000741C, 19, 4}, /*DS_SPK_QUAN_CAP_TRIM*/ + {0x00007434, 17, 1}, /*FORCE_CAL*/ + {0x00007434, 18, 7}, /*CAL_OVERRIDE*/ + {0x00007068, 0, 9}, /*MODIX*/ + {0x0000410C, 7, 1}, /*VIMON_DLY_NOT_COMB*/ + {0x0000400C, 0, 7}, /*VIMON_DLY*/ + {0x00004000, 11, 1}, /*VMON_POL*/ + {0x00017040, 0, 8}, /*X_COORDINATE*/ + {0x00017040, 8, 8}, /*Y_COORDINATE*/ + {0x00017040, 16, 8}, /*WAFER_ID*/ + {0x00017040, 24, 8}, /*DVS*/ + {0x00017044, 0, 24}, /*LOT_NUMBER*/ +}; + +const struct cs35l41_otp_map_element_t + cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] = { + { + .id = 0x01, + .map = otp_map_1, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x02, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x03, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x06, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x08, + .map = otp_map_1, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, +}; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c new file mode 100644 index 000000000000..dbec54a28a9e --- /dev/null +++ b/sound/soc/codecs/cs35l41.c @@ -0,0 +1,1545 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41.c -- CS35l41 ALSA SoC audio driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <[email protected]> + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/of_device.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "cs35l41.h" + +static const char * const cs35l41_supplies[CS35L41_NUM_SUPPLIES] = { + "VA", + "VP", +}; + +struct cs35l41_pll_sysclk_config { + int freq; + int clk_cfg; +}; + +static const struct cs35l41_pll_sysclk_config cs35l41_pll_sysclk[] = { + { 32768, 0x00 }, + { 8000, 0x01 }, + { 11025, 0x02 }, + { 12000, 0x03 }, + { 16000, 0x04 }, + { 22050, 0x05 }, + { 24000, 0x06 }, + { 32000, 0x07 }, + { 44100, 0x08 }, + { 48000, 0x09 }, + { 88200, 0x0A }, + { 96000, 0x0B }, + { 128000, 0x0C }, + { 176400, 0x0D }, + { 192000, 0x0E }, + { 256000, 0x0F }, + { 352800, 0x10 }, + { 384000, 0x11 }, + { 512000, 0x12 }, + { 705600, 0x13 }, + { 750000, 0x14 }, + { 768000, 0x15 }, + { 1000000, 0x16 }, + { 1024000, 0x17 }, + { 1200000, 0x18 }, + { 1411200, 0x19 }, + { 1500000, 0x1A }, + { 1536000, 0x1B }, + { 2000000, 0x1C }, + { 2048000, 0x1D }, + { 2400000, 0x1E }, + { 2822400, 0x1F }, + { 3000000, 0x20 }, + { 3072000, 0x21 }, + { 3200000, 0x22 }, + { 4000000, 0x23 }, + { 4096000, 0x24 }, + { 4800000, 0x25 }, + { 5644800, 0x26 }, + { 6000000, 0x27 }, + { 6144000, 0x28 }, + { 6250000, 0x29 }, + { 6400000, 0x2A }, + { 6500000, 0x2B }, + { 6750000, 0x2C }, + { 7526400, 0x2D }, + { 8000000, 0x2E }, + { 8192000, 0x2F }, + { 9600000, 0x30 }, + { 11289600, 0x31 }, + { 12000000, 0x32 }, + { 12288000, 0x33 }, + { 12500000, 0x34 }, + { 12800000, 0x35 }, + { 13000000, 0x36 }, + { 13500000, 0x37 }, + { 19200000, 0x38 }, + { 22579200, 0x39 }, + { 24000000, 0x3A }, + { 24576000, 0x3B }, + { 25000000, 0x3C }, + { 25600000, 0x3D }, + { 26000000, 0x3E }, + { 27000000, 0x3F }, +}; + +struct cs35l41_fs_mon_config { + int freq; + unsigned int fs1; + unsigned int fs2; +}; + +static const struct cs35l41_fs_mon_config cs35l41_fs_mon[] = { + { 32768, 2254, 3754 }, + { 8000, 9220, 15364 }, + { 11025, 6148, 10244 }, + { 12000, 6148, 10244 }, + { 16000, 4612, 7684 }, + { 22050, 3076, 5124 }, + { 24000, 3076, 5124 }, + { 32000, 2308, 3844 }, + { 44100, 1540, 2564 }, + { 48000, 1540, 2564 }, + { 88200, 772, 1284 }, + { 96000, 772, 1284 }, + { 128000, 580, 964 }, + { 176400, 388, 644 }, + { 192000, 388, 644 }, + { 256000, 292, 484 }, + { 352800, 196, 324 }, + { 384000, 196, 324 }, + { 512000, 148, 244 }, + { 705600, 100, 164 }, + { 750000, 100, 164 }, + { 768000, 100, 164 }, + { 1000000, 76, 124 }, + { 1024000, 76, 124 }, + { 1200000, 64, 104 }, + { 1411200, 52, 84 }, + { 1500000, 52, 84 }, + { 1536000, 52, 84 }, + { 2000000, 40, 64 }, + { 2048000, 40, 64 }, + { 2400000, 34, 54 }, + { 2822400, 28, 44 }, + { 3000000, 28, 44 }, + { 3072000, 28, 44 }, + { 3200000, 27, 42 }, + { 4000000, 22, 34 }, + { 4096000, 22, 34 }, + { 4800000, 19, 29 }, + { 5644800, 16, 24 }, + { 6000000, 16, 24 }, + { 6144000, 16, 24 }, +}; + +static const unsigned char cs35l41_bst_k1_table[4][5] = { + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 } +}; + +static const unsigned char cs35l41_bst_k2_table[4][5] = { + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA } +}; + +static const unsigned char cs35l41_bst_slope_table[4] = { + 0x75, 0x6B, 0x3B, 0x28}; + +static int cs35l41_get_fs_mon_config_index(int freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_mon); i++) { + if (cs35l41_fs_mon[i].freq == freq) + return i; + } + + return -EINVAL; +} + +static const DECLARE_TLV_DB_RANGE(dig_vol_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 1, 913, TLV_DB_MINMAX_ITEM(-10200, 1200)); +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); + +static const struct snd_kcontrol_new dre_ctrl = + SOC_DAPM_SINGLE("Switch", CS35L41_PWR_CTRL3, 20, 1, 0); + +static const char * const cs35l41_pcm_sftramp_text[] = { + "Off", ".5ms", "1ms", "2ms", "4ms", "8ms", "15ms", "30ms"}; + +static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, + CS35L41_AMP_DIG_VOL_CTRL, 0, + cs35l41_pcm_sftramp_text); + +static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"}; +static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32}; +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum, + CS35L41_DAC_PCM1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_pcm_source_texts, + cs35l41_pcm_source_values); + +static const struct snd_kcontrol_new pcm_source_mux = + SOC_DAPM_ENUM("PCM Source", cs35l41_pcm_source_enum); + +static const char * const cs35l41_tx_input_texts[] = {"Zero", "ASPRX1", + "ASPRX2", "VMON", + "IMON", "VPMON", + "VBSTMON", + "DSPTX1", "DSPTX2"}; +static const unsigned int cs35l41_tx_input_values[] = {0x00, + CS35L41_INPUT_SRC_ASPRX1, + CS35L41_INPUT_SRC_ASPRX2, + CS35L41_INPUT_SRC_VMON, + CS35L41_INPUT_SRC_IMON, + CS35L41_INPUT_SRC_VPMON, + CS35L41_INPUT_SRC_VBSTMON, + CS35L41_INPUT_DSP_TX1, + CS35L41_INPUT_DSP_TX2}; + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx1_enum, + CS35L41_ASP_TX1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx1_mux = + SOC_DAPM_ENUM("ASPTX1 SRC", cs35l41_asptx1_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx2_enum, + CS35L41_ASP_TX2_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx2_mux = + SOC_DAPM_ENUM("ASPTX2 SRC", cs35l41_asptx2_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx3_enum, + CS35L41_ASP_TX3_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx3_mux = + SOC_DAPM_ENUM("ASPTX3 SRC", cs35l41_asptx3_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx4_enum, + CS35L41_ASP_TX4_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx4_mux = + SOC_DAPM_ENUM("ASPTX4 SRC", cs35l41_asptx4_enum); + +static const struct snd_kcontrol_new cs35l41_aud_controls[] = { + SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L41_AMP_DIG_VOL_CTRL, + 3, 0x4CF, 0x391, dig_vol_tlv), + SOC_SINGLE_TLV("Analog PCM Volume", CS35L41_AMP_GAIN_CTRL, 5, 0x14, 0, + amp_gain_tlv), + SOC_ENUM("PCM Soft Ramp", pcm_sft_ramp), + SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0), + SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0), + SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0), + SOC_SINGLE("Aux Noise Gate CH1 Enable", + CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0), + SOC_SINGLE("Aux Noise Gate CH1 Entry Delay", + CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0), + SOC_SINGLE("Aux Noise Gate CH1 Threshold", + CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0), + SOC_SINGLE("Aux Noise Gate CH2 Entry Delay", + CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0), + SOC_SINGLE("Aux Noise Gate CH2 Enable", + CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0), + SOC_SINGLE("Aux Noise Gate CH2 Threshold", + CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0), + SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL, + CS35L41_AMP_INV_PCM_SHIFT, 1, 0), + SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL, + CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0), +}; + +static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { + if (cs35l41_otp_map_map[i].id == otp_id) + return &cs35l41_otp_map_map[i]; + } + + return NULL; +} + +static int cs35l41_otp_unpack(void *data) +{ + const struct cs35l41_otp_map_element_t *otp_map_match; + const struct cs35l41_otp_packed_element_t *otp_map; + struct cs35l41_private *cs35l41 = data; + int bit_offset, word_offset, ret, i; + unsigned int orig_spi_freq; + unsigned int bit_sum = 8; + u32 otp_val, otp_id_reg; + u32 *otp_mem; + + otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), + GFP_KERNEL); + if (!otp_mem) + return -ENOMEM; + + ret = regmap_read(cs35l41->regmap, CS35L41_OTPID, &otp_id_reg); + if (ret < 0) { + dev_err(cs35l41->dev, "Read OTP ID failed\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + + otp_map_match = cs35l41_find_otp_map(otp_id_reg); + + if (!otp_map_match) { + dev_err(cs35l41->dev, "OTP Map matching ID %d not found\n", + otp_id_reg); + ret = -EINVAL; + goto err_otp_unpack; + } + + if (cs35l41->otp_setup) + cs35l41->otp_setup(cs35l41, true, &orig_spi_freq); + + ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0, otp_mem, + CS35L41_OTP_SIZE_WORDS); + if (ret < 0) { + dev_err(cs35l41->dev, "Read OTP Mem failed\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + + if (cs35l41->otp_setup) + cs35l41->otp_setup(cs35l41, false, &orig_spi_freq); + + otp_map = otp_map_match->map; + + bit_offset = otp_map_match->bit_offset; + word_offset = otp_map_match->word_offset; + + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000055); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Unlock key failed 1/2\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Unlock key failed 2/2\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + + for (i = 0; i < otp_map_match->num_elements; i++) { + dev_dbg(cs35l41->dev, + "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", + bit_offset, word_offset, bit_sum % 32); + if (bit_offset + otp_map[i].size - 1 >= 32) { + otp_val = (otp_mem[word_offset] & + GENMASK(31, bit_offset)) >> + bit_offset; + otp_val |= (otp_mem[++word_offset] & + GENMASK(bit_offset + + otp_map[i].size - 33, 0)) << + (32 - bit_offset); + bit_offset += otp_map[i].size - 32; + } else { + + otp_val = (otp_mem[word_offset] & + GENMASK(bit_offset + otp_map[i].size - 1, + bit_offset)) >> bit_offset; + bit_offset += otp_map[i].size; + } + bit_sum += otp_map[i].size; + + if (bit_offset == 32) { + bit_offset = 0; + word_offset++; + } + + if (otp_map[i].reg != 0) { + ret = regmap_update_bits(cs35l41->regmap, + otp_map[i].reg, + GENMASK(otp_map[i].shift + + otp_map[i].size - 1, + otp_map[i].shift), + otp_val << otp_map[i].shift); + if (ret < 0) { + dev_err(cs35l41->dev, "Write OTP val failed\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + } + } + + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Lock key failed 1/2\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000033); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Lock key failed 2/2\n"); + ret = -EINVAL; + goto err_otp_unpack; + } + ret = 0; + +err_otp_unpack: + kfree(otp_mem); + return ret; +} + +static irqreturn_t cs35l41_irq(int irq, void *data) +{ + struct cs35l41_private *cs35l41 = data; + unsigned int status[4] = { 0, 0, 0, 0 }; + unsigned int masks[4] = { 0, 0, 0, 0 }; + int ret = IRQ_NONE; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(status); i++) { + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE), + &status[i]); + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_MASK1 + (i * CS35L41_REGSTRIDE), + &masks[i]); + } + + /* Check to see if unmasked bits are active */ + if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) && + !(status[2] & ~masks[2]) && !(status[3] & ~masks[3])) + return IRQ_NONE; + + if (status[3] & CS35L41_OTP_BOOT_DONE) { + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK4, + CS35L41_OTP_BOOT_DONE, CS35L41_OTP_BOOT_DONE); + } + + /* + * The following interrupts require a + * protection release cycle to get the + * speaker out of Safe-Mode. + */ + if (status[0] & CS35L41_AMP_SHORT_ERR) { + dev_crit_ratelimited(cs35l41->dev, "Amp short error\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_AMP_SHORT_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_AMP_SHORT_ERR_RLS, + CS35L41_AMP_SHORT_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_AMP_SHORT_ERR_RLS, 0); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_TEMP_WARN) { + dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_TEMP_WARN); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_WARN_ERR_RLS, + CS35L41_TEMP_WARN_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_WARN_ERR_RLS, 0); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_TEMP_ERR) { + dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_TEMP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_ERR_RLS, + CS35L41_TEMP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_ERR_RLS, 0); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_BST_OVP_ERR) { + dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_OVP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_OVP_ERR_RLS, + CS35L41_BST_OVP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_OVP_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << + CS35L41_BST_EN_SHIFT); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_BST_DCM_UVP_ERR) { + dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_DCM_UVP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_UVP_ERR_RLS, + CS35L41_BST_UVP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_UVP_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << + CS35L41_BST_EN_SHIFT); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_BST_SHORT_ERR) { + dev_crit_ratelimited(cs35l41->dev, "LBST error: powering off!\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_SHORT_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_SHORT_ERR_RLS, + CS35L41_BST_SHORT_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << + CS35L41_BST_EN_SHIFT); + ret = IRQ_HANDLED; + } + + return ret; +} + +static const struct reg_sequence cs35l41_pup_patch[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00002084, 0x002F1AA0 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_pdn_patch[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00002084, 0x002F1AA3 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = + snd_soc_component_get_drvdata(component); + unsigned int val; + int ret = 0; + bool pdn; + int i; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pup_patch, + ARRAY_SIZE(cs35l41_pup_patch)); + + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, + CS35L41_GLOBAL_EN_MASK, + 1 << CS35L41_GLOBAL_EN_SHIFT); + + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, + CS35L41_GLOBAL_EN_MASK, 0); + + pdn = false; + for (i = 0; i < 100; i++) { + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_STATUS1, + &val); + if (val & CS35L41_PDN_DONE_MASK) { + pdn = true; + break; + } + usleep_range(1000, 1100); + } + + if (!pdn) + dev_warn(cs35l41->dev, "PDN failed\n"); + + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_PDN_DONE_MASK); + + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pdn_patch, + ARRAY_SIZE(cs35l41_pdn_patch)); + break; + default: + dev_err(cs35l41->dev, "Invalid event = 0x%x\n", event); + ret = -EINVAL; + } + return ret; +} + +static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("SPK"), + + SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, CS35L41_SP_ENABLES, 16, 0), + SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, CS35L41_SP_ENABLES, 17, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0, CS35L41_SP_ENABLES, 0, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 0, CS35L41_SP_ENABLES, 1, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 0, CS35L41_SP_ENABLES, 2, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 0, CS35L41_SP_ENABLES, 3, 0), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L41_PWR_CTRL2, 9, 0), + SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, CS35L41_PWR_CTRL2, 10, 0), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L41_PWR_CTRL3, 4, 0), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L41_PWR_CTRL2, 0, 0, NULL, 0, + cs35l41_main_amp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VBST"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + SND_SOC_DAPM_INPUT("TEMP"), + + SND_SOC_DAPM_MUX("ASP TX1 Source", SND_SOC_NOPM, 0, 0, &asp_tx1_mux), + SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux), + SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux), + SND_SOC_DAPM_MUX("ASP TX4 Source", SND_SOC_NOPM, 0, 0, &asp_tx4_mux), + SND_SOC_DAPM_MUX("PCM Source", SND_SOC_NOPM, 0, 0, &pcm_source_mux), + SND_SOC_DAPM_SWITCH("DRE", SND_SOC_NOPM, 0, 0, &dre_ctrl), +}; + +static const struct snd_soc_dapm_route cs35l41_audio_map[] = { + + {"ASP TX1 Source", "VMON", "VMON ADC"}, + {"ASP TX1 Source", "IMON", "IMON ADC"}, + {"ASP TX1 Source", "VPMON", "VPMON ADC"}, + {"ASP TX1 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX1 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX1 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX2 Source", "VMON", "VMON ADC"}, + {"ASP TX2 Source", "IMON", "IMON ADC"}, + {"ASP TX2 Source", "VPMON", "VPMON ADC"}, + {"ASP TX2 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX2 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX2 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX3 Source", "VMON", "VMON ADC"}, + {"ASP TX3 Source", "IMON", "IMON ADC"}, + {"ASP TX3 Source", "VPMON", "VPMON ADC"}, + {"ASP TX3 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX3 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX3 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX4 Source", "VMON", "VMON ADC"}, + {"ASP TX4 Source", "IMON", "IMON ADC"}, + {"ASP TX4 Source", "VPMON", "VPMON ADC"}, + {"ASP TX4 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX4 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX4 Source", "ASPRX2", "ASPRX2" }, + {"ASPTX1", NULL, "ASP TX1 Source"}, + {"ASPTX2", NULL, "ASP TX2 Source"}, + {"ASPTX3", NULL, "ASP TX3 Source"}, + {"ASPTX4", NULL, "ASP TX4 Source"}, + {"AMP Capture", NULL, "ASPTX1"}, + {"AMP Capture", NULL, "ASPTX2"}, + {"AMP Capture", NULL, "ASPTX3"}, + {"AMP Capture", NULL, "ASPTX4"}, + + {"VMON ADC", NULL, "VSENSE"}, + {"IMON ADC", NULL, "ISENSE"}, + {"VPMON ADC", NULL, "VP"}, + {"TEMPMON ADC", NULL, "TEMP"}, + {"VBSTMON ADC", NULL, "VBST"}, + + {"ASPRX1", NULL, "AMP Playback"}, + {"ASPRX2", NULL, "AMP Playback"}, + {"DRE", "Switch", "CLASS H"}, + {"Main AMP", NULL, "CLASS H"}, + {"Main AMP", NULL, "DRE"}, + {"SPK", NULL, "Main AMP"}, + + {"PCM Source", "ASP", "ASPRX1"}, + {"CLASS H", NULL, "PCM Source"}, + +}; + +static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, + unsigned int *tx_slot, unsigned int rx_num, + unsigned int *rx_slot) +{ + struct cs35l41_private *cs35l41 = + snd_soc_component_get_drvdata(dai->component); + int i; + + if (tx_num > 4 || rx_num > 2) + return -EINVAL; + + for (i = 0; i < rx_num; i++) { + dev_dbg(cs35l41->dev, "%s: rx slot %d position = %d\n", + __func__, i, rx_slot[i]); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_RX_SLOT, + 0x3F << (i * 8), rx_slot[i] << (i * 8)); + } + + for (i = 0; i < tx_num; i++) { + dev_dbg(cs35l41->dev, "%s: tx slot %d position = %d\n", + __func__, i, tx_slot[i]); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_TX_SLOT, + 0x3F << (i * 8), tx_slot[i] << (i * 8)); + } + + return 0; +} + +static int cs35l41_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct cs35l41_private *cs35l41 = + snd_soc_component_get_drvdata(codec_dai->component); + unsigned int asp_fmt, lrclk_fmt, sclk_fmt, clock_provider; + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + clock_provider = 1; + break; + case SND_SOC_DAIFMT_CBC_CFC: + clock_provider = 0; + break; + default: + dev_warn(cs35l41->dev, + "%s: Mixed provider/consumer mode unsupported\n", + __func__); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_SCLK_MSTR_MASK, + clock_provider << CS35L41_SCLK_MSTR_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_LRCLK_MSTR_MASK, + clock_provider << CS35L41_LRCLK_MSTR_SHIFT); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + asp_fmt = 0; + break; + case SND_SOC_DAIFMT_I2S: + asp_fmt = 2; + break; + default: + dev_warn(cs35l41->dev, + "%s: Invalid or unsupported DAI format\n", __func__); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_FMT_MASK, + asp_fmt << CS35L41_ASP_FMT_SHIFT); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + lrclk_fmt = 1; + sclk_fmt = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + lrclk_fmt = 0; + sclk_fmt = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + lrclk_fmt = 1; + sclk_fmt = 1; + break; + case SND_SOC_DAIFMT_NB_NF: + lrclk_fmt = 0; + sclk_fmt = 0; + break; + default: + dev_warn(cs35l41->dev, + "%s: Invalid DAI clock INV\n", __func__); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_LRCLK_INV_MASK, + lrclk_fmt << CS35L41_LRCLK_INV_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_SCLK_INV_MASK, + sclk_fmt << CS35L41_SCLK_INV_SHIFT); + + return 0; +} + +struct cs35l41_global_fs_config { + int rate; + int fs_cfg; +}; + +static const struct cs35l41_global_fs_config cs35l41_fs_rates[] = { + { 12000, 0x01 }, + { 24000, 0x02 }, + { 48000, 0x03 }, + { 96000, 0x04 }, + { 192000, 0x05 }, + { 11025, 0x09 }, + { 22050, 0x0A }, + { 44100, 0x0B }, + { 88200, 0x0C }, + { 176400, 0x0D }, + { 8000, 0x11 }, + { 16000, 0x12 }, + { 32000, 0x13 }, +}; + +static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs35l41_private *cs35l41 = + snd_soc_component_get_drvdata(dai->component); + unsigned int rate = params_rate(params); + u8 asp_wl; + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_rates); i++) { + if (rate == cs35l41_fs_rates[i].rate) + break; + } + + if (i >= ARRAY_SIZE(cs35l41_fs_rates)) { + dev_err(cs35l41->dev, "%s: Unsupported rate: %u\n", + __func__, rate); + return -EINVAL; + } + + asp_wl = params_width(params); + + if (i < ARRAY_SIZE(cs35l41_fs_rates)) + regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL, + CS35L41_GLOBAL_FS_MASK, + cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_RX_MASK, + asp_wl << CS35L41_ASP_WIDTH_RX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_RX_WL, + CS35L41_ASP_RX_WL_MASK, + asp_wl << CS35L41_ASP_RX_WL_SHIFT); + } else { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_TX_MASK, + asp_wl << CS35L41_ASP_WIDTH_TX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_TX_WL, + CS35L41_ASP_TX_WL_MASK, + asp_wl << CS35L41_ASP_TX_WL_SHIFT); + } + + return 0; +} + +static int cs35l41_get_clk_config(int freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_pll_sysclk); i++) { + if (cs35l41_pll_sysclk[i].freq == freq) + return cs35l41_pll_sysclk[i].clk_cfg; + } + + return -EINVAL; +} + +static const unsigned int cs35l41_src_rates[] = { + 8000, 12000, 11025, 16000, 22050, 24000, 32000, + 44100, 48000, 88200, 96000, 176400, 192000 +}; + +static const struct snd_pcm_hw_constraint_list cs35l41_constraints = { + .count = ARRAY_SIZE(cs35l41_src_rates), + .list = cs35l41_src_rates, +}; + +static int cs35l41_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (substream->runtime) + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &cs35l41_constraints); + return 0; +} + +static int cs35l41_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, + int dir) +{ + struct cs35l41_private *cs35l41 = + snd_soc_component_get_drvdata(component); + int extclk_cfg, clksrc; + + switch (clk_id) { + case CS35L41_CLKID_SCLK: + clksrc = CS35L41_PLLSRC_SCLK; + break; + case CS35L41_CLKID_LRCLK: + clksrc = CS35L41_PLLSRC_LRCLK; + break; + case CS35L41_CLKID_MCLK: + clksrc = CS35L41_PLLSRC_MCLK; + break; + default: + dev_err(cs35l41->dev, "Invalid CLK Config\n"); + return -EINVAL; + } + + extclk_cfg = cs35l41_get_clk_config(freq); + + if (extclk_cfg < 0) { + dev_err(cs35l41->dev, "Invalid CLK Config: %d, freq: %u\n", + extclk_cfg, freq); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_OPENLOOP_MASK, + 1 << CS35L41_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_REFCLK_FREQ_MASK, + extclk_cfg << CS35L41_REFCLK_FREQ_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_EN_MASK, + 0 << CS35L41_PLL_CLK_EN_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_SEL_MASK, clksrc); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_OPENLOOP_MASK, + 0 << CS35L41_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_EN_MASK, + 1 << CS35L41_PLL_CLK_EN_SHIFT); + + return 0; +} + +static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct cs35l41_private *cs35l41 = + snd_soc_component_get_drvdata(dai->component); + unsigned int fs1_val; + unsigned int fs2_val; + unsigned int val; + int fsIndex; + + fsIndex = cs35l41_get_fs_mon_config_index(freq); + if (fsIndex < 0) { + dev_err(cs35l41->dev, "Invalid CLK Config freq: %u\n", freq); + return -EINVAL; + } + + dev_dbg(cs35l41->dev, "Set DAI sysclk %d\n", freq); + if (freq <= 6144000) { + /* Use the lookup table */ + fs1_val = cs35l41_fs_mon[fsIndex].fs1; + fs2_val = cs35l41_fs_mon[fsIndex].fs2; + } else { + /* Use hard-coded values */ + fs1_val = 0x10; + fs2_val = 0x24; + } + + val = fs1_val; + val |= (fs2_val << CS35L41_FS2_WINDOW_SHIFT) & CS35L41_FS2_WINDOW_MASK; + regmap_write(cs35l41->regmap, CS35L41_TST_FS_MON0, val); + + return 0; +} + +static int cs35l41_boost_config(struct cs35l41_private *cs35l41, + int boost_ind, int boost_cap, int boost_ipk) +{ + unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; + struct regmap *regmap = cs35l41->regmap; + struct device *dev = cs35l41->dev; + int ret; + + switch (boost_ind) { + case 1000: /* 1.0 uH */ + bst_lbst_val = 0; + break; + case 1200: /* 1.2 uH */ + bst_lbst_val = 1; + break; + case 1500: /* 1.5 uH */ + bst_lbst_val = 2; + break; + case 2200: /* 2.2 uH */ + bst_lbst_val = 3; + break; + default: + dev_err(dev, "Invalid boost inductor value: %d nH\n", + boost_ind); + return -EINVAL; + } + + switch (boost_cap) { + case 0 ... 19: + bst_cbst_range = 0; + break; + case 20 ... 50: + bst_cbst_range = 1; + break; + case 51 ... 100: + bst_cbst_range = 2; + break; + case 101 ... 200: + bst_cbst_range = 3; + break; + default: /* 201 uF and greater */ + bst_cbst_range = 4; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K1_MASK, + cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K1_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost K1 coefficient\n"); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K2_MASK, + cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K2_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost K2 coefficient\n"); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_SLOPE_MASK, + cs35l41_bst_slope_table[bst_lbst_val] + << CS35L41_BST_SLOPE_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost slope coefficient\n"); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_LBST_VAL_MASK, + bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor value\n"); + return ret; + } + + if ((boost_ipk < 1600) || (boost_ipk > 4500)) { + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", + boost_ipk); + return -EINVAL; + } + bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, + CS35L41_BST_IPK_MASK, + bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor peak current\n"); + return ret; + } + + return 0; +} + +static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) +{ + int ret; + + /* Set Platform Data */ + /* Required */ + if (cs35l41->pdata.bst_ipk && + cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) { + ret = cs35l41_boost_config(cs35l41, cs35l41->pdata.bst_ind, + cs35l41->pdata.bst_cap, + cs35l41->pdata.bst_ipk); + if (ret) { + dev_err(cs35l41->dev, "Error in Boost DT config\n"); + return ret; + } + } else { + dev_err(cs35l41->dev, "Incomplete Boost component DT config\n"); + return -EINVAL; + } + + /* Optional */ + if (cs35l41->pdata.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && + cs35l41->pdata.dout_hiz >= 0) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, + CS35L41_ASP_DOUT_HIZ_MASK, + cs35l41->pdata.dout_hiz); + + return 0; +} + +static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41) +{ + struct cs35l41_irq_cfg *irq_gpio_cfg1 = &cs35l41->pdata.irq_config1; + struct cs35l41_irq_cfg *irq_gpio_cfg2 = &cs35l41->pdata.irq_config2; + int irq_pol = IRQF_TRIGGER_NONE; + + if (irq_gpio_cfg1->irq_pol_inv) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_POL_MASK, + CS35L41_GPIO_POL_MASK); + if (irq_gpio_cfg1->irq_out_en) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_DIR_MASK, + 0); + if (irq_gpio_cfg1->irq_src_sel) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO_PAD_CONTROL, + CS35L41_GPIO1_CTRL_MASK, + irq_gpio_cfg1->irq_src_sel << + CS35L41_GPIO1_CTRL_SHIFT); + + if (irq_gpio_cfg2->irq_pol_inv) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_POL_MASK, + CS35L41_GPIO_POL_MASK); + if (irq_gpio_cfg2->irq_out_en) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_DIR_MASK, + 0); + if (irq_gpio_cfg2->irq_src_sel) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO_PAD_CONTROL, + CS35L41_GPIO2_CTRL_MASK, + irq_gpio_cfg2->irq_src_sel << + CS35L41_GPIO2_CTRL_SHIFT); + + if ((irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_ACTV_LO | CS35L41_VALID_PDATA)) || + (irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_OPEN_INT | CS35L41_VALID_PDATA))) + irq_pol = IRQF_TRIGGER_LOW; + else if (irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_ACTV_HI | CS35L41_VALID_PDATA)) + irq_pol = IRQF_TRIGGER_HIGH; + + return irq_pol; +} + +static const struct snd_soc_dai_ops cs35l41_ops = { + .startup = cs35l41_pcm_startup, + .set_fmt = cs35l41_set_dai_fmt, + .hw_params = cs35l41_pcm_hw_params, + .set_sysclk = cs35l41_dai_set_sysclk, + .set_channel_map = cs35l41_set_channel_map, +}; + +static struct snd_soc_dai_driver cs35l41_dai[] = { + { + .name = "cs35l41-pcm", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L41_RX_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L41_TX_FORMATS, + }, + .ops = &cs35l41_ops, + .symmetric_rate = 1, + }, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs35l41 = { + .name = "cs35l41-codec", + + .dapm_widgets = cs35l41_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l41_dapm_widgets), + .dapm_routes = cs35l41_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l41_audio_map), + + .controls = cs35l41_aud_controls, + .num_controls = ARRAY_SIZE(cs35l41_aud_controls), + .set_sysclk = cs35l41_component_set_sysclk, +}; + +static int cs35l41_handle_pdata(struct device *dev, + struct cs35l41_platform_data *pdata, + struct cs35l41_private *cs35l41) +{ + struct cs35l41_irq_cfg *irq_gpio1_config = &pdata->irq_config1; + struct cs35l41_irq_cfg *irq_gpio2_config = &pdata->irq_config2; + unsigned int val; + int ret; + + ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val); + if (ret >= 0) + pdata->bst_ipk = val; + + ret = device_property_read_u32(dev, "cirrus,boost-ind-nanohenry", &val); + if (ret >= 0) + pdata->bst_ind = val; + + ret = device_property_read_u32(dev, "cirrus,boost-cap-microfarad", &val); + if (ret >= 0) + pdata->bst_cap = val; + + ret = device_property_read_u32(dev, "cirrus,asp-sdout-hiz", &val); + if (ret >= 0) + pdata->dout_hiz = val; + else + pdata->dout_hiz = -1; + + /* GPIO1 Pin Config */ + irq_gpio1_config->irq_pol_inv = device_property_read_bool(dev, + "cirrus,gpio1-polarity-invert"); + irq_gpio1_config->irq_out_en = device_property_read_bool(dev, + "cirrus,gpio1-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + irq_gpio1_config->irq_src_sel = val; + } + + /* GPIO2 Pin Config */ + irq_gpio2_config->irq_pol_inv = device_property_read_bool(dev, + "cirrus,gpio2-polarity-invert"); + irq_gpio2_config->irq_out_en = device_property_read_bool(dev, + "cirrus,gpio2-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + irq_gpio2_config->irq_src_sel = val; + } + + return 0; +} + +static const struct reg_sequence cs35l41_reva0_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { 0x00003854, 0x05180240 }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_OTP_TRIM_30, 0x9091A1C8 }, + { 0x00003014, 0x0200EE0E }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { 0x00000054, 0x00000004 }, + { CS35L41_IRQ1_DB3, 0x00000000 }, + { CS35L41_IRQ2_DB3, 0x00000000 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, +}; + +static const struct reg_sequence cs35l41_revb0_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, +}; + +static const struct reg_sequence cs35l41_revb2_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, +}; + +int cs35l41_probe(struct cs35l41_private *cs35l41, + struct cs35l41_platform_data *pdata) +{ + u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; + int irq_pol = 0; + int timeout; + int ret; + + if (pdata) { + cs35l41->pdata = *pdata; + } else { + ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->pdata, + cs35l41); + if (ret != 0) + return ret; + } + + for (i = 0; i < CS35L41_NUM_SUPPLIES; i++) + cs35l41->supplies[i].supply = cs35l41_supplies[i]; + + ret = devm_regulator_bulk_get(cs35l41->dev, CS35L41_NUM_SUPPLIES, + cs35l41->supplies); + if (ret != 0) { + dev_err(cs35l41->dev, + "Failed to request core supplies: %d\n", + ret); + return ret; + } + + ret = regulator_bulk_enable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); + if (ret != 0) { + dev_err(cs35l41->dev, + "Failed to enable core supplies: %d\n", ret); + return ret; + } + + /* returning NULL can be an option if in stereo mode */ + cs35l41->reset_gpio = devm_gpiod_get_optional(cs35l41->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(cs35l41->reset_gpio)) { + ret = PTR_ERR(cs35l41->reset_gpio); + cs35l41->reset_gpio = NULL; + if (ret == -EBUSY) { + dev_info(cs35l41->dev, + "Reset line busy, assuming shared reset\n"); + } else { + dev_err(cs35l41->dev, + "Failed to get reset GPIO: %d\n", ret); + goto err; + } + } + if (cs35l41->reset_gpio) { + /* satisfy minimum reset pulse width spec */ + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cs35l41->reset_gpio, 1); + } + + usleep_range(2000, 2100); + + timeout = 100; + do { + if (timeout == 0) { + dev_err(cs35l41->dev, + "Timeout waiting for OTP_BOOT_DONE\n"); + ret = -EBUSY; + goto err; + } + usleep_range(1000, 1100); + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS4, &int_status); + timeout--; + } while (!(int_status & CS35L41_OTP_BOOT_DONE)); + + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status); + if (int_status & CS35L41_OTP_BOOT_ERR) { + dev_err(cs35l41->dev, "OTP Boot error\n"); + ret = -EINVAL; + goto err; + } + + ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, ®id); + if (ret < 0) { + dev_err(cs35l41->dev, "Get Device ID failed\n"); + goto err; + } + + ret = regmap_read(cs35l41->regmap, CS35L41_REVID, ®_revid); + if (ret < 0) { + dev_err(cs35l41->dev, "Get Revision ID failed\n"); + goto err; + } + + mtl_revid = reg_revid & CS35L41_MTLREVID_MASK; + + /* CS35L41 will have even MTLREVID + * CS35L41R will have odd MTLREVID + */ + chipid_match = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID; + if (regid != chipid_match) { + dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", + regid, chipid_match); + ret = -ENODEV; + goto err; + } + + switch (reg_revid) { + case CS35L41_REVID_A0: + ret = regmap_register_patch(cs35l41->regmap, + cs35l41_reva0_errata_patch, + ARRAY_SIZE(cs35l41_reva0_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply A0 errata patch %d\n", ret); + goto err; + } + break; + case CS35L41_REVID_B0: + ret = regmap_register_patch(cs35l41->regmap, + cs35l41_revb0_errata_patch, + ARRAY_SIZE(cs35l41_revb0_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply B0 errata patch %d\n", ret); + goto err; + } + break; + case CS35L41_REVID_B2: + ret = regmap_register_patch(cs35l41->regmap, + cs35l41_revb2_errata_patch, + ARRAY_SIZE(cs35l41_revb2_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply B2 errata patch %d\n", ret); + goto err; + } + break; + } + + irq_pol = cs35l41_irq_gpio_config(cs35l41); + + /* Set interrupt masks for critical errors */ + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, + CS35L41_INT1_MASK_DEFAULT); + + ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, + cs35l41_irq, IRQF_ONESHOT | IRQF_SHARED | irq_pol, + "cs35l41", cs35l41); + + /* CS35L41 needs INT for PDN_DONE */ + if (ret != 0) { + dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret); + ret = -ENODEV; + goto err; + } + + ret = cs35l41_otp_unpack(cs35l41); + if (ret < 0) { + dev_err(cs35l41->dev, "OTP Unpack failed\n"); + goto err; + } + + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_CCM_CORE_CTRL, 0); + if (ret < 0) { + dev_err(cs35l41->dev, "Write CCM_CORE_CTRL failed\n"); + goto err; + } + + ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_AMP_EN_MASK, 0); + if (ret < 0) { + dev_err(cs35l41->dev, "Write CS35L41_PWR_CTRL2 failed\n"); + goto err; + } + + ret = regmap_update_bits(cs35l41->regmap, CS35L41_AMP_GAIN_CTRL, + CS35L41_AMP_GAIN_PCM_MASK, 0); + if (ret < 0) { + dev_err(cs35l41->dev, "Write CS35L41_AMP_GAIN_CTRL failed\n"); + goto err; + } + + ret = cs35l41_set_pdata(cs35l41); + if (ret < 0) { + dev_err(cs35l41->dev, "%s: Set pdata failed\n", __func__); + goto err; + } + + ret = devm_snd_soc_register_component(cs35l41->dev, + &soc_component_dev_cs35l41, + cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); + if (ret < 0) { + dev_err(cs35l41->dev, "%s: Register codec failed\n", __func__); + goto err; + } + + dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", + regid, reg_revid); + + return 0; + +err: + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); + gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); + return ret; +} + +int cs35l41_remove(struct cs35l41_private *cs35l41) +{ + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); + gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); + return 0; +} + +MODULE_DESCRIPTION("ASoC CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h new file mode 100644 index 000000000000..7a25430182f8 --- /dev/null +++ b/sound/soc/codecs/cs35l41.h @@ -0,0 +1,775 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * cs35l41.h -- CS35L41 ALSA SoC audio driver + * + * Copyright 2017-2021 Cirrus Logic, Inc. + * + * Author: David Rhodes <[email protected]> + */ + +#ifndef __CS35L41_H__ +#define __CS35L41_H__ + +#include <linux/gpio/consumer.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <sound/core.h> +#include <sound/cs35l41.h> + +#define CS35L41_FIRSTREG 0x00000000 +#define CS35L41_LASTREG 0x03804FE8 +#define CS35L41_DEVID 0x00000000 +#define CS35L41_REVID 0x00000004 +#define CS35L41_FABID 0x00000008 +#define CS35L41_RELID 0x0000000C +#define CS35L41_OTPID 0x00000010 +#define CS35L41_SFT_RESET 0x00000020 +#define CS35L41_TEST_KEY_CTL 0x00000040 +#define CS35L41_USER_KEY_CTL 0x00000044 +#define CS35L41_OTP_MEM0 0x00000400 +#define CS35L41_OTP_MEM31 0x0000047C +#define CS35L41_OTP_CTRL0 0x00000500 +#define CS35L41_OTP_CTRL1 0x00000504 +#define CS35L41_OTP_CTRL3 0x00000508 +#define CS35L41_OTP_CTRL4 0x0000050C +#define CS35L41_OTP_CTRL5 0x00000510 +#define CS35L41_OTP_CTRL6 0x00000514 +#define CS35L41_OTP_CTRL7 0x00000518 +#define CS35L41_OTP_CTRL8 0x0000051C +#define CS35L41_PWR_CTRL1 0x00002014 +#define CS35L41_PWR_CTRL2 0x00002018 +#define CS35L41_PWR_CTRL3 0x0000201C +#define CS35L41_CTRL_OVRRIDE 0x00002020 +#define CS35L41_AMP_OUT_MUTE 0x00002024 +#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034 +#define CS35L41_GPIO_PAD_CONTROL 0x0000242C +#define CS35L41_JTAG_CONTROL 0x00002438 +#define CS35L41_PLL_CLK_CTRL 0x00002C04 +#define CS35L41_DSP_CLK_CTRL 0x00002C08 +#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C +#define CS35L41_DATA_FS_SEL 0x00002C10 +#define CS35L41_TST_FS_MON0 0x00002D10 +#define CS35L41_MDSYNC_EN 0x00003400 +#define CS35L41_MDSYNC_TX_ID 0x00003408 +#define CS35L41_MDSYNC_PWR_CTRL 0x0000340C +#define CS35L41_MDSYNC_DATA_TX 0x00003410 +#define CS35L41_MDSYNC_TX_STATUS 0x00003414 +#define CS35L41_MDSYNC_DATA_RX 0x0000341C +#define CS35L41_MDSYNC_RX_STATUS 0x00003420 +#define CS35L41_MDSYNC_ERR_STATUS 0x00003424 +#define CS35L41_MDSYNC_SYNC_PTE2 0x00003528 +#define CS35L41_MDSYNC_SYNC_PTE3 0x0000352C +#define CS35L41_MDSYNC_SYNC_MSM_STATUS 0x0000353C +#define CS35L41_BSTCVRT_VCTRL1 0x00003800 +#define CS35L41_BSTCVRT_VCTRL2 0x00003804 +#define CS35L41_BSTCVRT_PEAK_CUR 0x00003808 +#define CS35L41_BSTCVRT_SFT_RAMP 0x0000380C +#define CS35L41_BSTCVRT_COEFF 0x00003810 +#define CS35L41_BSTCVRT_SLOPE_LBST 0x00003814 +#define CS35L41_BSTCVRT_SW_FREQ 0x00003818 +#define CS35L41_BSTCVRT_DCM_CTRL 0x0000381C +#define CS35L41_BSTCVRT_DCM_MODE_FORCE 0x00003820 +#define CS35L41_BSTCVRT_OVERVOLT_CTRL 0x00003830 +#define CS35L41_VI_VOL_POL 0x00004000 +#define CS35L41_VIMON_SPKMON_RESYNC 0x00004100 +#define CS35L41_DTEMP_WARN_THLD 0x00004220 +#define CS35L41_DTEMP_CFG 0x00004224 +#define CS35L41_DTEMP_EN 0x00004308 +#define CS35L41_VPVBST_FS_SEL 0x00004400 +#define CS35L41_SP_ENABLES 0x00004800 +#define CS35L41_SP_RATE_CTRL 0x00004804 +#define CS35L41_SP_FORMAT 0x00004808 +#define CS35L41_SP_HIZ_CTRL 0x0000480C +#define CS35L41_SP_FRAME_TX_SLOT 0x00004810 +#define CS35L41_SP_FRAME_RX_SLOT 0x00004820 +#define CS35L41_SP_TX_WL 0x00004830 +#define CS35L41_SP_RX_WL 0x00004840 +#define CS35L41_ASP_CONTROL4 0x00004854 +#define CS35L41_DAC_PCM1_SRC 0x00004C00 +#define CS35L41_ASP_TX1_SRC 0x00004C20 +#define CS35L41_ASP_TX2_SRC 0x00004C24 +#define CS35L41_ASP_TX3_SRC 0x00004C28 +#define CS35L41_ASP_TX4_SRC 0x00004C2C +#define CS35L41_DSP1_RX1_SRC 0x00004C40 +#define CS35L41_DSP1_RX2_SRC 0x00004C44 +#define CS35L41_DSP1_RX3_SRC 0x00004C48 +#define CS35L41_DSP1_RX4_SRC 0x00004C4C +#define CS35L41_DSP1_RX5_SRC 0x00004C50 +#define CS35L41_DSP1_RX6_SRC 0x00004C54 +#define CS35L41_DSP1_RX7_SRC 0x00004C58 +#define CS35L41_DSP1_RX8_SRC 0x00004C5C +#define CS35L41_NGATE1_SRC 0x00004C60 +#define CS35L41_NGATE2_SRC 0x00004C64 +#define CS35L41_AMP_DIG_VOL_CTRL 0x00006000 +#define CS35L41_VPBR_CFG 0x00006404 +#define CS35L41_VBBR_CFG 0x00006408 +#define CS35L41_VPBR_STATUS 0x0000640C +#define CS35L41_VBBR_STATUS 0x00006410 +#define CS35L41_OVERTEMP_CFG 0x00006414 +#define CS35L41_AMP_ERR_VOL 0x00006418 +#define CS35L41_VOL_STATUS_TO_DSP 0x00006450 +#define CS35L41_CLASSH_CFG 0x00006800 +#define CS35L41_WKFET_CFG 0x00006804 +#define CS35L41_NG_CFG 0x00006808 +#define CS35L41_AMP_GAIN_CTRL 0x00006C04 +#define CS35L41_DAC_MSM_CFG 0x00007400 +#define CS35L41_IRQ1_CFG 0x00010000 +#define CS35L41_IRQ1_STATUS 0x00010004 +#define CS35L41_IRQ1_STATUS1 0x00010010 +#define CS35L41_IRQ1_STATUS2 0x00010014 +#define CS35L41_IRQ1_STATUS3 0x00010018 +#define CS35L41_IRQ1_STATUS4 0x0001001C +#define CS35L41_IRQ1_RAW_STATUS1 0x00010090 +#define CS35L41_IRQ1_RAW_STATUS2 0x00010094 +#define CS35L41_IRQ1_RAW_STATUS3 0x00010098 +#define CS35L41_IRQ1_RAW_STATUS4 0x0001009C +#define CS35L41_IRQ1_MASK1 0x00010110 +#define CS35L41_IRQ1_MASK2 0x00010114 +#define CS35L41_IRQ1_MASK3 0x00010118 +#define CS35L41_IRQ1_MASK4 0x0001011C +#define CS35L41_IRQ1_FRC1 0x00010190 +#define CS35L41_IRQ1_FRC2 0x00010194 +#define CS35L41_IRQ1_FRC3 0x00010198 +#define CS35L41_IRQ1_FRC4 0x0001019C +#define CS35L41_IRQ1_EDGE1 0x00010210 +#define CS35L41_IRQ1_EDGE4 0x0001021C +#define CS35L41_IRQ1_POL1 0x00010290 +#define CS35L41_IRQ1_POL2 0x00010294 +#define CS35L41_IRQ1_POL3 0x00010298 +#define CS35L41_IRQ1_POL4 0x0001029C +#define CS35L41_IRQ1_DB3 0x00010318 +#define CS35L41_IRQ2_CFG 0x00010800 +#define CS35L41_IRQ2_STATUS 0x00010804 +#define CS35L41_IRQ2_STATUS1 0x00010810 +#define CS35L41_IRQ2_STATUS2 0x00010814 +#define CS35L41_IRQ2_STATUS3 0x00010818 +#define CS35L41_IRQ2_STATUS4 0x0001081C +#define CS35L41_IRQ2_RAW_STATUS1 0x00010890 +#define CS35L41_IRQ2_RAW_STATUS2 0x00010894 +#define CS35L41_IRQ2_RAW_STATUS3 0x00010898 +#define CS35L41_IRQ2_RAW_STATUS4 0x0001089C +#define CS35L41_IRQ2_MASK1 0x00010910 +#define CS35L41_IRQ2_MASK2 0x00010914 +#define CS35L41_IRQ2_MASK3 0x00010918 +#define CS35L41_IRQ2_MASK4 0x0001091C +#define CS35L41_IRQ2_FRC1 0x00010990 +#define CS35L41_IRQ2_FRC2 0x00010994 +#define CS35L41_IRQ2_FRC3 0x00010998 +#define CS35L41_IRQ2_FRC4 0x0001099C +#define CS35L41_IRQ2_EDGE1 0x00010A10 +#define CS35L41_IRQ2_EDGE4 0x00010A1C +#define CS35L41_IRQ2_POL1 0x00010A90 +#define CS35L41_IRQ2_POL2 0x00010A94 +#define CS35L41_IRQ2_POL3 0x00010A98 +#define CS35L41_IRQ2_POL4 0x00010A9C +#define CS35L41_IRQ2_DB3 0x00010B18 +#define CS35L41_GPIO_STATUS1 0x00011000 +#define CS35L41_GPIO1_CTRL1 0x00011008 +#define CS35L41_GPIO2_CTRL1 0x0001100C +#define CS35L41_MIXER_NGATE_CFG 0x00012000 +#define CS35L41_MIXER_NGATE_CH1_CFG 0x00012004 +#define CS35L41_MIXER_NGATE_CH2_CFG 0x00012008 +#define CS35L41_DSP_MBOX_1 0x00013000 +#define CS35L41_DSP_MBOX_2 0x00013004 +#define CS35L41_DSP_MBOX_3 0x00013008 +#define CS35L41_DSP_MBOX_4 0x0001300C +#define CS35L41_DSP_MBOX_5 0x00013010 +#define CS35L41_DSP_MBOX_6 0x00013014 +#define CS35L41_DSP_MBOX_7 0x00013018 +#define CS35L41_DSP_MBOX_8 0x0001301C +#define CS35L41_DSP_VIRT1_MBOX_1 0x00013020 +#define CS35L41_DSP_VIRT1_MBOX_2 0x00013024 +#define CS35L41_DSP_VIRT1_MBOX_3 0x00013028 +#define CS35L41_DSP_VIRT1_MBOX_4 0x0001302C +#define CS35L41_DSP_VIRT1_MBOX_5 0x00013030 +#define CS35L41_DSP_VIRT1_MBOX_6 0x00013034 +#define CS35L41_DSP_VIRT1_MBOX_7 0x00013038 +#define CS35L41_DSP_VIRT1_MBOX_8 0x0001303C +#define CS35L41_DSP_VIRT2_MBOX_1 0x00013040 +#define CS35L41_DSP_VIRT2_MBOX_2 0x00013044 +#define CS35L41_DSP_VIRT2_MBOX_3 0x00013048 +#define CS35L41_DSP_VIRT2_MBOX_4 0x0001304C +#define CS35L41_DSP_VIRT2_MBOX_5 0x00013050 +#define CS35L41_DSP_VIRT2_MBOX_6 0x00013054 +#define CS35L41_DSP_VIRT2_MBOX_7 0x00013058 +#define CS35L41_DSP_VIRT2_MBOX_8 0x0001305C +#define CS35L41_CLOCK_DETECT_1 0x00014000 +#define CS35L41_TIMER1_CONTROL 0x00015000 +#define CS35L41_TIMER1_COUNT_PRESET 0x00015004 +#define CS35L41_TIMER1_START_STOP 0x0001500C +#define CS35L41_TIMER1_STATUS 0x00015010 +#define CS35L41_TIMER1_COUNT_READBACK 0x00015014 +#define CS35L41_TIMER1_DSP_CLK_CFG 0x00015018 +#define CS35L41_TIMER1_DSP_CLK_STATUS 0x0001501C +#define CS35L41_TIMER2_CONTROL 0x00015100 +#define CS35L41_TIMER2_COUNT_PRESET 0x00015104 +#define CS35L41_TIMER2_START_STOP 0x0001510C +#define CS35L41_TIMER2_STATUS 0x00015110 +#define CS35L41_TIMER2_COUNT_READBACK 0x00015114 +#define CS35L41_TIMER2_DSP_CLK_CFG 0x00015118 +#define CS35L41_TIMER2_DSP_CLK_STATUS 0x0001511C +#define CS35L41_DFT_JTAG_CONTROL 0x00016000 +#define CS35L41_DIE_STS1 0x00017040 +#define CS35L41_DIE_STS2 0x00017044 +#define CS35L41_TEMP_CAL1 0x00017048 +#define CS35L41_TEMP_CAL2 0x0001704C +#define CS35L41_DSP1_XMEM_PACK_0 0x02000000 +#define CS35L41_DSP1_XMEM_PACK_3068 0x02002FF0 +#define CS35L41_DSP1_XMEM_UNPACK32_0 0x02400000 +#define CS35L41_DSP1_XMEM_UNPACK32_2046 0x02401FF8 +#define CS35L41_DSP1_TIMESTAMP_COUNT 0x025C0800 +#define CS35L41_DSP1_SYS_ID 0x025E0000 +#define CS35L41_DSP1_SYS_VERSION 0x025E0004 +#define CS35L41_DSP1_SYS_CORE_ID 0x025E0008 +#define CS35L41_DSP1_SYS_AHB_ADDR 0x025E000C +#define CS35L41_DSP1_SYS_XSRAM_SIZE 0x025E0010 +#define CS35L41_DSP1_SYS_YSRAM_SIZE 0x025E0018 +#define CS35L41_DSP1_SYS_PSRAM_SIZE 0x025E0020 +#define CS35L41_DSP1_SYS_PM_BOOT_SIZE 0x025E0028 +#define CS35L41_DSP1_SYS_FEATURES 0x025E002C +#define CS35L41_DSP1_SYS_FIR_FILTERS 0x025E0030 +#define CS35L41_DSP1_SYS_LMS_FILTERS 0x025E0034 +#define CS35L41_DSP1_SYS_XM_BANK_SIZE 0x025E0038 +#define CS35L41_DSP1_SYS_YM_BANK_SIZE 0x025E003C +#define CS35L41_DSP1_SYS_PM_BANK_SIZE 0x025E0040 +#define CS35L41_DSP1_AHBM_WIN0_CTRL0 0x025E2000 +#define CS35L41_DSP1_AHBM_WIN0_CTRL1 0x025E2004 +#define CS35L41_DSP1_AHBM_WIN1_CTRL0 0x025E2008 +#define CS35L41_DSP1_AHBM_WIN1_CTRL1 0x025E200C +#define CS35L41_DSP1_AHBM_WIN2_CTRL0 0x025E2010 +#define CS35L41_DSP1_AHBM_WIN2_CTRL1 0x025E2014 +#define CS35L41_DSP1_AHBM_WIN3_CTRL0 0x025E2018 +#define CS35L41_DSP1_AHBM_WIN3_CTRL1 0x025E201C +#define CS35L41_DSP1_AHBM_WIN4_CTRL0 0x025E2020 +#define CS35L41_DSP1_AHBM_WIN4_CTRL1 0x025E2024 +#define CS35L41_DSP1_AHBM_WIN5_CTRL0 0x025E2028 +#define CS35L41_DSP1_AHBM_WIN5_CTRL1 0x025E202C +#define CS35L41_DSP1_AHBM_WIN6_CTRL0 0x025E2030 +#define CS35L41_DSP1_AHBM_WIN6_CTRL1 0x025E2034 +#define CS35L41_DSP1_AHBM_WIN7_CTRL0 0x025E2038 +#define CS35L41_DSP1_AHBM_WIN7_CTRL1 0x025E203C +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL0 0x025E2040 +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL1 0x025E2044 +#define CS35L41_DSP1_XMEM_UNPACK24_0 0x02800000 +#define CS35L41_DSP1_XMEM_UNPACK24_4093 0x02803FF4 +#define CS35L41_DSP1_CTRL_BASE 0x02B80000 +#define CS35L41_DSP1_CORE_SOFT_RESET 0x02B80010 +#define CS35L41_DSP1_DEBUG 0x02B80040 +#define CS35L41_DSP1_TIMER_CTRL 0x02B80048 +#define CS35L41_DSP1_STREAM_ARB_CTRL 0x02B80050 +#define CS35L41_DSP1_RX1_RATE 0x02B80080 +#define CS35L41_DSP1_RX2_RATE 0x02B80088 +#define CS35L41_DSP1_RX3_RATE 0x02B80090 +#define CS35L41_DSP1_RX4_RATE 0x02B80098 +#define CS35L41_DSP1_RX5_RATE 0x02B800A0 +#define CS35L41_DSP1_RX6_RATE 0x02B800A8 +#define CS35L41_DSP1_RX7_RATE 0x02B800B0 +#define CS35L41_DSP1_RX8_RATE 0x02B800B8 +#define CS35L41_DSP1_TX1_RATE 0x02B80280 +#define CS35L41_DSP1_TX2_RATE 0x02B80288 +#define CS35L41_DSP1_TX3_RATE 0x02B80290 +#define CS35L41_DSP1_TX4_RATE 0x02B80298 +#define CS35L41_DSP1_TX5_RATE 0x02B802A0 +#define CS35L41_DSP1_TX6_RATE 0x02B802A8 +#define CS35L41_DSP1_TX7_RATE 0x02B802B0 +#define CS35L41_DSP1_TX8_RATE 0x02B802B8 +#define CS35L41_DSP1_NMI_CTRL1 0x02B80480 +#define CS35L41_DSP1_NMI_CTRL2 0x02B80488 +#define CS35L41_DSP1_NMI_CTRL3 0x02B80490 +#define CS35L41_DSP1_NMI_CTRL4 0x02B80498 +#define CS35L41_DSP1_NMI_CTRL5 0x02B804A0 +#define CS35L41_DSP1_NMI_CTRL6 0x02B804A8 +#define CS35L41_DSP1_NMI_CTRL7 0x02B804B0 +#define CS35L41_DSP1_NMI_CTRL8 0x02B804B8 +#define CS35L41_DSP1_RESUME_CTRL 0x02B80500 +#define CS35L41_DSP1_IRQ1_CTRL 0x02B80508 +#define CS35L41_DSP1_IRQ2_CTRL 0x02B80510 +#define CS35L41_DSP1_IRQ3_CTRL 0x02B80518 +#define CS35L41_DSP1_IRQ4_CTRL 0x02B80520 +#define CS35L41_DSP1_IRQ5_CTRL 0x02B80528 +#define CS35L41_DSP1_IRQ6_CTRL 0x02B80530 +#define CS35L41_DSP1_IRQ7_CTRL 0x02B80538 +#define CS35L41_DSP1_IRQ8_CTRL 0x02B80540 +#define CS35L41_DSP1_IRQ9_CTRL 0x02B80548 +#define CS35L41_DSP1_IRQ10_CTRL 0x02B80550 +#define CS35L41_DSP1_IRQ11_CTRL 0x02B80558 +#define CS35L41_DSP1_IRQ12_CTRL 0x02B80560 +#define CS35L41_DSP1_IRQ13_CTRL 0x02B80568 +#define CS35L41_DSP1_IRQ14_CTRL 0x02B80570 +#define CS35L41_DSP1_IRQ15_CTRL 0x02B80578 +#define CS35L41_DSP1_IRQ16_CTRL 0x02B80580 +#define CS35L41_DSP1_IRQ17_CTRL 0x02B80588 +#define CS35L41_DSP1_IRQ18_CTRL 0x02B80590 +#define CS35L41_DSP1_IRQ19_CTRL 0x02B80598 +#define CS35L41_DSP1_IRQ20_CTRL 0x02B805A0 +#define CS35L41_DSP1_IRQ21_CTRL 0x02B805A8 +#define CS35L41_DSP1_IRQ22_CTRL 0x02B805B0 +#define CS35L41_DSP1_IRQ23_CTRL 0x02B805B8 +#define CS35L41_DSP1_SCRATCH1 0x02B805C0 +#define CS35L41_DSP1_SCRATCH2 0x02B805C8 +#define CS35L41_DSP1_SCRATCH3 0x02B805D0 +#define CS35L41_DSP1_SCRATCH4 0x02B805D8 +#define CS35L41_DSP1_CCM_CORE_CTRL 0x02BC1000 +#define CS35L41_DSP1_CCM_CLK_OVERRIDE 0x02BC1008 +#define CS35L41_DSP1_XM_MSTR_EN 0x02BC2000 +#define CS35L41_DSP1_XM_CORE_PRI 0x02BC2008 +#define CS35L41_DSP1_XM_AHB_PACK_PL_PRI 0x02BC2010 +#define CS35L41_DSP1_XM_AHB_UP_PL_PRI 0x02BC2018 +#define CS35L41_DSP1_XM_ACCEL_PL0_PRI 0x02BC2020 +#define CS35L41_DSP1_XM_NPL0_PRI 0x02BC2078 +#define CS35L41_DSP1_YM_MSTR_EN 0x02BC20C0 +#define CS35L41_DSP1_YM_CORE_PRI 0x02BC20C8 +#define CS35L41_DSP1_YM_AHB_PACK_PL_PRI 0x02BC20D0 +#define CS35L41_DSP1_YM_AHB_UP_PL_PRI 0x02BC20D8 +#define CS35L41_DSP1_YM_ACCEL_PL0_PRI 0x02BC20E0 +#define CS35L41_DSP1_YM_NPL0_PRI 0x02BC2138 +#define CS35L41_DSP1_PM_MSTR_EN 0x02BC2180 +#define CS35L41_DSP1_PM_PATCH0_ADDR 0x02BC2188 +#define CS35L41_DSP1_PM_PATCH0_EN 0x02BC218C +#define CS35L41_DSP1_PM_PATCH0_DATA_LO 0x02BC2190 +#define CS35L41_DSP1_PM_PATCH0_DATA_HI 0x02BC2194 +#define CS35L41_DSP1_PM_PATCH1_ADDR 0x02BC2198 +#define CS35L41_DSP1_PM_PATCH1_EN 0x02BC219C +#define CS35L41_DSP1_PM_PATCH1_DATA_LO 0x02BC21A0 +#define CS35L41_DSP1_PM_PATCH1_DATA_HI 0x02BC21A4 +#define CS35L41_DSP1_PM_PATCH2_ADDR 0x02BC21A8 +#define CS35L41_DSP1_PM_PATCH2_EN 0x02BC21AC +#define CS35L41_DSP1_PM_PATCH2_DATA_LO 0x02BC21B0 +#define CS35L41_DSP1_PM_PATCH2_DATA_HI 0x02BC21B4 +#define CS35L41_DSP1_PM_PATCH3_ADDR 0x02BC21B8 +#define CS35L41_DSP1_PM_PATCH3_EN 0x02BC21BC +#define CS35L41_DSP1_PM_PATCH3_DATA_LO 0x02BC21C0 +#define CS35L41_DSP1_PM_PATCH3_DATA_HI 0x02BC21C4 +#define CS35L41_DSP1_PM_PATCH4_ADDR 0x02BC21C8 +#define CS35L41_DSP1_PM_PATCH4_EN 0x02BC21CC +#define CS35L41_DSP1_PM_PATCH4_DATA_LO 0x02BC21D0 +#define CS35L41_DSP1_PM_PATCH4_DATA_HI 0x02BC21D4 +#define CS35L41_DSP1_PM_PATCH5_ADDR 0x02BC21D8 +#define CS35L41_DSP1_PM_PATCH5_EN 0x02BC21DC +#define CS35L41_DSP1_PM_PATCH5_DATA_LO 0x02BC21E0 +#define CS35L41_DSP1_PM_PATCH5_DATA_HI 0x02BC21E4 +#define CS35L41_DSP1_PM_PATCH6_ADDR 0x02BC21E8 +#define CS35L41_DSP1_PM_PATCH6_EN 0x02BC21EC +#define CS35L41_DSP1_PM_PATCH6_DATA_LO 0x02BC21F0 +#define CS35L41_DSP1_PM_PATCH6_DATA_HI 0x02BC21F4 +#define CS35L41_DSP1_PM_PATCH7_ADDR 0x02BC21F8 +#define CS35L41_DSP1_PM_PATCH7_EN 0x02BC21FC +#define CS35L41_DSP1_PM_PATCH7_DATA_LO 0x02BC2200 +#define CS35L41_DSP1_PM_PATCH7_DATA_HI 0x02BC2204 +#define CS35L41_DSP1_MPU_XM_ACCESS0 0x02BC3000 +#define CS35L41_DSP1_MPU_YM_ACCESS0 0x02BC3004 +#define CS35L41_DSP1_MPU_WNDW_ACCESS0 0x02BC3008 +#define CS35L41_DSP1_MPU_XREG_ACCESS0 0x02BC300C +#define CS35L41_DSP1_MPU_YREG_ACCESS0 0x02BC3014 +#define CS35L41_DSP1_MPU_XM_ACCESS1 0x02BC3018 +#define CS35L41_DSP1_MPU_YM_ACCESS1 0x02BC301C +#define CS35L41_DSP1_MPU_WNDW_ACCESS1 0x02BC3020 +#define CS35L41_DSP1_MPU_XREG_ACCESS1 0x02BC3024 +#define CS35L41_DSP1_MPU_YREG_ACCESS1 0x02BC302C +#define CS35L41_DSP1_MPU_XM_ACCESS2 0x02BC3030 +#define CS35L41_DSP1_MPU_YM_ACCESS2 0x02BC3034 +#define CS35L41_DSP1_MPU_WNDW_ACCESS2 0x02BC3038 +#define CS35L41_DSP1_MPU_XREG_ACCESS2 0x02BC303C +#define CS35L41_DSP1_MPU_YREG_ACCESS2 0x02BC3044 +#define CS35L41_DSP1_MPU_XM_ACCESS3 0x02BC3048 +#define CS35L41_DSP1_MPU_YM_ACCESS3 0x02BC304C +#define CS35L41_DSP1_MPU_WNDW_ACCESS3 0x02BC3050 +#define CS35L41_DSP1_MPU_XREG_ACCESS3 0x02BC3054 +#define CS35L41_DSP1_MPU_YREG_ACCESS3 0x02BC305C +#define CS35L41_DSP1_MPU_XM_VIO_ADDR 0x02BC3100 +#define CS35L41_DSP1_MPU_XM_VIO_STATUS 0x02BC3104 +#define CS35L41_DSP1_MPU_YM_VIO_ADDR 0x02BC3108 +#define CS35L41_DSP1_MPU_YM_VIO_STATUS 0x02BC310C +#define CS35L41_DSP1_MPU_PM_VIO_ADDR 0x02BC3110 +#define CS35L41_DSP1_MPU_PM_VIO_STATUS 0x02BC3114 +#define CS35L41_DSP1_MPU_LOCK_CONFIG 0x02BC3140 +#define CS35L41_DSP1_MPU_WDT_RST_CTRL 0x02BC3180 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG0 0x02BC5000 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG1 0x02BC5004 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG2 0x02BC5008 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG0 0x02BC5010 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG1 0x02BC5014 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG2 0x02BC5018 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG0 0x02BC5020 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG1 0x02BC5024 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG2 0x02BC5028 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG0 0x02BC5030 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG1 0x02BC5034 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG2 0x02BC5038 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG0 0x02BC5040 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG1 0x02BC5044 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG2 0x02BC5048 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG0 0x02BC5050 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG1 0x02BC5054 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG2 0x02BC5058 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG0 0x02BC5060 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG1 0x02BC5064 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG2 0x02BC5068 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG0 0x02BC5070 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG1 0x02BC5074 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG2 0x02BC5078 +#define CS35L41_DSP1_STRMARB_TX0_CFG0 0x02BC5200 +#define CS35L41_DSP1_STRMARB_TX0_CFG1 0x02BC5204 +#define CS35L41_DSP1_STRMARB_TX1_CFG0 0x02BC5208 +#define CS35L41_DSP1_STRMARB_TX1_CFG1 0x02BC520C +#define CS35L41_DSP1_STRMARB_TX2_CFG0 0x02BC5210 +#define CS35L41_DSP1_STRMARB_TX2_CFG1 0x02BC5214 +#define CS35L41_DSP1_STRMARB_TX3_CFG0 0x02BC5218 +#define CS35L41_DSP1_STRMARB_TX3_CFG1 0x02BC521C +#define CS35L41_DSP1_STRMARB_TX4_CFG0 0x02BC5220 +#define CS35L41_DSP1_STRMARB_TX4_CFG1 0x02BC5224 +#define CS35L41_DSP1_STRMARB_TX5_CFG0 0x02BC5228 +#define CS35L41_DSP1_STRMARB_TX5_CFG1 0x02BC522C +#define CS35L41_DSP1_STRMARB_TX6_CFG0 0x02BC5230 +#define CS35L41_DSP1_STRMARB_TX6_CFG1 0x02BC5234 +#define CS35L41_DSP1_STRMARB_TX7_CFG0 0x02BC5238 +#define CS35L41_DSP1_STRMARB_TX7_CFG1 0x02BC523C +#define CS35L41_DSP1_STRMARB_RX0_CFG0 0x02BC5400 +#define CS35L41_DSP1_STRMARB_RX0_CFG1 0x02BC5404 +#define CS35L41_DSP1_STRMARB_RX1_CFG0 0x02BC5408 +#define CS35L41_DSP1_STRMARB_RX1_CFG1 0x02BC540C +#define CS35L41_DSP1_STRMARB_RX2_CFG0 0x02BC5410 +#define CS35L41_DSP1_STRMARB_RX2_CFG1 0x02BC5414 +#define CS35L41_DSP1_STRMARB_RX3_CFG0 0x02BC5418 +#define CS35L41_DSP1_STRMARB_RX3_CFG1 0x02BC541C +#define CS35L41_DSP1_STRMARB_RX4_CFG0 0x02BC5420 +#define CS35L41_DSP1_STRMARB_RX4_CFG1 0x02BC5424 +#define CS35L41_DSP1_STRMARB_RX5_CFG0 0x02BC5428 +#define CS35L41_DSP1_STRMARB_RX5_CFG1 0x02BC542C +#define CS35L41_DSP1_STRMARB_RX6_CFG0 0x02BC5430 +#define CS35L41_DSP1_STRMARB_RX6_CFG1 0x02BC5434 +#define CS35L41_DSP1_STRMARB_RX7_CFG0 0x02BC5438 +#define CS35L41_DSP1_STRMARB_RX7_CFG1 0x02BC543C +#define CS35L41_DSP1_STRMARB_IRQ0_CFG0 0x02BC5600 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG1 0x02BC5604 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG2 0x02BC5608 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG0 0x02BC5610 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG1 0x02BC5614 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG2 0x02BC5618 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG0 0x02BC5620 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG1 0x02BC5624 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG2 0x02BC5628 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG0 0x02BC5630 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG1 0x02BC5634 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG2 0x02BC5638 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG0 0x02BC5640 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG1 0x02BC5644 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG2 0x02BC5648 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG0 0x02BC5650 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG1 0x02BC5654 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG2 0x02BC5658 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG0 0x02BC5660 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG1 0x02BC5664 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG2 0x02BC5668 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG0 0x02BC5670 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG1 0x02BC5674 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG2 0x02BC5678 +#define CS35L41_DSP1_STRMARB_RESYNC_MSK 0x02BC5A00 +#define CS35L41_DSP1_STRMARB_ERR_STATUS 0x02BC5A08 +#define CS35L41_DSP1_INTPCTL_RES_STATIC 0x02BC6000 +#define CS35L41_DSP1_INTPCTL_RES_DYN 0x02BC6004 +#define CS35L41_DSP1_INTPCTL_NMI_CTRL 0x02BC6008 +#define CS35L41_DSP1_INTPCTL_IRQ_INV 0x02BC6010 +#define CS35L41_DSP1_INTPCTL_IRQ_MODE 0x02BC6014 +#define CS35L41_DSP1_INTPCTL_IRQ_EN 0x02BC6018 +#define CS35L41_DSP1_INTPCTL_IRQ_MSK 0x02BC601C +#define CS35L41_DSP1_INTPCTL_IRQ_FLUSH 0x02BC6020 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKCLR 0x02BC6024 +#define CS35L41_DSP1_INTPCTL_IRQ_FRC 0x02BC6028 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKSET 0x02BC602C +#define CS35L41_DSP1_INTPCTL_IRQ_ERR 0x02BC6030 +#define CS35L41_DSP1_INTPCTL_IRQ_PEND 0x02BC6034 +#define CS35L41_DSP1_INTPCTL_IRQ_GEN 0x02BC6038 +#define CS35L41_DSP1_INTPCTL_TESTBITS 0x02BC6040 +#define CS35L41_DSP1_WDT_CONTROL 0x02BC7000 +#define CS35L41_DSP1_WDT_STATUS 0x02BC7008 +#define CS35L41_DSP1_YMEM_PACK_0 0x02C00000 +#define CS35L41_DSP1_YMEM_PACK_1532 0x02C017F0 +#define CS35L41_DSP1_YMEM_UNPACK32_0 0x03000000 +#define CS35L41_DSP1_YMEM_UNPACK32_1022 0x03000FF8 +#define CS35L41_DSP1_YMEM_UNPACK24_0 0x03400000 +#define CS35L41_DSP1_YMEM_UNPACK24_2045 0x03401FF4 +#define CS35L41_DSP1_PMEM_0 0x03800000 +#define CS35L41_DSP1_PMEM_5114 0x03804FE8 + +/*test regs for emulation bringup*/ +#define CS35L41_PLL_OVR 0x00003018 +#define CS35L41_BST_TEST_DUTY 0x00003900 +#define CS35L41_DIGPWM_IOCTRL 0x0000706C + +/*registers populated by OTP*/ +#define CS35L41_OTP_TRIM_1 0x0000208c +#define CS35L41_OTP_TRIM_2 0x00002090 +#define CS35L41_OTP_TRIM_3 0x00003010 +#define CS35L41_OTP_TRIM_4 0x0000300C +#define CS35L41_OTP_TRIM_5 0x0000394C +#define CS35L41_OTP_TRIM_6 0x00003950 +#define CS35L41_OTP_TRIM_7 0x00003954 +#define CS35L41_OTP_TRIM_8 0x00003958 +#define CS35L41_OTP_TRIM_9 0x0000395C +#define CS35L41_OTP_TRIM_10 0x0000416C +#define CS35L41_OTP_TRIM_11 0x00004160 +#define CS35L41_OTP_TRIM_12 0x00004170 +#define CS35L41_OTP_TRIM_13 0x00004360 +#define CS35L41_OTP_TRIM_14 0x00004448 +#define CS35L41_OTP_TRIM_15 0x0000444C +#define CS35L41_OTP_TRIM_16 0x00006E30 +#define CS35L41_OTP_TRIM_17 0x00006E34 +#define CS35L41_OTP_TRIM_18 0x00006E38 +#define CS35L41_OTP_TRIM_19 0x00006E3C +#define CS35L41_OTP_TRIM_20 0x00006E40 +#define CS35L41_OTP_TRIM_21 0x00006E44 +#define CS35L41_OTP_TRIM_22 0x00006E48 +#define CS35L41_OTP_TRIM_23 0x00006E4C +#define CS35L41_OTP_TRIM_24 0x00006E50 +#define CS35L41_OTP_TRIM_25 0x00006E54 +#define CS35L41_OTP_TRIM_26 0x00006E58 +#define CS35L41_OTP_TRIM_27 0x00006E5C +#define CS35L41_OTP_TRIM_28 0x00006E60 +#define CS35L41_OTP_TRIM_29 0x00006E64 +#define CS35L41_OTP_TRIM_30 0x00007418 +#define CS35L41_OTP_TRIM_31 0x0000741C +#define CS35L41_OTP_TRIM_32 0x00007434 +#define CS35L41_OTP_TRIM_33 0x00007068 +#define CS35L41_OTP_TRIM_34 0x0000410C +#define CS35L41_OTP_TRIM_35 0x0000400C +#define CS35L41_OTP_TRIM_36 0x00002030 + +#define CS35L41_MAX_CACHE_REG 36 +#define CS35L41_OTP_SIZE_WORDS 32 +#define CS35L41_NUM_OTP_ELEM 100 +#define CS35L41_NUM_OTP_MAPS 5 + +#define CS35L41_VALID_PDATA 0x80000000 +#define CS35L41_NUM_SUPPLIES 2 + +#define CS35L41_SCLK_MSTR_MASK 0x10 +#define CS35L41_SCLK_MSTR_SHIFT 4 +#define CS35L41_LRCLK_MSTR_MASK 0x01 +#define CS35L41_LRCLK_MSTR_SHIFT 0 +#define CS35L41_SCLK_INV_MASK 0x40 +#define CS35L41_SCLK_INV_SHIFT 6 +#define CS35L41_LRCLK_INV_MASK 0x04 +#define CS35L41_LRCLK_INV_SHIFT 2 +#define CS35L41_SCLK_FRC_MASK 0x20 +#define CS35L41_SCLK_FRC_SHIFT 5 +#define CS35L41_LRCLK_FRC_MASK 0x02 +#define CS35L41_LRCLK_FRC_SHIFT 1 + +#define CS35L41_AMP_GAIN_PCM_MASK 0x3E0 +#define CS35L41_AMP_GAIN_ZC_MASK 0x0400 +#define CS35L41_AMP_GAIN_ZC_SHIFT 10 + +#define CS35L41_BST_CTL_MASK 0xFF +#define CS35L41_BST_CTL_SEL_MASK 0x03 +#define CS35L41_BST_CTL_SEL_REG 0x00 +#define CS35L41_BST_CTL_SEL_CLASSH 0x01 +#define CS35L41_BST_IPK_MASK 0x7F +#define CS35L41_BST_IPK_SHIFT 0 +#define CS35L41_BST_LIM_MASK 0x4 +#define CS35L41_BST_LIM_SHIFT 2 +#define CS35L41_BST_K1_MASK 0x000000FF +#define CS35L41_BST_K1_SHIFT 0 +#define CS35L41_BST_K2_MASK 0x0000FF00 +#define CS35L41_BST_K2_SHIFT 8 +#define CS35L41_BST_SLOPE_MASK 0x0000FF00 +#define CS35L41_BST_SLOPE_SHIFT 8 +#define CS35L41_BST_LBST_VAL_MASK 0x00000003 +#define CS35L41_BST_LBST_VAL_SHIFT 0 + +#define CS35L41_TEMP_THLD_MASK 0x03 +#define CS35L41_VMON_IMON_VOL_MASK 0x07FF07FF +#define CS35L41_PDM_MODE_MASK 0x01 +#define CS35L41_PDM_MODE_SHIFT 0 + +#define CS35L41_CH_MEM_DEPTH_MASK 0x07 +#define CS35L41_CH_MEM_DEPTH_SHIFT 0 +#define CS35L41_CH_HDRM_CTL_MASK 0x007F0000 +#define CS35L41_CH_HDRM_CTL_SHIFT 16 +#define CS35L41_CH_REL_RATE_MASK 0xFF00 +#define CS35L41_CH_REL_RATE_SHIFT 8 +#define CS35L41_CH_WKFET_DLY_MASK 0x001C +#define CS35L41_CH_WKFET_DLY_SHIFT 2 +#define CS35L41_CH_WKFET_THLD_MASK 0x0F00 +#define CS35L41_CH_WKFET_THLD_SHIFT 8 + +#define CS35L41_HW_NG_SEL_MASK 0x3F00 +#define CS35L41_HW_NG_SEL_SHIFT 8 +#define CS35L41_HW_NG_DLY_MASK 0x0070 +#define CS35L41_HW_NG_DLY_SHIFT 4 +#define CS35L41_HW_NG_THLD_MASK 0x0007 +#define CS35L41_HW_NG_THLD_SHIFT 0 + +#define CS35L41_DSP_NG_ENABLE_MASK 0x00010000 +#define CS35L41_DSP_NG_ENABLE_SHIFT 16 +#define CS35L41_DSP_NG_THLD_MASK 0x7 +#define CS35L41_DSP_NG_THLD_SHIFT 0 +#define CS35L41_DSP_NG_DELAY_MASK 0x0F00 +#define CS35L41_DSP_NG_DELAY_SHIFT 8 + +#define CS35L41_ASP_FMT_MASK 0x0700 +#define CS35L41_ASP_FMT_SHIFT 8 +#define CS35L41_ASP_DOUT_HIZ_MASK 0x03 +#define CS35L41_ASP_DOUT_HIZ_SHIFT 0 +#define CS35L41_ASP_WIDTH_16 0x10 +#define CS35L41_ASP_WIDTH_24 0x18 +#define CS35L41_ASP_WIDTH_32 0x20 +#define CS35L41_ASP_WIDTH_TX_MASK 0xFF0000 +#define CS35L41_ASP_WIDTH_TX_SHIFT 16 +#define CS35L41_ASP_WIDTH_RX_MASK 0xFF000000 +#define CS35L41_ASP_WIDTH_RX_SHIFT 24 +#define CS35L41_ASP_RX1_SLOT_MASK 0x3F +#define CS35L41_ASP_RX1_SLOT_SHIFT 0 +#define CS35L41_ASP_RX2_SLOT_MASK 0x3F00 +#define CS35L41_ASP_RX2_SLOT_SHIFT 8 +#define CS35L41_ASP_RX_WL_MASK 0x3F +#define CS35L41_ASP_TX_WL_MASK 0x3F +#define CS35L41_ASP_RX_WL_SHIFT 0 +#define CS35L41_ASP_TX_WL_SHIFT 0 +#define CS35L41_ASP_SOURCE_MASK 0x7F + +#define CS35L41_INPUT_SRC_ASPRX1 0x08 +#define CS35L41_INPUT_SRC_ASPRX2 0x09 +#define CS35L41_INPUT_SRC_VMON 0x18 +#define CS35L41_INPUT_SRC_IMON 0x19 +#define CS35L41_INPUT_SRC_CLASSH 0x21 +#define CS35L41_INPUT_SRC_VPMON 0x28 +#define CS35L41_INPUT_SRC_VBSTMON 0x29 +#define CS35L41_INPUT_SRC_TEMPMON 0x3A +#define CS35L41_INPUT_SRC_RSVD 0x3B +#define CS35L41_INPUT_DSP_TX1 0x32 +#define CS35L41_INPUT_DSP_TX2 0x33 + +#define CS35L41_PLL_CLK_SEL_MASK 0x07 +#define CS35L41_PLL_CLK_SEL_SHIFT 0 +#define CS35L41_PLL_CLK_EN_MASK 0x10 +#define CS35L41_PLL_CLK_EN_SHIFT 4 +#define CS35L41_PLL_OPENLOOP_MASK 0x0800 +#define CS35L41_PLL_OPENLOOP_SHIFT 11 +#define CS35L41_PLLSRC_SCLK 0 +#define CS35L41_PLLSRC_LRCLK 1 +#define CS35L41_PLLSRC_SELF 3 +#define CS35L41_PLLSRC_PDMCLK 4 +#define CS35L41_PLLSRC_MCLK 5 +#define CS35L41_PLLSRC_SWIRE 7 +#define CS35L41_REFCLK_FREQ_MASK 0x7E0 +#define CS35L41_REFCLK_FREQ_SHIFT 5 + +#define CS35L41_GLOBAL_FS_MASK 0x1F +#define CS35L41_GLOBAL_FS_SHIFT 0 + +#define CS35L41_GLOBAL_EN_MASK 0x01 +#define CS35L41_GLOBAL_EN_SHIFT 0 +#define CS35L41_BST_EN_MASK 0x0030 +#define CS35L41_BST_EN_SHIFT 4 +#define CS35L41_BST_EN_DEFAULT 0x2 +#define CS35L41_AMP_EN_SHIFT 0 +#define CS35L41_AMP_EN_MASK 1 + +#define CS35L41_PDN_DONE_MASK 0x00800000 +#define CS35L41_PDN_DONE_SHIFT 23 +#define CS35L41_PUP_DONE_MASK 0x01000000 +#define CS35L41_PUP_DONE_SHIFT 24 + +#define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F +#define CS35L36_PUP_DONE_IRQ_MASK 0xBF + +#define CS35L41_AMP_SHORT_ERR 0x80000000 +#define CS35L41_BST_SHORT_ERR 0x0100 +#define CS35L41_TEMP_WARN 0x8000 +#define CS35L41_TEMP_ERR 0x00020000 +#define CS35L41_BST_OVP_ERR 0x40 +#define CS35L41_BST_DCM_UVP_ERR 0x80 +#define CS35L41_OTP_BOOT_DONE 0x02 +#define CS35L41_PLL_UNLOCK 0x10 +#define CS35L41_OTP_BOOT_ERR 0x80000000 + +#define CS35L41_AMP_SHORT_ERR_RLS 0x02 +#define CS35L41_BST_SHORT_ERR_RLS 0x04 +#define CS35L41_BST_OVP_ERR_RLS 0x08 +#define CS35L41_BST_UVP_ERR_RLS 0x10 +#define CS35L41_TEMP_WARN_ERR_RLS 0x20 +#define CS35L41_TEMP_ERR_RLS 0x40 + + +#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F +#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF +#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF + +#define CS35L41_GPIO_DIR_MASK 0x80000000 +#define CS35L41_GPIO1_CTRL_MASK 0x00030000 +#define CS35L41_GPIO1_CTRL_SHIFT 16 +#define CS35L41_GPIO2_CTRL_MASK 0x07000000 +#define CS35L41_GPIO2_CTRL_SHIFT 24 +#define CS35L41_GPIO_CTRL_OPEN_INT 2 +#define CS35L41_GPIO_CTRL_ACTV_LO 4 +#define CS35L41_GPIO_CTRL_ACTV_HI 5 +#define CS35L41_GPIO_POL_MASK 0x1000 +#define CS35L41_GPIO_POL_SHIFT 12 + +#define CS35L41_AMP_INV_PCM_SHIFT 14 +#define CS35L41_AMP_INV_PCM_MASK (1 << CS35L41_AMP_INV_PCM_SHIFT) +#define CS35L41_AMP_PCM_VOL_SHIFT 3 +#define CS35L41_AMP_PCM_VOL_MASK (0x7FF << 3) +#define CS35L41_AMP_PCM_VOL_MUTE 0x4CF + +#define CS35L41_CHIP_ID 0x35a40 +#define CS35L41R_CHIP_ID 0x35b40 +#define CS35L41_MTLREVID_MASK 0x0F +#define CS35L41_REVID_A0 0xA0 +#define CS35L41_REVID_B0 0xB0 +#define CS35L41_REVID_B2 0xB2 + +#define CS35L41_HALO_CORE_RESET 0x00000200 + +#define CS35L41_FS1_WINDOW_MASK 0x000007FF +#define CS35L41_FS2_WINDOW_MASK 0x00FFF800 +#define CS35L41_FS2_WINDOW_SHIFT 12 + +#define CS35L41_SPI_MAX_FREQ_OTP 4000000 + +#define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) +#define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +bool cs35l41_readable_reg(struct device *dev, unsigned int reg); +bool cs35l41_precious_reg(struct device *dev, unsigned int reg); +bool cs35l41_volatile_reg(struct device *dev, unsigned int reg); + +struct cs35l41_otp_packed_element_t { + u32 reg; + u8 shift; + u8 size; +}; + +struct cs35l41_otp_map_element_t { + u32 id; + u32 num_elements; + const struct cs35l41_otp_packed_element_t *map; + u32 bit_offset; + u32 word_offset; +}; + +extern const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG]; +extern const struct cs35l41_otp_map_element_t + cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; + +#define CS35L41_REGSTRIDE 4 + +struct cs35l41_private { + struct snd_soc_codec *codec; + struct cs35l41_platform_data pdata; + struct device *dev; + struct regmap *regmap; + struct regulator_bulk_data supplies[CS35L41_NUM_SUPPLIES]; + int irq; + /* GPIO for /RST */ + struct gpio_desc *reset_gpio; + void (*otp_setup)(struct cs35l41_private *cs35l41, bool is_pre_setup, + unsigned int *freq); +}; + +int cs35l41_probe(struct cs35l41_private *cs35l41, + struct cs35l41_platform_data *pdata); +int cs35l41_remove(struct cs35l41_private *cs35l41); + +#endif /*__CS35L41_H__*/ diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index b8cfc250612c..f39f98bbc97f 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c @@ -17,7 +17,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = { .playback = { .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index faff2b558687..508597866dff 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1311,6 +1311,57 @@ static int rt1011_r0_load_info(struct snd_kcontrol *kcontrol, .put = rt1011_r0_load_mode_put \ } +static const char * const rt1011_i2s_ref[] = { + "None", "Left Channel", "Right Channel" +}; + +static SOC_ENUM_SINGLE_DECL(rt1011_i2s_ref_enum, 0, 0, + rt1011_i2s_ref); + +static int rt1011_i2s_ref_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rt1011_priv *rt1011 = + snd_soc_component_get_drvdata(component); + int i2s_ref_ch = ucontrol->value.integer.value[0]; + + switch (i2s_ref_ch) { + case RT1011_I2S_REF_LEFT_CH: + regmap_write(rt1011->regmap, RT1011_TDM_TOTAL_SET, 0x0240); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_2, 0x8); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_1, 0x1022); + regmap_write(rt1011->regmap, RT1011_ADCDAT_OUT_SOURCE, 0x4); + break; + case RT1011_I2S_REF_RIGHT_CH: + regmap_write(rt1011->regmap, RT1011_TDM_TOTAL_SET, 0x0240); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_2, 0x8); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_1, 0x10a2); + regmap_write(rt1011->regmap, RT1011_ADCDAT_OUT_SOURCE, 0x4); + break; + default: + dev_info(component->dev, "I2S Reference: Do nothing\n"); + } + + rt1011->i2s_ref = ucontrol->value.integer.value[0]; + + return 0; +} + +static int rt1011_i2s_ref_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rt1011_priv *rt1011 = + snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1011->i2s_ref; + + return 0; +} + static const struct snd_kcontrol_new rt1011_snd_controls[] = { /* I2S Data In Selection */ SOC_ENUM("DIN Source", rt1011_din_source_enum), @@ -1349,6 +1400,9 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = { /* R0 temperature */ SOC_SINGLE("R0 Temperature", RT1011_STP_INITIAL_RESISTANCE_TEMP, 2, 255, 0), + /* I2S Reference */ + SOC_ENUM_EXT("I2S Reference", rt1011_i2s_ref_enum, + rt1011_i2s_ref_get, rt1011_i2s_ref_put), }; static int rt1011_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 68fadc15fa8c..afb2fad94216 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -654,6 +654,12 @@ enum { RT1011_AIFS }; +enum { + RT1011_I2S_REF_NONE, + RT1011_I2S_REF_LEFT_CH, + RT1011_I2S_REF_RIGHT_CH, +}; + /* BiQual & DRC related settings */ #define RT1011_BQ_DRC_NUM 128 struct rt1011_bq_drc_params { @@ -692,6 +698,7 @@ struct rt1011_priv { unsigned int r0_reg, cali_done; unsigned int r0_calib, temperature_calib; int recv_spk_mode; + unsigned int i2s_ref; }; #endif /* end of _RT1011_H_ */ diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c new file mode 100644 index 000000000000..d878a20527f1 --- /dev/null +++ b/sound/soc/codecs/rt5682s.c @@ -0,0 +1,3188 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt5682s.c -- RT5682I-VS ALSA SoC audio component driver +// +// Copyright 2021 Realtek Semiconductor Corp. +// Author: Derek Fang <[email protected]> +// + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/mutex.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/rt5682s.h> + +#include "rt5682s.h" + +#define DEVICE_ID 0x6749 + +static const struct rt5682s_platform_data i2s_default_platform_data = { + .dmic1_data_pin = RT5682S_DMIC1_DATA_GPIO2, + .dmic1_clk_pin = RT5682S_DMIC1_CLK_GPIO3, + .jd_src = RT5682S_JD1, + .dai_clk_names[RT5682S_DAI_WCLK_IDX] = "rt5682-dai-wclk", + .dai_clk_names[RT5682S_DAI_BCLK_IDX] = "rt5682-dai-bclk", +}; + +const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = { + "AVDD", + "MICVDD", +}; + +static const struct reg_sequence patch_list[] = { + {RT5682S_I2C_CTRL, 0x0007}, + {RT5682S_DIG_IN_CTRL_1, 0x0000}, + {RT5682S_CHOP_DAC_2, 0x2020}, + {RT5682S_VREF_REC_OP_FB_CAP_CTRL_2, 0x0101}, + {RT5682S_VREF_REC_OP_FB_CAP_CTRL_1, 0x80c0}, + {RT5682S_HP_CALIB_CTRL_9, 0x0002}, + {RT5682S_DEPOP_1, 0x0000}, + {RT5682S_HP_CHARGE_PUMP_2, 0x3c15}, + {RT5682S_DAC1_DIG_VOL, 0xfefe}, + {RT5682S_SAR_IL_CMD_2, 0xac00}, + {RT5682S_SAR_IL_CMD_3, 0x024c}, + {RT5682S_CBJ_CTRL_6, 0x0804}, +}; + +static void rt5682s_apply_patch_list(struct rt5682s_priv *rt5682s, + struct device *dev) +{ + int ret; + + ret = regmap_multi_reg_write(rt5682s->regmap, patch_list, ARRAY_SIZE(patch_list)); + if (ret) + dev_warn(dev, "Failed to apply regmap patch: %d\n", ret); +} + +const struct reg_default rt5682s_reg[] = { + {0x0000, 0x0001}, + {0x0002, 0x8080}, + {0x0003, 0x0001}, + {0x0005, 0x0000}, + {0x0006, 0x0000}, + {0x0008, 0x8007}, + {0x000b, 0x0000}, + {0x000f, 0x4000}, + {0x0010, 0x4040}, + {0x0011, 0x0000}, + {0x0012, 0x0000}, + {0x0013, 0x1200}, + {0x0014, 0x200a}, + {0x0015, 0x0404}, + {0x0016, 0x0404}, + {0x0017, 0x05a4}, + {0x0019, 0xffff}, + {0x001c, 0x2f2f}, + {0x001f, 0x0000}, + {0x0022, 0x5757}, + {0x0023, 0x0039}, + {0x0024, 0x000b}, + {0x0026, 0xc0c4}, + {0x0029, 0x8080}, + {0x002a, 0xa0a0}, + {0x002b, 0x0300}, + {0x0030, 0x0000}, + {0x003c, 0x08c0}, + {0x0044, 0x1818}, + {0x004b, 0x00c0}, + {0x004c, 0x0000}, + {0x004d, 0x0000}, + {0x0061, 0x00c0}, + {0x0062, 0x008a}, + {0x0063, 0x0800}, + {0x0064, 0x0000}, + {0x0065, 0x0000}, + {0x0066, 0x0030}, + {0x0067, 0x000c}, + {0x0068, 0x0000}, + {0x0069, 0x0000}, + {0x006a, 0x0000}, + {0x006b, 0x0000}, + {0x006c, 0x0000}, + {0x006d, 0x2200}, + {0x006e, 0x0810}, + {0x006f, 0xe4de}, + {0x0070, 0x3320}, + {0x0071, 0x0000}, + {0x0073, 0x0000}, + {0x0074, 0x0000}, + {0x0075, 0x0002}, + {0x0076, 0x0001}, + {0x0079, 0x0000}, + {0x007a, 0x0000}, + {0x007b, 0x0000}, + {0x007c, 0x0100}, + {0x007e, 0x0000}, + {0x007f, 0x0000}, + {0x0080, 0x0000}, + {0x0083, 0x0000}, + {0x0084, 0x0000}, + {0x0085, 0x0000}, + {0x0086, 0x0005}, + {0x0087, 0x0000}, + {0x0088, 0x0000}, + {0x008c, 0x0003}, + {0x008e, 0x0060}, + {0x008f, 0x4da1}, + {0x0091, 0x1c15}, + {0x0092, 0x0425}, + {0x0093, 0x0000}, + {0x0094, 0x0080}, + {0x0095, 0x008f}, + {0x0096, 0x0000}, + {0x0097, 0x0000}, + {0x0098, 0x0000}, + {0x0099, 0x0000}, + {0x009a, 0x0000}, + {0x009b, 0x0000}, + {0x009c, 0x0000}, + {0x009d, 0x0000}, + {0x009e, 0x0000}, + {0x009f, 0x0009}, + {0x00a0, 0x0000}, + {0x00a3, 0x0002}, + {0x00a4, 0x0001}, + {0x00b6, 0x0000}, + {0x00b7, 0x0000}, + {0x00b8, 0x0000}, + {0x00b9, 0x0002}, + {0x00be, 0x0000}, + {0x00c0, 0x0160}, + {0x00c1, 0x82a0}, + {0x00c2, 0x0000}, + {0x00d0, 0x0000}, + {0x00d2, 0x3300}, + {0x00d3, 0x2200}, + {0x00d4, 0x0000}, + {0x00d9, 0x0000}, + {0x00da, 0x0000}, + {0x00db, 0x0000}, + {0x00dc, 0x00c0}, + {0x00dd, 0x2220}, + {0x00de, 0x3131}, + {0x00df, 0x3131}, + {0x00e0, 0x3131}, + {0x00e2, 0x0000}, + {0x00e3, 0x4000}, + {0x00e4, 0x0aa0}, + {0x00e5, 0x3131}, + {0x00e6, 0x3131}, + {0x00e7, 0x3131}, + {0x00e8, 0x3131}, + {0x00ea, 0xb320}, + {0x00eb, 0x0000}, + {0x00f0, 0x0000}, + {0x00f6, 0x0000}, + {0x00fa, 0x0000}, + {0x00fb, 0x0000}, + {0x00fc, 0x0000}, + {0x00fd, 0x0000}, + {0x00fe, 0x10ec}, + {0x00ff, 0x6749}, + {0x0100, 0xa000}, + {0x010b, 0x0066}, + {0x010c, 0x6666}, + {0x010d, 0x2202}, + {0x010e, 0x6666}, + {0x010f, 0xa800}, + {0x0110, 0x0006}, + {0x0111, 0x0460}, + {0x0112, 0x2000}, + {0x0113, 0x0200}, + {0x0117, 0x8000}, + {0x0118, 0x0303}, + {0x0125, 0x0020}, + {0x0132, 0x5026}, + {0x0136, 0x8000}, + {0x0139, 0x0005}, + {0x013a, 0x3030}, + {0x013b, 0xa000}, + {0x013c, 0x4110}, + {0x013f, 0x0000}, + {0x0145, 0x0022}, + {0x0146, 0x0000}, + {0x0147, 0x0000}, + {0x0148, 0x0000}, + {0x0156, 0x0022}, + {0x0157, 0x0303}, + {0x0158, 0x2222}, + {0x0159, 0x0000}, + {0x0160, 0x4ec0}, + {0x0161, 0x0080}, + {0x0162, 0x0200}, + {0x0163, 0x0800}, + {0x0164, 0x0000}, + {0x0165, 0x0000}, + {0x0166, 0x0000}, + {0x0167, 0x000f}, + {0x0168, 0x000f}, + {0x0169, 0x0001}, + {0x0190, 0x4131}, + {0x0194, 0x0000}, + {0x0195, 0x0000}, + {0x0197, 0x0022}, + {0x0198, 0x0000}, + {0x0199, 0x0000}, + {0x01ac, 0x0000}, + {0x01ad, 0x0000}, + {0x01ae, 0x0000}, + {0x01af, 0x2000}, + {0x01b0, 0x0000}, + {0x01b1, 0x0000}, + {0x01b2, 0x0000}, + {0x01b3, 0x0017}, + {0x01b4, 0x004b}, + {0x01b5, 0x0000}, + {0x01b6, 0x03e8}, + {0x01b7, 0x0000}, + {0x01b8, 0x0000}, + {0x01b9, 0x0400}, + {0x01ba, 0xb5b6}, + {0x01bb, 0x9124}, + {0x01bc, 0x4924}, + {0x01bd, 0x0009}, + {0x01be, 0x0018}, + {0x01bf, 0x002a}, + {0x01c0, 0x004c}, + {0x01c1, 0x0097}, + {0x01c2, 0x01c3}, + {0x01c3, 0x03e9}, + {0x01c4, 0x1389}, + {0x01c5, 0xc351}, + {0x01c6, 0x02a0}, + {0x01c7, 0x0b0f}, + {0x01c8, 0x402f}, + {0x01c9, 0x0702}, + {0x01ca, 0x0000}, + {0x01cb, 0x0000}, + {0x01cc, 0x5757}, + {0x01cd, 0x5757}, + {0x01ce, 0x5757}, + {0x01cf, 0x5757}, + {0x01d0, 0x5757}, + {0x01d1, 0x5757}, + {0x01d2, 0x5757}, + {0x01d3, 0x5757}, + {0x01d4, 0x5757}, + {0x01d5, 0x5757}, + {0x01d6, 0x0000}, + {0x01d7, 0x0000}, + {0x01d8, 0x0162}, + {0x01d9, 0x0007}, + {0x01da, 0x0000}, + {0x01db, 0x0004}, + {0x01dc, 0x0000}, + {0x01de, 0x7c00}, + {0x01df, 0x0020}, + {0x01e0, 0x04c1}, + {0x01e1, 0x0000}, + {0x01e2, 0x0000}, + {0x01e3, 0x0000}, + {0x01e4, 0x0000}, + {0x01e5, 0x0000}, + {0x01e6, 0x0001}, + {0x01e7, 0x0000}, + {0x01e8, 0x0000}, + {0x01eb, 0x0000}, + {0x01ec, 0x0000}, + {0x01ed, 0x0000}, + {0x01ee, 0x0000}, + {0x01ef, 0x0000}, + {0x01f0, 0x0000}, + {0x01f1, 0x0000}, + {0x01f2, 0x0000}, + {0x01f3, 0x0000}, + {0x01f4, 0x0000}, + {0x0210, 0x6297}, + {0x0211, 0xa004}, + {0x0212, 0x0365}, + {0x0213, 0xf7ff}, + {0x0214, 0xf24c}, + {0x0215, 0x0102}, + {0x0216, 0x00a3}, + {0x0217, 0x0048}, + {0x0218, 0xa2c0}, + {0x0219, 0x0400}, + {0x021a, 0x00c8}, + {0x021b, 0x00c0}, + {0x021c, 0x0000}, + {0x021d, 0x024c}, + {0x02fa, 0x0000}, + {0x02fb, 0x0000}, + {0x02fc, 0x0000}, + {0x03fe, 0x0000}, + {0x03ff, 0x0000}, + {0x0500, 0x0000}, + {0x0600, 0x0000}, + {0x0610, 0x6666}, + {0x0611, 0xa9aa}, + {0x0620, 0x6666}, + {0x0621, 0xa9aa}, + {0x0630, 0x6666}, + {0x0631, 0xa9aa}, + {0x0640, 0x6666}, + {0x0641, 0xa9aa}, + {0x07fa, 0x0000}, + {0x08fa, 0x0000}, + {0x08fb, 0x0000}, + {0x0d00, 0x0000}, + {0x1100, 0x0000}, + {0x1101, 0x0000}, + {0x1102, 0x0000}, + {0x1103, 0x0000}, + {0x1104, 0x0000}, + {0x1105, 0x0000}, + {0x1106, 0x0000}, + {0x1107, 0x0000}, + {0x1108, 0x0000}, + {0x1109, 0x0000}, + {0x110a, 0x0000}, + {0x110b, 0x0000}, + {0x110c, 0x0000}, + {0x1111, 0x0000}, + {0x1112, 0x0000}, + {0x1113, 0x0000}, + {0x1114, 0x0000}, + {0x1115, 0x0000}, + {0x1116, 0x0000}, + {0x1117, 0x0000}, + {0x1118, 0x0000}, + {0x1119, 0x0000}, + {0x111a, 0x0000}, + {0x111b, 0x0000}, + {0x111c, 0x0000}, + {0x1401, 0x0404}, + {0x1402, 0x0007}, + {0x1403, 0x0365}, + {0x1404, 0x0210}, + {0x1405, 0x0365}, + {0x1406, 0x0210}, + {0x1407, 0x0000}, + {0x1408, 0x0000}, + {0x1409, 0x0000}, + {0x140a, 0x0000}, + {0x140b, 0x0000}, + {0x140c, 0x0000}, + {0x140d, 0x0000}, + {0x140e, 0x0000}, + {0x140f, 0x0000}, + {0x1410, 0x0000}, + {0x1411, 0x0000}, + {0x1801, 0x0004}, + {0x1802, 0x0000}, + {0x1803, 0x0000}, + {0x1804, 0x0000}, + {0x1805, 0x00ff}, + {0x2c00, 0x0000}, + {0x3400, 0x0200}, + {0x3404, 0x0000}, + {0x3405, 0x0000}, + {0x3406, 0x0000}, + {0x3407, 0x0000}, + {0x3408, 0x0000}, + {0x3409, 0x0000}, + {0x340a, 0x0000}, + {0x340b, 0x0000}, + {0x340c, 0x0000}, + {0x340d, 0x0000}, + {0x340e, 0x0000}, + {0x340f, 0x0000}, + {0x3410, 0x0000}, + {0x3411, 0x0000}, + {0x3412, 0x0000}, + {0x3413, 0x0000}, + {0x3414, 0x0000}, + {0x3415, 0x0000}, + {0x3424, 0x0000}, + {0x3425, 0x0000}, + {0x3426, 0x0000}, + {0x3427, 0x0000}, + {0x3428, 0x0000}, + {0x3429, 0x0000}, + {0x342a, 0x0000}, + {0x342b, 0x0000}, + {0x342c, 0x0000}, + {0x342d, 0x0000}, + {0x342e, 0x0000}, + {0x342f, 0x0000}, + {0x3430, 0x0000}, + {0x3431, 0x0000}, + {0x3432, 0x0000}, + {0x3433, 0x0000}, + {0x3434, 0x0000}, + {0x3435, 0x0000}, + {0x3440, 0x6319}, + {0x3441, 0x3771}, + {0x3500, 0x0002}, + {0x3501, 0x5728}, + {0x3b00, 0x3010}, + {0x3b01, 0x3300}, + {0x3b02, 0x2200}, + {0x3b03, 0x0100}, +}; + +static bool rt5682s_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5682S_RESET: + case RT5682S_CBJ_CTRL_2: + case RT5682S_I2S1_F_DIV_CTRL_2: + case RT5682S_I2S2_F_DIV_CTRL_2: + case RT5682S_INT_ST_1: + case RT5682S_GPIO_ST: + case RT5682S_IL_CMD_1: + case RT5682S_4BTN_IL_CMD_1: + case RT5682S_AJD1_CTRL: + case RT5682S_VERSION_ID...RT5682S_DEVICE_ID: + case RT5682S_STO_NG2_CTRL_1: + case RT5682S_STO_NG2_CTRL_5...RT5682S_STO_NG2_CTRL_7: + case RT5682S_STO1_DAC_SIL_DET: + case RT5682S_HP_IMP_SENS_CTRL_1...RT5682S_HP_IMP_SENS_CTRL_4: + case RT5682S_HP_IMP_SENS_CTRL_13: + case RT5682S_HP_IMP_SENS_CTRL_14: + case RT5682S_HP_IMP_SENS_CTRL_43...RT5682S_HP_IMP_SENS_CTRL_46: + case RT5682S_HP_CALIB_CTRL_1: + case RT5682S_HP_CALIB_CTRL_10: + case RT5682S_HP_CALIB_ST_1...RT5682S_HP_CALIB_ST_11: + case RT5682S_SAR_IL_CMD_2...RT5682S_SAR_IL_CMD_5: + case RT5682S_SAR_IL_CMD_10: + case RT5682S_SAR_IL_CMD_11: + case RT5682S_VERSION_ID_HIDE: + case RT5682S_VERSION_ID_CUS: + case RT5682S_I2C_TRANS_CTRL: + case RT5682S_DMIC_FLOAT_DET: + case RT5682S_HA_CMP_OP_1: + case RT5682S_NEW_CBJ_DET_CTL_10...RT5682S_NEW_CBJ_DET_CTL_16: + case RT5682S_CLK_SW_TEST_1: + case RT5682S_CLK_SW_TEST_2: + case RT5682S_EFUSE_READ_1...RT5682S_EFUSE_READ_18: + case RT5682S_PILOT_DIG_CTL_1: + return true; + default: + return false; + } +} + +static bool rt5682s_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5682S_RESET: + case RT5682S_VERSION_ID: + case RT5682S_VENDOR_ID: + case RT5682S_DEVICE_ID: + case RT5682S_HP_CTRL_1: + case RT5682S_HP_CTRL_2: + case RT5682S_HPL_GAIN: + case RT5682S_HPR_GAIN: + case RT5682S_I2C_CTRL: + case RT5682S_CBJ_BST_CTRL: + case RT5682S_CBJ_DET_CTRL: + case RT5682S_CBJ_CTRL_1...RT5682S_CBJ_CTRL_8: + case RT5682S_DAC1_DIG_VOL: + case RT5682S_STO1_ADC_DIG_VOL: + case RT5682S_STO1_ADC_BOOST: + case RT5682S_HP_IMP_GAIN_1: + case RT5682S_HP_IMP_GAIN_2: + case RT5682S_SIDETONE_CTRL: + case RT5682S_STO1_ADC_MIXER: + case RT5682S_AD_DA_MIXER: + case RT5682S_STO1_DAC_MIXER: + case RT5682S_A_DAC1_MUX: + case RT5682S_DIG_INF2_DATA: + case RT5682S_REC_MIXER: + case RT5682S_CAL_REC: + case RT5682S_HP_ANA_OST_CTRL_1...RT5682S_HP_ANA_OST_CTRL_3: + case RT5682S_PWR_DIG_1...RT5682S_PWR_MIXER: + case RT5682S_MB_CTRL: + case RT5682S_CLK_GATE_TCON_1...RT5682S_CLK_GATE_TCON_3: + case RT5682S_CLK_DET...RT5682S_LPF_AD_DMIC: + case RT5682S_I2S1_SDP: + case RT5682S_I2S2_SDP: + case RT5682S_ADDA_CLK_1: + case RT5682S_ADDA_CLK_2: + case RT5682S_I2S1_F_DIV_CTRL_1: + case RT5682S_I2S1_F_DIV_CTRL_2: + case RT5682S_TDM_CTRL: + case RT5682S_TDM_ADDA_CTRL_1: + case RT5682S_TDM_ADDA_CTRL_2: + case RT5682S_DATA_SEL_CTRL_1: + case RT5682S_TDM_TCON_CTRL_1: + case RT5682S_TDM_TCON_CTRL_2: + case RT5682S_GLB_CLK: + case RT5682S_PLL_TRACK_1...RT5682S_PLL_TRACK_6: + case RT5682S_PLL_TRACK_11: + case RT5682S_DEPOP_1: + case RT5682S_HP_CHARGE_PUMP_1: + case RT5682S_HP_CHARGE_PUMP_2: + case RT5682S_HP_CHARGE_PUMP_3: + case RT5682S_MICBIAS_1...RT5682S_MICBIAS_3: + case RT5682S_PLL_TRACK_12...RT5682S_PLL_CTRL_7: + case RT5682S_RC_CLK_CTRL: + case RT5682S_I2S2_M_CLK_CTRL_1: + case RT5682S_I2S2_F_DIV_CTRL_1: + case RT5682S_I2S2_F_DIV_CTRL_2: + case RT5682S_IRQ_CTRL_1...RT5682S_IRQ_CTRL_4: + case RT5682S_INT_ST_1: + case RT5682S_GPIO_CTRL_1: + case RT5682S_GPIO_CTRL_2: + case RT5682S_GPIO_ST: + case RT5682S_HP_AMP_DET_CTRL_1: + case RT5682S_MID_HP_AMP_DET: + case RT5682S_LOW_HP_AMP_DET: + case RT5682S_DELAY_BUF_CTRL: + case RT5682S_SV_ZCD_1: + case RT5682S_SV_ZCD_2: + case RT5682S_IL_CMD_1...RT5682S_IL_CMD_6: + case RT5682S_4BTN_IL_CMD_1...RT5682S_4BTN_IL_CMD_7: + case RT5682S_ADC_STO1_HP_CTRL_1: + case RT5682S_ADC_STO1_HP_CTRL_2: + case RT5682S_AJD1_CTRL: + case RT5682S_JD_CTRL_1: + case RT5682S_DUMMY_1...RT5682S_DUMMY_3: + case RT5682S_DAC_ADC_DIG_VOL1: + case RT5682S_BIAS_CUR_CTRL_2...RT5682S_BIAS_CUR_CTRL_10: + case RT5682S_VREF_REC_OP_FB_CAP_CTRL_1: + case RT5682S_VREF_REC_OP_FB_CAP_CTRL_2: + case RT5682S_CHARGE_PUMP_1: + case RT5682S_DIG_IN_CTRL_1: + case RT5682S_PAD_DRIVING_CTRL: + case RT5682S_CHOP_DAC_1: + case RT5682S_CHOP_DAC_2: + case RT5682S_CHOP_ADC: + case RT5682S_CALIB_ADC_CTRL: + case RT5682S_VOL_TEST: + case RT5682S_SPKVDD_DET_ST: + case RT5682S_TEST_MODE_CTRL_1...RT5682S_TEST_MODE_CTRL_4: + case RT5682S_PLL_INTERNAL_1...RT5682S_PLL_INTERNAL_4: + case RT5682S_STO_NG2_CTRL_1...RT5682S_STO_NG2_CTRL_10: + case RT5682S_STO1_DAC_SIL_DET: + case RT5682S_SIL_PSV_CTRL1: + case RT5682S_SIL_PSV_CTRL2: + case RT5682S_SIL_PSV_CTRL3: + case RT5682S_SIL_PSV_CTRL4: + case RT5682S_SIL_PSV_CTRL5: + case RT5682S_HP_IMP_SENS_CTRL_1...RT5682S_HP_IMP_SENS_CTRL_46: + case RT5682S_HP_LOGIC_CTRL_1...RT5682S_HP_LOGIC_CTRL_3: + case RT5682S_HP_CALIB_CTRL_1...RT5682S_HP_CALIB_CTRL_11: + case RT5682S_HP_CALIB_ST_1...RT5682S_HP_CALIB_ST_11: + case RT5682S_SAR_IL_CMD_1...RT5682S_SAR_IL_CMD_14: + case RT5682S_DUMMY_4...RT5682S_DUMMY_6: + case RT5682S_VERSION_ID_HIDE: + case RT5682S_VERSION_ID_CUS: + case RT5682S_SCAN_CTL: + case RT5682S_HP_AMP_DET: + case RT5682S_BIAS_CUR_CTRL_11: + case RT5682S_BIAS_CUR_CTRL_12: + case RT5682S_BIAS_CUR_CTRL_13: + case RT5682S_BIAS_CUR_CTRL_14: + case RT5682S_BIAS_CUR_CTRL_15: + case RT5682S_BIAS_CUR_CTRL_16: + case RT5682S_BIAS_CUR_CTRL_17: + case RT5682S_BIAS_CUR_CTRL_18: + case RT5682S_I2C_TRANS_CTRL: + case RT5682S_DUMMY_7: + case RT5682S_DUMMY_8: + case RT5682S_DMIC_FLOAT_DET: + case RT5682S_HA_CMP_OP_1...RT5682S_HA_CMP_OP_13: + case RT5682S_HA_CMP_OP_14...RT5682S_HA_CMP_OP_25: + case RT5682S_NEW_CBJ_DET_CTL_1...RT5682S_NEW_CBJ_DET_CTL_16: + case RT5682S_DA_FILTER_1...RT5682S_DA_FILTER_5: + case RT5682S_CLK_SW_TEST_1: + case RT5682S_CLK_SW_TEST_2: + case RT5682S_CLK_SW_TEST_3...RT5682S_CLK_SW_TEST_14: + case RT5682S_EFUSE_MANU_WRITE_1...RT5682S_EFUSE_MANU_WRITE_6: + case RT5682S_EFUSE_READ_1...RT5682S_EFUSE_READ_18: + case RT5682S_EFUSE_TIMING_CTL_1: + case RT5682S_EFUSE_TIMING_CTL_2: + case RT5682S_PILOT_DIG_CTL_1: + case RT5682S_PILOT_DIG_CTL_2: + case RT5682S_HP_AMP_DET_CTL_1...RT5682S_HP_AMP_DET_CTL_4: + return true; + default: + return false; + } +} + +static void rt5682s_reset(struct rt5682s_priv *rt5682s) +{ + regmap_write(rt5682s->regmap, RT5682S_RESET, 0); +} + +static int rt5682s_button_detect(struct snd_soc_component *component) +{ + int btn_type, val; + + val = snd_soc_component_read(component, RT5682S_4BTN_IL_CMD_1); + btn_type = val & 0xfff0; + snd_soc_component_write(component, RT5682S_4BTN_IL_CMD_1, val); + dev_dbg(component->dev, "%s btn_type=%x\n", __func__, btn_type); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_2, + RT5682S_SAR_ADC_PSV_MASK, RT5682S_SAR_ADC_PSV_ENTRY); + + return btn_type; +} + +enum { + SAR_PWR_OFF, + SAR_PWR_NORMAL, + SAR_PWR_SAVING, +}; + +static void rt5682s_sar_power_mode(struct snd_soc_component *component, + int mode, int jd_step) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + mutex_lock(&rt5682s->sar_mutex); + + switch (mode) { + case SAR_PWR_SAVING: + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_DIS); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK, + RT5682S_CTRL_MB1_REG | RT5682S_CTRL_MB2_REG); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS | + RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK, RT5682S_SAR_BUTDET_EN); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_2, + RT5682S_SAR_ADC_PSV_MASK, RT5682S_SAR_ADC_PSV_ENTRY); + break; + case SAR_PWR_NORMAL: + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_EN); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK, + RT5682S_CTRL_MB1_FSM | RT5682S_CTRL_MB2_FSM); + if (!jd_step) { + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_SEL_MB1_2_AUTO); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK, + RT5682S_SAR_BUTDET_EN | RT5682S_SAR_BUTDET_POW_NORM); + } + break; + case SAR_PWR_OFF: + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS | + RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU); + break; + default: + dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode); + break; + } + + mutex_unlock(&rt5682s->sar_mutex); +} + +static void rt5682s_enable_push_button_irq(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, + RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_BTN); + snd_soc_component_write(component, RT5682S_IL_CMD_1, 0x0040); + snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, + RT5682S_4BTN_IL_MASK | RT5682S_4BTN_IL_RST_MASK, + RT5682S_4BTN_IL_EN | RT5682S_4BTN_IL_NOR); + snd_soc_component_update_bits(component, RT5682S_IRQ_CTRL_3, + RT5682S_IL_IRQ_MASK, RT5682S_IL_IRQ_EN); +} + +static void rt5682s_disable_push_button_irq(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, RT5682S_IRQ_CTRL_3, + RT5682S_IL_IRQ_MASK, RT5682S_IL_IRQ_DIS); + snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, + RT5682S_4BTN_IL_MASK, RT5682S_4BTN_IL_DIS); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, + RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_TYPE); +} + +/** + * rt5682s_headset_detect - Detect headset. + * @component: SoC audio component device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_insert) +{ + unsigned int val, count; + int jack_type = 0; + + if (jack_insert) { + rt5682s_disable_push_button_irq(component); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF1 | RT5682S_PWR_VREF2 | RT5682S_PWR_MB, + RT5682S_PWR_VREF1 | RT5682S_PWR_VREF2 | RT5682S_PWR_MB); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_FV1 | RT5682S_PWR_FV2, 0); + usleep_range(15000, 20000); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_FV1 | RT5682S_PWR_FV2, + RT5682S_PWR_FV1 | RT5682S_PWR_FV2); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_CBJ, RT5682S_PWR_CBJ); + snd_soc_component_write(component, RT5682S_SAR_IL_CMD_3, 0x0365); + snd_soc_component_update_bits(component, RT5682S_HP_CHARGE_PUMP_2, + RT5682S_OSW_L_MASK | RT5682S_OSW_R_MASK, + RT5682S_OSW_L_DIS | RT5682S_OSW_R_DIS); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, + RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_TYPE); + rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 1); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); + usleep_range(45000, 50000); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_HIGH); + + count = 0; + do { + usleep_range(10000, 15000); + val = snd_soc_component_read(component, RT5682S_CBJ_CTRL_2) + & RT5682S_JACK_TYPE_MASK; + count++; + } while (val == 0 && count < 50); + + pr_debug("%s, val=%d, count=%d\n", __func__, val, count); + + switch (val) { + case 0x1: + case 0x2: + jack_type = SND_JACK_HEADSET; + snd_soc_component_write(component, RT5682S_SAR_IL_CMD_3, 0x024c); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_EN); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_SEL_MB1_2_MASK, val << RT5682S_SAR_SEL_MB1_2_SFT); + rt5682s_sar_power_mode(component, SAR_PWR_SAVING, 1); + rt5682s_enable_push_button_irq(component); + break; + default: + jack_type = SND_JACK_HEADPHONE; + break; + } + snd_soc_component_update_bits(component, RT5682S_HP_CHARGE_PUMP_2, + RT5682S_OSW_L_MASK | RT5682S_OSW_R_MASK, + RT5682S_OSW_L_EN | RT5682S_OSW_R_EN); + } else { + rt5682s_sar_power_mode(component, SAR_PWR_OFF, 1); + rt5682s_disable_push_button_irq(component); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); + + if (!snd_soc_dapm_get_pin_status(&component->dapm, "MICBIAS")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); + if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_CBJ, 0); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_DIS); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_DIS); + jack_type = 0; + } + + dev_dbg(component->dev, "jack_type = %d\n", jack_type); + + return jack_type; +} + +static void rt5682s_jack_detect_handler(struct work_struct *work) +{ + struct rt5682s_priv *rt5682s = + container_of(work, struct rt5682s_priv, jack_detect_work.work); + int val, btn_type; + + while (!rt5682s->component) + usleep_range(10000, 15000); + + while (!rt5682s->component->card->instantiated) + usleep_range(10000, 15000); + + mutex_lock(&rt5682s->calibrate_mutex); + + val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) + & RT5682S_JDH_RS_MASK; + if (!val) { + /* jack in */ + if (rt5682s->jack_type == 0) { + /* jack was out, report jack type */ + rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 1); + rt5682s->irq_work_delay_time = 0; + } else if ((rt5682s->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) { + /* jack is already in, report button event */ + rt5682s->jack_type = SND_JACK_HEADSET; + btn_type = rt5682s_button_detect(rt5682s->component); + /** + * rt5682s can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + rt5682s->jack_type |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + rt5682s->jack_type |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + rt5682s->jack_type |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + rt5682s->jack_type |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + dev_err(rt5682s->component->dev, + "Unexpected button code 0x%04x\n", btn_type); + break; + } + } + } else { + /* jack out */ + rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 0); + rt5682s->irq_work_delay_time = 50; + } + + snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (rt5682s->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + schedule_delayed_work(&rt5682s->jd_check_work, 0); + else + cancel_delayed_work_sync(&rt5682s->jd_check_work); + + mutex_unlock(&rt5682s->calibrate_mutex); +} + +static void rt5682s_jd_check_handler(struct work_struct *work) +{ + struct rt5682s_priv *rt5682s = + container_of(work, struct rt5682s_priv, jd_check_work.work); + + if (snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) + & RT5682S_JDH_RS_MASK) { + /* jack out */ + rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 0); + + snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + } else { + schedule_delayed_work(&rt5682s->jd_check_work, 500); + } +} + +static irqreturn_t rt5682s_irq(int irq, void *data) +{ + struct rt5682s_priv *rt5682s = data; + + mod_delayed_work(system_power_efficient_wq, &rt5682s->jack_detect_work, + msecs_to_jiffies(rt5682s->irq_work_delay_time)); + + return IRQ_HANDLED; +} + +static int rt5682s_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int btndet_delay = 16; + + rt5682s->hs_jack = hs_jack; + + if (!hs_jack) { + regmap_update_bits(rt5682s->regmap, RT5682S_IRQ_CTRL_2, + RT5682S_JD1_EN_MASK, RT5682S_JD1_DIS); + regmap_update_bits(rt5682s->regmap, RT5682S_RC_CLK_CTRL, + RT5682S_POW_JDH, 0); + cancel_delayed_work_sync(&rt5682s->jack_detect_work); + + return 0; + } + + switch (rt5682s->pdata.jd_src) { + case RT5682S_JD1: + regmap_update_bits(rt5682s->regmap, RT5682S_CBJ_CTRL_5, + RT5682S_JD_FAST_OFF_SRC_MASK, RT5682S_JD_FAST_OFF_SRC_JDH); + regmap_update_bits(rt5682s->regmap, RT5682S_CBJ_CTRL_2, + RT5682S_EXT_JD_SRC, RT5682S_EXT_JD_SRC_MANUAL); + regmap_update_bits(rt5682s->regmap, RT5682S_CBJ_CTRL_1, + RT5682S_EMB_JD_MASK | RT5682S_DET_TYPE | + RT5682S_POL_FAST_OFF_MASK | RT5682S_MIC_CAP_MASK, + RT5682S_EMB_JD_EN | RT5682S_DET_TYPE | + RT5682S_POL_FAST_OFF_HIGH | RT5682S_MIC_CAP_HS); + regmap_update_bits(rt5682s->regmap, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_POW_MASK, RT5682S_SAR_POW_EN); + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP1_PIN_MASK, RT5682S_GP1_PIN_IRQ); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_ANLG_3, + RT5682S_PWR_BGLDO, RT5682S_PWR_BGLDO); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_ANLG_2, + RT5682S_PWR_JD_MASK, RT5682S_PWR_JD_ENABLE); + regmap_update_bits(rt5682s->regmap, RT5682S_RC_CLK_CTRL, + RT5682S_POW_IRQ | RT5682S_POW_JDH, RT5682S_POW_IRQ | RT5682S_POW_JDH); + regmap_update_bits(rt5682s->regmap, RT5682S_IRQ_CTRL_2, + RT5682S_JD1_EN_MASK | RT5682S_JD1_POL_MASK, + RT5682S_JD1_EN | RT5682S_JD1_POL_NOR); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_4, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_5, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_6, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_7, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + + mod_delayed_work(system_power_efficient_wq, + &rt5682s->jack_detect_work, msecs_to_jiffies(250)); + break; + + case RT5682S_JD_NULL: + regmap_update_bits(rt5682s->regmap, RT5682S_IRQ_CTRL_2, + RT5682S_JD1_EN_MASK, RT5682S_JD1_DIS); + regmap_update_bits(rt5682s->regmap, RT5682S_RC_CLK_CTRL, + RT5682S_POW_JDH, 0); + break; + + default: + dev_warn(component->dev, "Wrong JD source\n"); + break; + } + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(cbj_bst_tlv, -1200, 150, 0); + +static const struct snd_kcontrol_new rt5682s_snd_controls[] = { + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682S_DAC1_DIG_VOL, + RT5682S_L_VOL_SFT + 2, RT5682S_R_VOL_SFT + 2, 63, 0, dac_vol_tlv), + + /* CBJ Boost Volume */ + SOC_SINGLE_TLV("CBJ Boost Volume", RT5682S_REC_MIXER, + RT5682S_BST_CBJ_SFT, 35, 0, cbj_bst_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("STO1 ADC Capture Switch", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE_SFT, RT5682S_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_VOL_SFT + 1, RT5682S_R_VOL_SFT + 1, 63, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5682S_STO1_ADC_BOOST, + RT5682S_STO1_ADC_L_BST_SFT, RT5682S_STO1_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), +}; + +/** + * rt5682s_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @component: SoC audio component device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5682S can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the component driver will turn on + * ASRC for these filters if ASRC is selected as their clock source. + */ +int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component, + unsigned int filter_mask, unsigned int clk_src) +{ + switch (clk_src) { + case RT5682S_CLK_SEL_SYS: + case RT5682S_CLK_SEL_I2S1_ASRC: + case RT5682S_CLK_SEL_I2S2_ASRC: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5682S_DA_STEREO1_FILTER) { + snd_soc_component_update_bits(component, RT5682S_PLL_TRACK_2, + RT5682S_FILTER_CLK_SEL_MASK, clk_src << RT5682S_FILTER_CLK_SEL_SFT); + } + + if (filter_mask & RT5682S_AD_STEREO1_FILTER) { + snd_soc_component_update_bits(component, RT5682S_PLL_TRACK_3, + RT5682S_FILTER_CLK_SEL_MASK, clk_src << RT5682S_FILTER_CLK_SEL_SFT); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5682s_sel_asrc_clk_src); + +static int rt5682s_div_sel(struct rt5682s_priv *rt5682s, + int target, const int div[], int size) +{ + int i; + + if (rt5682s->sysclk < target) { + dev_err(rt5682s->component->dev, + "sysclk rate %d is too low\n", rt5682s->sysclk); + return 0; + } + + for (i = 0; i < size - 1; i++) { + dev_dbg(rt5682s->component->dev, "div[%d]=%d\n", i, div[i]); + if (target * div[i] == rt5682s->sysclk) + return i; + if (target * div[i + 1] > rt5682s->sysclk) { + dev_dbg(rt5682s->component->dev, + "can't find div for sysclk %d\n", rt5682s->sysclk); + return i; + } + } + + if (target * div[i] < rt5682s->sysclk) + dev_err(rt5682s->component->dev, + "sysclk rate %d is too high\n", rt5682s->sysclk); + + return size - 1; +} + +static int get_clk_info(int sclk, int rate) +{ + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; + + if (sclk <= 0 || rate <= 0) + return -EINVAL; + + rate = rate << 8; + for (i = 0; i < ARRAY_SIZE(pd); i++) + if (sclk == rate * pd[i]) + return i; + + return -EINVAL; +} + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int idx, dmic_clk_rate = 3072000; + static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128}; + + if (rt5682s->pdata.dmic_clk_rate) + dmic_clk_rate = rt5682s->pdata.dmic_clk_rate; + + idx = rt5682s_div_sel(rt5682s, dmic_clk_rate, div, ARRAY_SIZE(div)); + + snd_soc_component_update_bits(component, RT5682S_DMIC_CTRL_1, + RT5682S_DMIC_CLK_MASK, idx << RT5682S_DMIC_CLK_SFT); + + return 0; +} + +static int set_filter_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int ref, val, reg, idx; + static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; + static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + + val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1) + & RT5682S_GP4_PIN_MASK; + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2) + ref = 256 * rt5682s->lrck[RT5682S_AIF2]; + else + ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + + idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f)); + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT) + reg = RT5682S_PLL_TRACK_3; + else + reg = RT5682S_PLL_TRACK_2; + + snd_soc_component_update_bits(component, reg, + RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT); + + /* select over sample rate */ + for (idx = 0; idx < ARRAY_SIZE(div_o); idx++) { + if (rt5682s->sysclk <= 12288000 * div_o[idx]) + break; + } + + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1, + RT5682S_ADC_OSR_MASK | RT5682S_DAC_OSR_MASK, + (idx << RT5682S_ADC_OSR_SFT) | (idx << RT5682S_DAC_OSR_SFT)); + + return 0; +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int delay = 50, val; + + if (rt5682s->pdata.dmic_delay) + delay = rt5682s->pdata.dmic_delay; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = (snd_soc_component_read(component, RT5682S_GLB_CLK) + & RT5682S_SCLK_SRC_MASK) >> RT5682S_SCLK_SRC_SFT; + if (val == RT5682S_CLK_SRC_PLL1 || val == RT5682S_CLK_SRC_PLL2) + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB); + + /*Add delay to avoid pop noise*/ + msleep(delay); + break; + + case SND_SOC_DAPM_POST_PMD: + if (!rt5682s->jack_type) { + if (!snd_soc_dapm_get_pin_status(w->dapm, "MICBIAS")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); + if (!snd_soc_dapm_get_pin_status(w->dapm, "Vref2")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + } + break; + } + + return 0; +} + +static int set_i2s_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int pre_div, id; + unsigned int reg, mask, sft; + + if (event != SND_SOC_DAPM_PRE_PMU) + return 0; + + if (w->shift == RT5682S_PWR_I2S2_BIT) { + id = RT5682S_AIF2; + reg = RT5682S_I2S2_M_CLK_CTRL_1; + mask = RT5682S_I2S2_M_D_MASK; + sft = RT5682S_I2S2_M_D_SFT; + } else { + id = RT5682S_AIF1; + reg = RT5682S_ADDA_CLK_1; + mask = RT5682S_I2S_M_D_MASK; + sft = RT5682S_I2S_M_D_SFT; + } + + if (!rt5682s->master[id]) + return 0; + + pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]); + if (pre_div < 0) { + dev_err(component->dev, "get pre_div failed\n"); + return -EINVAL; + } + + dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n", + rt5682s->lrck[id], pre_div, id); + snd_soc_component_update_bits(component, reg, mask, pre_div << sft); + + return 0; +} + +static int is_sys_clk_from_plla(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + if ((rt5682s->sysclk_src == RT5682S_CLK_SRC_PLL1) || + (rt5682s->sysclk_src == RT5682S_CLK_SRC_PLL2 && rt5682s->pll_comb == USE_PLLAB)) + return 1; + + return 0; +} + +static int is_sys_clk_from_pllb(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + if (rt5682s->sysclk_src == RT5682S_CLK_SRC_PLL2) + return 1; + + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, sft, val; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (w->shift) { + case RT5682S_ADC_STO1_ASRC_SFT: + reg = RT5682S_PLL_TRACK_3; + sft = RT5682S_FILTER_CLK_SEL_SFT; + break; + case RT5682S_DAC_STO1_ASRC_SFT: + reg = RT5682S_PLL_TRACK_2; + sft = RT5682S_FILTER_CLK_SEL_SFT; + break; + default: + return 0; + } + + val = (snd_soc_component_read(component, reg) >> sft) & 0xf; + switch (val) { + case RT5682S_CLK_SEL_I2S1_ASRC: + case RT5682S_CLK_SEL_I2S2_ASRC: + return 1; + default: + return 0; + } +} + +static int is_headset_type(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + if ((rt5682s->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) + return 1; + + return 0; +} + +static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN, + RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN); + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN | + RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN, + RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN | + RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN); + break; + + case SND_SOC_DAPM_POST_PMU: + usleep_range(30000, 35000); + snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_11, 0x6666); + snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_12, 0xa82a); + snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2, + RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK | + RT5682S_HPO_SEL_IP_EN_SW, RT5682S_HPO_L_PATH_EN | + RT5682S_HPO_R_PATH_EN | RT5682S_HPO_IP_EN_GATING); + snd_soc_component_write(component, RT5682S_HP_AMP_DET_CTL_1, 0x3050); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2, + RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK | + RT5682S_HPO_SEL_IP_EN_SW, 0); + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN | + RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN, 0); + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN, 0); + break; + } + + return 0; +} + +static int sar_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 0); + break; + case SND_SOC_DAPM_POST_PMD: + rt5682s_sar_power_mode(component, SAR_PWR_SAVING, 0); + break; + } + + return 0; +} + +/* Interface data select */ +static const char * const rt5682s_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_if2_adc_enum, RT5682S_DIG_INF2_DATA, + RT5682S_IF2_ADC_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_01_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC1_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_23_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC2_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_45_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC3_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_67_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC4_SEL_SFT, rt5682s_data_select); + +static const struct snd_kcontrol_new rt5682s_if2_adc_swap_mux = + SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5682s_if2_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5682s_if1_01_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5682s_if1_23_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5682s_if1_45_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682s_if1_67_adc_enum); + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5682s_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_sto1_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_L1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_sto1_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_L1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_R1_STO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5682s_rec1_l_mix[] = { + SOC_DAPM_SINGLE("CBJ Switch", RT5682S_REC_MIXER, + RT5682S_M_CBJ_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_rec1_r_mix[] = { + SOC_DAPM_SINGLE("CBJ Switch", RT5682S_REC_MIXER, + RT5682S_M_CBJ_RM1_R_SFT, 1, 1), +}; + +/* STO1 ADC1 Source */ +/* MX-26 [13] [5] */ +static const char * const rt5682s_sto1_adc1_src[] = { + "DAC MIX", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc1l_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC1L_SRC_SFT, rt5682s_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc1l_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682s_sto1_adc1l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc1r_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC1R_SRC_SFT, rt5682s_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc1r_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682s_sto1_adc1r_enum); + +/* STO1 ADC Source */ +/* MX-26 [11:10] [3:2] */ +static const char * const rt5682s_sto1_adc_src[] = { + "ADC1 L", "ADC1 R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adcl_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADCL_SRC_SFT, rt5682s_sto1_adc_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adcl_mux = + SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5682s_sto1_adcl_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adcr_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADCR_SRC_SFT, rt5682s_sto1_adc_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adcr_mux = + SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5682s_sto1_adcr_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [12] [4] */ +static const char * const rt5682s_sto1_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc2l_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC2L_SRC_SFT, rt5682s_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc2l_mux = + SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5682s_sto1_adc2l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc2r_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC2R_SRC_SFT, rt5682s_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc2r_mux = + SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5682s_sto1_adc2r_enum); + +/* MX-79 [6:4] I2S1 ADC data location */ +static const unsigned int rt5682s_if1_adc_slot_values[] = { + 0, 2, 4, 6, +}; + +static const char * const rt5682s_if1_adc_slot_src[] = { + "Slot 0", "Slot 2", "Slot 4", "Slot 6" +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rt5682s_if1_adc_slot_enum, + RT5682S_TDM_CTRL, RT5682S_TDM_ADC_LCA_SFT, RT5682S_TDM_ADC_LCA_MASK, + rt5682s_if1_adc_slot_src, rt5682s_if1_adc_slot_values); + +static const struct snd_kcontrol_new rt5682s_if1_adc_slot_mux = + SOC_DAPM_ENUM("IF1 ADC Slot location", rt5682s_if1_adc_slot_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2B [4], MX-2B [0]*/ +static const char * const rt5682s_alg_dac1_src[] = { + "Stereo1 DAC Mixer", "DAC1" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_alg_dac_l1_enum, RT5682S_A_DAC1_MUX, + RT5682S_A_DACL1_SFT, rt5682s_alg_dac1_src); + +static const struct snd_kcontrol_new rt5682s_alg_dac_l1_mux = + SOC_DAPM_ENUM("Analog DAC L1 Source", rt5682s_alg_dac_l1_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_alg_dac_r1_enum, RT5682S_A_DAC1_MUX, + RT5682S_A_DACR1_SFT, rt5682s_alg_dac1_src); + +static const struct snd_kcontrol_new rt5682s_alg_dac_r1_mux = + SOC_DAPM_ENUM("Analog DAC R1 Source", rt5682s_alg_dac_r1_enum); + +static const unsigned int rt5682s_adcdat_pin_values[] = { + 1, 3, +}; + +static const char * const rt5682s_adcdat_pin_select[] = { + "ADCDAT1", "ADCDAT2", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rt5682s_adcdat_pin_enum, + RT5682S_GPIO_CTRL_1, RT5682S_GP4_PIN_SFT, RT5682S_GP4_PIN_MASK, + rt5682s_adcdat_pin_select, rt5682s_adcdat_pin_values); + +static const struct snd_kcontrol_new rt5682s_adcdat_pin_ctrl = + SOC_DAPM_ENUM("ADCDAT", rt5682s_adcdat_pin_enum); + +static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO MB1", RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO MB2", RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_MB2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO", RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* PLL Powers */ + SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB_LDO", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLB_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLA_BIAS", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_BIAS_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB_BIAS", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_BIAS_PLLB_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLA", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_PLLB_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("PLLA_RST", 1, RT5682S_PWR_ANLG_3, + RT5682S_RSTB_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB_RST", 1, RT5682S_PWR_ANLG_3, + RT5682S_RSTB_PLLB_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_DAC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_AD_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_DA_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_DMIC_ASRC_SFT, 0, NULL, 0), + + /* Input Side */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5682S_PWR_ANLG_2, + RT5682S_PWR_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5682S_PWR_ANLG_2, + RT5682S_PWR_MB2_BIT, 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + + SND_SOC_DAPM_INPUT("IN1P"), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5682S_DMIC_CTRL_1, RT5682S_DMIC_1_EN_SFT, 0, + set_dmic_power, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682s_rec1_l_mix, + ARRAY_SIZE(rt5682s_rec1_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5682s_rec1_r_mix, + ARRAY_SIZE(rt5682s_rec1_r_mix)), + SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5682S_CAL_REC, + RT5682S_PWR_RM1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5682S_CAL_REC, + RT5682S_PWR_RM1_R_BIT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5682S_PWR_DIG_1, + RT5682S_PWR_ADC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5682S_PWR_DIG_1, + RT5682S_PWR_ADC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5682S_CHOP_ADC, + RT5682S_CKGEN_ADC1_SFT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc1l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc1r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc2l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc2r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adcl_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adcr_mux), + SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_adc_slot_mux), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682S_PWR_DIG_2, + RT5682S_PWR_ADC_S1F_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE_SFT, 1, rt5682s_sto1_adc_l_mix, + ARRAY_SIZE(rt5682s_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_R_MUTE_SFT, 1, rt5682s_sto1_adc_r_mix, + ARRAY_SIZE(rt5682s_sto1_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S1_BIT, + 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("I2S2", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S2_BIT, + 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if2_adc_swap_mux), + + SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0, &rt5682s_adcdat_pin_ctrl), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, RT5682S_I2S1_SDP, + RT5682S_SEL_ADCDAT_SFT, 1), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, RT5682S_I2S2_SDP, + RT5682S_I2S2_PIN_CFG_SFT, 1), + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5682s_dac_l_mix, ARRAY_SIZE(rt5682s_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5682s_dac_r_mix, ARRAY_SIZE(rt5682s_dac_r_mix)), + + /* DAC channel Mux */ + SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, &rt5682s_alg_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, &rt5682s_alg_dac_r1_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5682S_PWR_DIG_2, + RT5682S_PWR_DAC_S1F_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5682s_sto1_dac_l_mix, ARRAY_SIZE(rt5682s_sto1_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5682s_sto1_dac_r_mix, ARRAY_SIZE(rt5682s_sto1_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5682S_PWR_DIG_1, RT5682S_PWR_DAC_L1_BIT, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5682S_PWR_DIG_1, RT5682S_PWR_DAC_R1_BIT, 0), + + /* HPO */ + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5682s_hp_amp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + /* CLK DET */ + SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682S_CLK_DET, + RT5682S_SYS_CLK_DET_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5682S_CLK_DET, + RT5682S_PLL1_CLK_DET_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MCLK0 DET PWR", RT5682S_PWR_ANLG_2, + RT5682S_PWR_MCLK0_WD_BIT, 0, NULL, 0), + + /* SAR */ + SND_SOC_DAPM_SUPPLY("SAR", SND_SOC_NOPM, 0, 0, sar_power_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_route rt5682s_dapm_routes[] = { + /*PLL*/ + {"ADC Stereo1 Filter", NULL, "PLLA", is_sys_clk_from_plla}, + {"ADC Stereo1 Filter", NULL, "PLLB", is_sys_clk_from_pllb}, + {"DAC Stereo1 Filter", NULL, "PLLA", is_sys_clk_from_plla}, + {"DAC Stereo1 Filter", NULL, "PLLB", is_sys_clk_from_pllb}, + {"PLLA", NULL, "PLLA_LDO"}, + {"PLLA", NULL, "PLLA_BIAS"}, + {"PLLA", NULL, "PLLA_RST"}, + {"PLLB", NULL, "PLLB_LDO"}, + {"PLLB", NULL, "PLLB_BIAS"}, + {"PLLB", NULL, "PLLB_RST"}, + + /*ASRC*/ + {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, + {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, + {"ADC STO1 ASRC", NULL, "AD ASRC"}, + {"ADC STO1 ASRC", NULL, "DA ASRC"}, + {"DAC STO1 ASRC", NULL, "AD ASRC"}, + {"DAC STO1 ASRC", NULL, "DA ASRC"}, + + {"CLKDET SYS", NULL, "MCLK0 DET PWR"}, + + {"BST1 CBJ", NULL, "IN1P"}, + {"BST1 CBJ", NULL, "SAR", is_headset_type}, + + {"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX1L", NULL, "RECMIX1L Power"}, + {"RECMIX1R", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX1R", NULL, "RECMIX1R Power"}, + + {"ADC1 L", NULL, "RECMIX1L"}, + {"ADC1 L", NULL, "ADC1 L Power"}, + {"ADC1 L", NULL, "ADC1 clock"}, + {"ADC1 R", NULL, "RECMIX1R"}, + {"ADC1 R", NULL, "ADC1 R Power"}, + {"ADC1 R", NULL, "ADC1 clock"}, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC1 Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC1 Power"}, + {"DMIC CLK", NULL, "DMIC ASRC"}, + + {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"}, + + {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"}, + {"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"}, + {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"}, + {"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"}, + + {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"}, + {"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"}, + {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"}, + {"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, + {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, + {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, + {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, + {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"}, + + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"}, + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"}, + + {"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + + {"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"}, + {"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"}, + {"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"}, + {"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"}, + {"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"}, + {"AIF1TX", NULL, "I2S1"}, + {"AIF1TX", NULL, "ADCDAT Mux"}, + {"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"}, + {"AIF2TX", NULL, "ADCDAT Mux"}, + + {"IF1 DAC1 L", NULL, "AIF1RX"}, + {"IF1 DAC1 L", NULL, "I2S1"}, + {"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"}, + {"IF1 DAC1 R", NULL, "AIF1RX"}, + {"IF1 DAC1 R", NULL, "I2S1"}, + {"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"}, + + {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"}, + {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"}, + + {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, + + {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, + + {"DAC L1 Source", "DAC1", "DAC1 MIXL"}, + {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, + {"DAC R1 Source", "DAC1", "DAC1 MIXR"}, + {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, + + {"DAC L1", NULL, "DAC L1 Source"}, + {"DAC R1", NULL, "DAC R1 Source"}, + + {"HP Amp", NULL, "DAC L1"}, + {"HP Amp", NULL, "DAC R1"}, + {"HP Amp", NULL, "CLKDET SYS"}, + {"HP Amp", NULL, "SAR", is_headset_type}, + + {"HPOL", NULL, "HP Amp"}, + {"HPOR", NULL, "HP Amp"}, +}; + +static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + unsigned int cl, val = 0; + + if (tx_mask || rx_mask) + snd_soc_component_update_bits(component, + RT5682S_TDM_ADDA_CTRL_2, RT5682S_TDM_EN, RT5682S_TDM_EN); + else + snd_soc_component_update_bits(component, + RT5682S_TDM_ADDA_CTRL_2, RT5682S_TDM_EN, 0); + + switch (slots) { + case 4: + val |= RT5682S_TDM_TX_CH_4; + val |= RT5682S_TDM_RX_CH_4; + break; + case 6: + val |= RT5682S_TDM_TX_CH_6; + val |= RT5682S_TDM_RX_CH_6; + break; + case 8: + val |= RT5682S_TDM_TX_CH_8; + val |= RT5682S_TDM_RX_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT5682S_TDM_CTRL, + RT5682S_TDM_TX_CH_MASK | RT5682S_TDM_RX_CH_MASK, val); + + switch (slot_width) { + case 8: + if (tx_mask || rx_mask) + return -EINVAL; + cl = RT5682S_I2S1_TX_CHL_8 | RT5682S_I2S1_RX_CHL_8; + break; + case 16: + val = RT5682S_TDM_CL_16; + cl = RT5682S_I2S1_TX_CHL_16 | RT5682S_I2S1_RX_CHL_16; + break; + case 20: + val = RT5682S_TDM_CL_20; + cl = RT5682S_I2S1_TX_CHL_20 | RT5682S_I2S1_RX_CHL_20; + break; + case 24: + val = RT5682S_TDM_CL_24; + cl = RT5682S_I2S1_TX_CHL_24 | RT5682S_I2S1_RX_CHL_24; + break; + case 32: + val = RT5682S_TDM_CL_32; + cl = RT5682S_I2S1_TX_CHL_32 | RT5682S_I2S1_RX_CHL_32; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_CL_MASK, val); + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_TX_CHL_MASK | RT5682S_I2S1_RX_CHL_MASK, cl); + + return 0; +} + +static int rt5682s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int len_1 = 0, len_2 = 0; + int frame_size; + + rt5682s->lrck[dai->id] = params_rate(params); + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(component->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + break; + case 20: + len_1 |= RT5682S_I2S1_DL_20; + len_2 |= RT5682S_I2S2_DL_20; + break; + case 24: + len_1 |= RT5682S_I2S1_DL_24; + len_2 |= RT5682S_I2S2_DL_24; + break; + case 32: + len_1 |= RT5682S_I2S1_DL_32; + len_2 |= RT5682S_I2S2_DL_24; + break; + case 8: + len_1 |= RT5682S_I2S2_DL_8; + len_2 |= RT5682S_I2S2_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5682S_AIF1: + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_DL_MASK, len_1); + if (params_channels(params) == 1) /* mono mode */ + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_MONO_MASK, RT5682S_I2S1_MONO_EN); + else + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_MONO_MASK, RT5682S_I2S1_MONO_DIS); + break; + case RT5682S_AIF2: + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_DL_MASK, len_2); + if (params_channels(params) == 1) /* mono mode */ + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_MONO_MASK, RT5682S_I2S2_MONO_EN); + else + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_MONO_MASK, RT5682S_I2S2_MONO_DIS); + break; + default: + dev_err(component->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5682s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int reg_val = 0, tdm_ctrl = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5682s->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + rt5682s->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5682S_I2S_BP_INV; + tdm_ctrl |= RT5682S_TDM_S_BP_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + if (dai->id == RT5682S_AIF1) + tdm_ctrl |= RT5682S_TDM_S_LP_INV | RT5682S_TDM_M_BP_INV; + else + return -EINVAL; + break; + case SND_SOC_DAIFMT_IB_IF: + if (dai->id == RT5682S_AIF1) + tdm_ctrl |= RT5682S_TDM_S_BP_INV | RT5682S_TDM_S_LP_INV | + RT5682S_TDM_M_BP_INV | RT5682S_TDM_M_LP_INV; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5682S_I2S_DF_LEFT; + tdm_ctrl |= RT5682S_TDM_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5682S_I2S_DF_PCM_A; + tdm_ctrl |= RT5682S_TDM_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5682S_I2S_DF_PCM_B; + tdm_ctrl |= RT5682S_TDM_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5682S_AIF1: + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S_DF_MASK, reg_val); + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_MS_MASK | RT5682S_TDM_S_BP_MASK | + RT5682S_TDM_DF_MASK | RT5682S_TDM_M_BP_MASK | + RT5682S_TDM_M_LP_MASK | RT5682S_TDM_S_LP_MASK, + tdm_ctrl | rt5682s->master[dai->id]); + break; + case RT5682S_AIF2: + if (rt5682s->master[dai->id] == 0) + reg_val |= RT5682S_I2S2_MS_S; + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_MS_MASK | RT5682S_I2S_BP_MASK | + RT5682S_I2S_DF_MASK, reg_val); + break; + default: + dev_err(component->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5682s_set_component_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, int dir) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int src = 0; + + if (freq == rt5682s->sysclk && clk_id == rt5682s->sysclk_src) + return 0; + + switch (clk_id) { + case RT5682S_SCLK_S_MCLK: + src = RT5682S_CLK_SRC_MCLK; + break; + case RT5682S_SCLK_S_PLL1: + src = RT5682S_CLK_SRC_PLL1; + break; + case RT5682S_SCLK_S_PLL2: + src = RT5682S_CLK_SRC_PLL2; + break; + case RT5682S_SCLK_S_RCCLK: + src = RT5682S_CLK_SRC_RCCLK; + break; + default: + dev_err(component->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_SCLK_SRC_MASK, src << RT5682S_SCLK_SRC_SFT); + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1, + RT5682S_I2S_M_CLK_SRC_MASK, src << RT5682S_I2S_M_CLK_SRC_SFT); + snd_soc_component_update_bits(component, RT5682S_I2S2_M_CLK_CTRL_1, + RT5682S_I2S2_M_CLK_SRC_MASK, src << RT5682S_I2S2_M_CLK_SRC_SFT); + + rt5682s->sysclk = freq; + rt5682s->sysclk_src = clk_id; + + dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n", + freq, clk_id); + + return 0; +} + +static const struct pll_calc_map plla_table[] = { + {2048000, 24576000, 0, 46, 2, true, false, false, false}, + {256000, 24576000, 0, 382, 2, true, false, false, false}, + {512000, 24576000, 0, 190, 2, true, false, false, false}, + {4096000, 24576000, 0, 22, 2, true, false, false, false}, + {1024000, 24576000, 0, 94, 2, true, false, false, false}, + {11289600, 22579200, 1, 22, 2, false, false, false, false}, + {1411200, 22579200, 0, 62, 2, true, false, false, false}, + {2822400, 22579200, 0, 30, 2, true, false, false, false}, + {12288000, 24576000, 1, 22, 2, false, false, false, false}, + {1536000, 24576000, 0, 62, 2, true, false, false, false}, + {3072000, 24576000, 0, 30, 2, true, false, false, false}, + {24576000, 49152000, 4, 22, 0, false, false, false, false}, + {3072000, 49152000, 0, 30, 0, true, false, false, false}, + {6144000, 49152000, 0, 30, 0, false, false, false, false}, + {49152000, 98304000, 10, 22, 0, false, true, false, false}, + {6144000, 98304000, 0, 30, 0, false, true, false, false}, + {12288000, 98304000, 1, 22, 0, false, true, false, false}, + {48000000, 3840000, 10, 22, 23, false, false, false, false}, + {24000000, 3840000, 4, 22, 23, false, false, false, false}, + {19200000, 3840000, 3, 23, 23, false, false, false, false}, + {38400000, 3840000, 8, 23, 23, false, false, false, false}, +}; + +static const struct pll_calc_map pllb_table[] = { + {48000000, 24576000, 8, 6, 3, false, false, false, false}, + {48000000, 22579200, 23, 12, 3, false, false, false, true}, + {24000000, 24576000, 3, 6, 3, false, false, false, false}, + {24000000, 22579200, 23, 26, 3, false, false, false, true}, + {19200000, 24576000, 2, 6, 3, false, false, false, false}, + {19200000, 22579200, 3, 5, 3, false, false, false, true}, + {38400000, 24576000, 6, 6, 3, false, false, false, false}, + {38400000, 22579200, 8, 5, 3, false, false, false, true}, + {3840000, 49152000, 0, 6, 0, true, false, false, false}, +}; + +static int find_pll_inter_combination(unsigned int f_in, unsigned int f_out, + struct pll_calc_map *a, struct pll_calc_map *b) +{ + int i, j; + + /* Look at PLLA table */ + for (i = 0; i < ARRAY_SIZE(plla_table); i++) { + if (plla_table[i].freq_in == f_in && plla_table[i].freq_out == f_out) { + memcpy(a, plla_table + i, sizeof(*a)); + return USE_PLLA; + } + } + + /* Look at PLLB table */ + for (i = 0; i < ARRAY_SIZE(pllb_table); i++) { + if (pllb_table[i].freq_in == f_in && pllb_table[i].freq_out == f_out) { + memcpy(b, pllb_table + i, sizeof(*b)); + return USE_PLLB; + } + } + + /* Find a combination of PLLA & PLLB */ + for (i = ARRAY_SIZE(plla_table) - 1; i >= 0; i--) { + if (plla_table[i].freq_in == f_in && plla_table[i].freq_out == 3840000) { + for (j = ARRAY_SIZE(pllb_table) - 1; j >= 0; j--) { + if (pllb_table[j].freq_in == 3840000 && + pllb_table[j].freq_out == f_out) { + memcpy(a, plla_table + i, sizeof(*a)); + memcpy(b, pllb_table + j, sizeof(*b)); + return USE_PLLAB; + } + } + } + } + + return -EINVAL; +} + +static int rt5682s_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, unsigned int freq_in, + unsigned int freq_out) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + struct pll_calc_map a_map, b_map; + + if (source == rt5682s->pll_src[pll_id] && freq_in == rt5682s->pll_in[pll_id] && + freq_out == rt5682s->pll_out[pll_id]) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(component->dev, "PLL disabled\n"); + rt5682s->pll_in[pll_id] = 0; + rt5682s->pll_out[pll_id] = 0; + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_SCLK_SRC_MASK, RT5682S_CLK_SRC_MCLK << RT5682S_SCLK_SRC_SFT); + return 0; + } + + switch (source) { + case RT5682S_PLL_S_MCLK: + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_PLL_SRC_MASK, RT5682S_PLL_SRC_MCLK); + break; + case RT5682S_PLL_S_BCLK1: + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_PLL_SRC_MASK, RT5682S_PLL_SRC_BCLK1); + break; + default: + dev_err(component->dev, "Unknown PLL Source %d\n", source); + return -EINVAL; + } + + rt5682s->pll_comb = find_pll_inter_combination(freq_in, freq_out, + &a_map, &b_map); + + if ((pll_id == RT5682S_PLL1 && rt5682s->pll_comb == USE_PLLA) || + (pll_id == RT5682S_PLL2 && (rt5682s->pll_comb == USE_PLLB || + rt5682s->pll_comb == USE_PLLAB))) { + dev_dbg(component->dev, + "Supported freq conversion for PLL%d:(%d->%d): %d\n", + pll_id + 1, freq_in, freq_out, rt5682s->pll_comb); + } else { + dev_err(component->dev, + "Unsupported freq conversion for PLL%d:(%d->%d): %d\n", + pll_id + 1, freq_in, freq_out, rt5682s->pll_comb); + return -EINVAL; + } + + if (rt5682s->pll_comb == USE_PLLA || rt5682s->pll_comb == USE_PLLAB) { + dev_dbg(component->dev, + "PLLA: fin=%d fout=%d m_bp=%d k_bp=%d m=%d n=%d k=%d\n", + a_map.freq_in, a_map.freq_out, a_map.m_bp, a_map.k_bp, + (a_map.m_bp ? 0 : a_map.m), a_map.n, (a_map.k_bp ? 0 : a_map.k)); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_1, + RT5682S_PLLA_N_MASK, a_map.n); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_2, + RT5682S_PLLA_M_MASK | RT5682S_PLLA_K_MASK, + a_map.m << RT5682S_PLLA_M_SFT | a_map.k); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_6, + RT5682S_PLLA_M_BP_MASK | RT5682S_PLLA_K_BP_MASK, + a_map.m_bp << RT5682S_PLLA_M_BP_SFT | + a_map.k_bp << RT5682S_PLLA_K_BP_SFT); + } + + if (rt5682s->pll_comb == USE_PLLB || rt5682s->pll_comb == USE_PLLAB) { + dev_dbg(component->dev, + "PLLB: fin=%d fout=%d m_bp=%d k_bp=%d m=%d n=%d k=%d byp_ps=%d sel_ps=%d\n", + b_map.freq_in, b_map.freq_out, b_map.m_bp, b_map.k_bp, + (b_map.m_bp ? 0 : b_map.m), b_map.n, (b_map.k_bp ? 0 : b_map.k), + b_map.byp_ps, b_map.sel_ps); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_3, + RT5682S_PLLB_N_MASK, b_map.n); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_4, + RT5682S_PLLB_M_MASK | RT5682S_PLLB_K_MASK, + b_map.m << RT5682S_PLLB_M_SFT | b_map.k); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_6, + RT5682S_PLLB_SEL_PS_MASK | RT5682S_PLLB_BYP_PS_MASK | + RT5682S_PLLB_M_BP_MASK | RT5682S_PLLB_K_BP_MASK, + b_map.sel_ps << RT5682S_PLLB_SEL_PS_SFT | + b_map.byp_ps << RT5682S_PLLB_BYP_PS_SFT | + b_map.m_bp << RT5682S_PLLB_M_BP_SFT | + b_map.k_bp << RT5682S_PLLB_K_BP_SFT); + } + + if (rt5682s->pll_comb == USE_PLLB) + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_7, + RT5682S_PLLB_SRC_MASK, RT5682S_PLLB_SRC_DFIN); + + rt5682s->pll_in[pll_id] = freq_in; + rt5682s->pll_out[pll_id] = freq_out; + rt5682s->pll_src[pll_id] = source; + + return 0; +} + +static int rt5682s_set_bclk1_ratio(struct snd_soc_dai *dai, + unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + rt5682s->bclk[dai->id] = ratio; + + switch (ratio) { + case 256: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_256); + break; + case 128: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_128); + break; + case 64: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_64); + break; + case 32: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_32); + break; + default: + dev_err(dai->dev, "Invalid bclk1 ratio %d\n", ratio); + return -EINVAL; + } + + return 0; +} + +static int rt5682s_set_bclk2_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + rt5682s->bclk[dai->id] = ratio; + + switch (ratio) { + case 64: + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_2, + RT5682S_I2S2_BCLK_MS2_MASK, RT5682S_I2S2_BCLK_MS2_64); + break; + case 32: + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_2, + RT5682S_I2S2_BCLK_MS2_MASK, RT5682S_I2S2_BCLK_MS2_32); + break; + default: + dev_err(dai->dev, "Invalid bclk2 ratio %d\n", ratio); + return -EINVAL; + } + + return 0; +} + +static int rt5682s_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_PWR_LDO, RT5682S_PWR_LDO); + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); + break; + case SND_SOC_BIAS_OFF: + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL | RT5682S_PWR_LDO, 0); + break; + case SND_SOC_BIAS_ON: + break; + } + + return 0; +} + +#ifdef CONFIG_COMMON_CLK +#define CLK_PLL2_FIN 48000000 +#define CLK_48 48000 +#define CLK_44 44100 + +static bool rt5682s_clk_check(struct rt5682s_priv *rt5682s) +{ + if (!rt5682s->master[RT5682S_AIF1]) { + dev_dbg(rt5682s->component->dev, "dai clk fmt not set correctly\n"); + return false; + } + return true; +} + +static int rt5682s_wclk_prepare(struct clk_hw *hw) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_MB, RT5682S_PWR_MB); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Vref2"); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_FV2, RT5682S_PWR_VREF2); + usleep_range(15000, 20000); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_FV2, RT5682S_PWR_FV2); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1"); + /* Only need to power PLLB due to the rate set restriction */ + snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB"); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + +static void rt5682s_wclk_unprepare(struct clk_hw *hw) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + if (!rt5682s_clk_check(rt5682s)) + return; + + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Vref2"); + if (!rt5682s->jack_type) + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0); + + snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB"); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); +} + +static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + const char * const clk_name = clk_hw_get_name(hw); + + if (!rt5682s_clk_check(rt5682s)) + return 0; + /* + * Only accept to set wclk rate to 44.1k or 48kHz. + */ + if (rt5682s->lrck[RT5682S_AIF1] != CLK_48 && + rt5682s->lrck[RT5682S_AIF1] != CLK_44) { + dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", + __func__, clk_name, CLK_44, CLK_48); + return 0; + } + + return rt5682s->lrck[RT5682S_AIF1]; +} + +static long rt5682s_wclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + const char * const clk_name = clk_hw_get_name(hw); + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + /* + * Only accept to set wclk rate to 44.1k or 48kHz. + * It will force to 48kHz if not both. + */ + if (rate != CLK_48 && rate != CLK_44) { + dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", + __func__, clk_name, CLK_44, CLK_48); + rate = CLK_48; + } + + return rate; +} + +static int rt5682s_wclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct clk *parent_clk; + const char * const clk_name = clk_hw_get_name(hw); + unsigned int clk_pll2_fout; + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + + /* + * Whether the wclk's parent clk (mclk) exists or not, please ensure + * it is fixed or set to 48MHz before setting wclk rate. It's a + * temporary limitation. Only accept 48MHz clk as the clk provider. + * + * It will set the codec anyway by assuming mclk is 48MHz. + */ + parent_clk = clk_get_parent(hw->clk); + if (!parent_clk) + dev_warn(component->dev, + "Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n", + CLK_PLL2_FIN); + + if (parent_rate != CLK_PLL2_FIN) + dev_warn(component->dev, "clk %s only support %d Hz input\n", + clk_name, CLK_PLL2_FIN); + + /* + * To achieve the rate conversion from 48MHz to 44.1k or 48kHz, + * PLL2 is needed. + */ + clk_pll2_fout = rate * 512; + rt5682s_set_component_pll(component, RT5682S_PLL2, RT5682S_PLL_S_MCLK, + CLK_PLL2_FIN, clk_pll2_fout); + + rt5682s_set_component_sysclk(component, RT5682S_SCLK_S_PLL2, 0, + clk_pll2_fout, SND_SOC_CLOCK_IN); + + rt5682s->lrck[RT5682S_AIF1] = rate; + + return 0; +} + +static unsigned long rt5682s_bclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + unsigned int bclks_per_wclk; + + bclks_per_wclk = snd_soc_component_read(component, RT5682S_TDM_TCON_CTRL_1); + + switch (bclks_per_wclk & RT5682S_TDM_BCLK_MS1_MASK) { + case RT5682S_TDM_BCLK_MS1_256: + return parent_rate * 256; + case RT5682S_TDM_BCLK_MS1_128: + return parent_rate * 128; + case RT5682S_TDM_BCLK_MS1_64: + return parent_rate * 64; + case RT5682S_TDM_BCLK_MS1_32: + return parent_rate * 32; + default: + return 0; + } +} + +static unsigned long rt5682s_bclk_get_factor(unsigned long rate, + unsigned long parent_rate) +{ + unsigned long factor; + + factor = rate / parent_rate; + if (factor < 64) + return 32; + else if (factor < 128) + return 64; + else if (factor < 256) + return 128; + else + return 256; +} + +static long rt5682s_bclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); + unsigned long factor; + + if (!*parent_rate || !rt5682s_clk_check(rt5682s)) + return -EINVAL; + + /* + * BCLK rates are set as a multiplier of WCLK in HW. + * We don't allow changing the parent WCLK. We just do + * some rounding down based on the parent WCLK rate + * and find the appropriate multiplier of BCLK to + * get the rounded down BCLK value. + */ + factor = rt5682s_bclk_get_factor(rate, *parent_rate); + + return *parent_rate * factor; +} + +static int rt5682s_bclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct snd_soc_dai *dai; + unsigned long factor; + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + + factor = rt5682s_bclk_get_factor(rate, parent_rate); + + for_each_component_dais(component, dai) + if (dai->id == RT5682S_AIF1) + break; + if (!dai) { + dev_err(component->dev, "dai %d not found in component\n", + RT5682S_AIF1); + return -ENODEV; + } + + return rt5682s_set_bclk1_ratio(dai, factor); +} + +static const struct clk_ops rt5682s_dai_clk_ops[RT5682S_DAI_NUM_CLKS] = { + [RT5682S_DAI_WCLK_IDX] = { + .prepare = rt5682s_wclk_prepare, + .unprepare = rt5682s_wclk_unprepare, + .recalc_rate = rt5682s_wclk_recalc_rate, + .round_rate = rt5682s_wclk_round_rate, + .set_rate = rt5682s_wclk_set_rate, + }, + [RT5682S_DAI_BCLK_IDX] = { + .recalc_rate = rt5682s_bclk_recalc_rate, + .round_rate = rt5682s_bclk_round_rate, + .set_rate = rt5682s_bclk_set_rate, + }, +}; + +static int rt5682s_register_dai_clks(struct snd_soc_component *component) +{ + struct device *dev = component->dev; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + struct rt5682s_platform_data *pdata = &rt5682s->pdata; + struct clk_hw *dai_clk_hw; + int i, ret; + + for (i = 0; i < RT5682S_DAI_NUM_CLKS; ++i) { + struct clk_init_data init = { }; + + dai_clk_hw = &rt5682s->dai_clks_hw[i]; + + switch (i) { + case RT5682S_DAI_WCLK_IDX: + /* Make MCLK the parent of WCLK */ + if (rt5682s->mclk) { + init.parent_data = &(struct clk_parent_data){ + .fw_name = "mclk", + }; + init.num_parents = 1; + } + break; + case RT5682S_DAI_BCLK_IDX: + /* Make WCLK the parent of BCLK */ + init.parent_hws = &(const struct clk_hw *){ + &rt5682s->dai_clks_hw[RT5682S_DAI_WCLK_IDX] + }; + init.num_parents = 1; + break; + default: + dev_err(dev, "Invalid clock index\n"); + return -EINVAL; + } + + init.name = pdata->dai_clk_names[i]; + init.ops = &rt5682s_dai_clk_ops[i]; + init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE; + dai_clk_hw->init = &init; + + ret = devm_clk_hw_register(dev, dai_clk_hw); + if (ret) { + dev_warn(dev, "Failed to register %s: %d\n", init.name, ret); + return ret; + } + + if (dev->of_node) { + devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + } else { + ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw, + init.name, dev_name(dev)); + if (ret) + return ret; + } + } + + return 0; +} + +static int rt5682s_dai_probe_clks(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int ret; + + /* Check if MCLK provided */ + rt5682s->mclk = devm_clk_get(component->dev, "mclk"); + if (IS_ERR(rt5682s->mclk)) { + if (PTR_ERR(rt5682s->mclk) != -ENOENT) { + ret = PTR_ERR(rt5682s->mclk); + return ret; + } + rt5682s->mclk = NULL; + } + + /* Register CCF DAI clock control */ + ret = rt5682s_register_dai_clks(component); + if (ret) + return ret; + + /* Initial setup for CCF */ + rt5682s->lrck[RT5682S_AIF1] = CLK_48; + + return 0; +} +#else +static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_COMMON_CLK */ + +static int rt5682s_probe(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = &component->dapm; + int ret; + + rt5682s->component = component; + + ret = rt5682s_dai_probe_clks(component); + if (ret) + return ret; + + snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + snd_soc_dapm_disable_pin(dapm, "Vref2"); + snd_soc_dapm_sync(dapm); + return 0; +} + +static void rt5682s_remove(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + rt5682s_reset(rt5682s); +} + +#ifdef CONFIG_PM +static int rt5682s_suspend(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + cancel_delayed_work_sync(&rt5682s->jack_detect_work); + cancel_delayed_work_sync(&rt5682s->jd_check_work); + + if (rt5682s->hs_jack && rt5682s->jack_type == SND_JACK_HEADSET) + snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, + RT5682S_4BTN_IL_MASK, RT5682S_4BTN_IL_DIS); + + regcache_cache_only(rt5682s->regmap, true); + regcache_mark_dirty(rt5682s->regmap); + + return 0; +} + +static int rt5682s_resume(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt5682s->regmap, false); + regcache_sync(rt5682s->regmap); + + if (rt5682s->hs_jack) { + rt5682s->jack_type = 0; + mod_delayed_work(system_power_efficient_wq, + &rt5682s->jack_detect_work, msecs_to_jiffies(250)); + } + + return 0; +} +#else +#define rt5682s_suspend NULL +#define rt5682s_resume NULL +#endif + +const struct snd_soc_dai_ops rt5682s_aif1_dai_ops = { + .hw_params = rt5682s_hw_params, + .set_fmt = rt5682s_set_dai_fmt, + .set_tdm_slot = rt5682s_set_tdm_slot, + .set_bclk_ratio = rt5682s_set_bclk1_ratio, +}; + +const struct snd_soc_dai_ops rt5682s_aif2_dai_ops = { + .hw_params = rt5682s_hw_params, + .set_fmt = rt5682s_set_dai_fmt, + .set_bclk_ratio = rt5682s_set_bclk2_ratio, +}; + +const struct snd_soc_component_driver rt5682s_soc_component_dev = { + .probe = rt5682s_probe, + .remove = rt5682s_remove, + .suspend = rt5682s_suspend, + .resume = rt5682s_resume, + .set_bias_level = rt5682s_set_bias_level, + .controls = rt5682s_snd_controls, + .num_controls = ARRAY_SIZE(rt5682s_snd_controls), + .dapm_widgets = rt5682s_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5682s_dapm_widgets), + .dapm_routes = rt5682s_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5682s_dapm_routes), + .set_sysclk = rt5682s_set_component_sysclk, + .set_pll = rt5682s_set_component_pll, + .set_jack = rt5682s_set_jack_detect, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) +{ + device_property_read_u32(dev, "realtek,dmic1-data-pin", + &rt5682s->pdata.dmic1_data_pin); + device_property_read_u32(dev, "realtek,dmic1-clk-pin", + &rt5682s->pdata.dmic1_clk_pin); + device_property_read_u32(dev, "realtek,jd-src", + &rt5682s->pdata.jd_src); + device_property_read_u32(dev, "realtek,dmic-clk-rate-hz", + &rt5682s->pdata.dmic_clk_rate); + device_property_read_u32(dev, "realtek,dmic-delay-ms", + &rt5682s->pdata.dmic_delay); + + rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, + "realtek,ldo1-en-gpios", 0); + + if (device_property_read_string_array(dev, "clock-output-names", + rt5682s->pdata.dai_clk_names, + RT5682S_DAI_NUM_CLKS) < 0) + dev_warn(dev, "Using default DAI clk names: %s, %s\n", + rt5682s->pdata.dai_clk_names[RT5682S_DAI_WCLK_IDX], + rt5682s->pdata.dai_clk_names[RT5682S_DAI_BCLK_IDX]); + + rt5682s->pdata.dmic_clk_driving_high = device_property_read_bool(dev, + "realtek,dmic-clk-driving-high"); + + return 0; +} + +static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) +{ + unsigned int count, value; + + mutex_lock(&rt5682s->calibrate_mutex); + + regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80); + usleep_range(15000, 20000); + regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xfa80); + regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x01c0); + regmap_write(rt5682s->regmap, RT5682S_MICBIAS_2, 0x0380); + regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x8000); + regmap_write(rt5682s->regmap, RT5682S_ADDA_CLK_1, 0x1001); + regmap_write(rt5682s->regmap, RT5682S_CHOP_DAC_2, 0x3030); + regmap_write(rt5682s->regmap, RT5682S_CHOP_ADC, 0xb000); + regmap_write(rt5682s->regmap, RT5682S_STO1_ADC_MIXER, 0x686c); + regmap_write(rt5682s->regmap, RT5682S_CAL_REC, 0x5151); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_2, 0x0321); + regmap_write(rt5682s->regmap, RT5682S_HP_LOGIC_CTRL_2, 0x0004); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_1, 0x7c00); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_1, 0xfc00); + + for (count = 0; count < 60; count++) { + regmap_read(rt5682s->regmap, RT5682S_HP_CALIB_ST_1, &value); + if (!(value & 0x8000)) + break; + + usleep_range(10000, 10005); + } + + if (count >= 60) + dev_err(rt5682s->component->dev, "HP Calibration Failure\n"); + + /* restore settings */ + regmap_write(rt5682s->regmap, RT5682S_MICBIAS_2, 0x0180); + regmap_write(rt5682s->regmap, RT5682S_CAL_REC, 0x5858); + regmap_write(rt5682s->regmap, RT5682S_STO1_ADC_MIXER, 0xc0c4); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_2, 0x0320); + regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0); + regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800); + regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000); + + mutex_unlock(&rt5682s->calibrate_mutex); +} + +static const struct regmap_config rt5682s_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = RT5682S_MAX_REG, + .volatile_reg = rt5682s_volatile_register, + .readable_reg = rt5682s_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5682s_reg, + .num_reg_defaults = ARRAY_SIZE(rt5682s_reg), + .use_single_read = true, + .use_single_write = true, +}; + +static struct snd_soc_dai_driver rt5682s_dai[] = { + { + .name = "rt5682s-aif1", + .id = RT5682S_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682S_STEREO_RATES, + .formats = RT5682S_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682S_STEREO_RATES, + .formats = RT5682S_FORMATS, + }, + .ops = &rt5682s_aif1_dai_ops, + }, + { + .name = "rt5682s-aif2", + .id = RT5682S_AIF2, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682S_STEREO_RATES, + .formats = RT5682S_FORMATS, + }, + .ops = &rt5682s_aif2_dai_ops, + }, +}; + +static void rt5682s_i2c_disable_regulators(void *data) +{ + struct rt5682s_priv *rt5682s = data; + + regulator_bulk_disable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); +} + +static int rt5682s_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5682s_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5682s_priv *rt5682s; + int i, ret; + unsigned int val; + + rt5682s = devm_kzalloc(&i2c->dev, sizeof(struct rt5682s_priv), GFP_KERNEL); + if (!rt5682s) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5682s); + + rt5682s->pdata = i2s_default_platform_data; + + if (pdata) + rt5682s->pdata = *pdata; + else + rt5682s_parse_dt(rt5682s, &i2c->dev); + + rt5682s->regmap = devm_regmap_init_i2c(i2c, &rt5682s_regmap); + if (IS_ERR(rt5682s->regmap)) { + ret = PTR_ERR(rt5682s->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(rt5682s->supplies); i++) + rt5682s->supplies[i].supply = rt5682s_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(&i2c->dev, rt5682s_i2c_disable_regulators, rt5682s); + if (ret) + return ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + if (gpio_is_valid(rt5682s->pdata.ldo1_en)) { + if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en, + GPIOF_OUT_INIT_HIGH, "rt5682s")) + dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + } + + /* Sleep for 50 ms minimum */ + usleep_range(50000, 55000); + + regmap_read(rt5682s->regmap, RT5682S_DEVICE_ID, &val); + if (val != DEVICE_ID) { + dev_err(&i2c->dev, "Device with ID register %x is not rt5682s\n", val); + return -ENODEV; + } + + rt5682s_reset(rt5682s); + rt5682s_apply_patch_list(rt5682s, &i2c->dev); + + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_2, + RT5682S_DLDO_I_LIMIT_MASK, RT5682S_DLDO_I_LIMIT_DIS); + usleep_range(20000, 25000); + + mutex_init(&rt5682s->calibrate_mutex); + mutex_init(&rt5682s->sar_mutex); + rt5682s_calibrate(rt5682s); + + regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2, + RT5682S_PWR_CLK25M_MASK | RT5682S_PWR_CLK1M_MASK, + RT5682S_PWR_CLK25M_PD | RT5682S_PWR_CLK1M_PU); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_ANLG_1, + RT5682S_PWR_BG, RT5682S_PWR_BG); + regmap_update_bits(rt5682s->regmap, RT5682S_HP_LOGIC_CTRL_2, + RT5682S_HP_SIG_SRC_MASK, RT5682S_HP_SIG_SRC_1BIT_CTL); + regmap_update_bits(rt5682s->regmap, RT5682S_HP_CHARGE_PUMP_2, + RT5682S_PM_HP_MASK, RT5682S_PM_HP_HV); + + /* DMIC data pin */ + switch (rt5682s->pdata.dmic1_data_pin) { + case RT5682S_DMIC1_DATA_NULL: + break; + case RT5682S_DMIC1_DATA_GPIO2: /* share with LRCK2 */ + regmap_update_bits(rt5682s->regmap, RT5682S_DMIC_CTRL_1, + RT5682S_DMIC_1_DP_MASK, RT5682S_DMIC_1_DP_GPIO2); + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP2_PIN_MASK, RT5682S_GP2_PIN_DMIC_SDA); + break; + case RT5682S_DMIC1_DATA_GPIO5: /* share with DACDAT1 */ + regmap_update_bits(rt5682s->regmap, RT5682S_DMIC_CTRL_1, + RT5682S_DMIC_1_DP_MASK, RT5682S_DMIC_1_DP_GPIO5); + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP5_PIN_MASK, RT5682S_GP5_PIN_DMIC_SDA); + break; + default: + dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n"); + break; + } + + /* DMIC clk pin */ + switch (rt5682s->pdata.dmic1_clk_pin) { + case RT5682S_DMIC1_CLK_NULL: + break; + case RT5682S_DMIC1_CLK_GPIO1: /* share with IRQ */ + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP1_PIN_MASK, RT5682S_GP1_PIN_DMIC_CLK); + break; + case RT5682S_DMIC1_CLK_GPIO3: /* share with BCLK2 */ + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP3_PIN_MASK, RT5682S_GP3_PIN_DMIC_CLK); + if (rt5682s->pdata.dmic_clk_driving_high) + regmap_update_bits(rt5682s->regmap, RT5682S_PAD_DRIVING_CTRL, + RT5682S_PAD_DRV_GP3_MASK, RT5682S_PAD_DRV_GP3_HIGH); + break; + default: + dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n"); + break; + } + + INIT_DELAYED_WORK(&rt5682s->jack_detect_work, rt5682s_jack_detect_handler); + INIT_DELAYED_WORK(&rt5682s->jd_check_work, rt5682s_jd_check_handler); + + if (i2c->irq) { + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rt5682s_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "rt5682s", rt5682s); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + } + + return devm_snd_soc_register_component(&i2c->dev, &rt5682s_soc_component_dev, + rt5682s_dai, ARRAY_SIZE(rt5682s_dai)); +} + +static void rt5682s_i2c_shutdown(struct i2c_client *client) +{ + struct rt5682s_priv *rt5682s = i2c_get_clientdata(client); + + disable_irq(client->irq); + cancel_delayed_work_sync(&rt5682s->jack_detect_work); + cancel_delayed_work_sync(&rt5682s->jd_check_work); + + rt5682s_reset(rt5682s); +} + +static int rt5682s_i2c_remove(struct i2c_client *client) +{ + rt5682s_i2c_shutdown(client); + + return 0; +} + +static const struct of_device_id rt5682s_of_match[] = { + {.compatible = "realtek,rt5682s"}, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5682s_of_match); + +static const struct acpi_device_id rt5682s_acpi_match[] = { + {"RTL5682", 0,}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5682s_acpi_match); + +static const struct i2c_device_id rt5682s_i2c_id[] = { + {"rt5682s", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5682s_i2c_id); + +static struct i2c_driver rt5682s_i2c_driver = { + .driver = { + .name = "rt5682s", + .of_match_table = rt5682s_of_match, + .acpi_match_table = rt5682s_acpi_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = rt5682s_i2c_probe, + .remove = rt5682s_i2c_remove, + .shutdown = rt5682s_i2c_shutdown, + .id_table = rt5682s_i2c_id, +}; +module_i2c_driver(rt5682s_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5682I-VS driver"); +MODULE_AUTHOR("Derek Fang <[email protected]>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h new file mode 100644 index 000000000000..7c755e5efb81 --- /dev/null +++ b/sound/soc/codecs/rt5682s.h @@ -0,0 +1,1455 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt5682s.h -- RT5682I-VS ALSA SoC audio driver + * + * Copyright 2021 Realtek Microelectronics + * Author: Derek Fang <[email protected]> + */ + +#ifndef __RT5682S_H__ +#define __RT5682S_H__ + +#include <sound/rt5682s.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> + + +/* Info */ +#define RT5682S_RESET 0x0000 +#define RT5682S_VERSION_ID 0x00fd +#define RT5682S_VENDOR_ID 0x00fe +#define RT5682S_DEVICE_ID 0x00ff +/* I/O - Output */ +#define RT5682S_HP_CTRL_1 0x0002 +#define RT5682S_HP_CTRL_2 0x0003 +#define RT5682S_HPL_GAIN 0x0005 +#define RT5682S_HPR_GAIN 0x0006 + +#define RT5682S_I2C_CTRL 0x0008 + +/* I/O - Input */ +#define RT5682S_CBJ_BST_CTRL 0x000b +#define RT5682S_CBJ_DET_CTRL 0x000f +#define RT5682S_CBJ_CTRL_1 0x0010 +#define RT5682S_CBJ_CTRL_2 0x0011 +#define RT5682S_CBJ_CTRL_3 0x0012 +#define RT5682S_CBJ_CTRL_4 0x0013 +#define RT5682S_CBJ_CTRL_5 0x0014 +#define RT5682S_CBJ_CTRL_6 0x0015 +#define RT5682S_CBJ_CTRL_7 0x0016 +#define RT5682S_CBJ_CTRL_8 0x0017 +/* I/O - ADC/DAC/DMIC */ +#define RT5682S_DAC1_DIG_VOL 0x0019 +#define RT5682S_STO1_ADC_DIG_VOL 0x001c +#define RT5682S_STO1_ADC_BOOST 0x001f +#define RT5682S_HP_IMP_GAIN_1 0x0022 +#define RT5682S_HP_IMP_GAIN_2 0x0023 +/* Mixer - D-D */ +#define RT5682S_SIDETONE_CTRL 0x0024 +#define RT5682S_STO1_ADC_MIXER 0x0026 +#define RT5682S_AD_DA_MIXER 0x0029 +#define RT5682S_STO1_DAC_MIXER 0x002a +#define RT5682S_A_DAC1_MUX 0x002b +#define RT5682S_DIG_INF2_DATA 0x0030 +/* Mixer - ADC */ +#define RT5682S_REC_MIXER 0x003c +#define RT5682S_CAL_REC 0x0044 +/* HP Analog Offset Control */ +#define RT5682S_HP_ANA_OST_CTRL_1 0x004b +#define RT5682S_HP_ANA_OST_CTRL_2 0x004c +#define RT5682S_HP_ANA_OST_CTRL_3 0x004d +/* Power */ +#define RT5682S_PWR_DIG_1 0x0061 +#define RT5682S_PWR_DIG_2 0x0062 +#define RT5682S_PWR_ANLG_1 0x0063 +#define RT5682S_PWR_ANLG_2 0x0064 +#define RT5682S_PWR_ANLG_3 0x0065 +#define RT5682S_PWR_MIXER 0x0066 + +#define RT5682S_MB_CTRL 0x0067 +#define RT5682S_CLK_GATE_TCON_1 0x0068 +#define RT5682S_CLK_GATE_TCON_2 0x0069 +#define RT5682S_CLK_GATE_TCON_3 0x006a +/* Clock Detect */ +#define RT5682S_CLK_DET 0x006b +/* Filter Auto Reset */ +#define RT5682S_RESET_LPF_CTRL 0x006c +#define RT5682S_RESET_HPF_CTRL 0x006d +/* DMIC */ +#define RT5682S_DMIC_CTRL_1 0x006e +#define RT5682S_LPF_AD_DMIC 0x006f +/* Format - ADC/DAC */ +#define RT5682S_I2S1_SDP 0x0070 +#define RT5682S_I2S2_SDP 0x0071 +#define RT5682S_ADDA_CLK_1 0x0073 +#define RT5682S_ADDA_CLK_2 0x0074 +#define RT5682S_I2S1_F_DIV_CTRL_1 0x0075 +#define RT5682S_I2S1_F_DIV_CTRL_2 0x0076 +/* Format - TDM Control */ +#define RT5682S_TDM_CTRL 0x0079 +#define RT5682S_TDM_ADDA_CTRL_1 0x007a +#define RT5682S_TDM_ADDA_CTRL_2 0x007b +#define RT5682S_DATA_SEL_CTRL_1 0x007c +#define RT5682S_TDM_TCON_CTRL_1 0x007e +#define RT5682S_TDM_TCON_CTRL_2 0x007f +/* Function - Analog */ +#define RT5682S_GLB_CLK 0x0080 +#define RT5682S_PLL_TRACK_1 0x0083 +#define RT5682S_PLL_TRACK_2 0x0084 +#define RT5682S_PLL_TRACK_3 0x0085 +#define RT5682S_PLL_TRACK_4 0x0086 +#define RT5682S_PLL_TRACK_5 0x0087 +#define RT5682S_PLL_TRACK_6 0x0088 +#define RT5682S_PLL_TRACK_11 0x008c +#define RT5682S_DEPOP_1 0x008e +#define RT5682S_HP_CHARGE_PUMP_1 0x008f +#define RT5682S_HP_CHARGE_PUMP_2 0x0091 +#define RT5682S_HP_CHARGE_PUMP_3 0x0092 +#define RT5682S_MICBIAS_1 0x0093 +#define RT5682S_MICBIAS_2 0x0094 +#define RT5682S_MICBIAS_3 0x0095 + +#define RT5682S_PLL_TRACK_12 0x0096 +#define RT5682S_PLL_TRACK_14 0x0097 +#define RT5682S_PLL_CTRL_1 0x0098 +#define RT5682S_PLL_CTRL_2 0x0099 +#define RT5682S_PLL_CTRL_3 0x009a +#define RT5682S_PLL_CTRL_4 0x009b +#define RT5682S_PLL_CTRL_5 0x009c +#define RT5682S_PLL_CTRL_6 0x009d +#define RT5682S_PLL_CTRL_7 0x009e + +#define RT5682S_RC_CLK_CTRL 0x009f +#define RT5682S_I2S2_M_CLK_CTRL_1 0x00a0 +#define RT5682S_I2S2_F_DIV_CTRL_1 0x00a3 +#define RT5682S_I2S2_F_DIV_CTRL_2 0x00a4 + +#define RT5682S_IRQ_CTRL_1 0x00b6 +#define RT5682S_IRQ_CTRL_2 0x00b7 +#define RT5682S_IRQ_CTRL_3 0x00b8 +#define RT5682S_IRQ_CTRL_4 0x00b9 +#define RT5682S_INT_ST_1 0x00be +#define RT5682S_GPIO_CTRL_1 0x00c0 +#define RT5682S_GPIO_CTRL_2 0x00c1 +#define RT5682S_GPIO_ST 0x00c2 +#define RT5682S_HP_AMP_DET_CTRL_1 0x00d0 +#define RT5682S_MID_HP_AMP_DET 0x00d2 +#define RT5682S_LOW_HP_AMP_DET 0x00d3 +#define RT5682S_DELAY_BUF_CTRL 0x00d4 +#define RT5682S_SV_ZCD_1 0x00d9 +#define RT5682S_SV_ZCD_2 0x00da +#define RT5682S_IL_CMD_1 0x00db +#define RT5682S_IL_CMD_2 0x00dc +#define RT5682S_IL_CMD_3 0x00dd +#define RT5682S_IL_CMD_4 0x00de +#define RT5682S_IL_CMD_5 0x00df +#define RT5682S_IL_CMD_6 0x00e0 +#define RT5682S_4BTN_IL_CMD_1 0x00e2 +#define RT5682S_4BTN_IL_CMD_2 0x00e3 +#define RT5682S_4BTN_IL_CMD_3 0x00e4 +#define RT5682S_4BTN_IL_CMD_4 0x00e5 +#define RT5682S_4BTN_IL_CMD_5 0x00e6 +#define RT5682S_4BTN_IL_CMD_6 0x00e7 +#define RT5682S_4BTN_IL_CMD_7 0x00e8 + +#define RT5682S_ADC_STO1_HP_CTRL_1 0x00ea +#define RT5682S_ADC_STO1_HP_CTRL_2 0x00eb +#define RT5682S_AJD1_CTRL 0x00f0 +#define RT5682S_JD_CTRL_1 0x00f6 +/* General Control */ +#define RT5682S_DUMMY_1 0x00fa +#define RT5682S_DUMMY_2 0x00fb +#define RT5682S_DUMMY_3 0x00fc + +#define RT5682S_DAC_ADC_DIG_VOL1 0x0100 +#define RT5682S_BIAS_CUR_CTRL_2 0x010b +#define RT5682S_BIAS_CUR_CTRL_3 0x010c +#define RT5682S_BIAS_CUR_CTRL_4 0x010d +#define RT5682S_BIAS_CUR_CTRL_5 0x010e +#define RT5682S_BIAS_CUR_CTRL_6 0x010f +#define RT5682S_BIAS_CUR_CTRL_7 0x0110 +#define RT5682S_BIAS_CUR_CTRL_8 0x0111 +#define RT5682S_BIAS_CUR_CTRL_9 0x0112 +#define RT5682S_BIAS_CUR_CTRL_10 0x0113 +#define RT5682S_VREF_REC_OP_FB_CAP_CTRL_1 0x0117 +#define RT5682S_VREF_REC_OP_FB_CAP_CTRL_2 0x0118 +#define RT5682S_CHARGE_PUMP_1 0x0125 +#define RT5682S_DIG_IN_CTRL_1 0x0132 +#define RT5682S_PAD_DRIVING_CTRL 0x0136 +#define RT5682S_CHOP_DAC_1 0x0139 +#define RT5682S_CHOP_DAC_2 0x013a +#define RT5682S_CHOP_ADC 0x013b +#define RT5682S_CALIB_ADC_CTRL 0x013c +#define RT5682S_VOL_TEST 0x013f +#define RT5682S_SPKVDD_DET_ST 0x0142 +#define RT5682S_TEST_MODE_CTRL_1 0x0145 +#define RT5682S_TEST_MODE_CTRL_2 0x0146 +#define RT5682S_TEST_MODE_CTRL_3 0x0147 +#define RT5682S_TEST_MODE_CTRL_4 0x0148 +#define RT5682S_PLL_INTERNAL_1 0x0156 +#define RT5682S_PLL_INTERNAL_2 0x0157 +#define RT5682S_PLL_INTERNAL_3 0x0158 +#define RT5682S_PLL_INTERNAL_4 0x0159 +#define RT5682S_STO_NG2_CTRL_1 0x0160 +#define RT5682S_STO_NG2_CTRL_2 0x0161 +#define RT5682S_STO_NG2_CTRL_3 0x0162 +#define RT5682S_STO_NG2_CTRL_4 0x0163 +#define RT5682S_STO_NG2_CTRL_5 0x0164 +#define RT5682S_STO_NG2_CTRL_6 0x0165 +#define RT5682S_STO_NG2_CTRL_7 0x0166 +#define RT5682S_STO_NG2_CTRL_8 0x0167 +#define RT5682S_STO_NG2_CTRL_9 0x0168 +#define RT5682S_STO_NG2_CTRL_10 0x0169 +#define RT5682S_STO1_DAC_SIL_DET 0x0190 +#define RT5682S_SIL_PSV_CTRL1 0x0194 +#define RT5682S_SIL_PSV_CTRL2 0x0195 +#define RT5682S_SIL_PSV_CTRL3 0x0197 +#define RT5682S_SIL_PSV_CTRL4 0x0198 +#define RT5682S_SIL_PSV_CTRL5 0x0199 +#define RT5682S_HP_IMP_SENS_CTRL_1 0x01ac +#define RT5682S_HP_IMP_SENS_CTRL_2 0x01ad +#define RT5682S_HP_IMP_SENS_CTRL_3 0x01ae +#define RT5682S_HP_IMP_SENS_CTRL_4 0x01af +#define RT5682S_HP_IMP_SENS_CTRL_5 0x01b0 +#define RT5682S_HP_IMP_SENS_CTRL_6 0x01b1 +#define RT5682S_HP_IMP_SENS_CTRL_7 0x01b2 +#define RT5682S_HP_IMP_SENS_CTRL_8 0x01b3 +#define RT5682S_HP_IMP_SENS_CTRL_9 0x01b4 +#define RT5682S_HP_IMP_SENS_CTRL_10 0x01b5 +#define RT5682S_HP_IMP_SENS_CTRL_11 0x01b6 +#define RT5682S_HP_IMP_SENS_CTRL_12 0x01b7 +#define RT5682S_HP_IMP_SENS_CTRL_13 0x01b8 +#define RT5682S_HP_IMP_SENS_CTRL_14 0x01b9 +#define RT5682S_HP_IMP_SENS_CTRL_15 0x01ba +#define RT5682S_HP_IMP_SENS_CTRL_16 0x01bb +#define RT5682S_HP_IMP_SENS_CTRL_17 0x01bc +#define RT5682S_HP_IMP_SENS_CTRL_18 0x01bd +#define RT5682S_HP_IMP_SENS_CTRL_19 0x01be +#define RT5682S_HP_IMP_SENS_CTRL_20 0x01bf +#define RT5682S_HP_IMP_SENS_CTRL_21 0x01c0 +#define RT5682S_HP_IMP_SENS_CTRL_22 0x01c1 +#define RT5682S_HP_IMP_SENS_CTRL_23 0x01c2 +#define RT5682S_HP_IMP_SENS_CTRL_24 0x01c3 +#define RT5682S_HP_IMP_SENS_CTRL_25 0x01c4 +#define RT5682S_HP_IMP_SENS_CTRL_26 0x01c5 +#define RT5682S_HP_IMP_SENS_CTRL_27 0x01c6 +#define RT5682S_HP_IMP_SENS_CTRL_28 0x01c7 +#define RT5682S_HP_IMP_SENS_CTRL_29 0x01c8 +#define RT5682S_HP_IMP_SENS_CTRL_30 0x01c9 +#define RT5682S_HP_IMP_SENS_CTRL_31 0x01ca +#define RT5682S_HP_IMP_SENS_CTRL_32 0x01cb +#define RT5682S_HP_IMP_SENS_CTRL_33 0x01cc +#define RT5682S_HP_IMP_SENS_CTRL_34 0x01cd +#define RT5682S_HP_IMP_SENS_CTRL_35 0x01ce +#define RT5682S_HP_IMP_SENS_CTRL_36 0x01cf +#define RT5682S_HP_IMP_SENS_CTRL_37 0x01d0 +#define RT5682S_HP_IMP_SENS_CTRL_38 0x01d1 +#define RT5682S_HP_IMP_SENS_CTRL_39 0x01d2 +#define RT5682S_HP_IMP_SENS_CTRL_40 0x01d3 +#define RT5682S_HP_IMP_SENS_CTRL_41 0x01d4 +#define RT5682S_HP_IMP_SENS_CTRL_42 0x01d5 +#define RT5682S_HP_IMP_SENS_CTRL_43 0x01d6 +#define RT5682S_HP_IMP_SENS_CTRL_44 0x01d7 +#define RT5682S_HP_IMP_SENS_CTRL_45 0x01d8 +#define RT5682S_HP_IMP_SENS_CTRL_46 0x01d9 +#define RT5682S_HP_LOGIC_CTRL_1 0x01da +#define RT5682S_HP_LOGIC_CTRL_2 0x01db +#define RT5682S_HP_LOGIC_CTRL_3 0x01dc +#define RT5682S_HP_CALIB_CTRL_1 0x01de +#define RT5682S_HP_CALIB_CTRL_2 0x01df +#define RT5682S_HP_CALIB_CTRL_3 0x01e0 +#define RT5682S_HP_CALIB_CTRL_4 0x01e1 +#define RT5682S_HP_CALIB_CTRL_5 0x01e2 +#define RT5682S_HP_CALIB_CTRL_6 0x01e3 +#define RT5682S_HP_CALIB_CTRL_7 0x01e4 +#define RT5682S_HP_CALIB_CTRL_8 0x01e5 +#define RT5682S_HP_CALIB_CTRL_9 0x01e6 +#define RT5682S_HP_CALIB_CTRL_10 0x01e7 +#define RT5682S_HP_CALIB_CTRL_11 0x01e8 +#define RT5682S_HP_CALIB_ST_1 0x01ea +#define RT5682S_HP_CALIB_ST_2 0x01eb +#define RT5682S_HP_CALIB_ST_3 0x01ec +#define RT5682S_HP_CALIB_ST_4 0x01ed +#define RT5682S_HP_CALIB_ST_5 0x01ee +#define RT5682S_HP_CALIB_ST_6 0x01ef +#define RT5682S_HP_CALIB_ST_7 0x01f0 +#define RT5682S_HP_CALIB_ST_8 0x01f1 +#define RT5682S_HP_CALIB_ST_9 0x01f2 +#define RT5682S_HP_CALIB_ST_10 0x01f3 +#define RT5682S_HP_CALIB_ST_11 0x01f4 +#define RT5682S_SAR_IL_CMD_1 0x0210 +#define RT5682S_SAR_IL_CMD_2 0x0211 +#define RT5682S_SAR_IL_CMD_3 0x0212 +#define RT5682S_SAR_IL_CMD_4 0x0213 +#define RT5682S_SAR_IL_CMD_5 0x0214 +#define RT5682S_SAR_IL_CMD_6 0x0215 +#define RT5682S_SAR_IL_CMD_7 0x0216 +#define RT5682S_SAR_IL_CMD_8 0x0217 +#define RT5682S_SAR_IL_CMD_9 0x0218 +#define RT5682S_SAR_IL_CMD_10 0x0219 +#define RT5682S_SAR_IL_CMD_11 0x021a +#define RT5682S_SAR_IL_CMD_12 0x021b +#define RT5682S_SAR_IL_CMD_13 0x021c +#define RT5682S_SAR_IL_CMD_14 0x021d +#define RT5682S_DUMMY_4 0x02fa +#define RT5682S_DUMMY_5 0x02fb +#define RT5682S_DUMMY_6 0x02fc +#define RT5682S_VERSION_ID_HIDE 0x03fe +#define RT5682S_VERSION_ID_CUS 0x03ff +#define RT5682S_SCAN_CTL 0x0500 +#define RT5682S_HP_AMP_DET 0x0600 +#define RT5682S_BIAS_CUR_CTRL_11 0x0610 +#define RT5682S_BIAS_CUR_CTRL_12 0x0611 +#define RT5682S_BIAS_CUR_CTRL_13 0x0620 +#define RT5682S_BIAS_CUR_CTRL_14 0x0621 +#define RT5682S_BIAS_CUR_CTRL_15 0x0630 +#define RT5682S_BIAS_CUR_CTRL_16 0x0631 +#define RT5682S_BIAS_CUR_CTRL_17 0x0640 +#define RT5682S_BIAS_CUR_CTRL_18 0x0641 +#define RT5682S_I2C_TRANS_CTRL 0x07fa +#define RT5682S_DUMMY_7 0x08fa +#define RT5682S_DUMMY_8 0x08fb +#define RT5682S_DMIC_FLOAT_DET 0x0d00 +#define RT5682S_HA_CMP_OP_1 0x1100 +#define RT5682S_HA_CMP_OP_2 0x1101 +#define RT5682S_HA_CMP_OP_3 0x1102 +#define RT5682S_HA_CMP_OP_4 0x1103 +#define RT5682S_HA_CMP_OP_5 0x1104 +#define RT5682S_HA_CMP_OP_6 0x1105 +#define RT5682S_HA_CMP_OP_7 0x1106 +#define RT5682S_HA_CMP_OP_8 0x1107 +#define RT5682S_HA_CMP_OP_9 0x1108 +#define RT5682S_HA_CMP_OP_10 0x1109 +#define RT5682S_HA_CMP_OP_11 0x110a +#define RT5682S_HA_CMP_OP_12 0x110b +#define RT5682S_HA_CMP_OP_13 0x110c +#define RT5682S_HA_CMP_OP_14 0x1111 +#define RT5682S_HA_CMP_OP_15 0x1112 +#define RT5682S_HA_CMP_OP_16 0x1113 +#define RT5682S_HA_CMP_OP_17 0x1114 +#define RT5682S_HA_CMP_OP_18 0x1115 +#define RT5682S_HA_CMP_OP_19 0x1116 +#define RT5682S_HA_CMP_OP_20 0x1117 +#define RT5682S_HA_CMP_OP_21 0x1118 +#define RT5682S_HA_CMP_OP_22 0x1119 +#define RT5682S_HA_CMP_OP_23 0x111a +#define RT5682S_HA_CMP_OP_24 0x111b +#define RT5682S_HA_CMP_OP_25 0x111c +#define RT5682S_NEW_CBJ_DET_CTL_1 0x1401 +#define RT5682S_NEW_CBJ_DET_CTL_2 0x1402 +#define RT5682S_NEW_CBJ_DET_CTL_3 0x1403 +#define RT5682S_NEW_CBJ_DET_CTL_4 0x1404 +#define RT5682S_NEW_CBJ_DET_CTL_5 0x1406 +#define RT5682S_NEW_CBJ_DET_CTL_6 0x1407 +#define RT5682S_NEW_CBJ_DET_CTL_7 0x1408 +#define RT5682S_NEW_CBJ_DET_CTL_8 0x1409 +#define RT5682S_NEW_CBJ_DET_CTL_9 0x140a +#define RT5682S_NEW_CBJ_DET_CTL_10 0x140b +#define RT5682S_NEW_CBJ_DET_CTL_11 0x140c +#define RT5682S_NEW_CBJ_DET_CTL_12 0x140d +#define RT5682S_NEW_CBJ_DET_CTL_13 0x140e +#define RT5682S_NEW_CBJ_DET_CTL_14 0x140f +#define RT5682S_NEW_CBJ_DET_CTL_15 0x1410 +#define RT5682S_NEW_CBJ_DET_CTL_16 0x1411 +#define RT5682S_DA_FILTER_1 0x1801 +#define RT5682S_DA_FILTER_2 0x1802 +#define RT5682S_DA_FILTER_3 0x1803 +#define RT5682S_DA_FILTER_4 0x1804 +#define RT5682S_DA_FILTER_5 0x1805 +#define RT5682S_CLK_SW_TEST_1 0x2c00 +#define RT5682S_CLK_SW_TEST_2 0x3400 +#define RT5682S_CLK_SW_TEST_3 0x3404 +#define RT5682S_CLK_SW_TEST_4 0x3405 +#define RT5682S_CLK_SW_TEST_5 0x3406 +#define RT5682S_CLK_SW_TEST_6 0x3407 +#define RT5682S_CLK_SW_TEST_7 0x3408 +#define RT5682S_CLK_SW_TEST_8 0x3409 +#define RT5682S_CLK_SW_TEST_9 0x340a +#define RT5682S_CLK_SW_TEST_10 0x340b +#define RT5682S_CLK_SW_TEST_11 0x340c +#define RT5682S_CLK_SW_TEST_12 0x340d +#define RT5682S_CLK_SW_TEST_13 0x340e +#define RT5682S_CLK_SW_TEST_14 0x340f +#define RT5682S_EFUSE_MANU_WRITE_1 0x3410 +#define RT5682S_EFUSE_MANU_WRITE_2 0x3411 +#define RT5682S_EFUSE_MANU_WRITE_3 0x3412 +#define RT5682S_EFUSE_MANU_WRITE_4 0x3413 +#define RT5682S_EFUSE_MANU_WRITE_5 0x3414 +#define RT5682S_EFUSE_MANU_WRITE_6 0x3415 +#define RT5682S_EFUSE_READ_1 0x3424 +#define RT5682S_EFUSE_READ_2 0x3425 +#define RT5682S_EFUSE_READ_3 0x3426 +#define RT5682S_EFUSE_READ_4 0x3427 +#define RT5682S_EFUSE_READ_5 0x3428 +#define RT5682S_EFUSE_READ_6 0x3429 +#define RT5682S_EFUSE_READ_7 0x342a +#define RT5682S_EFUSE_READ_8 0x342b +#define RT5682S_EFUSE_READ_9 0x342c +#define RT5682S_EFUSE_READ_10 0x342d +#define RT5682S_EFUSE_READ_11 0x342e +#define RT5682S_EFUSE_READ_12 0x342f +#define RT5682S_EFUSE_READ_13 0x3430 +#define RT5682S_EFUSE_READ_14 0x3431 +#define RT5682S_EFUSE_READ_15 0x3432 +#define RT5682S_EFUSE_READ_16 0x3433 +#define RT5682S_EFUSE_READ_17 0x3434 +#define RT5682S_EFUSE_READ_18 0x3435 +#define RT5682S_EFUSE_TIMING_CTL_1 0x3440 +#define RT5682S_EFUSE_TIMING_CTL_2 0x3441 +#define RT5682S_PILOT_DIG_CTL_1 0x3500 +#define RT5682S_PILOT_DIG_CTL_2 0x3501 +#define RT5682S_HP_AMP_DET_CTL_1 0x3b00 +#define RT5682S_HP_AMP_DET_CTL_2 0x3b01 +#define RT5682S_HP_AMP_DET_CTL_3 0x3b02 +#define RT5682S_HP_AMP_DET_CTL_4 0x3b03 + +#define RT5682S_MAX_REG (RT5682S_HP_AMP_DET_CTL_4) + +/* global definition */ +#define RT5682S_L_MUTE (0x1 << 15) +#define RT5682S_L_MUTE_SFT 15 +#define RT5682S_R_MUTE (0x1 << 7) +#define RT5682S_R_MUTE_SFT 7 +#define RT5682S_L_VOL_SFT 8 +#define RT5682S_R_VOL_SFT 0 +#define RT5682S_CLK_SRC_MCLK (0x0) +#define RT5682S_CLK_SRC_PLL1 (0x1) +#define RT5682S_CLK_SRC_PLL2 (0x2) +#define RT5682S_CLK_SRC_RCCLK (0x4) /* 25M */ + + +/* Headphone Amp Control 2 (0x0003) */ +#define RT5682S_HPO_L_PATH_MASK (0x1 << 14) +#define RT5682S_HPO_L_PATH_EN (0x1 << 14) +#define RT5682S_HPO_L_PATH_DIS (0x0 << 14) +#define RT5682S_HPO_R_PATH_MASK (0x1 << 13) +#define RT5682S_HPO_R_PATH_EN (0x1 << 13) +#define RT5682S_HPO_R_PATH_DIS (0x0 << 13) +#define RT5682S_HPO_SEL_IP_EN_SW (0x1) +#define RT5682S_HPO_IP_EN_GATING (0x1) +#define RT5682S_HPO_IP_NO_GATING (0x0) + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5682S_G_HP (0xf << 8) +#define RT5682S_G_HP_SFT 8 +#define RT5682S_G_STO_DA_DMIX (0xf) +#define RT5682S_G_STO_DA_SFT 0 + +/* Embeeded Jack and Type Detection Control 2 (0x0010) */ +#define RT5682S_EMB_JD_MASK (0x1 << 15) +#define RT5682S_EMB_JD_EN (0x1 << 15) +#define RT5682S_EMB_JD_EN_SFT 15 +#define RT5682S_EMB_JD_RST (0x1 << 14) +#define RT5682S_JD_MODE (0x1 << 13) +#define RT5682S_JD_MODE_SFT 13 +#define RT5682S_DET_TYPE (0x1 << 12) +#define RT5682S_DET_TYPE_SFT 12 +#define RT5682S_POLA_EXT_JD_MASK (0x1 << 11) +#define RT5682S_POLA_EXT_JD_LOW (0x1 << 11) +#define RT5682S_POLA_EXT_JD_HIGH (0x0 << 11) +#define RT5682S_SEL_FAST_OFF_MASK (0x3 << 9) +#define RT5682S_SEL_FAST_OFF_SFT 9 +#define RT5682S_POL_FAST_OFF_MASK (0x1 << 8) +#define RT5682S_POL_FAST_OFF_HIGH (0x1 << 8) +#define RT5682S_POL_FAST_OFF_LOW (0x0 << 8) +#define RT5682S_FAST_OFF_MASK (0x1 << 7) +#define RT5682S_FAST_OFF_EN (0x1 << 7) +#define RT5682S_FAST_OFF_DIS (0x0 << 7) +#define RT5682S_VREF_POW_MASK (0x1 << 6) +#define RT5682S_VREF_POW_FSM (0x0 << 6) +#define RT5682S_VREF_POW_REG (0x1 << 6) +#define RT5682S_MB1_PATH_BIT 5 +#define RT5682S_MB1_PATH_MASK (0x1 << 5) +#define RT5682S_CTRL_MB1_REG (0x1 << 5) +#define RT5682S_CTRL_MB1_FSM (0x0 << 5) +#define RT5682S_MB2_PATH_BIT 4 +#define RT5682S_MB2_PATH_MASK (0x1 << 4) +#define RT5682S_CTRL_MB2_REG (0x1 << 4) +#define RT5682S_CTRL_MB2_FSM (0x0 << 4) +#define RT5682S_TRIG_JD_MASK (0x1 << 3) +#define RT5682S_TRIG_JD_HIGH (0x1 << 3) +#define RT5682S_TRIG_JD_LOW (0x0 << 3) +#define RT5682S_MIC_CAP_MASK (0x1 << 1) +#define RT5682S_MIC_CAP_HS (0x1 << 1) +#define RT5682S_MIC_CAP_HP (0x0 << 1) +#define RT5682S_MIC_CAP_SRC_MASK (0x1) +#define RT5682S_MIC_CAP_SRC_REG (0x1) +#define RT5682S_MIC_CAP_SRC_ANA (0x0) + +/* Embeeded Jack and Type Detection Control 3 (0x0011) */ +#define RT5682S_SEL_CBJ_TYPE_SLOW (0x1 << 15) +#define RT5682S_SEL_CBJ_TYPE_NORM (0x0 << 15) +#define RT5682S_SEL_CBJ_TYPE_MASK (0x1 << 15) +#define RT5682S_POW_BG_MB1_MASK (0x1 << 13) +#define RT5682S_POW_BG_MB1_REG (0x1 << 13) +#define RT5682S_POW_BG_MB1_FSM (0x0 << 13) +#define RT5682S_POW_BG_MB2_MASK (0x1 << 12) +#define RT5682S_POW_BG_MB2_REG (0x1 << 12) +#define RT5682S_POW_BG_MB2_FSM (0x0 << 12) +#define RT5682S_EXT_JD_SRC (0x7 << 4) +#define RT5682S_EXT_JD_SRC_SFT 4 +#define RT5682S_EXT_JD_SRC_GPIO_JD1 (0x0 << 4) +#define RT5682S_EXT_JD_SRC_GPIO_JD2 (0x1 << 4) +#define RT5682S_EXT_JD_SRC_JDH (0x2 << 4) +#define RT5682S_EXT_JD_SRC_JDL (0x3 << 4) +#define RT5682S_EXT_JD_SRC_MANUAL (0x4 << 4) +#define RT5682S_JACK_TYPE_MASK (0x3) + +/* Combo Jack and Type Detection Control 4 (0x0012) */ +#define RT5682S_CBJ_IN_BUF_MASK (0x1 << 7) +#define RT5682S_CBJ_IN_BUF_EN (0x1 << 7) +#define RT5682S_CBJ_IN_BUF_DIS (0x0 << 7) +#define RT5682S_CBJ_IN_BUF_BIT 7 + +/* Combo Jack and Type Detection Control 5 (0x0013) */ +#define RT5682S_SEL_SHT_MID_TON_MASK (0x3 << 12) +#define RT5682S_SEL_SHT_MID_TON_2 (0x0 << 12) +#define RT5682S_SEL_SHT_MID_TON_3 (0x1 << 12) +#define RT5682S_CBJ_JD_TEST_MASK (0x1 << 6) +#define RT5682S_CBJ_JD_TEST_NORM (0x0 << 6) +#define RT5682S_CBJ_JD_TEST_MODE (0x1 << 6) + +/* Combo Jack and Type Detection Control 6 (0x0014) */ +#define RT5682S_JD_FAST_OFF_SRC_MASK (0x7 << 8) +#define RT5682S_JD_FAST_OFF_SRC_JDH (0x6 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO6 (0x5 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO5 (0x4 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO4 (0x3 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO3 (0x2 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO2 (0x1 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO1 (0x0 << 8) + +/* DAC1 Digital Volume (0x0019) */ +#define RT5682S_DAC_L1_VOL_MASK (0xff << 8) +#define RT5682S_DAC_L1_VOL_SFT 8 +#define RT5682S_DAC_R1_VOL_MASK (0xff) +#define RT5682S_DAC_R1_VOL_SFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5682S_ADC_L_VOL_MASK (0x7f << 8) +#define RT5682S_ADC_L_VOL_SFT 8 +#define RT5682S_ADC_R_VOL_MASK (0x7f) +#define RT5682S_ADC_R_VOL_SFT 0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5682S_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5682S_STO1_ADC_L_BST_SFT 14 +#define RT5682S_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5682S_STO1_ADC_R_BST_SFT 12 + +/* Sidetone Control (0x0024) */ +#define RT5682S_ST_SRC_SEL (0x1 << 8) +#define RT5682S_ST_SRC_SFT 8 +#define RT5682S_ST_EN_MASK (0x1 << 6) +#define RT5682S_ST_DIS (0x0 << 6) +#define RT5682S_ST_EN (0x1 << 6) +#define RT5682S_ST_EN_SFT 6 + +/* Stereo1 ADC Mixer Control (0x0026) */ +#define RT5682S_M_STO1_ADC_L1 (0x1 << 15) +#define RT5682S_M_STO1_ADC_L1_SFT 15 +#define RT5682S_M_STO1_ADC_L2 (0x1 << 14) +#define RT5682S_M_STO1_ADC_L2_SFT 14 +#define RT5682S_STO1_ADC1L_SRC_MASK (0x1 << 13) +#define RT5682S_STO1_ADC1L_SRC_SFT 13 +#define RT5682S_STO1_ADC1_SRC_ADC (0x1 << 13) +#define RT5682S_STO1_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5682S_STO1_ADC2L_SRC_MASK (0x1 << 12) +#define RT5682S_STO1_ADC2L_SRC_SFT 12 +#define RT5682S_STO1_ADCL_SRC_MASK (0x3 << 10) +#define RT5682S_STO1_ADCL_SRC_SFT 10 +#define RT5682S_M_STO1_ADC_R1 (0x1 << 7) +#define RT5682S_M_STO1_ADC_R1_SFT 7 +#define RT5682S_M_STO1_ADC_R2 (0x1 << 6) +#define RT5682S_M_STO1_ADC_R2_SFT 6 +#define RT5682S_STO1_ADC1R_SRC_MASK (0x1 << 5) +#define RT5682S_STO1_ADC1R_SRC_SFT 5 +#define RT5682S_STO1_ADC2R_SRC_MASK (0x1 << 4) +#define RT5682S_STO1_ADC2R_SRC_SFT 4 +#define RT5682S_STO1_ADCR_SRC_MASK (0x3 << 2) +#define RT5682S_STO1_ADCR_SRC_SFT 2 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5682S_M_ADCMIX_L (0x1 << 15) +#define RT5682S_M_ADCMIX_L_SFT 15 +#define RT5682S_M_DAC1_L (0x1 << 14) +#define RT5682S_M_DAC1_L_SFT 14 +#define RT5682S_M_ADCMIX_R (0x1 << 7) +#define RT5682S_M_ADCMIX_R_SFT 7 +#define RT5682S_M_DAC1_R (0x1 << 6) +#define RT5682S_M_DAC1_R_SFT 6 + +/* Stereo1 DAC Mixer Control (0x002a) */ +#define RT5682S_M_DAC_L1_STO_L (0x1 << 15) +#define RT5682S_M_DAC_L1_STO_L_SFT 15 +#define RT5682S_G_DAC_L1_STO_L_MASK (0x1 << 14) +#define RT5682S_G_DAC_L1_STO_L_SFT 14 +#define RT5682S_M_DAC_R1_STO_L (0x1 << 13) +#define RT5682S_M_DAC_R1_STO_L_SFT 13 +#define RT5682S_G_DAC_R1_STO_L_MASK (0x1 << 12) +#define RT5682S_G_DAC_R1_STO_L_SFT 12 +#define RT5682S_M_DAC_L1_STO_R (0x1 << 7) +#define RT5682S_M_DAC_L1_STO_R_SFT 7 +#define RT5682S_G_DAC_L1_STO_R_MASK (0x1 << 6) +#define RT5682S_G_DAC_L1_STO_R_SFT 6 +#define RT5682S_M_DAC_R1_STO_R (0x1 << 5) +#define RT5682S_M_DAC_R1_STO_R_SFT 5 +#define RT5682S_G_DAC_R1_STO_R_MASK (0x1 << 4) +#define RT5682S_G_DAC_R1_STO_R_SFT 4 + +/* Analog DAC1 Input Source Control (0x002b) */ +#define RT5682S_M_ST_STO_L (0x1 << 9) +#define RT5682S_M_ST_STO_L_SFT 9 +#define RT5682S_M_ST_STO_R (0x1 << 8) +#define RT5682S_M_ST_STO_R_SFT 8 +#define RT5682S_DAC_L1_SRC_MASK (0x1 << 4) +#define RT5682S_A_DACL1_SFT 4 +#define RT5682S_DAC_R1_SRC_MASK (0x1) +#define RT5682S_A_DACR1_SFT 0 + +/* Digital Interface Data Control (0x0030) */ +#define RT5682S_IF2_DAC_SEL_MASK (0x3 << 2) +#define RT5682S_IF2_DAC_SEL_SFT 2 +#define RT5682S_IF2_ADC_SEL_MASK (0x3 << 0) +#define RT5682S_IF2_ADC_SEL_SFT 0 + +/* REC Left/Right Mixer Control 2 (0x003c) */ +#define RT5682S_BST_CBJ_MASK (0x3f << 8) +#define RT5682S_BST_CBJ_SFT 8 +#define RT5682S_M_CBJ_RM1_L (0x1 << 7) +#define RT5682S_M_CBJ_RM1_L_SFT 7 +#define RT5682S_M_CBJ_RM1_R (0x1 << 6) +#define RT5682S_M_CBJ_RM1_R_SFT 6 + +/* REC Left/Right Mixer Calibration Control(0x0044) */ +#define RT5682S_PWR_RM1_R_BIT 8 +#define RT5682S_PWR_RM1_L_BIT 0 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5682S_PWR_I2S1 (0x1 << 15) +#define RT5682S_PWR_I2S1_BIT 15 +#define RT5682S_PWR_I2S2 (0x1 << 14) +#define RT5682S_PWR_I2S2_BIT 14 +#define RT5682S_PRE_CHR_DAC_L1 (0x1 << 13) +#define RT5682S_PRE_CHR_DAC_L1_BIT 13 +#define RT5682S_PRE_CHR_DAC_R1 (0x1 << 12) +#define RT5682S_PRE_CHR_DAC_R1_BIT 12 +#define RT5682S_PWR_DAC_L1 (0x1 << 11) +#define RT5682S_PWR_DAC_L1_BIT 11 +#define RT5682S_PWR_DAC_R1 (0x1 << 10) +#define RT5682S_PWR_DAC_R1_BIT 10 +#define RT5682S_PWR_LDO (0x1 << 8) +#define RT5682S_PWR_LDO_BIT 8 +#define RT5682S_PWR_D2S_L (0x1 << 7) +#define RT5682S_PWR_D2S_L_BIT 7 +#define RT5682S_PWR_D2S_R (0x1 << 6) +#define RT5682S_PWR_D2S_R_BIT 6 +#define RT5682S_PWR_ADC_L1 (0x1 << 4) +#define RT5682S_PWR_ADC_L1_BIT 4 +#define RT5682S_PWR_ADC_R1 (0x1 << 3) +#define RT5682S_PWR_ADC_R1_BIT 3 +#define RT5682S_EFUSE_SW_EN (0x1 << 2) +#define RT5682S_EFUSE_SW_DIS (0x0 << 2) +#define RT5682S_PWR_EFUSE (0x1 << 1) +#define RT5682S_PWR_EFUSE_BIT 1 +#define RT5682S_DIG_GATE_CTRL (0x1 << 0) +#define RT5682S_DIG_GATE_CTRL_SFT 0 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5682S_PWR_ADC_S1F (0x1 << 15) +#define RT5682S_PWR_ADC_S1F_BIT 15 +#define RT5682S_PWR_DAC_S1F (0x1 << 10) +#define RT5682S_PWR_DAC_S1F_BIT 10 +#define RT5682S_DLDO_I_LIMIT_MASK (0x1 << 7) +#define RT5682S_DLDO_I_LIMIT_EN (0x1 << 7) +#define RT5682S_DLDO_I_LIMIT_DIS (0x0 << 7) +#define RT5682S_DLDO_I_BIAS_SEL_4 (0x1 << 6) +#define RT5682S_DLDO_I_BIAS_SEL_0 (0x0 << 6) +#define RT5682S_DLDO_REG_TEST_1 (0x1 << 5) +#define RT5682S_DLDO_REG_TEST_0 (0x0 << 5) +#define RT5682S_DLDO_SRC_REG (0x1 << 4) +#define RT5682S_DLDO_SRC_EFUSE (0x0 << 4) + +/* Power Management for Analog 1 (0x0063) */ +#define RT5682S_PWR_VREF1 (0x1 << 15) +#define RT5682S_PWR_VREF1_BIT 15 +#define RT5682S_PWR_FV1 (0x1 << 14) +#define RT5682S_PWR_FV1_BIT 14 +#define RT5682S_PWR_VREF2 (0x1 << 13) +#define RT5682S_PWR_VREF2_BIT 13 +#define RT5682S_PWR_FV2 (0x1 << 12) +#define RT5682S_PWR_FV2_BIT 12 +#define RT5682S_LDO1_DBG_MASK (0x3 << 10) +#define RT5682S_PWR_MB (0x1 << 9) +#define RT5682S_PWR_MB_BIT 9 +#define RT5682S_PWR_BG (0x1 << 7) +#define RT5682S_PWR_BG_BIT 7 +#define RT5682S_LDO1_BYPASS_MASK (0x1 << 6) +#define RT5682S_LDO1_BYPASS (0x1 << 6) +#define RT5682S_LDO1_NOT_BYPASS (0x0 << 6) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5682S_PWR_MCLK0_WD (0x1 << 15) +#define RT5682S_PWR_MCLK0_WD_BIT 15 +#define RT5682S_PWR_MCLK1_WD (0x1 << 14) +#define RT5682S_PWR_MCLK1_WD_BIT 14 +#define RT5682S_RST_MCLK0 (0x1 << 13) +#define RT5682S_RST_MCLK0_BIT 13 +#define RT5682S_RST_MCLK1 (0x1 << 12) +#define RT5682S_RST_MCLK1_BIT 12 +#define RT5682S_PWR_MB1 (0x1 << 11) +#define RT5682S_PWR_MB1_PWR_DOWN (0x0 << 11) +#define RT5682S_PWR_MB1_BIT 11 +#define RT5682S_PWR_MB2 (0x1 << 10) +#define RT5682S_PWR_MB2_PWR_DOWN (0x0 << 10) +#define RT5682S_PWR_MB2_BIT 10 +#define RT5682S_PWR_JD_MASK (0x1 << 0) +#define RT5682S_PWR_JD_ENABLE (0x1 << 0) +#define RT5682S_PWR_JD_DISABLE (0x0 << 0) + +/* Power Management for Analog 3 (0x0065) */ +#define RT5682S_PWR_LDO_PLLA (0x1 << 15) +#define RT5682S_PWR_LDO_PLLA_BIT 15 +#define RT5682S_PWR_LDO_PLLB (0x1 << 14) +#define RT5682S_PWR_LDO_PLLB_BIT 14 +#define RT5682S_PWR_BIAS_PLLA (0x1 << 13) +#define RT5682S_PWR_BIAS_PLLA_BIT 13 +#define RT5682S_PWR_BIAS_PLLB (0x1 << 12) +#define RT5682S_PWR_BIAS_PLLB_BIT 12 +#define RT5682S_PWR_CBJ (0x1 << 9) +#define RT5682S_PWR_CBJ_BIT 9 +#define RT5682S_RSTB_PLLB (0x1 << 7) +#define RT5682S_RSTB_PLLB_BIT 7 +#define RT5682S_RSTB_PLLA (0x1 << 6) +#define RT5682S_RSTB_PLLA_BIT 6 +#define RT5682S_PWR_PLLB (0x1 << 5) +#define RT5682S_PWR_PLLB_BIT 5 +#define RT5682S_PWR_PLLA (0x1 << 4) +#define RT5682S_PWR_PLLA_BIT 4 +#define RT5682S_PWR_LDO_MB2 (0x1 << 2) +#define RT5682S_PWR_LDO_MB2_BIT 2 +#define RT5682S_PWR_LDO_MB1 (0x1 << 1) +#define RT5682S_PWR_LDO_MB1_BIT 1 +#define RT5682S_PWR_BGLDO (0x1 << 0) +#define RT5682S_PWR_BGLDO_BIT 0 + +/* Power Management for Mixer (0x0066) */ +#define RT5682S_PWR_CLK_COMP_8FS (0x1 << 15) +#define RT5682S_PWR_CLK_COMP_8FS_BIT 15 +#define RT5682S_DBG_BGLDO_MASK (0x3 << 12) +#define RT5682S_DBG_BGLDO_SFT 12 +#define RT5682S_DBG_BGLDO_MB1_MASK (0x3 << 10) +#define RT5682S_DBG_BGLDO_MB1_SFT 10 +#define RT5682S_DBG_BGLDO_MB2_MASK (0x3 << 8) +#define RT5682S_DBG_BGLDO_MB2_SFT 8 +#define RT5682S_DLDO_BGLDO_MASK (0x3 << 6) +#define RT5682S_DLDO_BGLDO_MB2_SFT 6 +#define RT5682S_PWR_STO1_DAC_L (0x1 << 5) +#define RT5682S_PWR_STO1_DAC_L_BIT 5 +#define RT5682S_PWR_STO1_DAC_R (0x1 << 4) +#define RT5682S_PWR_STO1_DAC_R_BIT 4 +#define RT5682S_DVO_BGLDO_MB1_MASK (0x3 << 2) +#define RT5682S_DVO_BGLDO_MB1_SFT 2 +#define RT5682S_DVO_BGLDO_MB2_MASK (0x3 << 0) + +/* MCLK and System Clock Detection Control (0x006b) */ +#define RT5682S_SYS_CLK_DET (0x1 << 15) +#define RT5682S_SYS_CLK_DET_SFT 15 +#define RT5682S_PLL1_CLK_DET (0x1 << 14) +#define RT5682S_PLL1_CLK_DET_SFT 14 + +/* Digital Microphone Control 1 (0x006e) */ +#define RT5682S_DMIC_1_EN_MASK (0x1 << 15) +#define RT5682S_DMIC_1_EN_SFT 15 +#define RT5682S_DMIC_1_DIS (0x0 << 15) +#define RT5682S_DMIC_1_EN (0x1 << 15) +#define RT5682S_FIFO_CLK_DIV_MASK (0x7 << 12) +#define RT5682S_FIFO_CLK_DIV_2 (0x1 << 12) +#define RT5682S_DMIC_1_DP_MASK (0x3 << 4) +#define RT5682S_DMIC_1_DP_SFT 4 +#define RT5682S_DMIC_1_DP_GPIO2 (0x0 << 4) +#define RT5682S_DMIC_1_DP_GPIO5 (0x1 << 4) +#define RT5682S_DMIC_CLK_MASK (0xf << 0) +#define RT5682S_DMIC_CLK_SFT 0 + +/* I2S1 Audio Serial Data Port Control (0x0070) */ +#define RT5682S_SEL_ADCDAT_MASK (0x1 << 15) +#define RT5682S_SEL_ADCDAT_OUT (0x0 << 15) +#define RT5682S_SEL_ADCDAT_IN (0x1 << 15) +#define RT5682S_SEL_ADCDAT_SFT 15 +#define RT5682S_I2S1_TX_CHL_MASK (0x7 << 12) +#define RT5682S_I2S1_TX_CHL_SFT 12 +#define RT5682S_I2S1_TX_CHL_16 (0x0 << 12) +#define RT5682S_I2S1_TX_CHL_20 (0x1 << 12) +#define RT5682S_I2S1_TX_CHL_24 (0x2 << 12) +#define RT5682S_I2S1_TX_CHL_32 (0x3 << 12) +#define RT5682S_I2S1_TX_CHL_8 (0x4 << 12) +#define RT5682S_I2S1_RX_CHL_MASK (0x7 << 8) +#define RT5682S_I2S1_RX_CHL_SFT 8 +#define RT5682S_I2S1_RX_CHL_16 (0x0 << 8) +#define RT5682S_I2S1_RX_CHL_20 (0x1 << 8) +#define RT5682S_I2S1_RX_CHL_24 (0x2 << 8) +#define RT5682S_I2S1_RX_CHL_32 (0x3 << 8) +#define RT5682S_I2S1_RX_CHL_8 (0x4 << 8) +#define RT5682S_I2S1_MONO_MASK (0x1 << 7) +#define RT5682S_I2S1_MONO_EN (0x1 << 7) +#define RT5682S_I2S1_MONO_DIS (0x0 << 7) +#define RT5682S_I2S1_DL_MASK (0x7 << 4) +#define RT5682S_I2S1_DL_SFT 4 +#define RT5682S_I2S1_DL_16 (0x0 << 4) +#define RT5682S_I2S1_DL_20 (0x1 << 4) +#define RT5682S_I2S1_DL_24 (0x2 << 4) +#define RT5682S_I2S1_DL_32 (0x3 << 4) +#define RT5682S_I2S1_DL_8 (0x4 << 4) + +/* I2S1/2 Audio Serial Data Port Control (0x0071) */ +#define RT5682S_I2S2_MS_MASK (0x1 << 15) +#define RT5682S_I2S2_MS_SFT 15 +#define RT5682S_I2S2_MS_M (0x0 << 15) +#define RT5682S_I2S2_MS_S (0x1 << 15) +#define RT5682S_I2S2_PIN_CFG_MASK (0x1 << 14) +#define RT5682S_I2S2_PIN_CFG_SFT 14 +#define RT5682S_I2S2_OUT_MASK (0x1 << 9) +#define RT5682S_I2S2_OUT_SFT 9 +#define RT5682S_I2S2_OUT_UM (0x0 << 9) +#define RT5682S_I2S2_OUT_M (0x1 << 9) +#define RT5682S_I2S_BP_MASK (0x1 << 8) +#define RT5682S_I2S_BP_SFT 8 +#define RT5682S_I2S_BP_NOR (0x0 << 8) +#define RT5682S_I2S_BP_INV (0x1 << 8) +#define RT5682S_I2S2_MONO_MASK (0x1 << 7) +#define RT5682S_I2S2_MONO_EN (0x1 << 7) +#define RT5682S_I2S2_MONO_DIS (0x0 << 7) +#define RT5682S_I2S2_DL_MASK (0x7 << 4) +#define RT5682S_I2S2_DL_SFT 4 +#define RT5682S_I2S2_DL_8 (0x0 << 4) +#define RT5682S_I2S2_DL_16 (0x1 << 4) +#define RT5682S_I2S2_DL_20 (0x2 << 4) +#define RT5682S_I2S2_DL_24 (0x3 << 4) +#define RT5682S_I2S2_DL_32 (0x4 << 4) +#define RT5682S_I2S_DF_MASK (0x7) +#define RT5682S_I2S_DF_SFT 0 +#define RT5682S_I2S_DF_I2S (0x0) +#define RT5682S_I2S_DF_LEFT (0x1) +#define RT5682S_I2S_DF_PCM_A (0x2) +#define RT5682S_I2S_DF_PCM_B (0x3) +#define RT5682S_I2S_DF_PCM_A_N (0x6) +#define RT5682S_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5682S_ADC_OSR_MASK (0xf << 12) +#define RT5682S_ADC_OSR_SFT 12 +#define RT5682S_ADC_OSR_D_1 (0x0 << 12) +#define RT5682S_ADC_OSR_D_2 (0x1 << 12) +#define RT5682S_ADC_OSR_D_4 (0x2 << 12) +#define RT5682S_ADC_OSR_D_6 (0x3 << 12) +#define RT5682S_ADC_OSR_D_8 (0x4 << 12) +#define RT5682S_ADC_OSR_D_12 (0x5 << 12) +#define RT5682S_ADC_OSR_D_16 (0x6 << 12) +#define RT5682S_ADC_OSR_D_24 (0x7 << 12) +#define RT5682S_ADC_OSR_D_32 (0x8 << 12) +#define RT5682S_ADC_OSR_D_48 (0x9 << 12) +#define RT5682S_I2S_M_D_MASK (0xf << 8) +#define RT5682S_I2S_M_D_SFT 8 +#define RT5682S_I2S_M_D_1 (0x0 << 8) +#define RT5682S_I2S_M_D_2 (0x1 << 8) +#define RT5682S_I2S_M_D_3 (0x2 << 8) +#define RT5682S_I2S_M_D_4 (0x3 << 8) +#define RT5682S_I2S_M_D_6 (0x4 << 8) +#define RT5682S_I2S_M_D_8 (0x5 << 8) +#define RT5682S_I2S_M_D_12 (0x6 << 8) +#define RT5682S_I2S_M_D_16 (0x7 << 8) +#define RT5682S_I2S_M_D_24 (0x8 << 8) +#define RT5682S_I2S_M_D_32 (0x9 << 8) +#define RT5682S_I2S_M_D_48 (0x10 << 8) +#define RT5682S_I2S_M_CLK_SRC_MASK (0x7 << 4) +#define RT5682S_I2S_M_CLK_SRC_SFT 4 +#define RT5682S_DAC_OSR_MASK (0xf << 0) +#define RT5682S_DAC_OSR_SFT 0 +#define RT5682S_DAC_OSR_D_1 (0x0 << 0) +#define RT5682S_DAC_OSR_D_2 (0x1 << 0) +#define RT5682S_DAC_OSR_D_4 (0x2 << 0) +#define RT5682S_DAC_OSR_D_6 (0x3 << 0) +#define RT5682S_DAC_OSR_D_8 (0x4 << 0) +#define RT5682S_DAC_OSR_D_12 (0x5 << 0) +#define RT5682S_DAC_OSR_D_16 (0x6 << 0) +#define RT5682S_DAC_OSR_D_24 (0x7 << 0) +#define RT5682S_DAC_OSR_D_32 (0x8 << 0) +#define RT5682S_DAC_OSR_D_48 (0x9 << 0) + +/* ADC/DAC Clock Control 2 (0x0074) */ +#define RT5682S_I2S2_BCLK_MS2_MASK (0x1 << 11) +#define RT5682S_I2S2_BCLK_MS2_SFT 11 +#define RT5682S_I2S2_BCLK_MS2_32 (0x0 << 11) +#define RT5682S_I2S2_BCLK_MS2_64 (0x1 << 11) + + +/* TDM control 1 (0x0079) */ +#define RT5682S_TDM_TX_CH_MASK (0x3 << 12) +#define RT5682S_TDM_TX_CH_2 (0x0 << 12) +#define RT5682S_TDM_TX_CH_4 (0x1 << 12) +#define RT5682S_TDM_TX_CH_6 (0x2 << 12) +#define RT5682S_TDM_TX_CH_8 (0x3 << 12) +#define RT5682S_TDM_RX_CH_MASK (0x3 << 8) +#define RT5682S_TDM_RX_CH_2 (0x0 << 8) +#define RT5682S_TDM_RX_CH_4 (0x1 << 8) +#define RT5682S_TDM_RX_CH_6 (0x2 << 8) +#define RT5682S_TDM_RX_CH_8 (0x3 << 8) +#define RT5682S_TDM_ADC_LCA_MASK (0x7 << 4) +#define RT5682S_TDM_ADC_LCA_SFT 4 +#define RT5682S_TDM_ADC_DL_SFT 0 + +/* TDM control 2 (0x007a) */ +#define RT5682S_IF1_ADC1_SEL_SFT 14 +#define RT5682S_IF1_ADC2_SEL_SFT 12 +#define RT5682S_IF1_ADC3_SEL_SFT 10 +#define RT5682S_IF1_ADC4_SEL_SFT 8 +#define RT5682S_TDM_ADC_SEL_SFT 3 + +/* TDM control 3 (0x007b) */ +#define RT5682S_TDM_EN (0x1 << 7) + +/* TDM/I2S control (0x007e) */ +#define RT5682S_TDM_S_BP_MASK (0x1 << 15) +#define RT5682S_TDM_S_BP_SFT 15 +#define RT5682S_TDM_S_BP_NOR (0x0 << 15) +#define RT5682S_TDM_S_BP_INV (0x1 << 15) +#define RT5682S_TDM_S_LP_MASK (0x1 << 14) +#define RT5682S_TDM_S_LP_SFT 14 +#define RT5682S_TDM_S_LP_NOR (0x0 << 14) +#define RT5682S_TDM_S_LP_INV (0x1 << 14) +#define RT5682S_TDM_DF_MASK (0x7 << 11) +#define RT5682S_TDM_DF_SFT 11 +#define RT5682S_TDM_DF_I2S (0x0 << 11) +#define RT5682S_TDM_DF_LEFT (0x1 << 11) +#define RT5682S_TDM_DF_PCM_A (0x2 << 11) +#define RT5682S_TDM_DF_PCM_B (0x3 << 11) +#define RT5682S_TDM_DF_PCM_A_N (0x6 << 11) +#define RT5682S_TDM_DF_PCM_B_N (0x7 << 11) +#define RT5682S_TDM_BCLK_MS1_MASK (0x3 << 8) +#define RT5682S_TDM_BCLK_MS1_SFT 8 +#define RT5682S_TDM_BCLK_MS1_32 (0x0 << 8) +#define RT5682S_TDM_BCLK_MS1_64 (0x1 << 8) +#define RT5682S_TDM_BCLK_MS1_128 (0x2 << 8) +#define RT5682S_TDM_BCLK_MS1_256 (0x3 << 8) +#define RT5682S_TDM_BCLK_MS1_16 (0x4 << 8) +#define RT5682S_TDM_CL_MASK (0x3 << 4) +#define RT5682S_TDM_CL_16 (0x0 << 4) +#define RT5682S_TDM_CL_20 (0x1 << 4) +#define RT5682S_TDM_CL_24 (0x2 << 4) +#define RT5682S_TDM_CL_32 (0x3 << 4) +#define RT5682S_TDM_M_BP_MASK (0x1 << 2) +#define RT5682S_TDM_M_BP_SFT 2 +#define RT5682S_TDM_M_BP_NOR (0x0 << 2) +#define RT5682S_TDM_M_BP_INV (0x1 << 2) +#define RT5682S_TDM_M_LP_MASK (0x1 << 1) +#define RT5682S_TDM_M_LP_SFT 1 +#define RT5682S_TDM_M_LP_NOR (0x0 << 1) +#define RT5682S_TDM_M_LP_INV (0x1 << 1) +#define RT5682S_TDM_MS_MASK (0x1 << 0) +#define RT5682S_TDM_MS_SFT 0 +#define RT5682S_TDM_MS_S (0x0 << 0) +#define RT5682S_TDM_MS_M (0x1 << 0) + +/* Global Clock Control (0x0080) */ +#define RT5682S_SCLK_SRC_MASK (0x7 << 13) +#define RT5682S_SCLK_SRC_SFT 13 +#define RT5682S_PLL_SRC_MASK (0x3 << 8) +#define RT5682S_PLL_SRC_SFT 8 +#define RT5682S_PLL_SRC_MCLK (0x0 << 8) +#define RT5682S_PLL_SRC_BCLK1 (0x1 << 8) +#define RT5682S_PLL_SRC_RC (0x3 << 8) + +/* PLL tracking mode 1 (0x0083) */ +#define RT5682S_DA_ASRC_MASK (0x1 << 13) +#define RT5682S_DA_ASRC_SFT 13 +#define RT5682S_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5682S_DAC_STO1_ASRC_SFT 12 +#define RT5682S_AD_ASRC_MASK (0x1 << 8) +#define RT5682S_AD_ASRC_SFT 8 +#define RT5682S_AD_ASRC_SEL_MASK (0x1 << 4) +#define RT5682S_AD_ASRC_SEL_SFT 4 +#define RT5682S_DMIC_ASRC_MASK (0x1 << 3) +#define RT5682S_DMIC_ASRC_SFT 3 +#define RT5682S_ADC_STO1_ASRC_MASK (0x1 << 2) +#define RT5682S_ADC_STO1_ASRC_SFT 2 +#define RT5682S_DA_ASRC_SEL_MASK (0x1 << 0) +#define RT5682S_DA_ASRC_SEL_SFT 0 + +/* PLL tracking mode 2 3 (0x0084)(0x0085)*/ +#define RT5682S_FILTER_CLK_SEL_MASK (0x7 << 12) +#define RT5682S_FILTER_CLK_SEL_SFT 12 +#define RT5682S_FILTER_CLK_DIV_MASK (0xf << 8) +#define RT5682S_FILTER_CLK_DIV_SFT 8 + +/* ASRC Control 4 (0x0086) */ +#define RT5682S_ASRCIN_FTK_N1_MASK (0x3 << 14) +#define RT5682S_ASRCIN_FTK_N1_SFT 14 +#define RT5682S_ASRCIN_FTK_N2_MASK (0x3 << 12) +#define RT5682S_ASRCIN_FTK_N2_SFT 12 +#define RT5682S_ASRCIN_FTK_M1_MASK (0x7 << 8) +#define RT5682S_ASRCIN_FTK_M1_SFT 8 +#define RT5682S_ASRCIN_FTK_M2_MASK (0x7 << 4) +#define RT5682S_ASRCIN_FTK_M2_SFT 4 + +/* Depop Mode Control 1 (0x008e) */ +#define RT5682S_OUT_HP_L_EN (0x1 << 6) +#define RT5682S_OUT_HP_R_EN (0x1 << 5) +#define RT5682S_LDO_PUMP_EN (0x1 << 4) +#define RT5682S_LDO_PUMP_EN_SFT 4 +#define RT5682S_PUMP_EN (0x1 << 3) +#define RT5682S_PUMP_EN_SFT 3 +#define RT5682S_CAPLESS_L_EN (0x1 << 1) +#define RT5682S_CAPLESS_L_EN_SFT 1 +#define RT5682S_CAPLESS_R_EN (0x1 << 0) +#define RT5682S_CAPLESS_R_EN_SFT 0 + +/* Depop Mode Control 2 (0x8f) */ +#define RT5682S_RAMP_MASK (0x1 << 12) +#define RT5682S_RAMP_SFT 12 +#define RT5682S_RAMP_DIS (0x0 << 12) +#define RT5682S_RAMP_EN (0x1 << 12) +#define RT5682S_BPS_MASK (0x1 << 11) +#define RT5682S_BPS_SFT 11 +#define RT5682S_BPS_DIS (0x0 << 11) +#define RT5682S_BPS_EN (0x1 << 11) +#define RT5682S_FAST_UPDN_MASK (0x1 << 10) +#define RT5682S_FAST_UPDN_SFT 10 +#define RT5682S_FAST_UPDN_DIS (0x0 << 10) +#define RT5682S_FAST_UPDN_EN (0x1 << 10) +#define RT5682S_VLO_MASK (0x1 << 7) +#define RT5682S_VLO_SFT 7 +#define RT5682S_VLO_3V (0x0 << 7) +#define RT5682S_VLO_33V (0x1 << 7) + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5682S_OSW_L_MASK (0x1 << 11) +#define RT5682S_OSW_L_SFT 11 +#define RT5682S_OSW_L_DIS (0x0 << 11) +#define RT5682S_OSW_L_EN (0x1 << 11) +#define RT5682S_OSW_R_MASK (0x1 << 10) +#define RT5682S_OSW_R_SFT 10 +#define RT5682S_OSW_R_DIS (0x0 << 10) +#define RT5682S_OSW_R_EN (0x1 << 10) +#define RT5682S_PM_HP_MASK (0x3 << 8) +#define RT5682S_PM_HP_SFT 8 +#define RT5682S_PM_HP_LV (0x0 << 8) +#define RT5682S_PM_HP_MV (0x1 << 8) +#define RT5682S_PM_HP_HV (0x2 << 8) + +/* Micbias Control1 (0x93) */ +#define RT5682S_MIC1_OV_MASK (0x3 << 14) +#define RT5682S_MIC1_OV_SFT 14 +#define RT5682S_MIC1_OV_2V7 (0x0 << 14) +#define RT5682S_MIC1_OV_2V4 (0x1 << 14) +#define RT5682S_MIC1_OV_2V25 (0x3 << 14) +#define RT5682S_MIC1_OV_1V8 (0x4 << 14) +#define RT5682S_MIC2_OV_MASK (0x3 << 8) +#define RT5682S_MIC2_OV_SFT 8 +#define RT5682S_MIC2_OV_2V7 (0x0 << 8) +#define RT5682S_MIC2_OV_2V4 (0x1 << 8) +#define RT5682S_MIC2_OV_2V25 (0x3 << 8) +#define RT5682S_MIC2_OV_1V8 (0x4 << 8) + +/* Micbias Control2 (0x0094) */ +#define RT5682S_PWR_CLK25M_MASK (0x1 << 9) +#define RT5682S_PWR_CLK25M_SFT 9 +#define RT5682S_PWR_CLK25M_PD (0x0 << 9) +#define RT5682S_PWR_CLK25M_PU (0x1 << 9) +#define RT5682S_PWR_CLK1M_MASK (0x1 << 8) +#define RT5682S_PWR_CLK1M_SFT 8 +#define RT5682S_PWR_CLK1M_PD (0x0 << 8) +#define RT5682S_PWR_CLK1M_PU (0x1 << 8) + +/* PLL M/N/K Code Control 1 (0x0098) */ +#define RT5682S_PLLA_N_MASK (0x1ff << 0) + +/* PLL M/N/K Code Control 2 (0x0099) */ +#define RT5682S_PLLA_M_MASK (0x1f << 8) +#define RT5682S_PLLA_M_SFT 8 +#define RT5682S_PLLA_K_MASK (0x1f << 0) + +/* PLL M/N/K Code Control 3 (0x009a) */ +#define RT5682S_PLLB_N_MASK (0x3ff << 0) + +/* PLL M/N/K Code Control 4 (0x009b) */ +#define RT5682S_PLLB_M_MASK (0x1f << 8) +#define RT5682S_PLLB_M_SFT 8 +#define RT5682S_PLLB_K_MASK (0x1f << 0) + +/* PLL M/N/K Code Control 6 (0x009d) */ +#define RT5682S_PLLB_SEL_PS_MASK (0x1 << 13) +#define RT5682S_PLLB_SEL_PS_SFT 13 +#define RT5682S_PLLB_BYP_PS_MASK (0x1 << 12) +#define RT5682S_PLLB_BYP_PS_SFT 12 +#define RT5682S_PLLB_M_BP_MASK (0x1 << 11) +#define RT5682S_PLLB_M_BP_SFT 11 +#define RT5682S_PLLB_K_BP_MASK (0x1 << 10) +#define RT5682S_PLLB_K_BP_SFT 10 +#define RT5682S_PLLA_M_BP_MASK (0x1 << 7) +#define RT5682S_PLLA_M_BP_SFT 7 +#define RT5682S_PLLA_K_BP_MASK (0x1 << 6) +#define RT5682S_PLLA_K_BP_SFT 6 + +/* PLL M/N/K Code Control 7 (0x009e) */ +#define RT5682S_PLLB_SRC_MASK (0x3 << 0) +#define RT5682S_PLLB_SRC_DFIN (0x1) +#define RT5682S_PLLB_SRC_PLLA (0x0) + +/* RC Clock Control (0x009f) */ +#define RT5682S_POW_IRQ (0x1 << 15) +#define RT5682S_POW_JDH (0x1 << 14) + +/* I2S2 Master Mode Clock Control 1 (0x00a0) */ +#define RT5682S_I2S2_M_CLK_SRC_MASK (0x7 << 4) +#define RT5682S_I2S2_M_CLK_SRC_SFT 4 +#define RT5682S_I2S2_M_D_MASK (0xf << 0) +#define RT5682S_I2S2_M_D_1 (0x0) +#define RT5682S_I2S2_M_D_2 (0x1) +#define RT5682S_I2S2_M_D_3 (0x2) +#define RT5682S_I2S2_M_D_4 (0x3) +#define RT5682S_I2S2_M_D_6 (0x4) +#define RT5682S_I2S2_M_D_8 (0x5) +#define RT5682S_I2S2_M_D_12 (0x6) +#define RT5682S_I2S2_M_D_16 (0x7) +#define RT5682S_I2S2_M_D_24 (0x8) +#define RT5682S_I2S2_M_D_32 (0x9) +#define RT5682S_I2S2_M_D_48 (0xa) +#define RT5682S_I2S2_M_D_SFT 0 + +/* IRQ Control 1 (0x00b6) */ +#define RT5682S_JD1_PULSE_EN_MASK (0x1 << 10) +#define RT5682S_JD1_PULSE_EN_SFT 10 +#define RT5682S_JD1_PULSE_DIS (0x0 << 10) +#define RT5682S_JD1_PULSE_EN (0x1 << 10) + +/* IRQ Control 2 (0x00b7) */ +#define RT5682S_JD1_EN_MASK (0x1 << 15) +#define RT5682S_JD1_EN_SFT 15 +#define RT5682S_JD1_DIS (0x0 << 15) +#define RT5682S_JD1_EN (0x1 << 15) +#define RT5682S_JD1_POL_MASK (0x1 << 13) +#define RT5682S_JD1_POL_NOR (0x0 << 13) +#define RT5682S_JD1_POL_INV (0x1 << 13) +#define RT5682S_JD1_IRQ_MASK (0x1 << 10) +#define RT5682S_JD1_IRQ_LEV (0x0 << 10) +#define RT5682S_JD1_IRQ_PUL (0x1 << 10) + +/* IRQ Control 3 (0x00b8) */ +#define RT5682S_IL_IRQ_MASK (0x1 << 7) +#define RT5682S_IL_IRQ_DIS (0x0 << 7) +#define RT5682S_IL_IRQ_EN (0x1 << 7) +#define RT5682S_IL_IRQ_TYPE_MASK (0x1 << 4) +#define RT5682S_IL_IRQ_LEV (0x0 << 4) +#define RT5682S_IL_IRQ_PUL (0x1 << 4) + +/* GPIO Control 1 (0x00c0) */ +#define RT5682S_GP1_PIN_MASK (0x3 << 14) +#define RT5682S_GP1_PIN_SFT 14 +#define RT5682S_GP1_PIN_GPIO1 (0x0 << 14) +#define RT5682S_GP1_PIN_IRQ (0x1 << 14) +#define RT5682S_GP1_PIN_DMIC_CLK (0x2 << 14) +#define RT5682S_GP2_PIN_MASK (0x3 << 12) +#define RT5682S_GP2_PIN_SFT 12 +#define RT5682S_GP2_PIN_GPIO2 (0x0 << 12) +#define RT5682S_GP2_PIN_LRCK2 (0x1 << 12) +#define RT5682S_GP2_PIN_DMIC_SDA (0x2 << 12) +#define RT5682S_GP3_PIN_MASK (0x3 << 10) +#define RT5682S_GP3_PIN_SFT 10 +#define RT5682S_GP3_PIN_GPIO3 (0x0 << 10) +#define RT5682S_GP3_PIN_BCLK2 (0x1 << 10) +#define RT5682S_GP3_PIN_DMIC_CLK (0x2 << 10) +#define RT5682S_GP4_PIN_MASK (0x3 << 8) +#define RT5682S_GP4_PIN_SFT 8 +#define RT5682S_GP4_PIN_GPIO4 (0x0 << 8) +#define RT5682S_GP4_PIN_ADCDAT1 (0x1 << 8) +#define RT5682S_GP4_PIN_DMIC_CLK (0x2 << 8) +#define RT5682S_GP4_PIN_ADCDAT2 (0x3 << 8) +#define RT5682S_GP5_PIN_MASK (0x3 << 6) +#define RT5682S_GP5_PIN_SFT 6 +#define RT5682S_GP5_PIN_GPIO5 (0x0 << 6) +#define RT5682S_GP5_PIN_DACDAT1 (0x1 << 6) +#define RT5682S_GP5_PIN_DMIC_SDA (0x2 << 6) +#define RT5682S_GP6_PIN_MASK (0x1 << 5) +#define RT5682S_GP6_PIN_SFT 5 +#define RT5682S_GP6_PIN_GPIO6 (0x0 << 5) +#define RT5682S_GP6_PIN_LRCK1 (0x1 << 5) + +/* GPIO Control 2 (0x00c1)*/ +#define RT5682S_GP1_PF_MASK (0x1 << 15) +#define RT5682S_GP1_PF_IN (0x0 << 15) +#define RT5682S_GP1_PF_OUT (0x1 << 15) +#define RT5682S_GP1_OUT_MASK (0x1 << 14) +#define RT5682S_GP1_OUT_L (0x0 << 14) +#define RT5682S_GP1_OUT_H (0x1 << 14) +#define RT5682S_GP2_PF_MASK (0x1 << 13) +#define RT5682S_GP2_PF_IN (0x0 << 13) +#define RT5682S_GP2_PF_OUT (0x1 << 13) +#define RT5682S_GP2_OUT_MASK (0x1 << 12) +#define RT5682S_GP2_OUT_L (0x0 << 12) +#define RT5682S_GP2_OUT_H (0x1 << 12) +#define RT5682S_GP3_PF_MASK (0x1 << 11) +#define RT5682S_GP3_PF_IN (0x0 << 11) +#define RT5682S_GP3_PF_OUT (0x1 << 11) +#define RT5682S_GP3_OUT_MASK (0x1 << 10) +#define RT5682S_GP3_OUT_L (0x0 << 10) +#define RT5682S_GP3_OUT_H (0x1 << 10) +#define RT5682S_GP4_PF_MASK (0x1 << 9) +#define RT5682S_GP4_PF_IN (0x0 << 9) +#define RT5682S_GP4_PF_OUT (0x1 << 9) +#define RT5682S_GP4_OUT_MASK (0x1 << 8) +#define RT5682S_GP4_OUT_L (0x0 << 8) +#define RT5682S_GP4_OUT_H (0x1 << 8) +#define RT5682S_GP5_PF_MASK (0x1 << 7) +#define RT5682S_GP5_PF_IN (0x0 << 7) +#define RT5682S_GP5_PF_OUT (0x1 << 7) +#define RT5682S_GP5_OUT_MASK (0x1 << 6) +#define RT5682S_GP5_OUT_L (0x0 << 6) +#define RT5682S_GP5_OUT_H (0x1 << 6) +#define RT5682S_GP6_PF_MASK (0x1 << 5) +#define RT5682S_GP6_PF_IN (0x0 << 5) +#define RT5682S_GP6_PF_OUT (0x1 << 5) +#define RT5682S_GP6_OUT_MASK (0x1 << 4) +#define RT5682S_GP6_OUT_L (0x0 << 4) +#define RT5682S_GP6_OUT_H (0x1 << 4) + +/* GPIO Status (0x00c2) */ +#define RT5682S_GP6_ST (0x1 << 6) +#define RT5682S_GP5_ST (0x1 << 5) +#define RT5682S_GP4_ST (0x1 << 4) +#define RT5682S_GP3_ST (0x1 << 3) +#define RT5682S_GP2_ST (0x1 << 2) +#define RT5682S_GP1_ST (0x1 << 1) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5682S_ZCD_MASK (0x1 << 10) +#define RT5682S_ZCD_SFT 10 +#define RT5682S_ZCD_PD (0x0 << 10) +#define RT5682S_ZCD_PU (0x1 << 10) + +/* 4 Button Inline Command Control 2 (0x00e3) */ +#define RT5682S_4BTN_IL_MASK (0x1 << 15) +#define RT5682S_4BTN_IL_EN (0x1 << 15) +#define RT5682S_4BTN_IL_DIS (0x0 << 15) +#define RT5682S_4BTN_IL_RST_MASK (0x1 << 14) +#define RT5682S_4BTN_IL_NOR (0x1 << 14) +#define RT5682S_4BTN_IL_RST (0x0 << 14) + +/* 4 Button Inline Command Control 3~6 (0x00e5~0x00e8) */ +#define RT5682S_4BTN_IL_HOLD_WIN_MASK (0x7f << 8) +#define RT5682S_4BTN_IL_HOLD_WIN_SFT 8 +#define RT5682S_4BTN_IL_CLICK_WIN_MASK (0x7f) +#define RT5682S_4BTN_IL_CLICK_WIN_SFT 0 + +/* Analog JD Control (0x00f0) */ +#define RT5682S_JDH_RS_MASK (0x1 << 4) +#define RT5682S_JDH_NO_PLUG (0x1 << 4) +#define RT5682S_JDH_PLUG (0x0 << 4) + +/* Charge Pump Internal Register1 (0x0125) */ +#define RT5682S_CP_CLK_HP_MASK (0x3 << 4) +#define RT5682S_CP_CLK_HP_100KHZ (0x0 << 4) +#define RT5682S_CP_CLK_HP_200KHZ (0x1 << 4) +#define RT5682S_CP_CLK_HP_300KHZ (0x2 << 4) +#define RT5682S_CP_CLK_HP_600KHZ (0x3 << 4) + +/* Pad Driving Control (0x0136) */ +#define RT5682S_PAD_DRV_GP1_MASK (0x1 << 14) +#define RT5682S_PAD_DRV_GP1_HIGH (0x1 << 14) +#define RT5682S_PAD_DRV_GP1_LOW (0x0 << 14) +#define RT5682S_PAD_DRV_GP2_MASK (0x1 << 12) +#define RT5682S_PAD_DRV_GP2_HIGH (0x1 << 12) +#define RT5682S_PAD_DRV_GP2_LOW (0x0 << 12) +#define RT5682S_PAD_DRV_GP3_MASK (0x1 << 10) +#define RT5682S_PAD_DRV_GP3_HIGH (0x1 << 10) +#define RT5682S_PAD_DRV_GP3_LOW (0x0 << 10) +#define RT5682S_PAD_DRV_GP4_MASK (0x1 << 8) +#define RT5682S_PAD_DRV_GP4_HIGH (0x1 << 8) +#define RT5682S_PAD_DRV_GP4_LOW (0x0 << 8) +#define RT5682S_PAD_DRV_GP5_MASK (0x1 << 6) +#define RT5682S_PAD_DRV_GP5_HIGH (0x1 << 6) +#define RT5682S_PAD_DRV_GP5_LOW (0x0 << 6) +#define RT5682S_PAD_DRV_GP6_MASK (0x1 << 4) +#define RT5682S_PAD_DRV_GP6_HIGH (0x1 << 4) +#define RT5682S_PAD_DRV_GP6_LOW (0x0 << 4) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5682S_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5682S_CKXEN_DAC1_SFT 13 +#define RT5682S_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5682S_CKGEN_DAC1_SFT 12 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5682S_CKXEN_ADC1_MASK (0x1 << 13) +#define RT5682S_CKXEN_ADC1_SFT 13 +#define RT5682S_CKGEN_ADC1_MASK (0x1 << 12) +#define RT5682S_CKGEN_ADC1_SFT 12 + +/* Volume test (0x013f)*/ +#define RT5682S_SEL_CLK_VOL_MASK (0x1 << 15) +#define RT5682S_SEL_CLK_VOL_EN (0x1 << 15) +#define RT5682S_SEL_CLK_VOL_DIS (0x0 << 15) + +/* Test Mode Control 1 (0x0145) */ +#define RT5682S_AD2DA_LB_MASK (0x1 << 10) +#define RT5682S_AD2DA_LB_SFT 10 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5682S_NG2_EN_MASK (0x1 << 15) +#define RT5682S_NG2_EN (0x1 << 15) +#define RT5682S_NG2_DIS (0x0 << 15) + +/* Stereo1 DAC Silence Detection Control (0x0190) */ +#define RT5682S_DEB_STO_DAC_MASK (0x7 << 4) +#define RT5682S_DEB_80_MS (0x0 << 4) + +/* HP Behavior Logic Control 2 (0x01db) */ +#define RT5682S_HP_SIG_SRC_MASK (0x3) +#define RT5682S_HP_SIG_SRC_1BIT_CTL (0x3) +#define RT5682S_HP_SIG_SRC_REG (0x2) +#define RT5682S_HP_SIG_SRC_IMPE_REG (0x1) +#define RT5682S_HP_SIG_SRC_DC_CALI (0x0) + +/* SAR ADC Inline Command Control 1 (0x0210) */ +#define RT5682S_SAR_BUTDET_MASK (0x1 << 15) +#define RT5682S_SAR_BUTDET_EN (0x1 << 15) +#define RT5682S_SAR_BUTDET_DIS (0x0 << 15) +#define RT5682S_SAR_BUTDET_POW_MASK (0x1 << 14) +#define RT5682S_SAR_BUTDET_POW_SAV (0x1 << 14) +#define RT5682S_SAR_BUTDET_POW_NORM (0x0 << 14) +#define RT5682S_SAR_BUTDET_RST_MASK (0x1 << 13) +#define RT5682S_SAR_BUTDET_RST_NORM (0x1 << 13) +#define RT5682S_SAR_BUTDET_RST (0x0 << 13) +#define RT5682S_SAR_POW_MASK (0x1 << 12) +#define RT5682S_SAR_POW_EN (0x1 << 12) +#define RT5682S_SAR_POW_DIS (0x0 << 12) +#define RT5682S_SAR_RST_MASK (0x1 << 11) +#define RT5682S_SAR_RST_NORMAL (0x1 << 11) +#define RT5682S_SAR_RST (0x0 << 11) +#define RT5682S_SAR_BYPASS_MASK (0x1 << 10) +#define RT5682S_SAR_BYPASS_EN (0x1 << 10) +#define RT5682S_SAR_BYPASS_DIS (0x0 << 10) +#define RT5682S_SAR_SEL_MB1_2_MASK (0x3 << 8) +#define RT5682S_SAR_SEL_MB1_2_SFT 8 +#define RT5682S_SAR_SEL_MODE_MASK (0x1 << 7) +#define RT5682S_SAR_SEL_MODE_CMP (0x1 << 7) +#define RT5682S_SAR_SEL_MODE_ADC (0x0 << 7) +#define RT5682S_SAR_SEL_MB1_2_CTL_MASK (0x1 << 5) +#define RT5682S_SAR_SEL_MB1_2_AUTO (0x1 << 5) +#define RT5682S_SAR_SEL_MB1_2_MANU (0x0 << 5) +#define RT5682S_SAR_SEL_SIGNAL_MASK (0x1 << 4) +#define RT5682S_SAR_SEL_SIGNAL_AUTO (0x1 << 4) +#define RT5682S_SAR_SEL_SIGNAL_MANU (0x0 << 4) + +/* SAR ADC Inline Command Control 2 (0x0211) */ +#define RT5682S_SAR_ADC_PSV_MASK (0x1 << 4) +#define RT5682S_SAR_ADC_PSV_ENTRY (0x1 << 4) + + +/* SAR ADC Inline Command Control 13 (0x021c) */ +#define RT5682S_SAR_SOUR_MASK (0x3f) +#define RT5682S_SAR_SOUR_BTN (0x3f) +#define RT5682S_SAR_SOUR_TYPE (0x0) + + +#define RT5682S_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5682S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +/* System Clock Source */ +enum { + RT5682S_SCLK_S_MCLK, + RT5682S_SCLK_S_PLL1, + RT5682S_SCLK_S_PLL2, + RT5682S_SCLK_S_RCCLK, +}; + +/* PLL Source */ +enum { + RT5682S_PLL_S_MCLK, + RT5682S_PLL_S_BCLK1, + RT5682S_PLL_S_BCLK2, + RT5682S_PLL_S_RCCLK, +}; + +enum { + RT5682S_PLL1, + RT5682S_PLL2, + RT5682S_PLLS, +}; + +enum { + RT5682S_AIF1, + RT5682S_AIF2, + RT5682S_AIFS +}; + +/* filter mask */ +enum { + RT5682S_DA_STEREO1_FILTER = 0x1, + RT5682S_AD_STEREO1_FILTER = (0x1 << 1), +}; + +enum { + RT5682S_CLK_SEL_SYS, + RT5682S_CLK_SEL_I2S1_ASRC, + RT5682S_CLK_SEL_I2S2_ASRC, +}; + +enum { + USE_PLLA, + USE_PLLB, + USE_PLLAB, +}; + +struct pll_calc_map { + unsigned int freq_in; + unsigned int freq_out; + int m; + int n; + int k; + bool m_bp; + bool k_bp; + bool byp_ps; + bool sel_ps; +}; + +#define RT5682S_NUM_SUPPLIES 2 + +struct rt5682s_priv { + struct snd_soc_component *component; + struct rt5682s_platform_data pdata; + struct regmap *regmap; + struct snd_soc_jack *hs_jack; + struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES]; + struct delayed_work jack_detect_work; + struct delayed_work jd_check_work; + struct mutex calibrate_mutex; + struct mutex sar_mutex; + +#ifdef CONFIG_COMMON_CLK + struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS]; + struct clk *mclk; +#endif + + int sysclk; + int sysclk_src; + int lrck[RT5682S_AIFS]; + int bclk[RT5682S_AIFS]; + int master[RT5682S_AIFS]; + + int pll_src[RT5682S_PLLS]; + int pll_in[RT5682S_PLLS]; + int pll_out[RT5682S_PLLS]; + int pll_comb; + + int jack_type; + int irq_work_delay_time; +}; + +int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component, + unsigned int filter_mask, unsigned int clk_src); + +#endif /* __RT5682S_H__ */ diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index d60f4dac6c1b..07abad7fe372 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -138,11 +138,42 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-rpmsg", }; +static const struct fsl_rpmsg_soc_data imx7ulp_data = { + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, +}; + +static const struct fsl_rpmsg_soc_data imx8mm_data = { + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U8 | + SNDRV_PCM_FMTBIT_DSD_U16_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE, +}; + +static const struct fsl_rpmsg_soc_data imx8mn_data = { + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, +}; + +static const struct fsl_rpmsg_soc_data imx8mp_data = { + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, +}; + static const struct of_device_id fsl_rpmsg_ids[] = { - { .compatible = "fsl,imx7ulp-rpmsg-audio"}, - { .compatible = "fsl,imx8mm-rpmsg-audio"}, - { .compatible = "fsl,imx8mn-rpmsg-audio"}, - { .compatible = "fsl,imx8mp-rpmsg-audio"}, + { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data}, + { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data}, + { .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data}, + { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); @@ -157,6 +188,13 @@ static int fsl_rpmsg_probe(struct platform_device *pdev) if (!rpmsg) return -ENOMEM; + rpmsg->soc_data = of_device_get_match_data(&pdev->dev); + + fsl_rpmsg_dai.playback.rates = rpmsg->soc_data->rates; + fsl_rpmsg_dai.capture.rates = rpmsg->soc_data->rates; + fsl_rpmsg_dai.playback.formats = rpmsg->soc_data->formats; + fsl_rpmsg_dai.capture.formats = rpmsg->soc_data->formats; + if (of_property_read_bool(np, "fsl,enable-lpa")) { rpmsg->enable_lpa = 1; rpmsg->buffer_size = LPA_LARGE_BUFFER_SIZE; diff --git a/sound/soc/fsl/fsl_rpmsg.h b/sound/soc/fsl/fsl_rpmsg.h index 4f5b49eb18d8..b04086fbf828 100644 --- a/sound/soc/fsl/fsl_rpmsg.h +++ b/sound/soc/fsl/fsl_rpmsg.h @@ -7,6 +7,16 @@ #define __FSL_RPMSG_H /* + * struct fsl_rpmsg_soc_data + * @rates: supported rates + * @formats: supported formats + */ +struct fsl_rpmsg_soc_data { + int rates; + u64 formats; +}; + +/* * struct fsl_rpmsg - rpmsg private data * * @ipg: ipg clock for cpu dai (SAI) @@ -15,6 +25,7 @@ * @pll8k: parent clock for multiple of 8kHz frequency * @pll11k: parent clock for multiple of 11kHz frequency * @card_pdev: Platform_device pointer to register a sound card + * @soc_data: soc specific data * @mclk_streams: Active streams that are using baudclk * @force_lpa: force enable low power audio routine if condition satisfy * @enable_lpa: enable low power audio routine according to dts setting @@ -27,6 +38,7 @@ struct fsl_rpmsg { struct clk *pll8k; struct clk *pll11k; struct platform_device *card_pdev; + const struct fsl_rpmsg_soc_data *soc_data; unsigned int mclk_streams; int force_lpa; int enable_lpa; diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index e95c7c018e7d..4f2c2379531b 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -288,7 +288,6 @@ const struct snd_soc_dai_ops mtk_afe_fe_ops = { }; EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); -static DEFINE_MUTEX(irqs_lock); int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) { int i; diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 6635c3f72ecc..df8b90baf981 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -3057,7 +3057,6 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8195_afe_private *afe_priv; - struct resource *res; struct device *dev = &pdev->dev; int i, irq_id, ret; struct snd_soc_component *component; @@ -3078,8 +3077,7 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); @@ -3266,9 +3264,7 @@ static struct platform_driver mt8195_afe_pcm_driver = { .driver = { .name = "mt8195-audio", .of_match_table = mt8195_afe_pcm_dt_match, -#ifdef CONFIG_PM .pm = &mt8195_afe_pm_ops, -#endif }, .probe = mt8195_afe_pcm_dev_probe, .remove = mt8195_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index 7378e42f2766..ac591d453e1e 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2094,7 +2094,7 @@ static int mtk_dai_etdm_set_sysclk(struct snd_soc_dai *dai, { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; int dai_id; dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n", diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f6e5ac3e0314..73e1b7b48ce9 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1473,10 +1473,6 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, goto widget; } - control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; - dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", - w->name, w->num_kcontrols, control_hdr->type); - template.num_kcontrols = le32_to_cpu(w->num_kcontrols); kc = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(*kc), GFP_KERNEL); if (!kc) @@ -1536,6 +1532,8 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, } template.kcontrol_news = kc; + dev_dbg(tplg->dev, "ASoC: template %s with %d/%d/%d (mixer/enum/bytes) control\n", + w->name, mixer_count, enum_count, bytes_count); widget: ret = soc_tplg_widget_load(tplg, &template, w); diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index a5dd728c580a..58bb89af4de1 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -65,6 +65,40 @@ static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) return i - 1; } +static void snd_sof_refresh_control(struct snd_sof_control *scontrol) +{ + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_soc_component *scomp = scontrol->scomp; + enum sof_ipc_ctrl_type ctrl_type; + int ret; + + if (!scontrol->comp_data_dirty) + return; + + if (!pm_runtime_active(scomp->dev)) + return; + + if (scontrol->cmd == SOF_CTRL_CMD_BINARY) + ctrl_type = SOF_IPC_COMP_GET_DATA; + else + ctrl_type = SOF_IPC_COMP_GET_VALUE; + + /* set the ABI header values */ + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + + /* refresh the component data from DSP */ + scontrol->comp_data_dirty = false; + ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + scontrol->cmd, false); + if (ret < 0) { + dev_err(scomp->dev, "error: failed to get control data: %d\n", ret); + /* Set the flag to re-try next time to get the data */ + scontrol->comp_data_dirty = true; + } +} + int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -74,6 +108,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + snd_sof_refresh_control(scontrol); + /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = @@ -108,7 +144,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_VOLUME, true); return change; @@ -145,6 +181,8 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + snd_sof_refresh_control(scontrol); + /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value; @@ -179,7 +217,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_SWITCH, true); @@ -195,6 +233,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + snd_sof_refresh_control(scontrol); + /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; @@ -226,7 +266,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_ENUM, true); @@ -244,6 +284,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct sof_abi_hdr *data = cdata->data; size_t size; + snd_sof_refresh_control(scontrol); + if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(scomp->dev, "error: data max %d exceeds ucontrol data array size\n", @@ -475,6 +517,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, (struct snd_ctl_tlv __user *)binary_data; size_t data_size; + snd_sof_refresh_control(scontrol); + /* * Decrement the limit by ext bytes header size to * ensure the user space buffer is not exceeded. @@ -511,3 +555,145 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, return 0; } + +static void snd_sof_update_control(struct snd_sof_control *scontrol, + struct sof_ipc_ctrl_data *cdata) +{ + struct snd_soc_component *scomp = scontrol->scomp; + struct sof_ipc_ctrl_data *local_cdata; + int i; + + local_cdata = scontrol->control_data; + + if (cdata->cmd == SOF_CTRL_CMD_BINARY) { + if (cdata->num_elems != local_cdata->data->size) { + dev_err(scomp->dev, + "error: cdata binary size mismatch %u - %u\n", + cdata->num_elems, local_cdata->data->size); + return; + } + + /* copy the new binary data */ + memcpy(local_cdata->data, cdata->data, cdata->num_elems); + } else if (cdata->num_elems != scontrol->num_channels) { + dev_err(scomp->dev, + "error: cdata channel count mismatch %u - %d\n", + cdata->num_elems, scontrol->num_channels); + } else { + /* copy the new values */ + for (i = 0; i < cdata->num_elems; i++) + local_cdata->chanv[i].value = cdata->chanv[i].value; + } +} + +void snd_sof_control_notify(struct snd_sof_dev *sdev, + struct sof_ipc_ctrl_data *cdata) +{ + struct snd_soc_dapm_widget *widget; + struct snd_sof_control *scontrol; + struct snd_sof_widget *swidget; + struct snd_kcontrol *kc = NULL; + struct soc_mixer_control *sm; + struct soc_bytes_ext *be; + size_t expected_size; + struct soc_enum *se; + bool found = false; + int i, type; + + /* Find the swidget first */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->comp_id == cdata->comp_id) { + found = true; + break; + } + } + + if (!found) + return; + + /* Translate SOF cmd to TPLG type */ + switch (cdata->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_SWITCH: + type = SND_SOC_TPLG_TYPE_MIXER; + break; + case SOF_CTRL_CMD_BINARY: + type = SND_SOC_TPLG_TYPE_BYTES; + break; + case SOF_CTRL_CMD_ENUM: + type = SND_SOC_TPLG_TYPE_ENUM; + break; + default: + dev_err(sdev->dev, "error: unknown cmd %u\n", cdata->cmd); + return; + } + + widget = swidget->widget; + for (i = 0; i < widget->num_kcontrols; i++) { + /* skip non matching types or non matching indexes within type */ + if (widget->dobj.widget.kcontrol_type[i] == type && + widget->kcontrol_news[i].index == cdata->index) { + kc = widget->kcontrols[i]; + break; + } + } + + if (!kc) + return; + + switch (cdata->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_SWITCH: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + break; + case SOF_CTRL_CMD_BINARY: + be = (struct soc_bytes_ext *)kc->private_value; + scontrol = be->dobj.private; + break; + case SOF_CTRL_CMD_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + default: + return; + } + + expected_size = sizeof(struct sof_ipc_ctrl_data); + switch (cdata->type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + expected_size += cdata->num_elems * + sizeof(struct sof_ipc_ctrl_value_chan); + break; + case SOF_CTRL_TYPE_VALUE_COMP_GET: + case SOF_CTRL_TYPE_VALUE_COMP_SET: + expected_size += cdata->num_elems * + sizeof(struct sof_ipc_ctrl_value_comp); + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr); + break; + default: + return; + } + + if (cdata->rhdr.hdr.size != expected_size) { + dev_err(sdev->dev, "error: component notification size mismatch\n"); + return; + } + + if (cdata->num_elems) + /* + * The message includes the updated value/data, update the + * control's local cache using the received notification + */ + snd_sof_update_control(scontrol, cdata); + else + /* Mark the scontrol that the value/data is changed in SOF */ + scontrol->comp_data_dirty = true; + + snd_ctl_notify_one(swidget->scomp->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); +} diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 3e4dd4a86363..6be4f159ee35 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -19,7 +19,7 @@ #endif /* see SOF_DBG_ flags */ -int sof_core_debug; +int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE); module_param_named(sof_debug, sof_core_debug, int, 0444); MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); @@ -202,8 +202,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_run_err; } - if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || - (sof_core_debug & SOF_DBG_ENABLE_TRACE)) { + if (sof_core_debug & SOF_DBG_ENABLE_TRACE) { sdev->dtrace_is_supported = true; /* init DMA trace */ diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index c2d07b783f60..a4fe007a0e4d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -369,6 +369,32 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } EXPORT_SYMBOL(snd_sof_ipc_reply); +static void ipc_comp_notification(struct snd_sof_dev *sdev, + struct sof_ipc_cmd_hdr *hdr) +{ + u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + struct sof_ipc_ctrl_data *cdata; + + switch (msg_type) { + case SOF_IPC_COMP_GET_VALUE: + case SOF_IPC_COMP_GET_DATA: + cdata = kmalloc(hdr->size, GFP_KERNEL); + if (!cdata) + return; + + /* read back full message */ + snd_sof_ipc_msg_data(sdev, NULL, cdata, hdr->size); + break; + default: + dev_err(sdev->dev, "error: unhandled component message %#x\n", msg_type); + return; + } + + snd_sof_control_notify(sdev, cdata); + + kfree(cdata); +} + /* DSP firmware has sent host a message */ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) { @@ -404,7 +430,9 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) case SOF_IPC_GLB_COMPOUND: case SOF_IPC_GLB_TPLG_MSG: case SOF_IPC_GLB_PM_MSG: + break; case SOF_IPC_GLB_COMP_MSG: + ipc_comp_notification(sdev, &hdr); break; case SOF_IPC_GLB_STREAM_MSG: /* need to pass msg id into the function */ diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index dc274e63ed9a..9a8d005e75a0 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -75,6 +75,9 @@ struct snd_sof_control { struct list_head list; /* list in sdev control list */ struct snd_sof_led_control led_ctl; + + /* if true, the control's data needs to be updated from Firmware */ + bool comp_data_dirty; }; /* ASoC SOF DAPM widget */ @@ -148,6 +151,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, unsigned int size); int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, unsigned int size); +void snd_sof_control_notify(struct snd_sof_dev *sdev, + struct sof_ipc_ctrl_data *cdata); /* * Topology. diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index 1d9fe3fca193..40110e9a9e8a 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -212,7 +212,7 @@ config SND_SOC_DM365_VOICE_CODEC Say Y if you want to add support for SoC On-chip voice codec endchoice -config SND_SOC_DM365_VOICE_CODEC_MODULE +config SND_SOC_DM365_SELECT_VOICE_CODECS def_tristate y depends on SND_SOC_DM365_VOICE_CODEC && SND_SOC select MFD_DAVINCI_VOICECODEC |