linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Add support for the internal RK3308 audio codec
@ 2022-09-07 14:21 luca.ceresoli
  2022-09-07 14:21 ` [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings luca.ceresoli
                   ` (8 more replies)
  0 siblings, 9 replies; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

This series of patches adds support to use the internal audio codec of the
Rockchip RK3308 SoC. This codec is internally connected to the I2S
peripherals on the same chip, and it has some peculiarities arising from
that interconnection.

For proper bidirectional operation with the internal codec, the I2S
peripheral needs two clock sources (tx and rx), while connection with an
external codec commonly needs only one. Since v5.16 there is a driver for
the I2S in sound/soc/rockchip/rockchip_i2s_tdm.c, but it does not correctly
handle receiving those two clocks via the .set_sysclk op. Patch 5 fixes
that.

However the simple-audio-card and audio-graph-card sound card drivers do
not support calling .set_sysclk twice, thus patch 6 makes the .init op of
struct asoc_simple_priv overridable by a driver in order to be able to call
.set_sysclk twice and thus configure both clocks.

Patch 7 adds the codec driver and patch 8 builds on top of all the above by
implementing a simple RK3308-specific audio card, based on
audio-graph-card. This card sets all the I2S input clocks.

Patches 1-2 add DT bindings for the codec and the card. Patches 3-4 add to
the SoC DT file two I2S controllers (those which are internally connected
to the internal codec) and the codec itself.

Luca

Luca Ceresoli (8):
  ASoC: rockchip: rk3308: add internal audio codec bindings
  ASoC: rockchip: rk3308: add audio card bindings
  arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3
  arm64: dts: rockchip: add the internal audio codec
  ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk()
  ASoC: audio-graph: let dai_link->init be overridable
  ASoC: codecs: Add RK3308 internal audio codec driver
  ASoC: rockchip: add new RK3308 sound card

 .../rockchip,rk3308-audio-graph-card.yaml     |   50 +
 .../bindings/sound/rockchip,rk3308-codec.yaml |  102 +
 MAINTAINERS                                   |   14 +
 arch/arm64/boot/dts/rockchip/rk3308.dtsi      |   68 +
 .../dt-bindings/sound/rockchip,rk3308-codec.h |   15 +
 include/sound/simple_card_utils.h             |    1 +
 sound/soc/codecs/Kconfig                      |   11 +
 sound/soc/codecs/Makefile                     |    2 +
 sound/soc/codecs/rk3308_codec.c               | 2122 +++++++++++++++++
 sound/soc/codecs/rk3308_codec.h               |  648 +++++
 sound/soc/generic/audio-graph-card.c          |    2 +
 sound/soc/rockchip/Kconfig                    |   14 +
 sound/soc/rockchip/Makefile                   |    1 +
 sound/soc/rockchip/rockchip_i2s_tdm.c         |   18 +-
 sound/soc/rockchip/rockchip_rk3308_card.c     |   97 +
 15 files changed, 3159 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
 create mode 100644 include/dt-bindings/sound/rockchip,rk3308-codec.h
 create mode 100644 sound/soc/codecs/rk3308_codec.c
 create mode 100644 sound/soc/codecs/rk3308_codec.h
 create mode 100644 sound/soc/rockchip/rockchip_rk3308_card.c

-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-08 11:53   ` Krzysztof Kozlowski
  2022-09-07 14:21 ` [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings luca.ceresoli
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

Add device tree bindings document for the internal audio codec of the
Rockchip RK3308 SoC.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 .../bindings/sound/rockchip,rk3308-codec.yaml | 102 ++++++++++++++++++
 MAINTAINERS                                   |   6 ++
 .../dt-bindings/sound/rockchip,rk3308-codec.h |  15 +++
 3 files changed, 123 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
 create mode 100644 include/dt-bindings/sound/rockchip,rk3308-codec.h

diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
new file mode 100644
index 000000000000..f3458f86ef06
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/rockchip,rk3308-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip RK3308 Internal Codec
+
+description: |
+  This is the audio codec embedded in the Rockchip RK3308
+  SoC. It has 8 24-bit ADCs and 2 24-bit DACs. The maximum supported
+  sampling rate is 192 kHz.
+
+  It is connected internally to one out of a selection of the internal I2S
+  controllers.
+
+  The RK3308 audio codec has 8 independent capture channels, but some
+  features work on stereo pairs called groups:
+    * grp 0 -- MIC1 / MIC2
+    * grp 1 -- MIC3 / MIC4
+    * grp 2 -- MIC5 / MIC6
+    * grp 3 -- MIC7 / MIC8
+
+maintainers:
+  - Luca Ceresoli <luca.ceresoli@bootlin.com>
+
+properties:
+  compatible:
+    const: rockchip,rk3308-codec
+
+  reg:
+    maxItems: 1
+
+  rockchip,grf:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the General Register Files (GRF)
+
+  clocks:
+    items:
+      - description: clock for TX
+      - description: clock for RX
+      - description: AHB clock driving the interface
+
+  clock-names:
+    items:
+      - const: mclk_tx
+      - const: mclk_rx
+      - const: hclk
+
+  resets: true
+
+  reset-names:
+    items:
+      - const: "acodec"
+
+  "#sound-dai-cells":
+    const: 0
+
+  rockchip,micbias-avdd-multiplier:
+    description: |
+      Voltage setting for the MICBIAS pins expressed as a multiplier of
+      AVDD.
+
+      E.g. if rockchip,micbias-avdd-multiplier = 7 (x0.85) and AVDD = 3v3,
+      then MIC BIAS voltage will be 3.3 V * 0.85 = 2.805 V.
+
+      Value 0: multiplier = 0.50
+      Value N: multiplier = 0.50 + 0.05 * N
+      Value 7: multiplier = 0.85
+
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 7
+
+required:
+  - compatible
+  - reg
+  - rockchip,grf
+  - clocks
+  - resets
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/rk3308-cru.h>
+
+    acodec: acodec@ff560000 {
+        compatible = "rockchip,rk3308-codec";
+        reg = <0xff560000 0x10000>;
+        rockchip,grf = <&grf>;
+        clock-names = "mclk_tx", "mclk_rx", "hclk";
+        clocks = <&cru SCLK_I2S2_8CH_TX_OUT>,
+                 <&cru SCLK_I2S2_8CH_RX_OUT>,
+                 <&cru PCLK_ACODEC>;
+        reset-names = "acodec";
+        resets = <&cru SRST_ACODEC_P>;
+        #sound-dai-cells = <0>;
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 895e8ace80dd..d53a8e74cb1e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17588,6 +17588,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/rockchip-rga.yaml
 F:	drivers/media/platform/rockchip/rga/
 
+ROCKCHIP RK3308 INTERNAL AUDIO CODEC
+M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
+F:	include/dt-bindings/sound/rockchip,rk3308-codec.h
+
 ROCKCHIP VIDEO DECODER DRIVER
 M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 L:	linux-media@vger.kernel.org
diff --git a/include/dt-bindings/sound/rockchip,rk3308-codec.h b/include/dt-bindings/sound/rockchip,rk3308-codec.h
new file mode 100644
index 000000000000..9f1b210a048e
--- /dev/null
+++ b/include/dt-bindings/sound/rockchip,rk3308-codec.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __DT_BINDINGS_ROCKCHIP_RK3308_CODEC_H__
+#define __DT_BINDINGS_ROCKCHIP_RK3308_CODEC_H__
+
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_50	0
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_55	1
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_60	2
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_65	3
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_70	4
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_75	5
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_80	6
+#define RK3308_CODEC_MICBIAS_AVDD_x_0_85	7
+#define RK3308_CODEC_MICBIAS_NUM		8
+
+#endif /* __DT_BINDINGS_ROCKCHIP_RK3308_CODEC_H__ */
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
  2022-09-07 14:21 ` [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-08 11:49   ` Krzysztof Kozlowski
  2022-09-07 14:21 ` [PATCH 3/8] arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3 luca.ceresoli
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

Add device tree bindings document for the audio card based on the internal
I2S of the Rockchip RK3308 SoC.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 .../rockchip,rk3308-audio-graph-card.yaml     | 50 +++++++++++++++++++
 MAINTAINERS                                   |  5 ++
 2 files changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml

diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
new file mode 100644
index 000000000000..8445a69dcdbb
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/rockchip,rk3308-audio-graph-card.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip RK3308 Audio card based on internal I2S
+
+maintainers:
+  - Luca Ceresoli <luca.ceresoli@bootlin.com>
+
+allOf:
+  - $ref: /schemas/sound/audio-graph.yaml#
+
+properties:
+  compatible:
+    const: rockchip,rk3308-audio-graph-card
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    sound {
+        compatible = "rockchip,rk3308-audio-graph-card";
+        dais = <&i2s_8ch_2_port>;
+    };
+
+    i2s_8ch_2 {
+        i2s_8ch_2_port: port {
+            i2s_8ch_2_endpoint: endpoint {
+                remote-endpoint = <&acodec_endpoint>;
+                dai-format = "i2s";
+
+                /* The RK3308 acodec has no clock dividers, use the CPU */
+                bitclock-master = <&i2s_8ch_2_endpoint>;
+                frame-master = <&i2s_8ch_2_endpoint>;
+            };
+        };
+    };
+
+    acodec {
+        port {
+            acodec_endpoint: endpoint {
+                remote-endpoint = <&i2s_8ch_2_endpoint>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index d53a8e74cb1e..079bdd95dc49 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17594,6 +17594,11 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
 F:	include/dt-bindings/sound/rockchip,rk3308-codec.h
 
+ROCKCHIP RK3308 SOUND CARD DRIVER
+M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
+
 ROCKCHIP VIDEO DECODER DRIVER
 M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 L:	linux-media@vger.kernel.org
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 3/8] arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
  2022-09-07 14:21 ` [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings luca.ceresoli
  2022-09-07 14:21 ` [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-07 14:21 ` [PATCH 4/8] arm64: dts: rockchip: add the internal audio codec luca.ceresoli
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

These are I2S engines internally connected to the built-in audio codec.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 arch/arm64/boot/dts/rockchip/rk3308.dtsi | 54 ++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
index 2dfa67f1cd67..093b70563b23 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
@@ -571,6 +571,60 @@ dmac1: dma-controller@ff2d0000 {
 		#dma-cells = <1>;
 	};
 
+	/*
+	 * - can be clock producer or consumer
+	 * - up to 8 capture channels and 2 playback channels
+	 * - connected internally to audio codec
+	 */
+	i2s_8ch_2: i2s@ff320000 {
+		compatible = "rockchip,rk3308-i2s-tdm";
+		reg = <0x0 0xff320000 0x0 0x1000>;
+		interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+		clock-names = "mclk_tx", "mclk_rx", "hclk",
+			      "mclk_tx_src", "mclk_rx_src",
+			      "mclk_root0", "mclk_root1";
+		clocks = <&cru SCLK_I2S2_8CH_TX>,
+			 <&cru SCLK_I2S2_8CH_RX>,
+			 <&cru HCLK_I2S2_8CH>,
+			 <&cru SCLK_I2S2_8CH_TX_SRC>,
+			 <&cru SCLK_I2S2_8CH_RX_SRC>,
+			 <&cru PLL_VPLL0>,
+			 <&cru PLL_VPLL1>;
+		dmas = <&dmac1 5>, <&dmac1 4>;
+		dma-names = "rx", "tx";
+		resets = <&cru SRST_I2S2_8CH_TX_M>, <&cru SRST_I2S2_8CH_RX_M>;
+		reset-names = "tx-m", "rx-m";
+		rockchip,grf = <&grf>;
+		status = "disabled";
+	};
+
+	/*
+	 * - can be clock consumer only
+	 * - up to 4 capture channels, no playback
+	 * - connected internally to audio codec
+	 */
+	i2s_8ch_3: i2s@ff330000 {
+		compatible = "rockchip,rk3308-i2s-tdm";
+		reg = <0x0 0xff330000 0x0 0x1000>;
+		interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+		clock-names = "mclk_tx", "mclk_rx", "hclk",
+			      "mclk_tx_src", "mclk_rx_src",
+			      "mclk_root0", "mclk_root1";
+		clocks = <&cru SCLK_I2S3_8CH_TX>,
+			 <&cru SCLK_I2S3_8CH_RX>,
+			 <&cru HCLK_I2S3_8CH>,
+			 <&cru SCLK_I2S3_8CH_TX_SRC>,
+			 <&cru SCLK_I2S3_8CH_RX_SRC>,
+			 <&cru PLL_VPLL0>,
+			 <&cru PLL_VPLL1>;
+		dmas = <&dmac1 7>;
+		dma-names = "rx";
+		resets = <&cru SRST_I2S3_8CH_TX_M>, <&cru SRST_I2S3_8CH_RX_M>;
+		reset-names = "tx-m", "rx-m";
+		rockchip,grf = <&grf>;
+		status = "disabled";
+	};
+
 	i2s_2ch_0: i2s@ff350000 {
 		compatible = "rockchip,rk3308-i2s", "rockchip,rk3066-i2s";
 		reg = <0x0 0xff350000 0x0 0x1000>;
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 4/8] arm64: dts: rockchip: add the internal audio codec
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
                   ` (2 preceding siblings ...)
  2022-09-07 14:21 ` [PATCH 3/8] arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3 luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-08 11:53   ` Krzysztof Kozlowski
  2022-09-07 14:21 ` [PATCH 5/8] ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk() luca.ceresoli
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

The RK3308 has a built-in audio codec that connects internally to i2s_8ch_2
or i2s_8ch_3.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 arch/arm64/boot/dts/rockchip/rk3308.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
index 093b70563b23..221cde49dc98 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
@@ -808,6 +808,20 @@ cru: clock-controller@ff500000 {
 		assigned-clock-rates = <32768>;
 	};
 
+	acodec: acodec@ff560000 {
+		compatible = "rockchip,rk3308-codec";
+		reg = <0x0 0xff560000 0x0 0x10000>;
+		rockchip,grf = <&grf>;
+		clock-names = "mclk_tx", "mclk_rx", "hclk";
+		clocks = <&cru SCLK_I2S2_8CH_TX_OUT>,
+			 <&cru SCLK_I2S2_8CH_RX_OUT>,
+			 <&cru PCLK_ACODEC>;
+		reset-names = "acodec-reset";
+		resets = <&cru SRST_ACODEC_P>;
+		#sound-dai-cells = <0>;
+		status = "disabled";
+	};
+
 	gic: interrupt-controller@ff580000 {
 		compatible = "arm,gic-400";
 		reg = <0x0 0xff581000 0x0 0x1000>,
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 5/8] ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk()
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
                   ` (3 preceding siblings ...)
  2022-09-07 14:21 ` [PATCH 4/8] arm64: dts: rockchip: add the internal audio codec luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-08 16:36   ` Mark Brown
  2022-09-07 14:21 ` [PATCH 6/8] ASoC: audio-graph: let dai_link->init be overridable luca.ceresoli
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

There are two problems with the second parameter of
rockchip_i2s_tdm_set_sysclk():

 1. The second argument to a .set_sysclk() op is a clk_id, not a stream
    index, so it is incorrect to compare it with SNDRV_PCM_STREAM_PLAYBACK.

    Technically this code works correctly anyway because
    SNDRV_PCM_STREAM_PLAYBACK is defined as 0, which is also the clk_id for
    the mclk_tx as enforced by the device tree bindings. So this is a
    formal error, not triggering incorrect behaviour.

 2. The else branch will consider any nonzero value as "rx", while only
    value 1 should be allowed for the mclk_rx clock. This does trigger
    incorrect behaviour if passing clk_id not equal to 0 or 1.

Fix problem 1 by adding a new enum for the clock indexes as enforced in
device tree and replace accordingly:

 * stream -> clk_id
 * SNDRV_PCM_STREAM_PLAYBACK -> CLK_MCLK_TX (value 0)

Fix problem 2 by adding an 'else if' and returning error if clk_id is not 0
or 1.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 sound/soc/rockchip/rockchip_i2s_tdm.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index 2550bd2a5e78..4aa80fedb996 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -34,6 +34,9 @@
 #define TRCM_TX 1
 #define TRCM_RX 2
 
+/* Clock indexes as enforced by the DT bindings */
+enum { CLK_IDX_MCLK_TX, CLK_IDX_MCLK_RX };
+
 struct txrx_config {
 	u32 addr;
 	u32 reg;
@@ -969,7 +972,7 @@ static int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,
+static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
 				       unsigned int freq, int dir)
 {
 	struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai);
@@ -978,15 +981,18 @@ static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,
 	if (i2s_tdm->clk_trcm) {
 		i2s_tdm->mclk_tx_freq = freq;
 		i2s_tdm->mclk_rx_freq = freq;
+
+		dev_dbg(i2s_tdm->dev, "mclk freq: %u", freq);
 	} else {
-		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		if (clk_id == CLK_IDX_MCLK_TX)
 			i2s_tdm->mclk_tx_freq = freq;
-		else
+		else if (clk_id == CLK_IDX_MCLK_RX)
 			i2s_tdm->mclk_rx_freq = freq;
-	}
+		else
+			return -ENOTSUPP;
 
-	dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n",
-		stream ? "rx" : "tx", freq);
+		dev_dbg(i2s_tdm->dev, "mclk[%d] freq: %u", clk_id, freq);
+	}
 
 	return 0;
 }
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 6/8] ASoC: audio-graph: let dai_link->init be overridable
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
                   ` (4 preceding siblings ...)
  2022-09-07 14:21 ` [PATCH 5/8] ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk() luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-07 14:21 ` [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver luca.ceresoli
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

We can already override dai_link->ops via a custom pointer in
asoc_simple_priv. Do the same for dai_link->init.

This is needed for a card that need to call .set_sysclk multiple times to
initialize more than one clock. The current code does not allow to do it
cleanly.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 include/sound/simple_card_utils.h    | 1 +
 sound/soc/generic/audio-graph-card.c | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index a0b827f0c2f6..60dab5f68f5e 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -75,6 +75,7 @@ struct asoc_simple_priv {
 	struct snd_soc_dai_link_component dummy;
 	struct snd_soc_codec_conf *codec_conf;
 	struct gpio_desc *pa_gpio;
+	int (*init)(struct snd_soc_pcm_runtime *rtd);
 	const struct snd_soc_ops *ops;
 	unsigned int dpcm_selectable:1;
 	unsigned int force_dpcm:1;
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index b327372f2e4a..38c05eb1c650 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -263,6 +263,8 @@ static int graph_link_init(struct asoc_simple_priv *priv,
 
 	dai_link->init		= asoc_simple_dai_init;
 	dai_link->ops		= &graph_ops;
+	if (priv->init)
+		dai_link->init	= priv->init;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
 
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
                   ` (5 preceding siblings ...)
  2022-09-07 14:21 ` [PATCH 6/8] ASoC: audio-graph: let dai_link->init be overridable luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-07 19:53   ` kernel test robot
                     ` (3 more replies)
  2022-09-07 14:21 ` [PATCH 8/8] ASoC: rockchip: add new RK3308 sound card luca.ceresoli
  2022-09-07 15:41 ` [PATCH 0/8] Add support for the internal RK3308 audio codec Mark Brown
  8 siblings, 4 replies; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

Add driver for the internal audio codec of the Rockchip RK3308 SoC.

Initially based on the vendor kernel driver [0], with lots of cleanups,
fixes, improvements and removal of some features.

[0] https://github.com/rockchip-linux/kernel/blob/develop-4.19/sound/soc/codecs/rk3308_codec.c

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 MAINTAINERS                     |    2 +
 sound/soc/codecs/Kconfig        |   11 +
 sound/soc/codecs/Makefile       |    2 +
 sound/soc/codecs/rk3308_codec.c | 2122 +++++++++++++++++++++++++++++++
 sound/soc/codecs/rk3308_codec.h |  648 ++++++++++
 5 files changed, 2785 insertions(+)
 create mode 100644 sound/soc/codecs/rk3308_codec.c
 create mode 100644 sound/soc/codecs/rk3308_codec.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 079bdd95dc49..fb2a0a6e3c1f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17593,6 +17593,8 @@ M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
 F:	include/dt-bindings/sound/rockchip,rk3308-codec.h
+F:	sound/soc/codecs/rk3308_codec.c
+F:	sound/soc/codecs/rk3308_codec.h
 
 ROCKCHIP RK3308 SOUND CARD DRIVER
 M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c7d83fe999e9..e05b084308f4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -164,6 +164,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_PCM5102A
 	imply SND_SOC_PCM512x_I2C
 	imply SND_SOC_PCM512x_SPI
+	imply SND_SOC_RK3308
 	imply SND_SOC_RK3328
 	imply SND_SOC_RK817
 	imply SND_SOC_RT274
@@ -1191,6 +1192,16 @@ config SND_SOC_PCM512x_SPI
 	select SND_SOC_PCM512x
 	select REGMAP_SPI
 
+config SND_SOC_RK3308
+	tristate "Rockchip RK3308 audio CODEC"
+	select REGMAP_MMIO
+	help
+	  This is a device driver for the audio codec embedded in the
+	  Rockchip RK3308 SoC.
+
+	  It has 8 24-bit ADCs and 2 24-bit DACs. The maximum supported
+	  sampling rate is 192 kHz.
+
 config SND_SOC_RK3328
 	tristate "Rockchip RK3328 audio CODEC"
 	select REGMAP_MMIO
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 16a01635dd04..8f6a473c2467 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -181,6 +181,7 @@ snd-soc-pcm5102a-objs := pcm5102a.o
 snd-soc-pcm512x-objs := pcm512x.o
 snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
+snd-soc-rk3308-objs := rk3308_codec.o
 snd-soc-rk3328-objs := rk3328_codec.o
 snd-soc-rk817-objs := rk817_codec.o
 snd-soc-rl6231-objs := rl6231.o
@@ -534,6 +535,7 @@ obj-$(CONFIG_SND_SOC_PCM5102A)	+= snd-soc-pcm5102a.o
 obj-$(CONFIG_SND_SOC_PCM512x)	+= snd-soc-pcm512x.o
 obj-$(CONFIG_SND_SOC_PCM512x_I2C)	+= snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)	+= snd-soc-pcm512x-spi.o
+obj-$(CONFIG_SND_SOC_RK3308)	+= snd-soc-rk3308.o
 obj-$(CONFIG_SND_SOC_RK3328)	+= snd-soc-rk3328.o
 obj-$(CONFIG_SND_SOC_RK817)	+= snd-soc-rk817.o
 obj-$(CONFIG_SND_SOC_RL6231)	+= snd-soc-rl6231.o
diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c
new file mode 100644
index 000000000000..2c001689dce7
--- /dev/null
+++ b/sound/soc/codecs/rk3308_codec.c
@@ -0,0 +1,2122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Rockchip RK3308 internal audio codec driver
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
+ * Copyright (c) 2022, Vivax-Metrotech Ltd
+ */
+
+#include <dt-bindings/sound/rockchip,rk3308-codec.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/util_macros.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "rk3308_codec.h"
+
+#define ADC_LR_GROUP_MAX		4
+#define RK3308_N_MICBIAS_MAX		2
+
+#define GRF_CHIP_ID			0x800
+
+#define ACODEC_VERSION_A		0xa
+#define ACODEC_VERSION_B		0xb
+
+enum {
+	ADC_GRP0_MICIN = 0,
+	ADC_GRP0_LINEIN
+};
+
+enum {
+	DAC_LINEOUT = 0,
+	DAC_HPOUT = 1,
+	DAC_LINEOUT_HPOUT = 11,
+};
+
+struct rk3308_codec_priv {
+	const struct device *dev;
+	struct regmap *regmap;
+	struct regmap *grf;
+	struct reset_control *reset;
+	struct clk *pclk;
+	struct clk *mclk_rx;
+	struct clk *mclk_tx;
+	struct snd_soc_component *component;
+	u32 codec_ver;
+
+	/*
+	 * To select ADCs for groups:
+	 *
+	 * grp 0 -- select ADC1 / ADC2
+	 * grp 1 -- select ADC3 / ADC4
+	 * grp 2 -- select ADC5 / ADC6
+	 * grp 3 -- select ADC7 / ADC8
+	 */
+	u32 used_adc_grps;
+	int adc_grp0_using_linein;
+	/* 0: line out, 1: hp out, 11: lineout and hpout */
+	int dac_output;
+
+	/* AGC L/R Off/on */
+	unsigned int agc_l[ADC_LR_GROUP_MAX];
+	unsigned int agc_r[ADC_LR_GROUP_MAX];
+
+	/* Only hpout do fade-in and fade-out */
+	unsigned int hpout_l_dgain;
+	unsigned int hpout_r_dgain;
+
+	bool micbias_enabled[RK3308_N_MICBIAS_MAX];
+	u32 micbias_avdd_mult;
+};
+
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_gain_tlv,     -1800, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_max_gain_tlv, -1350, 600, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_min_gain_tlv, -1800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv,	 -1800, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv,	 -3900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv,	  -600, 600, 0);
+
+static const DECLARE_TLV_DB_RANGE(rk3308_codec_dac_lineout_gain_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-300, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-150, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(0,    0, 0),
+);
+
+static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_agc_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_micbias_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol);
+static int rk3308_codec_micbias_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol);
+
+static const char *offon_text[2] = {
+	[0] = "Off",
+	[1] = "On",
+};
+
+static const struct soc_enum rk3308_micbias_enum[] = {
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(offon_text), offon_text),
+};
+
+/* ALC AGC Switch */
+static const struct soc_enum rk3308_agc_enum_array[] = {
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(offon_text), offon_text),
+	SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(offon_text), offon_text),
+};
+
+static const unsigned int agc_approx_rate[] = {
+	96000, 48000, 44100, 32000, 24000, 16000, 12000, 8000
+};
+
+static const struct snd_kcontrol_new rk3308_codec_controls[] = {
+	/* Despite the register names, these set the gain when AGC is OFF */
+	SOC_SINGLE_RANGE_TLV("MIC1 Capture Volume",
+			     RK3308_ADC_ANA_CON03(0),
+			     RK3308_ADC_CH1_ALC_GAIN_SFT,
+			     RK3308_ADC_CH1_ALC_GAIN_MIN,
+			     RK3308_ADC_CH1_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC2 Capture Volume",
+			     RK3308_ADC_ANA_CON04(0),
+			     RK3308_ADC_CH2_ALC_GAIN_SFT,
+			     RK3308_ADC_CH2_ALC_GAIN_MIN,
+			     RK3308_ADC_CH2_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC3 Capture Volume",
+			     RK3308_ADC_ANA_CON03(1),
+			     RK3308_ADC_CH1_ALC_GAIN_SFT,
+			     RK3308_ADC_CH1_ALC_GAIN_MIN,
+			     RK3308_ADC_CH1_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC4 Capture Volume",
+			     RK3308_ADC_ANA_CON04(1),
+			     RK3308_ADC_CH2_ALC_GAIN_SFT,
+			     RK3308_ADC_CH2_ALC_GAIN_MIN,
+			     RK3308_ADC_CH2_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC5 Capture Volume",
+			     RK3308_ADC_ANA_CON03(2),
+			     RK3308_ADC_CH1_ALC_GAIN_SFT,
+			     RK3308_ADC_CH1_ALC_GAIN_MIN,
+			     RK3308_ADC_CH1_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC6 Capture Volume",
+			     RK3308_ADC_ANA_CON04(2),
+			     RK3308_ADC_CH2_ALC_GAIN_SFT,
+			     RK3308_ADC_CH2_ALC_GAIN_MIN,
+			     RK3308_ADC_CH2_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC7 Capture Volume",
+			     RK3308_ADC_ANA_CON03(3),
+			     RK3308_ADC_CH1_ALC_GAIN_SFT,
+			     RK3308_ADC_CH1_ALC_GAIN_MIN,
+			     RK3308_ADC_CH1_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC8 Capture Volume",
+			     RK3308_ADC_ANA_CON04(3),
+			     RK3308_ADC_CH2_ALC_GAIN_SFT,
+			     RK3308_ADC_CH2_ALC_GAIN_MIN,
+			     RK3308_ADC_CH2_ALC_GAIN_MAX,
+			     0, rk3308_codec_adc_alc_gain_tlv),
+	SOC_SINGLE("MIC1 Capture Switch", RK3308_ADC_DIG_CON03(0), RK3308_ADC_L_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC2 Capture Switch", RK3308_ADC_DIG_CON03(0), RK3308_ADC_R_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC3 Capture Switch", RK3308_ADC_DIG_CON03(1), RK3308_ADC_L_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC4 Capture Switch", RK3308_ADC_DIG_CON03(1), RK3308_ADC_R_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC5 Capture Switch", RK3308_ADC_DIG_CON03(2), RK3308_ADC_L_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC6 Capture Switch", RK3308_ADC_DIG_CON03(2), RK3308_ADC_R_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC7 Capture Switch", RK3308_ADC_DIG_CON03(3), RK3308_ADC_L_CH_BIST_SFT, 1, 1),
+	SOC_SINGLE("MIC8 Capture Switch", RK3308_ADC_DIG_CON03(3), RK3308_ADC_R_CH_BIST_SFT, 1, 1),
+
+	SOC_ENUM_EXT("MIC1 AGC Capture Switch", rk3308_agc_enum_array[0],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC2 AGC Capture Switch", rk3308_agc_enum_array[1],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC3 AGC Capture Switch", rk3308_agc_enum_array[2],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC4 AGC Capture Switch", rk3308_agc_enum_array[3],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC5 AGC Capture Switch", rk3308_agc_enum_array[4],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC6 AGC Capture Switch", rk3308_agc_enum_array[5],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC7 AGC Capture Switch", rk3308_agc_enum_array[6],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+	SOC_ENUM_EXT("MIC8 AGC Capture Switch", rk3308_agc_enum_array[7],
+		     rk3308_codec_agc_get, rk3308_codec_agc_put),
+
+	SOC_SINGLE_RANGE_TLV("MIC1 AGC Max Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(0),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC2 AGC Max Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(0),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC3 AGC Max Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(1),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC4 AGC Max Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(1),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC5 AGC Max Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(2),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC6 AGC Max Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(2),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC7 AGC Max Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(3),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC8 AGC Max Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(3),
+			     RK3308_AGC_MAX_GAIN_PGA_SFT,
+			     RK3308_AGC_MAX_GAIN_PGA_MIN,
+			     RK3308_AGC_MAX_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_max_gain_tlv),
+
+	SOC_SINGLE_RANGE_TLV("MIC1 AGC Min Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(0),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC2 AGC Min Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(0),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC3 AGC Min Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(1),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC4 AGC Min Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(1),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC5 AGC Min Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(2),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC6 AGC Min Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(2),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC7 AGC Min Capture Volume",
+			     RK3308_ALC_L_DIG_CON09(3),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC8 AGC Min Capture Volume",
+			     RK3308_ALC_R_DIG_CON09(3),
+			     RK3308_AGC_MIN_GAIN_PGA_SFT,
+			     RK3308_AGC_MIN_GAIN_PGA_MIN,
+			     RK3308_AGC_MIN_GAIN_PGA_MAX,
+			     0, rk3308_codec_alc_agc_grp_min_gain_tlv),
+
+	SOC_SINGLE_RANGE_TLV("MIC1 PGA Gain Capture Volume",
+			     RK3308_ALC_L_DIG_CON03(0),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC2 PGA Gain Capture Volume",
+			     RK3308_ALC_R_DIG_CON03(0),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC3 PGA Gain Capture Volume",
+			     RK3308_ALC_L_DIG_CON03(1),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC4 PGA Gain Capture Volume",
+			     RK3308_ALC_R_DIG_CON03(1),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC5 PGA Gain Capture Volume",
+			     RK3308_ALC_L_DIG_CON03(2),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC6 PGA Gain Capture Volume",
+			     RK3308_ALC_R_DIG_CON03(2),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC7 PGA Gain Capture Volume",
+			     RK3308_ALC_L_DIG_CON03(3),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC8 PGA Gain Capture Volume",
+			     RK3308_ALC_R_DIG_CON03(3),
+			     RK3308_AGC_PGA_GAIN_SFT,
+			     RK3308_AGC_PGA_GAIN_MIN,
+			     RK3308_AGC_PGA_GAIN_MAX,
+			     0, rk3308_codec_alc_agc_grp_gain_tlv),
+
+	SOC_ENUM_EXT("MICBIAS1 Capture Switch", rk3308_micbias_enum[0],
+		     rk3308_codec_micbias_get, rk3308_codec_micbias_put),
+	SOC_ENUM_EXT("MICBIAS2 Capture Switch", rk3308_micbias_enum[1],
+		     rk3308_codec_micbias_get, rk3308_codec_micbias_put),
+
+	SOC_SINGLE_TLV("Line Out Left Playback Volume",
+		       RK3308_DAC_ANA_CON04,
+		       RK3308_DAC_L_LINEOUT_GAIN_SFT,
+		       RK3308_DAC_L_LINEOUT_GAIN_MAX,
+		       0, rk3308_codec_dac_lineout_gain_tlv),
+	SOC_SINGLE_TLV("Line Out Right Playback Volume",
+		       RK3308_DAC_ANA_CON04,
+		       RK3308_DAC_R_LINEOUT_GAIN_SFT,
+		       RK3308_DAC_R_LINEOUT_GAIN_MAX,
+		       0, rk3308_codec_dac_lineout_gain_tlv),
+
+	SOC_SINGLE_EXT_TLV("Headphone Left Playback Volume",
+			   RK3308_DAC_ANA_CON05,
+			   RK3308_DAC_L_HPOUT_GAIN_SFT,
+			   RK3308_DAC_L_HPOUT_GAIN_MAX,
+			   0,
+			   rk3308_codec_hpout_l_get_tlv,
+			   rk3308_codec_hpout_l_put_tlv,
+			   rk3308_codec_dac_hpout_gain_tlv),
+	SOC_SINGLE_EXT_TLV("Headphone Right Playback Volume",
+			   RK3308_DAC_ANA_CON06,
+			   RK3308_DAC_R_HPOUT_GAIN_SFT,
+			   RK3308_DAC_R_HPOUT_GAIN_MAX,
+			   0,
+			   rk3308_codec_hpout_r_get_tlv,
+			   rk3308_codec_hpout_r_put_tlv,
+			   rk3308_codec_dac_hpout_gain_tlv),
+
+	SOC_SINGLE_RANGE_TLV("Headphone Mix Left Playback Volume",
+			     RK3308_DAC_ANA_CON12,
+			     RK3308_DAC_L_HPMIX_GAIN_SFT,
+			     RK3308_DAC_L_HPMIX_GAIN_MIN,
+			     RK3308_DAC_L_HPMIX_GAIN_MAX,
+			     0, rk3308_codec_dac_hpmix_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("Headphone Mix Right Playback Volume",
+			     RK3308_DAC_ANA_CON12,
+			     RK3308_DAC_R_HPMIX_GAIN_SFT,
+			     RK3308_DAC_R_HPMIX_GAIN_MIN,
+			     RK3308_DAC_R_HPMIX_GAIN_MAX,
+			     0, rk3308_codec_dac_hpmix_gain_tlv),
+};
+
+static void rk3308_codec_update_zerocross(struct rk3308_codec_priv *rk3308)
+{
+	unsigned int agc_on, value;
+	int grp;
+
+	/* 14: enable zero-cross detection if AGC enabled, else AGC won't work */
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), &agc_on);
+		value = (agc_on & RK3308_AGC_FUNC_SEL_MSK) ? RK3308_ADC_CH1_ZEROCROSS_DET_EN : 0;
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				   RK3308_ADC_CH1_ZEROCROSS_DET_EN, value);
+
+		regmap_read(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), &agc_on);
+		value = (agc_on & RK3308_AGC_FUNC_SEL_MSK) ? RK3308_ADC_CH2_ZEROCROSS_DET_EN : 0;
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				   RK3308_ADC_CH2_ZEROCROSS_DET_EN, value);
+	}
+}
+
+static int rk3308_codec_agc_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	snd_BUG_ON(e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1);
+
+	if (e->shift_l)
+		ucontrol->value.integer.value[0] = rk3308->agc_r[e->reg];
+	else
+		ucontrol->value.integer.value[0] = rk3308->agc_l[e->reg];
+
+	return 0;
+}
+
+static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int value = ucontrol->value.integer.value[0];
+	int grp = e->reg;
+
+	snd_BUG_ON(e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1);
+
+	if (value) {
+		/* ALC AGC On */
+		if (e->shift_l) {
+			/* ALC AGC Right On */
+			regmap_set_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp),
+					RK3308_AGC_FUNC_SEL_MSK);
+			regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp),
+					RK3308_ADC_ALCR_CON_GAIN_PGAR_EN);
+
+			rk3308->agc_r[e->reg] = 1;
+		} else {
+			/* ALC AGC Left On */
+			regmap_set_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp),
+					RK3308_AGC_FUNC_SEL_MSK);
+			regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp),
+					RK3308_ADC_ALCL_CON_GAIN_PGAL_EN);
+
+			rk3308->agc_l[e->reg] = 1;
+		}
+	} else {
+		/* ALC AGC Off */
+		if (e->shift_l) {
+			/* ALC AGC Right Off */
+			regmap_clear_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp),
+					  RK3308_AGC_FUNC_SEL_MSK);
+			regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp),
+					  RK3308_ADC_ALCR_CON_GAIN_PGAR_EN);
+
+			rk3308->agc_r[e->reg] = 0;
+		} else {
+			/* ALC AGC Left Off */
+			regmap_clear_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp),
+					  RK3308_AGC_FUNC_SEL_MSK);
+			regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp),
+					  RK3308_ADC_ALCL_CON_GAIN_PGAL_EN);
+
+			rk3308->agc_l[e->reg] = 0;
+		}
+	}
+
+	rk3308_codec_update_zerocross(rk3308);
+
+	return 0;
+}
+
+/*
+ * Disable all BIAS circuits, but do not change the driver status (rk3308->micbias_*).
+ * Useful e.g. for suspend.
+ */
+static void rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308)
+{
+	regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), RK3308_ADC_MIC_BIAS_BUF_EN);
+	regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), RK3308_ADC_MIC_BIAS_BUF_EN);
+	regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), RK3308_ADC_MICBIAS_CURRENT_EN);
+}
+
+/*
+ * Enable or disable MIC BIAS HW components based on the status (rk3308->micbias_*).
+ */
+static void rk3308_codec_micbias_apply(struct rk3308_codec_priv *rk3308)
+{
+	bool any_micbias_enabled = (rk3308->micbias_enabled[0] || rk3308->micbias_enabled[1]);
+	unsigned int i;
+
+	/*
+	 * MICBIAS programming sequence from TRM:
+	 *
+	 * - Enable MICBIAS:
+	 *   1. Configure ACODEC_ADC_ANA_CON7[2:0] (AVDD voltage multiplier)
+	 *   2. Wait until the VCMH stable
+	 *   3. Configure ACODEC_ADC_ANA_CON8[4] to 1 (enable current source)
+	 *   4. Configure the (ADC_ANA_CON7+{0x40|0x80})[3] (enable MICBIAS{1|2})
+	 *
+	 * - Disable MICBIAS:
+	 *   1. Clear (ADC_ANA_CON7+{0x40|0x80})[3] (disable MICBIAS{1|2})
+	 *   2. Clear ACODEC_ADC_ANA_CON8[4] (disenable current source)
+	 */
+
+	if (any_micbias_enabled) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0),
+				   RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK,
+				   rk3308->micbias_avdd_mult);
+
+		/* Wait until the VCMH keep stable */
+		msleep(20);	/* estimated value */
+
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0),
+				RK3308_ADC_MICBIAS_CURRENT_EN);
+	}
+
+	for (i = 0; i < RK3308_N_MICBIAS_MAX; i++)
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(i + 1),
+				   RK3308_ADC_MIC_BIAS_BUF_EN,
+				   rk3308->micbias_enabled[i] ? RK3308_ADC_MIC_BIAS_BUF_EN : 0);
+
+	if (!any_micbias_enabled)
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0),
+				  RK3308_ADC_MICBIAS_CURRENT_EN);
+}
+
+static int rk3308_codec_micbias_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	struct soc_enum *priv = (struct soc_enum *)kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = rk3308->micbias_enabled[priv->reg];
+
+	return 0;
+}
+
+static int rk3308_codec_micbias_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	struct soc_enum *priv = (struct soc_enum *)kcontrol->private_value;
+	unsigned int on = ucontrol->value.integer.value[0];
+
+	rk3308->micbias_enabled[priv->reg] = on;
+
+	rk3308_codec_micbias_apply(rk3308);
+
+	return 0;
+}
+
+static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	return snd_soc_get_volsw_range(kcontrol, ucontrol);
+}
+
+static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	unsigned int dgain = ucontrol->value.integer.value[0];
+
+	rk3308->hpout_l_dgain = dgain;
+
+	return snd_soc_put_volsw_range(kcontrol, ucontrol);
+}
+
+static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	return snd_soc_get_volsw_range(kcontrol, ucontrol);
+}
+
+static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	unsigned int dgain = ucontrol->value.integer.value[0];
+
+	rk3308->hpout_r_dgain = dgain;
+
+	return snd_soc_put_volsw_range(kcontrol, ucontrol);
+}
+
+static int rk3308_codec_reset(struct snd_soc_component *component)
+{
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	reset_control_assert(rk3308->reset);
+	usleep_range(10000, 11000);     /* estimated value */
+	reset_control_deassert(rk3308->reset);
+
+	regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00);
+	usleep_range(10000, 11000);     /* estimated value */
+	regmap_write(rk3308->regmap, RK3308_GLB_CON,
+		     RK3308_SYS_WORK |
+		     RK3308_DAC_DIG_WORK |
+		     RK3308_ADC_DIG_WORK);
+
+	return 0;
+}
+
+static int rk3308_codec_adc_dig_reset(struct rk3308_codec_priv *rk3308)
+{
+	regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+	usleep_range(50, 100);
+	regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+	return 0;
+}
+
+static int rk3308_codec_dac_dig_reset(struct rk3308_codec_priv *rk3308)
+{
+	regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_DAC_DIG_WORK);
+	usleep_range(10000, 11000);
+	regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_DAC_DIG_WORK);
+
+	return 0;
+}
+
+static int rk3308_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		rk3308_codec_micbias_apply(rk3308);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		rk3308_codec_micbias_disable(rk3308);
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+static int rk3308_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	const unsigned int inv_bits = fmt & SND_SOC_DAIFMT_INV_MASK;
+	const bool inv_bitclk =
+		(inv_bits & SND_SOC_DAIFMT_IB_IF) ||
+		(inv_bits & SND_SOC_DAIFMT_IB_NF);
+	const bool inv_frmclk =
+		(inv_bits & SND_SOC_DAIFMT_IB_IF) ||
+		(inv_bits & SND_SOC_DAIFMT_NB_IF);
+
+	unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
+	int grp, is_master;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	case SND_SOC_DAIFMT_CBP_CFP:
+		adc_aif2 |= RK3308_ADC_IO_MODE_MASTER;
+		adc_aif2 |= RK3308_ADC_MODE_MASTER;
+		dac_aif2 |= RK3308_DAC_IO_MODE_MASTER;
+		dac_aif2 |= RK3308_DAC_MODE_MASTER;
+		is_master = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		adc_aif1 |= RK3308_ADC_I2S_MODE_PCM;
+		dac_aif1 |= RK3308_DAC_I2S_MODE_PCM;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		adc_aif1 |= RK3308_ADC_I2S_MODE_I2S;
+		dac_aif1 |= RK3308_DAC_I2S_MODE_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		adc_aif1 |= RK3308_ADC_I2S_MODE_RJ;
+		dac_aif1 |= RK3308_DAC_I2S_MODE_RJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		adc_aif1 |= RK3308_ADC_I2S_MODE_LJ;
+		dac_aif1 |= RK3308_DAC_I2S_MODE_LJ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (inv_bitclk) {
+		adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL;
+		dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL;
+	}
+
+	if (inv_frmclk) {
+		adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL;
+		dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL;
+	}
+
+	/*
+	 * Hold ADC Digital registers start at master mode
+	 *
+	 * There are 8 ADCs and use the same SCLK and LRCK internal for master
+	 * mode, We need to make sure that they are in effect at the same time,
+	 * otherwise they will cause the abnormal clocks.
+	 */
+	if (is_master)
+		regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+	for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
+				   RK3308_ADC_I2S_LRC_POL_REVERSAL |
+				   RK3308_ADC_I2S_MODE_MSK,
+				   adc_aif1);
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp),
+				   RK3308_ADC_IO_MODE_MASTER |
+				   RK3308_ADC_MODE_MASTER |
+				   RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL,
+				   adc_aif2);
+	}
+
+	/* Hold ADC Digital registers end at master mode */
+	if (is_master)
+		regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01,
+			   RK3308_DAC_I2S_LRC_POL_REVERSAL |
+			   RK3308_DAC_I2S_MODE_MSK,
+			   dac_aif1);
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02,
+			   RK3308_DAC_IO_MODE_MASTER |
+			   RK3308_DAC_MODE_MASTER |
+			   RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL,
+			   dac_aif2);
+
+	return 0;
+}
+
+static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308,
+				       struct snd_pcm_hw_params *params)
+{
+	unsigned int dac_aif1 = 0;
+
+	/* Clear the status of DAC DIG Digital reigisters */
+	rk3308_codec_dac_dig_reset(rk3308);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01,
+			   RK3308_DAC_I2S_VALID_LEN_MSK, dac_aif1);
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, RK3308_DAC_I2S_WORK);
+
+	return 0;
+}
+
+static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308,
+				       struct snd_pcm_hw_params *params)
+{
+	unsigned int adc_aif1 = 0;
+	int grp;
+
+	/* Clear the status of ADC DIG Digital reigisters */
+	rk3308_codec_adc_dig_reset(rk3308);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_channels(params)) {
+	case 1:
+		adc_aif1 |= RK3308_ADC_I2S_MONO;
+		break;
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
+				   RK3308_ADC_I2S_VALID_LEN_MSK | RK3308_ADC_I2S_MONO, adc_aif1);
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), RK3308_ADC_I2S_WORK);
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_agc_dig_config(struct rk3308_codec_priv *rk3308,
+				       struct snd_pcm_hw_params *params)
+{
+	int grp;
+
+	unsigned int value = find_closest_descending(params_rate(params),
+					  agc_approx_rate, ARRAY_SIZE(agc_approx_rate));
+
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON04(grp),
+				   RK3308_AGC_APPROX_RATE_MSK, value);
+		regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON04(grp),
+				   RK3308_AGC_APPROX_RATE_MSK, value);
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_update_adc_grps(struct rk3308_codec_priv *rk3308,
+					struct snd_pcm_hw_params *params)
+{
+	switch (params_channels(params)) {
+	case 1:
+		rk3308->used_adc_grps = 1;
+		break;
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+		rk3308->used_adc_grps = params_channels(params) / 2;
+		break;
+	default:
+		dev_err(rk3308->dev, "Invalid channels: %d\n",
+			params_channels(params));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rk3308_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		int dgain;
+
+		if (mute) {
+			for (dgain = 0x2; dgain <= 0x7; dgain++) {
+				/*
+				 * Keep the max -> min digital CIC interpolation
+				 * filter gain step by step.
+				 *
+				 * loud: 0x2; whisper: 0x7
+				 */
+				regmap_update_bits(rk3308->regmap,
+						   RK3308_DAC_DIG_CON04,
+						   RK3308_DAC_CIC_IF_GAIN_MSK,
+						   dgain);
+				usleep_range(200, 300);  /* estimated value */
+			}
+		} else {
+			for (dgain = 0x7; dgain >= 0x2; dgain--) {
+				/*
+				 * Keep the min -> max digital CIC interpolation
+				 * filter gain step by step
+				 *
+				 * loud: 0x2; whisper: 0x7
+				 */
+				regmap_update_bits(rk3308->regmap,
+						   RK3308_DAC_DIG_CON04,
+						   RK3308_DAC_CIC_IF_GAIN_MSK,
+						   dgain);
+				usleep_range(200, 300);  /* estimated value */
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_digital_fadein(struct rk3308_codec_priv *rk3308)
+{
+	unsigned int dgain, dgain_ref;
+
+	if (rk3308->hpout_l_dgain != rk3308->hpout_r_dgain) {
+		pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n",
+			rk3308->hpout_l_dgain, rk3308->hpout_r_dgain);
+		dgain_ref = min(rk3308->hpout_l_dgain, rk3308->hpout_r_dgain);
+	} else {
+		dgain_ref = rk3308->hpout_l_dgain;
+	}
+
+	/*
+	 * We'd better change the gain of the left and right channels
+	 * at the same time to avoid different listening
+	 */
+	for (dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39;
+	     dgain <= dgain_ref; dgain++) {
+		/* Step 02 decrease dgains for de-pop */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05,
+				   RK3308_DAC_L_HPOUT_GAIN_MSK,
+				   dgain);
+
+		/* Step 02 decrease dgains for de-pop */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06,
+				   RK3308_DAC_R_HPOUT_GAIN_MSK,
+				   dgain);
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_digital_fadeout(struct rk3308_codec_priv *rk3308)
+{
+	unsigned int l_dgain, r_dgain;
+
+	/*
+	 * Note. In the step2, adjusting the register step by step to
+	 * the appropriate value and taking 20ms as time step
+	 */
+	regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON05, &l_dgain);
+	l_dgain &= RK3308_DAC_L_HPOUT_GAIN_MSK;
+
+	regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON06, &r_dgain);
+	r_dgain &= RK3308_DAC_R_HPOUT_GAIN_MSK;
+
+	if (l_dgain != r_dgain) {
+		pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n",
+			l_dgain, r_dgain);
+		l_dgain = min(l_dgain, r_dgain);
+	}
+
+	/*
+	 * We'd better change the gain of the left and right channels
+	 * at the same time to avoid different listening
+	 */
+	while (l_dgain >= RK3308_DAC_L_HPOUT_GAIN_NDB_39) {
+		/* Step 02 decrease dgains for de-pop */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05,
+				   RK3308_DAC_L_HPOUT_GAIN_MSK,
+				   l_dgain);
+
+		/* Step 02 decrease dgains for de-pop */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06,
+				   RK3308_DAC_R_HPOUT_GAIN_MSK,
+				   l_dgain);
+
+		usleep_range(200, 300);  /* estimated value */
+
+		if (l_dgain == RK3308_DAC_L_HPOUT_GAIN_NDB_39)
+			break;
+
+		l_dgain--;
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308)
+{
+	/*
+	 * Note1. If the ACODEC_DAC_ANA_CON12[6] or ACODEC_DAC_ANA_CON12[2]
+	 * is set to 0x1, ignoring the step9~12.
+	 */
+
+	/*
+	 * Note2. If the ACODEC_ DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3]
+	 * is set to 0x1, the ADC0 or ADC1 should be enabled firstly, and
+	 * please refer to Enable ADC Configuration Standard Usage Flow(expect
+	 * step7~step9,step14).
+	 */
+
+	/*
+	 * Note3. If no opening the line out, ignoring the step6, step17 and
+	 * step19.
+	 */
+
+	/*
+	 * Note4. If no opening the headphone out, ignoring the step3,step7~8,
+	 * step16 and step18.
+	 */
+
+	/*
+	 * Note5. In the step18, adjust the register step by step to the
+	 * appropriate value and taking 10ms as one time step
+	 */
+
+	/*
+	 * 1. Set the ACODEC_DAC_ANA_CON0[0] to 0x1, to enable the current
+	 * source of DAC
+	 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON00,
+			RK3308_DAC_CURRENT_EN);
+
+	usleep_range(20, 40);
+
+	/*
+	 * 2. Set the ACODEC_DAC_ANA_CON1[6] and ACODEC_DAC_ANA_CON1[2] to 0x1,
+	 * to enable the reference voltage buffer
+	 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+			RK3308_DAC_BUF_REF_L_EN |
+			RK3308_DAC_BUF_REF_R_EN);
+
+	/* Waiting the stable reference voltage */
+	mdelay(1);
+
+	/* Step 03 */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+			   RK3308_DAC_HPOUT_POP_SOUND_L_MSK |
+			   RK3308_DAC_HPOUT_POP_SOUND_R_MSK,
+			   RK3308_DAC_HPOUT_POP_SOUND_L_WORK |
+			   RK3308_DAC_HPOUT_POP_SOUND_R_WORK);
+
+	usleep_range(20, 40);
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B &&
+	    (rk3308->dac_output == DAC_LINEOUT ||
+	     rk3308->dac_output == DAC_LINEOUT_HPOUT)) {
+		/* Step 04 */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15,
+				   RK3308_DAC_LINEOUT_POP_SOUND_L_MSK |
+				   RK3308_DAC_LINEOUT_POP_SOUND_R_MSK,
+				   RK3308_DAC_L_SEL_DC_FROM_INTERNAL |
+				   RK3308_DAC_R_SEL_DC_FROM_INTERNAL);
+
+		usleep_range(20, 40);
+	}
+
+	/* Step 05 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			RK3308_DAC_L_HPMIX_EN |
+			RK3308_DAC_R_HPMIX_EN);
+
+	/* Waiting the stable HPMIX */
+	mdelay(1);
+
+	/* Step 06. Reset HPMIX and recover HPMIX gains */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			  RK3308_DAC_L_HPMIX_WORK |
+			  RK3308_DAC_R_HPMIX_WORK);
+	usleep_range(50, 100);
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			RK3308_DAC_L_HPMIX_WORK |
+			RK3308_DAC_R_HPMIX_WORK);
+
+	usleep_range(20, 40);
+
+	if (rk3308->dac_output == DAC_LINEOUT ||
+	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
+		/* Step 07 */
+		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
+				RK3308_DAC_L_LINEOUT_EN |
+				RK3308_DAC_R_LINEOUT_EN);
+
+		usleep_range(20, 40);
+	}
+
+	if (rk3308->dac_output == DAC_HPOUT ||
+	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
+		/* Step 08 */
+		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
+				RK3308_DAC_L_HPOUT_EN |
+				RK3308_DAC_R_HPOUT_EN);
+
+		usleep_range(20, 40);
+
+		/* Step 09 */
+		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
+				RK3308_DAC_L_HPOUT_WORK |
+				RK3308_DAC_R_HPOUT_WORK);
+
+		usleep_range(20, 40);
+	}
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/* Step 10 */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15,
+				   RK3308_DAC_LINEOUT_POP_SOUND_L_MSK |
+				   RK3308_DAC_LINEOUT_POP_SOUND_R_MSK,
+				   RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL |
+				   RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL);
+
+		usleep_range(20, 40);
+	}
+
+	/* Step 11 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			RK3308_DAC_L_REF_EN | RK3308_DAC_R_REF_EN);
+
+	usleep_range(20, 40);
+
+	/* Step 12 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			RK3308_DAC_L_CLK_EN | RK3308_DAC_R_CLK_EN);
+
+	usleep_range(20, 40);
+
+	/* Step 13 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN);
+
+	usleep_range(20, 40);
+
+	/* Step 14 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			RK3308_DAC_L_DAC_WORK | RK3308_DAC_R_DAC_WORK);
+
+	usleep_range(20, 40);
+
+	/* Step 15 */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12,
+			   RK3308_DAC_L_HPMIX_SEL_MSK |
+			   RK3308_DAC_R_HPMIX_SEL_MSK,
+			   RK3308_DAC_L_HPMIX_I2S |
+			   RK3308_DAC_R_HPMIX_I2S);
+
+	usleep_range(20, 40);
+
+	/* Step 16 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			RK3308_DAC_L_HPMIX_UNMUTE | RK3308_DAC_R_HPMIX_UNMUTE);
+
+	usleep_range(20, 40);
+
+	/* Step 17: Put configuration HPMIX Gain */
+
+	if (rk3308->dac_output == DAC_HPOUT ||
+	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
+		/* Step 18 */
+		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
+				RK3308_DAC_L_HPOUT_UNMUTE | RK3308_DAC_R_HPOUT_UNMUTE);
+
+		usleep_range(20, 40);
+	}
+
+	if (rk3308->dac_output == DAC_LINEOUT ||
+	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
+		/* Step 19 */
+		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
+				RK3308_DAC_L_LINEOUT_UNMUTE | RK3308_DAC_R_LINEOUT_UNMUTE);
+		usleep_range(20, 40);
+	}
+
+	/* Step 20, put configuration HPOUT gain control */
+	/* Step 21, put configuration LINEOUT gain control */
+
+	if (rk3308->dac_output == DAC_HPOUT ||
+	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
+		/* Just for HPOUT */
+		rk3308_codec_digital_fadein(rk3308);
+	}
+
+	/* TODO: TRY TO TEST DRIVE STRENGTH */
+
+	return 0;
+}
+
+static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308)
+{
+	/*
+	 * Step 00 skipped. Keep the DAC channel work and input the mute signal.
+	 */
+
+	/* Step 01 skipped. May set the min gain for LINEOUT. */
+
+	/* Step 02 skipped. May set the min gain for HPOUT. */
+
+	if (rk3308->dac_output == DAC_HPOUT ||
+	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
+		/* Just for HPOUT */
+		rk3308_codec_digital_fadeout(rk3308);
+	}
+
+	/* Step 03 */
+	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			RK3308_DAC_L_HPMIX_UNMUTE | RK3308_DAC_R_HPMIX_UNMUTE);
+
+	/* Step 04 */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12,
+			   RK3308_DAC_L_HPMIX_SEL_MSK |
+			   RK3308_DAC_R_HPMIX_SEL_MSK,
+			   RK3308_DAC_L_HPMIX_NONE |
+			   RK3308_DAC_R_HPMIX_NONE);
+	/* Step 05 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
+			  RK3308_DAC_L_HPOUT_UNMUTE |
+			  RK3308_DAC_R_HPOUT_UNMUTE);
+
+	/* Step 06 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			  RK3308_DAC_L_DAC_WORK |
+			  RK3308_DAC_R_DAC_WORK);
+
+	/* Step 07 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
+			  RK3308_DAC_L_HPOUT_EN |
+			  RK3308_DAC_R_HPOUT_EN);
+
+	/* Step 08 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
+			  RK3308_DAC_L_LINEOUT_UNMUTE |
+			  RK3308_DAC_R_LINEOUT_UNMUTE);
+
+	/* Step 09 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
+			  RK3308_DAC_L_LINEOUT_EN |
+			  RK3308_DAC_R_LINEOUT_EN);
+
+	/* Step 10 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			  RK3308_DAC_L_HPMIX_EN |
+			  RK3308_DAC_R_HPMIX_EN);
+
+	/* Step 11 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			  RK3308_DAC_L_DAC_EN |
+			  RK3308_DAC_R_DAC_EN);
+
+	/* Step 12 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			  RK3308_DAC_L_CLK_EN |
+			  RK3308_DAC_R_CLK_EN);
+
+	/* Step 13 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+			  RK3308_DAC_L_REF_EN |
+			  RK3308_DAC_R_REF_EN);
+
+	/* Step 14 */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+			   RK3308_DAC_HPOUT_POP_SOUND_L_MSK |
+			   RK3308_DAC_HPOUT_POP_SOUND_R_MSK,
+			   RK3308_DAC_HPOUT_POP_SOUND_L_INIT |
+			   RK3308_DAC_HPOUT_POP_SOUND_R_INIT);
+
+	/* Step 15 */
+	if (rk3308->codec_ver == ACODEC_VERSION_B &&
+	    (rk3308->dac_output == DAC_LINEOUT ||
+	     rk3308->dac_output == DAC_LINEOUT_HPOUT)) {
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15,
+				   RK3308_DAC_LINEOUT_POP_SOUND_L_MSK |
+				   RK3308_DAC_LINEOUT_POP_SOUND_R_MSK,
+				   RK3308_DAC_L_SEL_DC_FROM_VCM |
+				   RK3308_DAC_R_SEL_DC_FROM_VCM);
+	}
+
+	/* Step 16 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+			  RK3308_DAC_BUF_REF_L_EN |
+			  RK3308_DAC_BUF_REF_R_EN);
+
+	/* Step 17 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON00,
+			  RK3308_DAC_CURRENT_EN);
+
+	/* Step 18 */
+	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
+			  RK3308_DAC_L_HPOUT_WORK |
+			  RK3308_DAC_R_HPOUT_WORK);
+
+	/* Step 19 */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
+			   RK3308_DAC_L_HPMIX_WORK |
+			   RK3308_DAC_R_HPMIX_WORK,
+			   RK3308_DAC_L_HPMIX_WORK |
+			   RK3308_DAC_R_HPMIX_WORK);
+
+	/* Step 20 skipped, may set the min gain for HPOUT. */
+
+	/*
+	 * Note2. If the ACODEC_DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3]
+	 * is set to 0x1, add the steps from the section Disable ADC
+	 * Configuration Standard Usage Flow after complete the step 19
+	 *
+	 * IF USING LINE-IN
+	 * rk3308_codec_adc_ana_disable(rk3308, type);
+	 */
+
+	return 0;
+}
+
+static int rk3308_codec_power_on(struct rk3308_codec_priv *rk3308)
+{
+	unsigned int v;
+
+	/* TRM Section 8.6.3 Power Up */
+
+	/* 0. Supply the power of digital part and reset the Audio Codec */
+
+	/*
+	 * 1. Configure ACODEC_DAC_ANA_CON1[1:0] and ACODEC_DAC_ANA_CON1[5:4]
+	 *    to 0x1, to setup dc voltage of the DAC channel output.
+	 */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+			   RK3308_DAC_HPOUT_POP_SOUND_L_MSK |
+			   RK3308_DAC_HPOUT_POP_SOUND_R_MSK,
+			   RK3308_DAC_HPOUT_POP_SOUND_L_INIT |
+			   RK3308_DAC_HPOUT_POP_SOUND_R_INIT);
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 2. Configure ACODEC_DAC_ANA_CON15[1:0] and
+		 *    ACODEC_DAC_ANA_CON15[5:4] to 0x1, to setup dc voltage of
+		 *    the DAC channel output.
+		 */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15,
+				   RK3308_DAC_LINEOUT_POP_SOUND_L_MSK |
+				   RK3308_DAC_LINEOUT_POP_SOUND_R_MSK,
+				   RK3308_DAC_L_SEL_DC_FROM_VCM |
+				   RK3308_DAC_R_SEL_DC_FROM_VCM);
+	}
+
+	/*
+	 * 3. Configure the register ACODEC_ADC_ANA_CON10[6:0] to 7’b000_0001.
+	 */
+	regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+			   RK3308_ADC_CURRENT_CHARGE_MSK,
+			   RK3308_ADC_SEL_I(0x1));
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 4. Configure the register ACODEC_ADC_ANA_CON14[3:0] to
+		 *    4’b0001.
+		 */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14,
+				   RK3308_DAC_CURRENT_CHARGE_MSK,
+				   RK3308_DAC_SEL_I(0x1));
+	}
+
+	/* 5. Supply the power of the analog part(AVDD,AVDDRV) */
+
+	/*
+	 * 6. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x1 to setup
+	 *    reference voltage
+	 */
+	regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), RK3308_ADC_REF_EN);
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 7. Configure the register ACODEC_ADC_ANA_CON14[4] to 0x1 to
+		 *    setup reference voltage
+		 */
+		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON14,
+				RK3308_DAC_VCM_LINEOUT_EN);
+	}
+
+	/*
+	 * 8. Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to
+	 *    0x7f step by step or configure the ACODEC_ADC_ANA_CON10[6:0] to
+	 *    0x7f directly. Here the slot time of the step is 200us.
+	 */
+	for (v = 0x1; v <= 0x7f; v++) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+				   RK3308_ADC_CURRENT_CHARGE_MSK, v);
+		usleep_range(200, 400);
+	}
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 9. Change the register ACODEC_ADC_ANA_CON14[3:0] from the 0x1
+		 *    to 0xf step by step or configure the
+		 *    ACODEC_ADC_ANA_CON14[3:0] to 0xf directly. Here the slot
+		 *    time of the step is 200us.
+		 */
+		for (v = 0x1; v <= 0xf; v++) {
+			regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14,
+					   RK3308_DAC_CURRENT_CHARGE_MSK, v);
+			usleep_range(200, 400);
+		}
+	}
+
+	/* 10. Wait until the voltage of VCM keeps stable at the AVDD/2 */
+	msleep(20);	/* estimated value */
+
+	/*
+	 * 11. Configure the register ACODEC_ADC_ANA_CON10[6:0] to the
+	 *     appropriate value (expect 0x0) for reducing power.
+	 */
+	regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+			   RK3308_ADC_CURRENT_CHARGE_MSK, 0x7c);
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 12. Configure the register ACODEC_DAC_ANA_CON14[6:0] to the
+		 *     appropriate value(expect 0x0) for reducing power.
+		 */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14,
+				   RK3308_DAC_CURRENT_CHARGE_MSK, 0xf);
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_power_off(struct rk3308_codec_priv *rk3308)
+{
+	unsigned int v;
+
+	/*
+	 * 0. Keep the power on and disable the DAC and ADC path according to
+	 *    the section power on configuration standard usage flow.
+	 */
+
+	/*
+	 * 1. Configure the register ACODEC_ADC_ANA_CON10[6:0] to 7’b000_0001.
+	 */
+	regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+			   RK3308_ADC_CURRENT_CHARGE_MSK,
+			   RK3308_ADC_SEL_I(0x1));
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 2. Configure the register ACODEC_DAC_ANA_CON14[3:0] to
+		 *    4’b0001.
+		 */
+		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14,
+				   RK3308_DAC_CURRENT_CHARGE_MSK,
+				   RK3308_DAC_SEL_I(0x1));
+	}
+
+	/* 3. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x0 */
+	regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), RK3308_ADC_REF_EN);
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/* 4. Configure the register ACODEC_DAC_ANA_CON14[7] to 0x0 */
+		regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON14,
+				  RK3308_DAC_VCM_LINEOUT_EN);
+	}
+
+	/*
+	 * 5. Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to 0x7f
+	 *    step by step or configure the ACODEC_ADC_ANA_CON10[6:0] to 0x7f
+	 *    directly. Here the slot time of the step is 200us.
+	 */
+	for (v = 0x1; v <= 0x7f; v++) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+				   RK3308_ADC_CURRENT_CHARGE_MSK, v);
+		usleep_range(200, 400);
+	}
+
+	if (rk3308->codec_ver == ACODEC_VERSION_B) {
+		/*
+		 * 6. Change the register ACODEC_DAC_ANA_CON14[3:0] from the 0x1
+		 *    to 0xf step by step or configure the
+		 *    ACODEC_DAC_ANA_CON14[3:0] to 0xf directly. Here the slot
+		 *    time of the step is 200us.
+		 */
+		for (v = 0x1; v <= 0x7f; v++) {
+			regmap_update_bits(rk3308->regmap,
+					   RK3308_ADC_ANA_CON10(0),
+					   RK3308_ADC_CURRENT_CHARGE_MSK, v);
+			usleep_range(200, 400);
+		}
+	}
+
+	/* 7. Wait until the voltage of VCM keeps stable at the AGND */
+	msleep(20);	/* estimated value */
+
+	/* 8. Power off the analog power supply */
+	/* 9. Power off the digital power supply */
+
+	/* Do something via hardware */
+
+	return 0;
+}
+
+static int rk3308_codec_adc_reinit_mics(struct rk3308_codec_priv *rk3308)
+{
+	int grp;
+
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		/* vendor step 1 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				  RK3308_ADC_CH1_ADC_WORK |
+				  RK3308_ADC_CH2_ADC_WORK);
+
+		/* vendor step 2 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				  RK3308_ADC_CH1_ALC_WORK |
+				  RK3308_ADC_CH2_ALC_WORK);
+
+		/* vendor step 3 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				  RK3308_ADC_CH1_MIC_WORK |
+				  RK3308_ADC_CH2_MIC_WORK);
+	}
+
+	usleep_range(200, 250);	/* estimated value */
+
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		/* vendor step 1 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				RK3308_ADC_CH1_ADC_WORK |
+				RK3308_ADC_CH2_ADC_WORK);
+
+		/* vendor step 2 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				RK3308_ADC_CH1_ALC_WORK |
+				RK3308_ADC_CH2_ALC_WORK);
+
+		/* vendor step 3 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				RK3308_ADC_CH1_MIC_WORK |
+				RK3308_ADC_CH2_MIC_WORK);
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308)
+{
+	int grp = 0;
+
+	/*
+	 * 1. Set the ACODEC_ADC_ANA_CON7[7:6] and ACODEC_ADC_ANA_CON7[5:4],
+	 * to select the line-in or microphone as input of ADC
+	 *
+	 * Note1. Please ignore the step1 for enabling ADC3, ADC4, ADC5,
+	 * ADC6, ADC7, and ADC8
+	 */
+	if (rk3308->adc_grp0_using_linein) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0),
+				   RK3308_ADC_CH1_IN_SEL_MSK |
+				   RK3308_ADC_CH2_IN_SEL_MSK,
+				   RK3308_ADC_CH1_IN_LINEIN |
+				   RK3308_ADC_CH2_IN_LINEIN);
+		grp++;
+	}
+
+	for (; grp < rk3308->used_adc_grps; grp++) {
+		regmap_update_bits(rk3308->regmap,
+				   RK3308_ADC_ANA_CON07(grp),
+				   RK3308_ADC_CH1_IN_SEL_MSK |
+				   RK3308_ADC_CH2_IN_SEL_MSK,
+				   RK3308_ADC_CH1_IN_MIC |
+				   RK3308_ADC_CH2_IN_MIC);
+	}
+
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		/*
+		 * 2. Set ACODEC_ADC_ANA_CON0[7] and [3] to 0x1, to end the mute station
+		 * of ADC, to enable the MIC module, to enable the reference voltage
+		 * buffer, and to end the initialization of MIC
+		 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				RK3308_ADC_CH1_MIC_UNMUTE |
+				RK3308_ADC_CH2_MIC_UNMUTE);
+
+		/*
+		 * 3. Set ACODEC_ADC_ANA_CON6[0] to 0x1, to enable the current source
+		 * of audio
+		 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp),
+				RK3308_ADC_CURRENT_EN);
+	}
+
+	/*
+	 * This is mainly used for BIST mode that wait ADCs are stable.
+	 *
+	 * By tested results, the type delay is >40us, but we need to leave
+	 * enough delay margin.
+	 */
+	usleep_range(400, 500);
+
+	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+		/* vendor step 4 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				RK3308_ADC_CH1_BUF_REF_EN |
+				RK3308_ADC_CH2_BUF_REF_EN);
+
+		/* vendor step 5 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				RK3308_ADC_CH1_MIC_EN |
+				RK3308_ADC_CH2_MIC_EN);
+
+		/* vendor step 6 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				RK3308_ADC_CH1_ALC_EN |
+				RK3308_ADC_CH2_ALC_EN);
+
+		/* vendor step 7 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				RK3308_ADC_CH1_CLK_EN |
+				RK3308_ADC_CH2_CLK_EN);
+
+		/* vendor step 8 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				RK3308_ADC_CH1_ADC_EN |
+				RK3308_ADC_CH2_ADC_EN);
+
+		/* vendor step 9 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				RK3308_ADC_CH1_ADC_WORK |
+				RK3308_ADC_CH2_ADC_WORK);
+
+		/* vendor step 10 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				RK3308_ADC_CH1_ALC_WORK |
+				RK3308_ADC_CH2_ALC_WORK);
+
+		/* vendor step 11 */
+		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				RK3308_ADC_CH1_MIC_WORK |
+				RK3308_ADC_CH2_MIC_WORK);
+	}
+
+	rk3308_codec_update_zerocross(rk3308);
+
+	return 0;
+}
+
+static int rk3308_codec_adc_ana_disable(struct rk3308_codec_priv *rk3308,
+					unsigned int num_grps)
+{
+	int grp;
+
+	for (grp = 0; grp < num_grps; grp++) {
+		/* vendor step 1 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				  RK3308_ADC_CH1_ZEROCROSS_DET_EN |
+				  RK3308_ADC_CH2_ZEROCROSS_DET_EN);
+
+		/* vendor step 2 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				  RK3308_ADC_CH1_ADC_EN |
+				  RK3308_ADC_CH2_ADC_EN);
+
+		/* vendor step 3 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				  RK3308_ADC_CH1_CLK_EN |
+				  RK3308_ADC_CH2_CLK_EN);
+
+		/* vendor step 4 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				  RK3308_ADC_CH1_ALC_EN |
+				  RK3308_ADC_CH2_ALC_EN);
+
+		/* vendor step 5 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				  RK3308_ADC_CH1_MIC_EN |
+				  RK3308_ADC_CH2_MIC_EN);
+
+		/* vendor step 6 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				  RK3308_ADC_CH1_BUF_REF_EN |
+				  RK3308_ADC_CH2_BUF_REF_EN);
+
+		/* vendor step 7 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp),
+				  RK3308_ADC_CURRENT_EN);
+
+		/* vendor step 8 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp),
+				  RK3308_ADC_CH1_ADC_WORK |
+				  RK3308_ADC_CH2_ADC_WORK);
+
+		/* vendor step 9 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+				  RK3308_ADC_CH1_ALC_WORK |
+				  RK3308_ADC_CH2_ALC_WORK);
+
+		/* vendor step 10 */
+		regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp),
+				  RK3308_ADC_CH1_MIC_WORK |
+				  RK3308_ADC_CH2_MIC_WORK);
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_open_capture(struct rk3308_codec_priv *rk3308)
+{
+	int grp = 0;
+
+	rk3308_codec_adc_ana_enable(rk3308);
+	rk3308_codec_adc_reinit_mics(rk3308);
+
+	if (rk3308->adc_grp0_using_linein) {
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(0),
+				   RK3308_ADC_L_CH_BIST_MSK,
+				   RK3308_ADC_L_CH_NORMAL_LEFT);
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(0),
+				   RK3308_ADC_R_CH_BIST_MSK,
+				   RK3308_ADC_R_CH_NORMAL_RIGHT);
+	} else {
+		for (grp = 0; grp < rk3308->used_adc_grps; grp++) {
+			regmap_update_bits(rk3308->regmap,
+					   RK3308_ADC_DIG_CON03(grp),
+					   RK3308_ADC_L_CH_BIST_MSK,
+					   RK3308_ADC_L_CH_NORMAL_LEFT);
+			regmap_update_bits(rk3308->regmap,
+					   RK3308_ADC_DIG_CON03(grp),
+					   RK3308_ADC_R_CH_BIST_MSK,
+					   RK3308_ADC_R_CH_NORMAL_RIGHT);
+		}
+	}
+
+	return 0;
+}
+
+static void rk3308_codec_adc_mclk_disable(struct rk3308_codec_priv *rk3308)
+{
+	regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_MCLK_GATING_MSK);
+}
+
+static void rk3308_codec_adc_mclk_enable(struct rk3308_codec_priv *rk3308)
+{
+	regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_MCLK_GATING_MSK);
+	usleep_range(20, 40);
+}
+
+static void rk3308_codec_dac_mclk_disable(struct rk3308_codec_priv *rk3308)
+{
+	regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_DAC_MCLK_GATING_MSK);
+}
+
+static void rk3308_codec_dac_mclk_enable(struct rk3308_codec_priv *rk3308)
+{
+	regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_DAC_MCLK_GATING_MSK);
+	usleep_range(20, 40);
+}
+
+static int rk3308_codec_llp_down(struct rk3308_codec_priv *rk3308)
+{
+	rk3308_codec_adc_mclk_disable(rk3308);
+	rk3308_codec_dac_mclk_disable(rk3308);
+
+	return 0;
+}
+
+static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* DAC only supports 2 channels */
+		rk3308_codec_dac_mclk_enable(rk3308);
+		rk3308_codec_dac_enable(rk3308);
+		rk3308_codec_dac_dig_config(rk3308, params);
+	} else {
+		rk3308_codec_micbias_apply(rk3308);
+		rk3308_codec_adc_mclk_enable(rk3308);
+		ret = rk3308_codec_update_adc_grps(rk3308, params);
+		if (ret < 0)
+			return ret;
+
+		rk3308_codec_open_capture(rk3308);
+		rk3308_codec_agc_dig_config(rk3308, params);
+		rk3308_codec_adc_dig_config(rk3308, params);
+	}
+
+	return 0;
+}
+
+static void rk3308_pcm_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		rk3308_codec_dac_disable(rk3308);
+		rk3308_codec_dac_mclk_disable(rk3308);
+	} else {
+		rk3308_codec_adc_ana_disable(rk3308, rk3308->used_adc_grps);
+		rk3308_codec_adc_mclk_disable(rk3308);
+		rk3308_codec_micbias_disable(rk3308);
+	}
+}
+
+static const struct snd_soc_dai_ops rk3308_dai_ops = {
+	.hw_params = rk3308_hw_params,
+	.set_fmt = rk3308_set_dai_fmt,
+	.mute_stream = rk3308_mute_stream,
+	.shutdown = rk3308_pcm_shutdown,
+};
+
+static struct snd_soc_dai_driver rk3308_dai[] = {
+	{
+		.name = "rk3308-hifi",
+		.id = RK3308_HIFI,
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S20_3LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_S32_LE),
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S20_3LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_S32_LE),
+		},
+		.ops = &rk3308_dai_ops,
+	},
+};
+
+static int rk3308_codec_default_gains(struct rk3308_codec_priv *rk3308)
+{
+	int grp;
+
+	for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+		/* 12: set ADC gain to 20 dB (recommended by TRM when using MIC input) */
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp),
+				   RK3308_ADC_CH1_MIC_GAIN_MSK |
+				   RK3308_ADC_CH2_MIC_GAIN_MSK,
+				   RK3308_ADC_CH1_MIC_GAIN_20DB |
+				   RK3308_ADC_CH2_MIC_GAIN_20DB);
+
+	/* vendor step 13, set ALC default gains */
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON03(grp),
+				   RK3308_ADC_CH1_ALC_GAIN_MSK,
+				   RK3308_ADC_CH1_ALC_GAIN_0DB);
+		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON04(grp),
+				   RK3308_ADC_CH2_ALC_GAIN_MSK,
+				   RK3308_ADC_CH2_ALC_GAIN_0DB);
+	}
+
+	/* Prepare DAC gains */
+	/* Step 15, set HPMIX default gains */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12,
+			   RK3308_DAC_L_HPMIX_GAIN_MSK |
+			   RK3308_DAC_R_HPMIX_GAIN_MSK,
+			   RK3308_DAC_L_HPMIX_GAIN_NDB_6 |
+			   RK3308_DAC_R_HPMIX_GAIN_NDB_6);
+
+	/* Step 18, set HPOUT default gains */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05,
+			   RK3308_DAC_L_HPOUT_GAIN_MSK,
+			   RK3308_DAC_L_HPOUT_GAIN_NDB_39);
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06,
+			   RK3308_DAC_R_HPOUT_GAIN_MSK,
+			   RK3308_DAC_R_HPOUT_GAIN_NDB_39);
+
+	/* Using the same gain to HPOUT LR channels */
+	rk3308->hpout_l_dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39;
+
+	/* Step 19, set LINEOUT default gains */
+	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
+			   RK3308_DAC_L_LINEOUT_GAIN_MSK |
+			   RK3308_DAC_R_LINEOUT_GAIN_MSK,
+			   RK3308_DAC_L_LINEOUT_GAIN_NDB_6 |
+			   RK3308_DAC_R_LINEOUT_GAIN_NDB_6);
+
+	return 0;
+}
+
+static int rk3308_codec_controls_prepare(struct rk3308_codec_priv *rk3308)
+{
+	int grp;
+
+	for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+		rk3308->agc_l[grp] = 0;
+		rk3308->agc_r[grp] = 0;
+	}
+
+	return 0;
+}
+
+static int rk3308_codec_prepare(struct rk3308_codec_priv *rk3308)
+{
+	/* Clear registers for ADC and DAC */
+	rk3308_codec_dac_disable(rk3308);
+	rk3308_codec_adc_ana_disable(rk3308, ADC_LR_GROUP_MAX);
+	rk3308_codec_default_gains(rk3308);
+	rk3308_codec_llp_down(rk3308);
+	rk3308_codec_controls_prepare(rk3308);
+
+	return 0;
+}
+
+static int rk3308_probe(struct snd_soc_component *component)
+{
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	rk3308->component = component;
+
+	rk3308_codec_reset(component);
+	rk3308_codec_power_on(rk3308);
+
+	rk3308_codec_micbias_disable(rk3308);
+
+	rk3308_codec_prepare(rk3308);
+
+	return 0;
+}
+
+static void rk3308_remove(struct snd_soc_component *component)
+{
+	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+	rk3308_codec_micbias_disable(rk3308);
+	rk3308_codec_power_off(rk3308);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_rk3308 = {
+	.probe = rk3308_probe,
+	.remove = rk3308_remove,
+	.set_bias_level = rk3308_set_bias_level,
+	.controls = rk3308_codec_controls,
+	.num_controls = ARRAY_SIZE(rk3308_codec_controls),
+};
+
+static const struct regmap_config rk3308_codec_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = RK3308_DAC_ANA_CON15,
+};
+
+static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308)
+{
+	unsigned int chip_id;
+
+	regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id);
+	switch (chip_id) {
+	case 3306:
+		rk3308->codec_ver = ACODEC_VERSION_A;
+		break;
+	case 0x3308:
+		rk3308->codec_ver = ACODEC_VERSION_B;
+		break;
+	default:
+		return dev_err_probe(rk3308->dev, -EINVAL, "Unknown chip_id: 0x%x\n", chip_id);
+	}
+
+	dev_info(rk3308->dev, "Found codec version %X\n", rk3308->codec_ver);
+	return 0;
+}
+
+static int rk3308_codec_parse_dt(struct rk3308_codec_priv *rk3308)
+{
+	struct device_node *np = rk3308->dev->of_node;
+	int err;
+
+	/* Default value is 0 */
+	err = of_property_read_u32(np, "rockchip,micbias-avdd-multiplier",
+				   &rk3308->micbias_avdd_mult);
+	if (rk3308->micbias_avdd_mult >= RK3308_CODEC_MICBIAS_NUM)
+		return dev_err_probe(rk3308->dev, -EINVAL,
+				     "Invalid value for 'rockchip,micbias-avdd-multiplier'\n");
+
+	return 0;
+}
+
+static int rk3308_platform_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct rk3308_codec_priv *rk3308;
+	struct resource *res;
+	void __iomem *base;
+	int err;
+
+	rk3308 = devm_kzalloc(&pdev->dev, sizeof(*rk3308), GFP_KERNEL);
+	if (!rk3308)
+		return -ENOMEM;
+
+	rk3308->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+	if (IS_ERR(rk3308->grf))
+		return dev_err_probe(&pdev->dev, PTR_ERR(rk3308->grf),
+			"Missing 'rockchip,grf' property\n");
+
+	rk3308->dev = &pdev->dev;
+
+	err = rk3308_codec_parse_dt(rk3308);
+	if (err)
+		return err;
+
+	rk3308->reset = devm_reset_control_get(&pdev->dev, "acodec");
+	if (IS_ERR(rk3308->reset)) {
+		err = PTR_ERR(rk3308->reset);
+		if (err != -ENOENT)
+			return err;
+
+		dev_dbg(&pdev->dev, "No reset control found\n");
+		rk3308->reset = NULL;
+	}
+
+	rk3308->pclk = devm_clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(rk3308->pclk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(rk3308->pclk), "Can't get hclk\n");
+
+	rk3308->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx");
+	if (IS_ERR(rk3308->mclk_rx))
+		return dev_err_probe(&pdev->dev, PTR_ERR(rk3308->mclk_rx), "Can't get mclk_rx\n");
+
+	rk3308->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx");
+	if (IS_ERR(rk3308->mclk_tx))
+		return dev_err_probe(&pdev->dev, PTR_ERR(rk3308->mclk_tx), "Can't get mclk_tx\n");
+
+	err = clk_prepare_enable(rk3308->pclk);
+	if (err)
+		return dev_err_probe(&pdev->dev, err, "Failed to enable acodec pclk\n");
+
+	err = clk_prepare_enable(rk3308->mclk_rx);
+	if (err)
+		return dev_err_probe(&pdev->dev, err, "Failed to enable i2s mclk_rx\n");
+
+	err = clk_prepare_enable(rk3308->mclk_tx);
+	if (err)
+		return dev_err_probe(&pdev->dev, err, "Failed to enable i2s mclk_tx\n");
+
+	err = rk3308_codec_get_version(rk3308);
+	if (err)
+		return dev_err_probe(&pdev->dev, err, "Failed to get acodec version\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return dev_err_probe(&pdev->dev, PTR_ERR(base), "Failed to ioremap resource\n");
+
+	rk3308->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					       &rk3308_codec_regmap_config);
+	if (IS_ERR(rk3308->regmap))
+		return dev_err_probe(&pdev->dev, PTR_ERR(rk3308->regmap),
+				     "Failed to init regmap\n");
+
+	rk3308->adc_grp0_using_linein = ADC_GRP0_MICIN;
+	rk3308->dac_output = DAC_LINEOUT;
+
+	platform_set_drvdata(pdev, rk3308);
+
+	err = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk3308,
+					      rk3308_dai, ARRAY_SIZE(rk3308_dai));
+	if (err)
+		return dev_err_probe(&pdev->dev, err, "Failed to register codec\n");
+
+	return 0;
+}
+
+static const struct of_device_id rk3308codec_of_match[] = {
+	{ .compatible = "rockchip,rk3308-codec", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rk3308codec_of_match);
+
+static struct platform_driver rk3308_codec_driver = {
+	.driver = {
+		.name = "rk3308-acodec",
+		.of_match_table = of_match_ptr(rk3308codec_of_match),
+	},
+	.probe = rk3308_platform_probe,
+};
+module_platform_driver(rk3308_codec_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
+MODULE_DESCRIPTION("ASoC RK3308 Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rk3308_codec.h b/sound/soc/codecs/rk3308_codec.h
new file mode 100644
index 000000000000..7ab08972141d
--- /dev/null
+++ b/sound/soc/codecs/rk3308_codec.h
@@ -0,0 +1,648 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Rockchip RK3308 internal audio codec driver -- register definitions
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
+ * Copyright (c) 2022, Vivax-Metrotech Ltd
+ */
+
+#ifndef __RK3308_CODEC_H__
+#define __RK3308_CODEC_H__
+
+#define RK3308_GLB_CON				0x00
+
+/* ADC DIGITAL REGISTERS */
+
+/*
+ * The ADC group are 0 ~ 3, that control:
+ *
+ * CH0: left_0(ADC1) and right_0(ADC2)
+ * CH1: left_1(ADC3) and right_1(ADC4)
+ * CH2: left_2(ADC5) and right_2(ADC6)
+ * CH3: left_3(ADC7) and right_3(ADC8)
+ */
+#define RK3308_ADC_DIG_OFFSET(ch)		(((ch) & 0x3) * 0xc0 + 0x0)
+
+#define RK3308_ADC_DIG_CON01(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x04)
+#define RK3308_ADC_DIG_CON02(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x08)
+#define RK3308_ADC_DIG_CON03(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x0c)
+#define RK3308_ADC_DIG_CON04(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x10)
+#define RK3308_ADC_DIG_CON07(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x1c)
+
+#define RK3308_ALC_L_DIG_CON00(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x40)
+#define RK3308_ALC_L_DIG_CON01(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x44)
+#define RK3308_ALC_L_DIG_CON02(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x48)
+#define RK3308_ALC_L_DIG_CON03(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x4c)
+#define RK3308_ALC_L_DIG_CON04(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x50)
+#define RK3308_ALC_L_DIG_CON05(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x54)
+#define RK3308_ALC_L_DIG_CON06(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x58)
+#define RK3308_ALC_L_DIG_CON07(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x5c)
+#define RK3308_ALC_L_DIG_CON08(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x60)
+#define RK3308_ALC_L_DIG_CON09(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x64)
+#define RK3308_ALC_L_DIG_CON12(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x70)
+
+#define RK3308_ALC_R_DIG_CON00(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x80)
+#define RK3308_ALC_R_DIG_CON01(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x84)
+#define RK3308_ALC_R_DIG_CON02(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x88)
+#define RK3308_ALC_R_DIG_CON03(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x8c)
+#define RK3308_ALC_R_DIG_CON04(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x90)
+#define RK3308_ALC_R_DIG_CON05(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x94)
+#define RK3308_ALC_R_DIG_CON06(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x98)
+#define RK3308_ALC_R_DIG_CON07(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0x9c)
+#define RK3308_ALC_R_DIG_CON08(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0xa0)
+#define RK3308_ALC_R_DIG_CON09(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0xa4)
+#define RK3308_ALC_R_DIG_CON12(ch)		(RK3308_ADC_DIG_OFFSET((ch)) + 0xb0)
+
+/* DAC DIGITAL REGISTERS */
+#define RK3308_DAC_DIG_OFFSET			0x300
+#define RK3308_DAC_DIG_CON01			(RK3308_DAC_DIG_OFFSET + 0x04)
+#define RK3308_DAC_DIG_CON02			(RK3308_DAC_DIG_OFFSET + 0x08)
+#define RK3308_DAC_DIG_CON03			(RK3308_DAC_DIG_OFFSET + 0x0c)
+#define RK3308_DAC_DIG_CON04			(RK3308_DAC_DIG_OFFSET + 0x10)
+#define RK3308_DAC_DIG_CON05			(RK3308_DAC_DIG_OFFSET + 0x14)
+#define RK3308_DAC_DIG_CON10			(RK3308_DAC_DIG_OFFSET + 0x28)
+#define RK3308_DAC_DIG_CON11			(RK3308_DAC_DIG_OFFSET + 0x2c)
+#define RK3308_DAC_DIG_CON13			(RK3308_DAC_DIG_OFFSET + 0x34)
+#define RK3308_DAC_DIG_CON14			(RK3308_DAC_DIG_OFFSET + 0x38)
+
+/* ADC ANALOG REGISTERS */
+/*
+ * The ADC group are 0 ~ 3, that control:
+ *
+ * CH0: left_0(ADC1) and right_0(ADC2)
+ * CH1: left_1(ADC3) and right_1(ADC4)
+ * CH2: left_2(ADC5) and right_2(ADC6)
+ * CH3: left_3(ADC7) and right_3(ADC8)
+ */
+#define RK3308_ADC_ANA_OFFSET(ch)		(((ch) & 0x3) * 0x40 + 0x340)
+#define RK3308_ADC_ANA_CON00(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x00)
+#define RK3308_ADC_ANA_CON01(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x04)
+#define RK3308_ADC_ANA_CON02(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x08)
+#define RK3308_ADC_ANA_CON03(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x0c)
+#define RK3308_ADC_ANA_CON04(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x10)
+#define RK3308_ADC_ANA_CON05(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x14)
+#define RK3308_ADC_ANA_CON06(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x18)
+#define RK3308_ADC_ANA_CON07(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x1c)
+#define RK3308_ADC_ANA_CON08(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x20)
+#define RK3308_ADC_ANA_CON10(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x28)
+#define RK3308_ADC_ANA_CON11(ch)		(RK3308_ADC_ANA_OFFSET((ch)) + 0x2c)
+
+/* DAC ANALOG REGISTERS */
+#define RK3308_DAC_ANA_OFFSET			0x440
+#define RK3308_DAC_ANA_CON00			(RK3308_DAC_ANA_OFFSET + 0x00)
+#define RK3308_DAC_ANA_CON01			(RK3308_DAC_ANA_OFFSET + 0x04)
+#define RK3308_DAC_ANA_CON02			(RK3308_DAC_ANA_OFFSET + 0x08)
+#define RK3308_DAC_ANA_CON03			(RK3308_DAC_ANA_OFFSET + 0x0c)
+#define RK3308_DAC_ANA_CON04			(RK3308_DAC_ANA_OFFSET + 0x10)
+#define RK3308_DAC_ANA_CON05			(RK3308_DAC_ANA_OFFSET + 0x14)
+#define RK3308_DAC_ANA_CON06			(RK3308_DAC_ANA_OFFSET + 0x18)
+#define RK3308_DAC_ANA_CON07			(RK3308_DAC_ANA_OFFSET + 0x1c)
+#define RK3308_DAC_ANA_CON08			(RK3308_DAC_ANA_OFFSET + 0x20)
+#define RK3308_DAC_ANA_CON12			(RK3308_DAC_ANA_OFFSET + 0x30)
+#define RK3308_DAC_ANA_CON13			(RK3308_DAC_ANA_OFFSET + 0x34)
+#define RK3308_DAC_ANA_CON14			(RK3308_DAC_ANA_OFFSET + 0x38)
+#define RK3308_DAC_ANA_CON15			(RK3308_DAC_ANA_OFFSET + 0x3c)
+
+/*
+ * These are the bits for registers
+ */
+
+/* RK3308_GLB_CON - REG: 0x0000 */
+#define RK3308_ADC_BIST_WORK			BIT(7)
+#define RK3308_DAC_BIST_WORK			BIT(6)
+#define RK3308_ADC_MCLK_GATING_MSK		BIT(5)
+#define RK3308_DAC_MCLK_GATING_MSK		BIT(4)
+#define RK3308_CODEC_RST_MSK			(0x7 << 0)
+#define RK3308_ADC_DIG_WORK			BIT(2)
+#define RK3308_DAC_DIG_WORK			BIT(1)
+#define RK3308_SYS_WORK				BIT(0)
+
+/* RK3308_ADC_DIG_CON01 - REG: 0x0004 */
+#define RK3308_ADC_I2S_LRC_POL_REVERSAL		BIT(7)
+#define RK3308_ADC_I2S_VALID_LEN_SFT		5
+#define RK3308_ADC_I2S_VALID_LEN_MSK		(0x3 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_32BITS		(0x3 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_24BITS		(0x2 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_20BITS		(0x1 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_16BITS		(0x0 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_MODE_SFT			3
+#define RK3308_ADC_I2S_MODE_MSK			(0x3 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_PCM			(0x3 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_I2S			(0x2 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_LJ			(0x1 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_RJ			(0x0 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_LR_SWAP			BIT(1)
+#define RK3308_ADC_I2S_MONO			BIT(0)
+
+/* RK3308_ADC_DIG_CON02 - REG: 0x0008 */
+#define RK3308_ADC_IO_MODE_MASTER		BIT(5)
+#define RK3308_ADC_MODE_MASTER			BIT(4)
+#define RK3308_ADC_I2S_FRAME_LEN_SFT		2
+#define RK3308_ADC_I2S_FRAME_LEN_MSK		(0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_32BITS		(0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_24BITS		(0x2 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_20BITS		(0x1 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_16BITS		(0x0 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_WORK			BIT(1)
+#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL	BIT(0)
+
+/* RK3308_ADC_DIG_CON03 - REG: 0x000c */
+#define RK3308_ADC_L_CH_BIST_SFT		2
+#define RK3308_ADC_L_CH_BIST_MSK		(0x3 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_NORMAL_RIGHT		(0x3 << RK3308_ADC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_L_CH_BIST_CUBE		(0x2 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_BIST_SINE		(0x1 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_NORMAL_LEFT		(0x0 << RK3308_ADC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_R_CH_BIST_SFT		0
+#define RK3308_ADC_R_CH_BIST_MSK		(0x3 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_NORMAL_LEFT		(0x3 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_R_CH_BIST_CUBE		(0x2 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_BIST_SINE		(0x1 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_NORMAL_RIGHT		(0x0 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */
+
+/* RK3308_ADC_DIG_CON04 - REG: 0x0010 */
+#define RK3308_ADC_HPF_PATH_DIS			BIT(2)
+#define RK3308_ADC_HPF_CUTOFF_SFT		0
+#define RK3308_ADC_HPF_CUTOFF_MSK		(0x3 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_612HZ		(0x2 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_245HZ		(0x1 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_20HZ		(0x0 << RK3308_ADC_HPF_CUTOFF_SFT)
+
+/* RK3308_ADC_DIG_CON07 - REG: 0x001c */
+#define RK3308_ADCL_DATA_SFT			4
+#define RK3308_ADCR_DATA_SFT			2
+#define RK3308_ADCL_DATA_SEL_ADCL		BIT(1)
+#define RK3308_ADCR_DATA_SEL_ADCR		BIT(0)
+
+/*
+ * RK3308_ALC_L_DIG_CON00 - REG: 0x0040 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON00 - REG: 0x0080 + ch * 0xc0
+ */
+#define RK3308_GAIN_ATTACK_JACK			BIT(6)
+#define RK3308_CTRL_GEN_SFT			4
+#define RK3308_CTRL_GEN_MSK			(0x3 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK3			(0x3 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK2			(0x2 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK1			(0x1 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_NORMAL			(0x0 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_AGC_HOLD_TIME_SFT		0
+#define RK3308_AGC_HOLD_TIME_MSK		(0xf << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_1S			(0xa << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_512MS		(0x9 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_256MS		(0x8 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_128MS		(0x7 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_64MS		(0x6 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_32MS		(0x5 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_16MS		(0x4 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_8MS		(0x3 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_4MS		(0x2 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_2MS		(0x1 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_0MS		(0x0 << RK3308_AGC_HOLD_TIME_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON01 - REG: 0x0044 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON01 - REG: 0x0084 + ch * 0xc0
+ */
+#define RK3308_AGC_DECAY_TIME_SFT		4
+#define RK3308_AGC_ATTACK_TIME_SFT		0
+
+/*
+ * RK3308_ALC_L_DIG_CON02 - REG: 0x0048 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON02 - REG: 0x0088 + ch * 0xc0
+ */
+#define RK3308_AGC_MODE_LIMITER			BIT(7)
+#define RK3308_AGC_ZERO_CRO_EN			BIT(6)
+#define RK3308_AGC_AMP_RECOVER_GAIN		BIT(5)
+#define RK3308_AGC_FAST_DEC_EN			BIT(4)
+#define RK3308_AGC_NOISE_GATE_EN		BIT(3)
+#define RK3308_AGC_NOISE_GATE_THRESH_SFT	0
+#define RK3308_AGC_NOISE_GATE_THRESH_MSK	(0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON03 - REG: 0x004c + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON03 - REG: 0x008c + ch * 0xc0
+ */
+#define RK3308_AGC_PGA_ZERO_CRO_EN		BIT(5)
+#define RK3308_AGC_PGA_GAIN_MAX			0x1f
+#define RK3308_AGC_PGA_GAIN_MIN			0
+#define RK3308_AGC_PGA_GAIN_SFT			0
+
+/*
+ * RK3308_ALC_L_DIG_CON04 - REG: 0x0050 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON04 - REG: 0x0090 + ch * 0xc0
+ */
+#define RK3308_AGC_SLOW_CLK_EN			BIT(3)
+#define RK3308_AGC_APPROX_RATE_SFT		0
+#define RK3308_AGC_APPROX_RATE_MSK		(0x7 << RK3308_AGC_APPROX_RATE_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON05 - REG: 0x0054 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON05 - REG: 0x0094 + ch * 0xc0
+ */
+#define RK3308_AGC_LO_8BITS_AGC_MAX_MSK		0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON06 - REG: 0x0058 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON06 - REG: 0x0098 + ch * 0xc0
+ */
+#define RK3308_AGC_HI_8BITS_AGC_MAX_MSK		0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON07 - REG: 0x005c + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON07 - REG: 0x009c + ch * 0xc0
+ */
+#define RK3308_AGC_LO_8BITS_AGC_MIN_MSK		0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON08 - REG: 0x0060 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON08 - REG: 0x00a0 + ch * 0xc0
+ */
+#define RK3308_AGC_HI_8BITS_AGC_MIN_MSK		0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON09 - REG: 0x0064 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON09 - REG: 0x00a4 + ch * 0xc0
+ */
+#define RK3308_AGC_FUNC_SEL_MSK			BIT(6)
+#define RK3308_AGC_MAX_GAIN_PGA_MAX		0x7
+#define RK3308_AGC_MAX_GAIN_PGA_MIN		0
+#define RK3308_AGC_MAX_GAIN_PGA_SFT		3
+#define RK3308_AGC_MAX_GAIN_PGA_MSK		(0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT)
+#define RK3308_AGC_MIN_GAIN_PGA_MAX		0x7
+#define RK3308_AGC_MIN_GAIN_PGA_MIN		0
+#define RK3308_AGC_MIN_GAIN_PGA_SFT		0
+#define RK3308_AGC_MIN_GAIN_PGA_MSK		(0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON12 - REG: 0x0068 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON12 - REG: 0x00a8 + ch * 0xc0
+ */
+#define RK3308_AGC_GAIN_MSK			0x1f
+
+/* RK3308_DAC_DIG_CON01 - REG: 0x0304 */
+#define RK3308_DAC_I2S_LRC_POL_REVERSAL		BIT(7)
+#define RK3308_DAC_I2S_VALID_LEN_SFT		5
+#define RK3308_DAC_I2S_VALID_LEN_MSK		(0x3 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_32BITS		(0x3 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_24BITS		(0x2 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_20BITS		(0x1 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_16BITS		(0x0 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_MODE_SFT			3
+#define RK3308_DAC_I2S_MODE_MSK			(0x3 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_PCM			(0x3 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_I2S			(0x2 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_LJ			(0x1 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_RJ			(0x0 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_LR_SWAP			BIT(2)
+
+/* RK3308_DAC_DIG_CON02 - REG: 0x0308 */
+#define RK3308_DAC_IO_MODE_MASTER		BIT(5)
+#define RK3308_DAC_MODE_MASTER			BIT(4)
+#define RK3308_DAC_I2S_FRAME_LEN_SFT		2
+#define RK3308_DAC_I2S_FRAME_LEN_MSK		(0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_32BITS		(0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_24BITS		(0x2 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_20BITS		(0x1 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_16BITS		(0x0 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_WORK			BIT(1)
+#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL	BIT(0)
+
+/* RK3308_DAC_DIG_CON03 - REG: 0x030C */
+#define RK3308_DAC_L_CH_BIST_SFT		2
+#define RK3308_DAC_L_CH_BIST_MSK		(0x3 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_LEFT		(0x3 << RK3308_DAC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_L_CH_BIST_CUBE		(0x2 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_SINE		(0x1 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_RIGHT		(0x0 << RK3308_DAC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_R_CH_BIST_SFT		0
+#define RK3308_DAC_R_CH_BIST_MSK		(0x3 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_LEFT		(0x3 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_R_CH_BIST_CUBE		(0x2 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_SINE		(0x1 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_RIGHT		(0x0 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */
+
+/* RK3308_DAC_DIG_CON04 - REG: 0x0310 */
+#define RK3308_DAC_MODULATOR_GAIN_SFT		4
+#define RK3308_DAC_MODULATOR_GAIN_MSK		(0x7 << RK3308_DAC_MODULATOR_GAIN_SFT)
+#define RK3308_DAC_CIC_IF_GAIN_SFT		0
+#define RK3308_DAC_CIC_IF_GAIN_MSK		(0x7 << RK3308_DAC_CIC_IF_GAIN_SFT)
+
+/* RK3308_DAC_DIG_CON05 - REG: 0x0314 */
+#define RK3308_DAC_L_REG_CTL_INDATA		BIT(2)
+#define RK3308_DAC_R_REG_CTL_INDATA		BIT(1)
+
+/* RK3308_DAC_DIG_CON10 - REG: 0x0328 */
+#define RK3308_DAC_DATA_HI4(x)			((x) & 0xf)
+
+/* RK3308_DAC_DIG_CON11 - REG: 0x032c */
+#define RK3308_DAC_DATA_LO8(x)			((x) & 0xff)
+
+/* RK3308_ADC_ANA_CON00 - REG: 0x0340 */
+#define RK3308_ADC_CH1_CH2_MIC_ALL_MSK		(0xff << 0)
+#define RK3308_ADC_CH1_CH2_MIC_ALL		0xff
+#define RK3308_ADC_CH2_MIC_UNMUTE		BIT(7)
+#define RK3308_ADC_CH2_MIC_WORK			BIT(6)
+#define RK3308_ADC_CH2_MIC_EN			BIT(5)
+#define RK3308_ADC_CH2_BUF_REF_EN		BIT(4)
+#define RK3308_ADC_CH1_MIC_UNMUTE		BIT(3)
+#define RK3308_ADC_CH1_MIC_WORK			BIT(2)
+#define RK3308_ADC_CH1_MIC_EN			BIT(1)
+#define RK3308_ADC_CH1_BUF_REF_EN		BIT(0)
+
+/* RK3308_ADC_ANA_CON01 - REG: 0x0344
+ *
+ * The PGA of MIC-INs:
+ * - HW version A:
+ *   0x0 - MIC1~MIC8  0 dB (recommended when ADC used as loopback)
+ *   0x3 - MIC1~MIC8 20 dB (recommended when ADC used as MIC input)
+ * - HW version B:
+ *   0x0 - MIC1~MIC8   0 dB
+ *   0x1 - MIC1~MIC8 6.6 dB
+ *   0x2 - MIC1~MIC8  13 dB
+ *   0x3 - MIC1~MIC8  20 dB
+ */
+#define RK3308_ADC_CH2_MIC_GAIN_MAX		0x3
+#define RK3308_ADC_CH2_MIC_GAIN_MIN		0
+#define RK3308_ADC_CH2_MIC_GAIN_SFT		4
+#define RK3308_ADC_CH2_MIC_GAIN_MSK		(0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_20DB		(0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_13DB		(0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_6_6DB		(0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_0DB		(0x0 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+
+#define RK3308_ADC_CH1_MIC_GAIN_MAX		0x3
+#define RK3308_ADC_CH1_MIC_GAIN_MIN		0
+#define RK3308_ADC_CH1_MIC_GAIN_SFT		0
+#define RK3308_ADC_CH1_MIC_GAIN_MSK		(0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_20DB		(0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_13DB		(0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_6_6DB		(0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_0DB		(0x0 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON02 - REG: 0x0348 */
+#define RK3308_ADC_CH2_ZEROCROSS_DET_EN		BIT(6)
+#define RK3308_ADC_CH2_ALC_WORK			BIT(5)
+#define RK3308_ADC_CH2_ALC_EN			BIT(4)
+#define RK3308_ADC_CH1_ZEROCROSS_DET_EN		BIT(2)
+#define RK3308_ADC_CH1_ALC_WORK			BIT(1)
+#define RK3308_ADC_CH1_ALC_EN			BIT(0)
+
+/* RK3308_ADC_ANA_CON03 - REG: 0x034c */
+#define RK3308_ADC_CH1_ALC_GAIN_MAX		0x1f
+#define RK3308_ADC_CH1_ALC_GAIN_MIN		0
+#define RK3308_ADC_CH1_ALC_GAIN_SFT		0
+#define RK3308_ADC_CH1_ALC_GAIN_MSK		(0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT)
+#define RK3308_ADC_CH1_ALC_GAIN_0DB		(0x0c << RK3308_ADC_CH1_ALC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON04 - REG: 0x0350 */
+#define RK3308_ADC_CH2_ALC_GAIN_MAX		0x1f
+#define RK3308_ADC_CH2_ALC_GAIN_MIN		0
+#define RK3308_ADC_CH2_ALC_GAIN_SFT		0
+#define RK3308_ADC_CH2_ALC_GAIN_MSK		(0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT)
+#define RK3308_ADC_CH2_ALC_GAIN_0DB		(0x0c << RK3308_ADC_CH2_ALC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON05 - REG: 0x0354 */
+#define RK3308_ADC_CH2_ADC_WORK			BIT(6)
+#define RK3308_ADC_CH2_ADC_EN			BIT(5)
+#define RK3308_ADC_CH2_CLK_EN			BIT(4)
+#define RK3308_ADC_CH1_ADC_WORK			BIT(2)
+#define RK3308_ADC_CH1_ADC_EN			BIT(1)
+#define RK3308_ADC_CH1_CLK_EN			BIT(0)
+
+/* RK3308_ADC_ANA_CON06 - REG: 0x0358 */
+#define RK3308_ADC_CURRENT_EN			BIT(0)
+
+/* RK3308_ADC_ANA_CON07 - REG: 0x035c */
+/* Note: The register configuration is only valid for ADC2 */
+#define RK3308_ADC_CH2_IN_SEL_SFT		6
+#define RK3308_ADC_CH2_IN_SEL_MSK		(0x3 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_LINEIN_MIC		(0x3 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_LINEIN		(0x2 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_MIC			(0x1 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_NONE			(0x0 << RK3308_ADC_CH2_IN_SEL_SFT)
+/* Note: The register configuration is only valid for ADC1 */
+#define RK3308_ADC_CH1_IN_SEL_SFT		4
+#define RK3308_ADC_CH1_IN_SEL_MSK		(0x3 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_LINEIN_MIC		(0x3 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_LINEIN		(0x2 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_MIC			(0x1 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_NONE			(0x0 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_MIC_BIAS_BUF_EN		BIT(3)
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT	0
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK	(0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT)
+
+/* RK3308_ADC_ANA_CON08 - REG: 0x0360 */
+#define RK3308_ADC_MICBIAS_CURRENT_EN		BIT(4)
+
+/* RK3308_ADC_ANA_CON10 - REG: 0x0368 */
+#define RK3308_ADC_REF_EN			BIT(7)
+#define RK3308_ADC_CURRENT_CHARGE_SFT		0
+#define RK3308_ADC_CURRENT_CHARGE_MSK		(0x7f << RK3308_ADC_CURRENT_CHARGE_SFT)
+/*
+ * 1: Choose the current I
+ * 0: Don't choose the current I
+ */
+#define RK3308_ADC_SEL_I(x)			((x) & 0x7f)
+
+/* RK3308_ADC_ANA_CON11 - REG: 0x036c */
+#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN	BIT(1)
+#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN	BIT(0)
+
+/* RK3308_DAC_ANA_CON00 - REG: 0x0440 */
+#define RK3308_DAC_HEADPHONE_DET_EN		BIT(1)
+#define RK3308_DAC_CURRENT_EN			BIT(0)
+
+/* RK3308_DAC_ANA_CON01 - REG: 0x0444 */
+#define RK3308_DAC_BUF_REF_R_EN			BIT(6)
+#define RK3308_DAC_HPOUT_POP_SOUND_R_SFT	4
+#define RK3308_DAC_HPOUT_POP_SOUND_R_MSK	(0x3 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_HPOUT_POP_SOUND_R_WORK	(0x2 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_HPOUT_POP_SOUND_R_INIT	(0x1 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_BUF_REF_L_EN			BIT(2)
+#define RK3308_DAC_HPOUT_POP_SOUND_L_SFT	0
+#define RK3308_DAC_HPOUT_POP_SOUND_L_MSK	(0x3 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_HPOUT_POP_SOUND_L_WORK	(0x2 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_HPOUT_POP_SOUND_L_INIT	(0x1 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT)
+
+/* RK3308_DAC_ANA_CON02 - REG: 0x0448 */
+#define RK3308_DAC_R_DAC_WORK			BIT(7)
+#define RK3308_DAC_R_DAC_EN			BIT(6)
+#define RK3308_DAC_R_CLK_EN			BIT(5)
+#define RK3308_DAC_R_REF_EN			BIT(4)
+#define RK3308_DAC_L_DAC_WORK			BIT(3)
+#define RK3308_DAC_L_DAC_EN			BIT(2)
+#define RK3308_DAC_L_CLK_EN			BIT(1)
+#define RK3308_DAC_L_REF_EN			BIT(0)
+
+/* RK3308_DAC_ANA_CON03 - REG: 0x044c */
+#define RK3308_DAC_R_HPOUT_WORK			BIT(6)
+#define RK3308_DAC_R_HPOUT_EN			BIT(5)
+#define RK3308_DAC_R_HPOUT_UNMUTE		BIT(4)
+#define RK3308_DAC_L_HPOUT_WORK			BIT(2)
+#define RK3308_DAC_L_HPOUT_EN			BIT(1)
+#define RK3308_DAC_L_HPOUT_UNMUTE		BIT(0)
+
+/* RK3308_DAC_ANA_CON04 - REG: 0x0450 */
+#define RK3308_DAC_R_LINEOUT_GAIN_MAX		0x3
+#define RK3308_DAC_R_LINEOUT_GAIN_SFT		6
+#define RK3308_DAC_R_LINEOUT_GAIN_MSK		(0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_0DB		(0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_1_5	(0x2 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_3		(0x1 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_6		(0x0 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_UNMUTE		BIT(5)
+#define RK3308_DAC_R_LINEOUT_EN			BIT(4)
+#define RK3308_DAC_L_LINEOUT_GAIN_MAX		0x3
+#define RK3308_DAC_L_LINEOUT_GAIN_SFT		2
+#define RK3308_DAC_L_LINEOUT_GAIN_MSK		(0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_0DB		(0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_1_5	(0x2 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_3		(0x1 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_6		(0x0 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_UNMUTE		BIT(1)
+#define RK3308_DAC_L_LINEOUT_EN			BIT(0)
+
+/* RK3308_DAC_ANA_CON05 - REG: 0x0454, step is 1.5db */
+#define RK3308_DAC_L_HPOUT_GAIN_MAX		0x1e
+#define RK3308_DAC_L_HPOUT_GAIN_SFT		0
+#define RK3308_DAC_L_HPOUT_GAIN_MSK		(0x1f << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_PDB_6		(0x1e << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_PDB_4_5		(0x1d << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_PDB_3		(0x1c << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_PDB_1_5		(0x1b << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_0DB		(0x1a << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_1_5		(0x19 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_3		(0x18 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_4_5		(0x17 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_6		(0x16 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_7_5		(0x15 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_9		(0x14 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_10_5	(0x13 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_12		(0x12 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_13_5	(0x11 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_15		(0x10 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_16_5	(0x0f << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_18		(0x0e << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_19_5	(0x0d << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_21		(0x0c << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_22_5	(0x0b << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_24		(0x0a << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_25_5	(0x09 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_27		(0x08 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_28_5	(0x07 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_30		(0x06 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_31_5	(0x05 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_33		(0x04 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_34_5	(0x03 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_36		(0x02 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_37_5	(0x01 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+#define RK3308_DAC_L_HPOUT_GAIN_NDB_39		(0x00 << RK3308_DAC_L_HPOUT_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON06 - REG: 0x0458, step is 1.5db */
+#define RK3308_DAC_R_HPOUT_GAIN_MAX		0x1e
+#define RK3308_DAC_R_HPOUT_GAIN_SFT		0
+#define RK3308_DAC_R_HPOUT_GAIN_MSK		(0x1f << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_PDB_6		(0x1e << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_PDB_4_5		(0x1d << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_PDB_3		(0x1c << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_PDB_1_5		(0x1b << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_0DB		(0x1a << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_1_5		(0x19 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_3		(0x18 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_4_5		(0x17 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_6		(0x16 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_7_5		(0x15 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_9		(0x14 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_10_5	(0x13 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_12		(0x12 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_13_5	(0x11 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_15		(0x10 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_16_5	(0x0f << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_18		(0x0e << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_19_5	(0x0d << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_21		(0x0c << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_22_5	(0x0b << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_24		(0x0a << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_25_5	(0x09 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_27		(0x08 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_28_5	(0x07 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_30		(0x06 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_31_5	(0x05 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_33		(0x04 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_34_5	(0x03 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_36		(0x02 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_37_5	(0x01 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+#define RK3308_DAC_R_HPOUT_GAIN_NDB_39		(0x00 << RK3308_DAC_R_HPOUT_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON07 - REG: 0x045c */
+#define RK3308_DAC_R_HPOUT_DRV_SFT		4
+#define RK3308_DAC_R_HPOUT_DRV_MSK		(0xf << RK3308_DAC_R_HPOUT_DRV_SFT)
+#define RK3308_DAC_L_HPOUT_DRV_SFT		0
+#define RK3308_DAC_L_HPOUT_DRV_MSK		(0xf << RK3308_DAC_L_HPOUT_DRV_SFT)
+
+/* RK3308_DAC_ANA_CON08 - REG: 0x0460 */
+#define RK3308_DAC_R_LINEOUT_DRV_SFT		4
+#define RK3308_DAC_R_LINEOUT_DRV_MSK		(0xf << RK3308_DAC_R_LINEOUT_DRV_SFT)
+#define RK3308_DAC_L_LINEOUT_DRV_SFT		0
+#define RK3308_DAC_L_LINEOUT_DRV_MSK		(0xf << RK3308_DAC_L_LINEOUT_DRV_SFT)
+
+/* RK3308_DAC_ANA_CON12 - REG: 0x0470 */
+#define RK3308_DAC_R_HPMIX_SEL_SFT		6
+#define RK3308_DAC_R_HPMIX_SEL_MSK		(0x3 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_LINEIN_I2S		(0x3 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_LINEIN		(0x2 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_I2S			(0x1 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_NONE			(0x0 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_MIN		0x1 /* 0xx0 and 0x3 are reserved */
+#define RK3308_DAC_R_HPMIX_GAIN_MAX		0x2
+#define RK3308_DAC_R_HPMIX_GAIN_SFT		4
+#define RK3308_DAC_R_HPMIX_GAIN_MSK		(0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_0DB		(0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_NDB_6		(0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_SEL_SFT		2
+#define RK3308_DAC_L_HPMIX_SEL_MSK		(0x3 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_LINEIN_I2S		(0x3 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_LINEIN		(0x2 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_I2S			(0x1 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_NONE			(0x0 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_MIN		0x1 /* 0xx0 and 0x3 are reserved */
+#define RK3308_DAC_L_HPMIX_GAIN_MAX		0x2
+#define RK3308_DAC_L_HPMIX_GAIN_SFT		0
+#define RK3308_DAC_L_HPMIX_GAIN_MSK		(0x3 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_0DB		(0x2 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_NDB_6		(0x1 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON13 - REG: 0x0474 */
+#define RK3308_DAC_R_HPMIX_UNMUTE		BIT(6)
+#define RK3308_DAC_R_HPMIX_WORK			BIT(5)
+#define RK3308_DAC_R_HPMIX_EN			BIT(4)
+#define RK3308_DAC_L_HPMIX_UNMUTE		BIT(2)
+#define RK3308_DAC_L_HPMIX_WORK			BIT(1)
+#define RK3308_DAC_L_HPMIX_EN			BIT(0)
+
+/* RK3308_DAC_ANA_CON14 - REG: 0x0478 */
+#define RK3308_DAC_VCM_LINEOUT_EN		(0x1 << 4)
+#define RK3308_DAC_CURRENT_CHARGE_SFT		0
+#define RK3308_DAC_CURRENT_CHARGE_MSK		(0xf << RK3308_DAC_CURRENT_CHARGE_SFT)
+
+/*
+ * 1: Choose the current I
+ * 0: Don't choose the current I
+ */
+#define RK3308_DAC_SEL_I(x)			((x) & 0xf)
+
+/* RK3308_DAC_ANA_CON15 - REG: 0x047C */
+#define RK3308_DAC_LINEOUT_POP_SOUND_R_SFT	4
+#define RK3308_DAC_LINEOUT_POP_SOUND_R_MSK	(0x3 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_DC_FROM_INTERNAL	(0x2 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_DC_FROM_VCM		(0x1 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL	(0x0 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_LINEOUT_POP_SOUND_L_SFT	0
+#define RK3308_DAC_LINEOUT_POP_SOUND_L_MSK	(0x3 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_DC_FROM_INTERNAL	(0x2 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_DC_FROM_VCM		(0x1 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL	(0x0 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+
+#define RK3308_HIFI				0x0
+
+#endif /* __RK3308_CODEC_H__ */
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 8/8] ASoC: rockchip: add new RK3308 sound card
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
                   ` (6 preceding siblings ...)
  2022-09-07 14:21 ` [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver luca.ceresoli
@ 2022-09-07 14:21 ` luca.ceresoli
  2022-09-07 15:41 ` [PATCH 0/8] Add support for the internal RK3308 audio codec Mark Brown
  8 siblings, 0 replies; 22+ messages in thread
From: luca.ceresoli @ 2022-09-07 14:21 UTC (permalink / raw)
  To: alsa-devel, linux-rockchip
  Cc: Luca Ceresoli, devicetree, linux-arm-kernel, linux-kernel,
	Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

From: Luca Ceresoli <luca.ceresoli@bootlin.com>

The Rockchip RK3308 8-channel I2S adapter has a mainline driver that can
work fine with an audio-graph-card or simple-audio-card. Those card drivers
call the .set_sysclk op once, and this is usually enough for applications
using an external codec.

But in reality the I2S adapter has two clock inputs (TX and RX), and the
preferred way to use the RK3308 internal codec is enabling both clocks,
potentially with different rates. The existing simple-card code does not
implement this possibility.

To allow setting both clocks, add a new minimal driver that builds on top
of audio-graph-card and changes the dai_link->init callback with a modified
version of asoc_simple_init_dai(). This ultimately calls the set_sysclk()
callback as many times as the number of clocks defined in device tree.

With this implementation, the same rate is set to all the sysclks. Setting
different rates can be added later.

Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 MAINTAINERS                               |  1 +
 sound/soc/rockchip/Kconfig                | 14 ++++
 sound/soc/rockchip/Makefile               |  1 +
 sound/soc/rockchip/rockchip_rk3308_card.c | 97 +++++++++++++++++++++++
 4 files changed, 113 insertions(+)
 create mode 100644 sound/soc/rockchip/rockchip_rk3308_card.c

diff --git a/MAINTAINERS b/MAINTAINERS
index fb2a0a6e3c1f..96ccda9625f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17600,6 +17600,7 @@ ROCKCHIP RK3308 SOUND CARD DRIVER
 M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
+F:	sound/soc/rockchip/rockchip_rk3308_card.c
 
 ROCKCHIP VIDEO DECODER DRIVER
 M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index 42f76bc0fb02..b00dc04f8fd0 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -45,6 +45,20 @@ config SND_SOC_ROCKCHIP_SPDIF
 	  Say Y or M if you want to add support for SPDIF driver for
 	  Rockchip SPDIF transceiver device.
 
+config SND_SOC_ROCKCHIP_RK3308_INTERNAL_CODEC
+	tristate "ASoC sound card based on the internal RK3308 codec"
+	depends on HAVE_CLK && SND_SOC_ROCKCHIP
+	depends on SND_AUDIO_GRAPH_CARD
+	select SND_SOC_ROCKCHIP_I2S_TDM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  ASoC sound card driver for the RK3308 internal audio codec.
+
+	  The Rockchip RK3308 SoC has a built-in audio codec that is
+	  connected internally to one out of a selection of the internal
+	  I2S controllers. This driver implements an audio card using these
+	  components.
+
 config SND_SOC_ROCKCHIP_MAX98090
 	tristate "ASoC support for Rockchip boards using a MAX98090 codec"
 	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index 30c57c0d7660..680decae0c02 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -15,6 +15,7 @@ snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
 snd-soc-rk3288-hdmi-analog-objs := rk3288_hdmi_analog.o
 snd-soc-rk3399-gru-sound-objs := rk3399_gru_sound.o
 
+obj-$(CONFIG_SND_SOC_ROCKCHIP_RK3308_INTERNAL_CODEC) += rockchip_rk3308_card.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
 obj-$(CONFIG_SND_SOC_RK3288_HDMI_ANALOG) += snd-soc-rk3288-hdmi-analog.o
diff --git a/sound/soc/rockchip/rockchip_rk3308_card.c b/sound/soc/rockchip/rockchip_rk3308_card.c
new file mode 100644
index 000000000000..3cfc751993fe
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_rk3308_card.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Audio card using the RK3308 internal I2S
+//
+// Allows driving the I2S peripheral with both the RX and TX clocks. This
+// is useful to use the RK3308 internal audio codec.
+//
+// Copyright (c) 2022, Vivax-Metrotech Ltd
+//
+// Based on sound/soc/generic/audio-graph-card.c
+
+#include <linux/module.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/graph_card.h>
+
+static int rk3308_audio_asoc_simple_init_dai(struct snd_soc_dai *dai,
+					     struct asoc_simple_dai *simple_dai)
+{
+	const int nclks = 2; /* The sysclks are clk_id 0 and 1 for the RK3308 driver */
+	int err;
+	int i;
+
+	if (!simple_dai || !simple_dai->sysclk)
+		return 0;
+
+	/* Can be extended to get two different sysclk values via device tree */
+	for (i = 0; i < nclks; i++) {
+		err = snd_soc_dai_set_sysclk(dai, i, simple_dai->sysclk,
+					     simple_dai->clk_direction);
+		if (err && err != -ENOTSUPP)
+			return dev_err_probe(dai->dev, err, "simple-card: set_sysclk error\n");
+	}
+
+	return 0;
+}
+
+static int rk3308_audio_asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
+	struct asoc_simple_dai *dai;
+	int i, ret;
+
+	for_each_prop_dai_codec(props, i, dai) {
+		ret = rk3308_audio_asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
+		if (ret < 0)
+			return ret;
+	}
+	for_each_prop_dai_cpu(props, i, dai) {
+		ret = rk3308_audio_asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int rk3308_audio_graph_probe(struct platform_device *pdev)
+{
+	struct asoc_simple_priv *priv;
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	card = simple_priv_to_card(priv);
+	card->driver_name = "rk3308-audio-graph-card";
+	card->probe = asoc_graph_card_probe;
+	priv->init = rk3308_audio_asoc_simple_dai_init;
+
+	return audio_graph_parse_of(priv, dev);
+}
+
+static const struct of_device_id graph_of_rk3308_card_match[] = {
+	{ .compatible = "rockchip,rk3308-audio-graph-card" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, graph_of_rk3308_card_match);
+
+static struct platform_driver rk3308_audio_graph_card = {
+	.driver = {
+		.name = "rk3308-audio-graph-card",
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = graph_of_rk3308_card_match,
+	},
+	.probe = rk3308_audio_graph_probe,
+	.remove = asoc_simple_remove,
+};
+module_platform_driver(rk3308_audio_graph_card);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC Audio Graph Card for Rockchip RK3308");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/8] Add support for the internal RK3308 audio codec
  2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
                   ` (7 preceding siblings ...)
  2022-09-07 14:21 ` [PATCH 8/8] ASoC: rockchip: add new RK3308 sound card luca.ceresoli
@ 2022-09-07 15:41 ` Mark Brown
  2022-09-07 17:15   ` Luca Ceresoli
  8 siblings, 1 reply; 22+ messages in thread
From: Mark Brown @ 2022-09-07 15:41 UTC (permalink / raw)
  To: luca.ceresoli
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan


[-- Attachment #1.1: Type: text/plain, Size: 877 bytes --]

On Wed, Sep 07, 2022 at 04:21:16PM +0200, luca.ceresoli@bootlin.com wrote:

> Luca Ceresoli (8):
>   ASoC: rockchip: rk3308: add internal audio codec bindings
>   ASoC: rockchip: rk3308: add audio card bindings
>   arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3
>   arm64: dts: rockchip: add the internal audio codec
>   ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk()
>   ASoC: audio-graph: let dai_link->init be overridable
>   ASoC: codecs: Add RK3308 internal audio codec driver
>   ASoC: rockchip: add new RK3308 sound card

Please pay attention to the ordering of your serieses when posting:
generally any bug fixes should come first so that they can be easily
sent as fixes, and normally DTS updates are at the very end of the
series rather than mixed in the middle since they go via the platform
maintainer tree normally rather than with everything else.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 0/8] Add support for the internal RK3308 audio codec
  2022-09-07 15:41 ` [PATCH 0/8] Add support for the internal RK3308 audio codec Mark Brown
@ 2022-09-07 17:15   ` Luca Ceresoli
  0 siblings, 0 replies; 22+ messages in thread
From: Luca Ceresoli @ 2022-09-07 17:15 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

Hello Mark,

thanks for the quick feedback!

On Wed, 7 Sep 2022 16:41:44 +0100
Mark Brown <broonie@kernel.org> wrote:

> On Wed, Sep 07, 2022 at 04:21:16PM +0200, luca.ceresoli@bootlin.com wrote:
> 
> > Luca Ceresoli (8):
> >   ASoC: rockchip: rk3308: add internal audio codec bindings
> >   ASoC: rockchip: rk3308: add audio card bindings
> >   arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3
> >   arm64: dts: rockchip: add the internal audio codec
> >   ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk()
> >   ASoC: audio-graph: let dai_link->init be overridable
> >   ASoC: codecs: Add RK3308 internal audio codec driver
> >   ASoC: rockchip: add new RK3308 sound card  
> 
> Please pay attention to the ordering of your serieses when posting:
> generally any bug fixes should come first so that they can be easily
> sent as fixes, and normally DTS updates are at the very end of the
> series rather than mixed in the middle since they go via the platform
> maintainer tree normally rather than with everything else.

Sorry about that. I've reordered the patches in my branch for the next
iteration.

Best regards,
Luca
-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver
  2022-09-07 14:21 ` [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver luca.ceresoli
@ 2022-09-07 19:53   ` kernel test robot
       [not found]   ` <202209082103.F4ICyyHT-lkp@intel.com>
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 22+ messages in thread
From: kernel test robot @ 2022-09-07 19:53 UTC (permalink / raw)
  To: luca.ceresoli, alsa-devel, linux-rockchip
  Cc: llvm, kbuild-all, Luca Ceresoli, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Heiko Stuebner, Jaroslav Kysela,
	Takashi Iwai, Nicolas Frattaroli, Philipp Zabel, Johan Jonker,
	Chris Morgan

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on rockchip/for-next tiwai-sound/for-next linus/master v6.0-rc4 next-20220907]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/luca-ceresoli-bootlin-com/Add-support-for-the-internal-RK3308-audio-codec/20220907-222555
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: riscv-randconfig-r042-20220907 (https://download.01.org/0day-ci/archive/20220908/202209080340.RFBeIVm2-lkp@intel.com/config)
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project c55b41d5199d2394dd6cdb8f52180d8b81d809d4)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install riscv cross compiling tool for clang build
        # apt-get install binutils-riscv64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/786c160ad64ae5a6c5266184b12ecf2674db2fbe
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review luca-ceresoli-bootlin-com/Add-support-for-the-internal-RK3308-audio-codec/20220907-222555
        git checkout 786c160ad64ae5a6c5266184b12ecf2674db2fbe
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/rk3308_codec.c:2007:6: warning: variable 'err' set but not used [-Wunused-but-set-variable]
           int err;
               ^
   1 warning generated.


vim +/err +2007 sound/soc/codecs/rk3308_codec.c

  2003	
  2004	static int rk3308_codec_parse_dt(struct rk3308_codec_priv *rk3308)
  2005	{
  2006		struct device_node *np = rk3308->dev->of_node;
> 2007		int err;
  2008	
  2009		/* Default value is 0 */
  2010		err = of_property_read_u32(np, "rockchip,micbias-avdd-multiplier",
  2011					   &rk3308->micbias_avdd_mult);
  2012		if (rk3308->micbias_avdd_mult >= RK3308_CODEC_MICBIAS_NUM)
  2013			return dev_err_probe(rk3308->dev, -EINVAL,
  2014					     "Invalid value for 'rockchip,micbias-avdd-multiplier'\n");
  2015	
  2016		return 0;
  2017	}
  2018	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings
  2022-09-07 14:21 ` [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings luca.ceresoli
@ 2022-09-08 11:49   ` Krzysztof Kozlowski
  2022-09-08 15:20     ` Luca Ceresoli
  0 siblings, 1 reply; 22+ messages in thread
From: Krzysztof Kozlowski @ 2022-09-08 11:49 UTC (permalink / raw)
  To: luca.ceresoli, alsa-devel, linux-rockchip
  Cc: devicetree, linux-arm-kernel, linux-kernel, Liam Girdwood,
	Mark Brown, Rob Herring, Krzysztof Kozlowski, Heiko Stuebner,
	Jaroslav Kysela, Takashi Iwai, Nicolas Frattaroli, Philipp Zabel,
	Johan Jonker, Chris Morgan

On 07/09/2022 16:21, luca.ceresoli@bootlin.com wrote:
> From: Luca Ceresoli <luca.ceresoli@bootlin.com>
> 
> Add device tree bindings document for the audio card based on the internal
> I2S of the Rockchip RK3308 SoC.

Use subject prefixes matching the subsystem (git log --oneline -- ...).

> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> ---
>  .../rockchip,rk3308-audio-graph-card.yaml     | 50 +++++++++++++++++++
>  MAINTAINERS                                   |  5 ++
>  2 files changed, 55 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
> new file mode 100644
> index 000000000000..8445a69dcdbb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
> @@ -0,0 +1,50 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/rockchip,rk3308-audio-graph-card.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip RK3308 Audio card based on internal I2S
> +
> +maintainers:
> +  - Luca Ceresoli <luca.ceresoli@bootlin.com>
> +
> +allOf:
> +  - $ref: /schemas/sound/audio-graph.yaml#
> +
> +properties:
> +  compatible:
> +    const: rockchip,rk3308-audio-graph-card

Is "graph" part of device name or you just put it there because of other
schema? The compatible should reflect the device name, not some other
pieces in Linux or in bindings.

> +
> +required:
> +  - compatible
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    sound {
> +        compatible = "rockchip,rk3308-audio-graph-card";
> +        dais = <&i2s_8ch_2_port>;
> +    };
> +
> +    i2s_8ch_2 {

No underscores in node names. Generic node names. This does not look
like related example...

> +        i2s_8ch_2_port: port {
> +            i2s_8ch_2_endpoint: endpoint {
> +                remote-endpoint = <&acodec_endpoint>;
> +                dai-format = "i2s";
> +
> +                /* The RK3308 acodec has no clock dividers, use the CPU */
> +                bitclock-master = <&i2s_8ch_2_endpoint>;
> +                frame-master = <&i2s_8ch_2_endpoint>;
> +            };
> +        };
> +    };
> +
> +    acodec {

codec or audio-codec

> +        port {
> +            acodec_endpoint: endpoint {
> +                remote-endpoint = <&i2s_8ch_2_endpoint>;
> +            };
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index d53a8e74cb1e..079bdd95dc49 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17594,6 +17594,11 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
>  F:	include/dt-bindings/sound/rockchip,rk3308-codec.h
>  
> +ROCKCHIP RK3308 SOUND CARD DRIVER
> +M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
> +
>  ROCKCHIP VIDEO DECODER DRIVER
>  M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
>  L:	linux-media@vger.kernel.org


Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings
  2022-09-07 14:21 ` [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings luca.ceresoli
@ 2022-09-08 11:53   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 22+ messages in thread
From: Krzysztof Kozlowski @ 2022-09-08 11:53 UTC (permalink / raw)
  To: luca.ceresoli, alsa-devel, linux-rockchip
  Cc: devicetree, linux-arm-kernel, linux-kernel, Liam Girdwood,
	Mark Brown, Rob Herring, Krzysztof Kozlowski, Heiko Stuebner,
	Jaroslav Kysela, Takashi Iwai, Nicolas Frattaroli, Philipp Zabel,
	Johan Jonker, Chris Morgan

On 07/09/2022 16:21, luca.ceresoli@bootlin.com wrote:
> From: Luca Ceresoli <luca.ceresoli@bootlin.com>
> 
> Add device tree bindings document for the internal audio codec of the
> Rockchip RK3308 SoC.
> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>

Use subject prefixes matching the subsystem (git log --oneline -- ...).

> ---
>  .../bindings/sound/rockchip,rk3308-codec.yaml | 102 ++++++++++++++++++
>  MAINTAINERS                                   |   6 ++
>  .../dt-bindings/sound/rockchip,rk3308-codec.h |  15 +++
>  3 files changed, 123 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
>  create mode 100644 include/dt-bindings/sound/rockchip,rk3308-codec.h
> 
> diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
> new file mode 100644
> index 000000000000..f3458f86ef06
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
> @@ -0,0 +1,102 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/rockchip,rk3308-codec.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip RK3308 Internal Codec
> +
> +description: |
> +  This is the audio codec embedded in the Rockchip RK3308
> +  SoC. It has 8 24-bit ADCs and 2 24-bit DACs. The maximum supported
> +  sampling rate is 192 kHz.
> +
> +  It is connected internally to one out of a selection of the internal I2S
> +  controllers.
> +
> +  The RK3308 audio codec has 8 independent capture channels, but some
> +  features work on stereo pairs called groups:
> +    * grp 0 -- MIC1 / MIC2
> +    * grp 1 -- MIC3 / MIC4
> +    * grp 2 -- MIC5 / MIC6
> +    * grp 3 -- MIC7 / MIC8
> +
> +maintainers:
> +  - Luca Ceresoli <luca.ceresoli@bootlin.com>
> +
> +properties:
> +  compatible:
> +    const: rockchip,rk3308-codec
> +
> +  reg:
> +    maxItems: 1
> +
> +  rockchip,grf:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      Phandle to the General Register Files (GRF)
> +
> +  clocks:
> +    items:
> +      - description: clock for TX
> +      - description: clock for RX
> +      - description: AHB clock driving the interface
> +
> +  clock-names:
> +    items:
> +      - const: mclk_tx
> +      - const: mclk_rx
> +      - const: hclk
> +
> +  resets: true

maxItems: 1

> +
> +  reset-names:
> +    items:
> +      - const: "acodec"

No quotes.

> +
> +  "#sound-dai-cells":
> +    const: 0
> +
> +  rockchip,micbias-avdd-multiplier:
> +    description: |
> +      Voltage setting for the MICBIAS pins expressed as a multiplier of
> +      AVDD.
> +
> +      E.g. if rockchip,micbias-avdd-multiplier = 7 (x0.85) and AVDD = 3v3,
> +      then MIC BIAS voltage will be 3.3 V * 0.85 = 2.805 V.
> +
> +      Value 0: multiplier = 0.50
> +      Value N: multiplier = 0.50 + 0.05 * N
> +      Value 7: multiplier = 0.85

Use logical values/units. The units is 0.05, so "-percent" in node name.
https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml
Then drop ref and use enum.

> +
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    maximum: 7
> +
> +required:
> +  - compatible
> +  - reg
> +  - rockchip,grf
> +  - clocks
> +  - resets
> +  - "#sound-dai-cells"
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/rk3308-cru.h>
> +
> +    acodec: acodec@ff560000 {

codec

Node names should be generic.
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation

> +        compatible = "rockchip,rk3308-codec";
> +        reg = <0xff560000 0x10000>;
> +        rockchip,grf = <&grf>;
> +        clock-names = "mclk_tx", "mclk_rx", "hclk";
> +        clocks = <&cru SCLK_I2S2_8CH_TX_OUT>,
> +                 <&cru SCLK_I2S2_8CH_RX_OUT>,
> +                 <&cru PCLK_ACODEC>;
> +        reset-names = "acodec";
> +        resets = <&cru SRST_ACODEC_P>;
> +        #sound-dai-cells = <0>;
> +    };
> +
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 895e8ace80dd..d53a8e74cb1e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17588,6 +17588,12 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/media/rockchip-rga.yaml
>  F:	drivers/media/platform/rockchip/rga/
>  
> +ROCKCHIP RK3308 INTERNAL AUDIO CODEC
> +M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
> +F:	include/dt-bindings/sound/rockchip,rk3308-codec.h
> +
>  ROCKCHIP VIDEO DECODER DRIVER
>  M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
>  L:	linux-media@vger.kernel.org
> diff --git a/include/dt-bindings/sound/rockchip,rk3308-codec.h b/include/dt-bindings/sound/rockchip,rk3308-codec.h
> new file mode 100644
> index 000000000000..9f1b210a048e
> --- /dev/null
> +++ b/include/dt-bindings/sound/rockchip,rk3308-codec.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */

Dual license.

> +#ifndef __DT_BINDINGS_ROCKCHIP_RK3308_CODEC_H__
> +#define __DT_BINDINGS_ROCKCHIP_RK3308_CODEC_H__
> +
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_50	0
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_55	1
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_60	2
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_65	3
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_70	4
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_75	5
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_80	6
> +#define RK3308_CODEC_MICBIAS_AVDD_x_0_85	7

You store register values in the bindings. Nope. Bindings are not for this.

Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 4/8] arm64: dts: rockchip: add the internal audio codec
  2022-09-07 14:21 ` [PATCH 4/8] arm64: dts: rockchip: add the internal audio codec luca.ceresoli
@ 2022-09-08 11:53   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 22+ messages in thread
From: Krzysztof Kozlowski @ 2022-09-08 11:53 UTC (permalink / raw)
  To: luca.ceresoli, alsa-devel, linux-rockchip
  Cc: devicetree, linux-arm-kernel, linux-kernel, Liam Girdwood,
	Mark Brown, Rob Herring, Krzysztof Kozlowski, Heiko Stuebner,
	Jaroslav Kysela, Takashi Iwai, Nicolas Frattaroli, Philipp Zabel,
	Johan Jonker, Chris Morgan

On 07/09/2022 16:21, luca.ceresoli@bootlin.com wrote:
> From: Luca Ceresoli <luca.ceresoli@bootlin.com>
> 
> The RK3308 has a built-in audio codec that connects internally to i2s_8ch_2
> or i2s_8ch_3.
> 
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> ---
>  arch/arm64/boot/dts/rockchip/rk3308.dtsi | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
> index 093b70563b23..221cde49dc98 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
> @@ -808,6 +808,20 @@ cru: clock-controller@ff500000 {
>  		assigned-clock-rates = <32768>;
>  	};
>  
> +	acodec: acodec@ff560000 {

Node names should be generic.
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation


Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings
  2022-09-08 11:49   ` Krzysztof Kozlowski
@ 2022-09-08 15:20     ` Luca Ceresoli
  2022-09-08 15:28       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 22+ messages in thread
From: Luca Ceresoli @ 2022-09-08 15:20 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Heiko Stuebner, Jaroslav Kysela,
	Takashi Iwai, Nicolas Frattaroli, Philipp Zabel, Johan Jonker,
	Chris Morgan

Hello Krzysztof,

thank you for reviewing my patches.

On Thu, 8 Sep 2022 13:49:34 +0200
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 07/09/2022 16:21, luca.ceresoli@bootlin.com wrote:
> > From: Luca Ceresoli <luca.ceresoli@bootlin.com>

[...]

> > +properties:
> > +  compatible:
> > +    const: rockchip,rk3308-audio-graph-card  
> 
> Is "graph" part of device name or you just put it there because of other
> schema?

Indeed this comes from the "audio-graph-card" compatible string.

> The compatible should reflect the device name, not some other
> pieces in Linux or in bindings.

Would it be OK to rename it to rockchip,rk3308-audio-card (i.e. drop
the "graph-" infix)?

Fixes for the other comments you made to this and the other patches are
already queued for v2.

Best regards,
Luca
-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings
  2022-09-08 15:20     ` Luca Ceresoli
@ 2022-09-08 15:28       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 22+ messages in thread
From: Krzysztof Kozlowski @ 2022-09-08 15:28 UTC (permalink / raw)
  To: Luca Ceresoli
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Heiko Stuebner, Jaroslav Kysela,
	Takashi Iwai, Nicolas Frattaroli, Philipp Zabel, Johan Jonker,
	Chris Morgan

On 08/09/2022 17:20, Luca Ceresoli wrote:
> Hello Krzysztof,
> 
> thank you for reviewing my patches.
> 
> On Thu, 8 Sep 2022 13:49:34 +0200
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 07/09/2022 16:21, luca.ceresoli@bootlin.com wrote:
>>> From: Luca Ceresoli <luca.ceresoli@bootlin.com>
> 
> [...]
> 
>>> +properties:
>>> +  compatible:
>>> +    const: rockchip,rk3308-audio-graph-card  
>>
>> Is "graph" part of device name or you just put it there because of other
>> schema?
> 
> Indeed this comes from the "audio-graph-card" compatible string.
> 
>> The compatible should reflect the device name, not some other
>> pieces in Linux or in bindings.
> 
> Would it be OK to rename it to rockchip,rk3308-audio-card (i.e. drop
> the "graph-" infix)?
> 
> Fixes for the other comments you made to this and the other patches are
> already queued for v2.

Yes, either rockchip,rk3308-audio-card or rockchip,rk3308-audio


Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver
       [not found]   ` <202209082103.F4ICyyHT-lkp@intel.com>
@ 2022-09-08 15:33     ` Luca Ceresoli
  0 siblings, 0 replies; 22+ messages in thread
From: Luca Ceresoli @ 2022-09-08 15:33 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: kbuild, alsa-devel, linux-rockchip, lkp, kbuild-all, devicetree,
	linux-arm-kernel, linux-kernel, Liam Girdwood, Mark Brown,
	Rob Herring, Krzysztof Kozlowski, Heiko Stuebner,
	Jaroslav Kysela, Takashi Iwai, Nicolas Frattaroli, Philipp Zabel,
	Johan Jonker, Chris Morgan

Hello Dan,

On Thu, 8 Sep 2022 16:35:19 +0300
Dan Carpenter <dan.carpenter@oracle.com> wrote:

> Hi,
> 
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/luca-ceresoli-bootlin-com/Add-support-for-the-internal-RK3308-audio-codec/20220907-222555
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
> config: arc-randconfig-m031-20220908 (https://download.01.org/0day-ci/archive/20220908/202209082103.F4ICyyHT-lkp@intel.com/config)
> compiler: arceb-elf-gcc (GCC) 12.1.0
> 
> If you fix the issue, kindly add following tag where applicable
> Reported-by: kernel test robot <lkp@intel.com>
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> 
> smatch warnings:
> sound/soc/codecs/rk3308_codec.c:748 rk3308_set_dai_fmt() error: uninitialized symbol 'is_master'.
> sound/soc/codecs/rk3308_codec.c:998 rk3308_codec_digital_fadeout() warn: always true condition '(l_dgain >= (0 << 0)) => (0-u32max >= 0)'
> sound/soc/codecs/rk3308_codec.c:998 rk3308_codec_digital_fadeout() warn: always true condition '(l_dgain >= (0 << 0)) => (0-u32max >= 0)'
> 
> vim +/is_master +748 sound/soc/codecs/rk3308_codec.c
> 
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  680  static int rk3308_set_dai_fmt(struct snd_soc_dai *codec_dai,
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  681  			      unsigned int fmt)
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  682  {
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  683  	struct snd_soc_component *component = codec_dai->component;
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  684  	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  685  	const unsigned int inv_bits = fmt & SND_SOC_DAIFMT_INV_MASK;
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  686  	const bool inv_bitclk =
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  687  		(inv_bits & SND_SOC_DAIFMT_IB_IF) ||
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  688  		(inv_bits & SND_SOC_DAIFMT_IB_NF);
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  689  	const bool inv_frmclk =
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  690  		(inv_bits & SND_SOC_DAIFMT_IB_IF) ||
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  691  		(inv_bits & SND_SOC_DAIFMT_NB_IF);
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  692  
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  693  	unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
> 786c160ad64ae5 Luca Ceresoli 2022-09-07  694  	int grp, is_master;
> 
> is_master needs to be initialized to false.

Fixed both, and also made is_master a bool for clarity. Changes queued
for v2.

Thank you.
-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver
  2022-09-07 14:21 ` [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver luca.ceresoli
  2022-09-07 19:53   ` kernel test robot
       [not found]   ` <202209082103.F4ICyyHT-lkp@intel.com>
@ 2022-09-08 16:27   ` Mark Brown
  2022-09-09 17:11     ` Luca Ceresoli
  2022-09-09 23:15   ` kernel test robot
  3 siblings, 1 reply; 22+ messages in thread
From: Mark Brown @ 2022-09-08 16:27 UTC (permalink / raw)
  To: luca.ceresoli
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan


[-- Attachment #1.1: Type: text/plain, Size: 13859 bytes --]

On Wed, Sep 07, 2022 at 04:21:23PM +0200, luca.ceresoli@bootlin.com wrote:

> +static const char *offon_text[2] = {
> +	[0] = "Off",
> +	[1] = "On",
> +};

Simple on/off controls should be normal switches, not enums.

> +/* ALC AGC Switch */
> +static const struct soc_enum rk3308_agc_enum_array[] = {
> +	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text),
> +	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(offon_text), offon_text),

Do not index into arrays of enums with magic numbers, this is hard to
read and maintain.  Use named variables for the enums like other drivers
do.

> +static void rk3308_codec_update_zerocross(struct rk3308_codec_priv *rk3308)
> +{
> +	unsigned int agc_on, value;
> +	int grp;
> +
> +	/* 14: enable zero-cross detection if AGC enabled, else AGC won't work */
> +	for (grp = 0; grp < rk3308->used_adc_grps; grp++) {

If you're going to force zero cross on then you need to generate an
event on the zero cross control so that UIs get updated, however it
might be a bit more idiomatic to either just leave zero cross always on
and not offer user control or return an error if the user tries to
enable AGC without zero cross (or tries to disable zero cross without
AGC).  Given that there's very few use cases for disabling zero cross
with actual audio usage it may be best to just force it on and worry
about offering control for those other use cases later if someone
actually needs that, it's probably more trouble than it's worth to
handle.

> +static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol,
> +				struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
> +	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
> +

> +	}
> +
> +	rk3308_codec_update_zerocross(rk3308);
> +
> +	return 0;
> +}

_put() operations need to return 1 if the value changed, please run the
mixer-test selftest on a system with your driver0 - it'll catch issues
like this for you.

> +	if (any_micbias_enabled) {
> +		regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0),
> +				   RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK,
> +				   rk3308->micbias_avdd_mult);
> +
> +		/* Wait until the VCMH keep stable */
> +		msleep(20);	/* estimated value */
> +
> +		regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0),
> +				RK3308_ADC_MICBIAS_CURRENT_EN);
> +	}

This should probably be modelled as a SUPPLY widget for the micbiases
rather than open coding.

> +static int rk3308_codec_micbias_put(struct snd_kcontrol *kcontrol,
> +				    struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
> +	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);

There should be no reason to offer userspace control over micbiases,
they should be modelled as supply widgets like with other drivers.  If
there's some system specific reason for offering control then the
machine driver can handle it.

> +static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol,
> +					struct snd_ctl_elem_value *ucontrol)
> +{
> +	return snd_soc_get_volsw_range(kcontrol, ucontrol);
> +}

Just use the generic function directly, no need for this wrapper.

> +static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol,
> +					struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
> +	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
> +	unsigned int dgain = ucontrol->value.integer.value[0];
> +
> +	rk3308->hpout_r_dgain = dgain;
> +
> +	return snd_soc_put_volsw_range(kcontrol, ucontrol);
> +}

Just model the headphone output as a stereo control.

> +	 * There are 8 ADCs and use the same SCLK and LRCK internal for master
> +	 * mode, We need to make sure that they are in effect at the same time,
> +	 * otherwise they will cause the abnormal clocks.
> +	 */
> +	if (is_master)
> +		regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
> +
> +	for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
> +		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
> +				   RK3308_ADC_I2S_LRC_POL_REVERSAL |
> +				   RK3308_ADC_I2S_MODE_MSK,
> +				   adc_aif1);
> +		regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp),
> +				   RK3308_ADC_IO_MODE_MASTER |
> +				   RK3308_ADC_MODE_MASTER |
> +				   RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL,
> +				   adc_aif2);
> +	}
> +
> +	/* Hold ADC Digital registers end at master mode */
> +	if (is_master)
> +		regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);

This looks like it might glitch other active streams, you should
probably have a check to see if the configuration is actually being
changed and skip updates entirely if not.

> +static int rk3308_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
> +
> +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		int dgain;
> +
> +		if (mute) {
> +			for (dgain = 0x2; dgain <= 0x7; dgain++) {
> +				/*
> +				 * Keep the max -> min digital CIC interpolation
> +				 * filter gain step by step.
> +				 *
> +				 * loud: 0x2; whisper: 0x7
> +				 */
> +				regmap_update_bits(rk3308->regmap,
> +						   RK3308_DAC_DIG_CON04,
> +						   RK3308_DAC_CIC_IF_GAIN_MSK,
> +						   dgain);
> +				usleep_range(200, 300);  /* estimated value */
> +			}

I'm not clear why a volume ramp is required here?  Generally when the
mute operation happens there's no audio running so we'd just be ramping
up the noise floor, it's for masking glitches from the controller.

> +static int rk3308_codec_digital_fadein(struct rk3308_codec_priv *rk3308)
> +{
> +	unsigned int dgain, dgain_ref;
> +
> +	if (rk3308->hpout_l_dgain != rk3308->hpout_r_dgain) {
> +		pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n",
> +			rk3308->hpout_l_dgain, rk3308->hpout_r_dgain);
> +		dgain_ref = min(rk3308->hpout_l_dgain, rk3308->hpout_r_dgain);
> +	} else {
> +		dgain_ref = rk3308->hpout_l_dgain;
> +	}

Does the device actively need this for masking some issue with clean
startup or is this just a nice to have?  It should be easy enough to
handle asymmatric volumes, you can just ramp by one step at once and
just stop ramping on whichever channel needs fewer steps whenever it
hits target.

If there's some other reason the gains absolutely must be identical just
offer a mono control.

> +	/*
> +	 * We'd better change the gain of the left and right channels
> +	 * at the same time to avoid different listening
> +	 */

Looks like it is working around a power up issue so it's fine to have
this.

> +static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308)
> +{

This looks way, way too open coded - you should be implementing a DAPM
graph for the device and splitting things up.

> +	/*
> +	 * 1. Set the ACODEC_DAC_ANA_CON0[0] to 0x1, to enable the current
> +	 * source of DAC
> +	 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON00,
> +			RK3308_DAC_CURRENT_EN);
> +
> +	usleep_range(20, 40);

This should be a DAC widget.

> +
> +	/*
> +	 * 2. Set the ACODEC_DAC_ANA_CON1[6] and ACODEC_DAC_ANA_CON1[2] to 0x1,
> +	 * to enable the reference voltage buffer
> +	 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
> +			RK3308_DAC_BUF_REF_L_EN |
> +			RK3308_DAC_BUF_REF_R_EN);
> +
> +	/* Waiting the stable reference voltage */
> +	mdelay(1);

This should be a supply.

> +	/* Step 03 */
> +	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
> +			   RK3308_DAC_HPOUT_POP_SOUND_L_MSK |
> +			   RK3308_DAC_HPOUT_POP_SOUND_R_MSK,
> +			   RK3308_DAC_HPOUT_POP_SOUND_L_WORK |
> +			   RK3308_DAC_HPOUT_POP_SOUND_R_WORK);
> +
> +	usleep_range(20, 40);
> +

You can probably push preparatory work like this into a fake supply
widget, wm8994 has some stuff like that.

> +	/* Step 05 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
> +			RK3308_DAC_L_HPMIX_EN |
> +			RK3308_DAC_R_HPMIX_EN);
> +
> +	/* Waiting the stable HPMIX */
> +	mdelay(1);
> +
> +	/* Step 06. Reset HPMIX and recover HPMIX gains */
> +	regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
> +			  RK3308_DAC_L_HPMIX_WORK |
> +			  RK3308_DAC_R_HPMIX_WORK);
> +	usleep_range(50, 100);
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
> +			RK3308_DAC_L_HPMIX_WORK |
> +			RK3308_DAC_R_HPMIX_WORK);
> +
> +	usleep_range(20, 40);

These are mixers.

> +	if (rk3308->dac_output == DAC_LINEOUT ||
> +	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
> +		/* Step 07 */
> +		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
> +				RK3308_DAC_L_LINEOUT_EN |
> +				RK3308_DAC_R_LINEOUT_EN);
> +
> +		usleep_range(20, 40);
> +	}
> +
> +	if (rk3308->dac_output == DAC_HPOUT ||
> +	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
> +		/* Step 08 */
> +		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
> +				RK3308_DAC_L_HPOUT_EN |
> +				RK3308_DAC_R_HPOUT_EN);
> +
> +		usleep_range(20, 40);
> +
> +		/* Step 09 */
> +		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
> +				RK3308_DAC_L_HPOUT_WORK |
> +				RK3308_DAC_R_HPOUT_WORK);
> +
> +		usleep_range(20, 40);
> +	}
> +
> +	if (rk3308->codec_ver == ACODEC_VERSION_B) {
> +		/* Step 10 */
> +		regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15,
> +				   RK3308_DAC_LINEOUT_POP_SOUND_L_MSK |
> +				   RK3308_DAC_LINEOUT_POP_SOUND_R_MSK,
> +				   RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL |
> +				   RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL);
> +
> +		usleep_range(20, 40);
> +	}
> +
> +	/* Step 11 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
> +			RK3308_DAC_L_REF_EN | RK3308_DAC_R_REF_EN);
> +
> +	usleep_range(20, 40);
> +
> +	/* Step 12 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
> +			RK3308_DAC_L_CLK_EN | RK3308_DAC_R_CLK_EN);
> +
> +	usleep_range(20, 40);
> +
> +	/* Step 13 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
> +			RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN);
> +
> +	usleep_range(20, 40);
> +
> +	/* Step 14 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
> +			RK3308_DAC_L_DAC_WORK | RK3308_DAC_R_DAC_WORK);
> +
> +	usleep_range(20, 40);
> +
> +	/* Step 15 */
> +	regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12,
> +			   RK3308_DAC_L_HPMIX_SEL_MSK |
> +			   RK3308_DAC_R_HPMIX_SEL_MSK,
> +			   RK3308_DAC_L_HPMIX_I2S |
> +			   RK3308_DAC_R_HPMIX_I2S);
> +
> +	usleep_range(20, 40);
> +
> +	/* Step 16 */
> +	regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON13,
> +			RK3308_DAC_L_HPMIX_UNMUTE | RK3308_DAC_R_HPMIX_UNMUTE);
> +
> +	usleep_range(20, 40);
> +
> +	/* Step 17: Put configuration HPMIX Gain */
> +
> +	if (rk3308->dac_output == DAC_HPOUT ||
> +	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
> +		/* Step 18 */
> +		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON03,
> +				RK3308_DAC_L_HPOUT_UNMUTE | RK3308_DAC_R_HPOUT_UNMUTE);
> +
> +		usleep_range(20, 40);
> +	}

These are all output drivers.

> +
> +	if (rk3308->dac_output == DAC_LINEOUT ||
> +	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
> +		/* Step 19 */
> +		regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON04,
> +				RK3308_DAC_L_LINEOUT_UNMUTE | RK3308_DAC_R_LINEOUT_UNMUTE);
> +		usleep_range(20, 40);
> +	}
> +
> +	/* Step 20, put configuration HPOUT gain control */
> +	/* Step 21, put configuration LINEOUT gain control */
> +
> +	if (rk3308->dac_output == DAC_HPOUT ||
> +	    rk3308->dac_output == DAC_LINEOUT_HPOUT) {
> +		/* Just for HPOUT */
> +		rk3308_codec_digital_fadein(rk3308);
> +	}

Use a _POST widget for this.

> +static int rk3308_codec_power_on(struct rk3308_codec_priv *rk3308)
> +{
> +	unsigned int v;
> +

> +static int rk3308_codec_power_off(struct rk3308_codec_priv *rk3308)
> +{
> +	unsigned int v;

This would normally be in set_bias_level() or a DAPM supply, probably
set_bias_level() as there's a few moderate delays.

> +static int rk3308_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
> +	int ret;
> +
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		/* DAC only supports 2 channels */
> +		rk3308_codec_dac_mclk_enable(rk3308);
> +		rk3308_codec_dac_enable(rk3308);
> +		rk3308_codec_dac_dig_config(rk3308, params);
> +	} else {
> +		rk3308_codec_micbias_apply(rk3308);
> +		rk3308_codec_adc_mclk_enable(rk3308);
> +		ret = rk3308_codec_update_adc_grps(rk3308, params);
> +		if (ret < 0)
> +			return ret;
> +
> +		rk3308_codec_open_capture(rk3308);
> +		rk3308_codec_agc_dig_config(rk3308, params);
> +		rk3308_codec_adc_dig_config(rk3308, params);
> +	}

Note that hw_params() can be called repeatedly before actually starting
the audio, you shouldn't be doing any refcounted operations.  There is
an open operation or again lots of this looks like powerup stuff which
could be moved to DAPM.

> +static int rk3308_codec_default_gains(struct rk3308_codec_priv *rk3308)
> +{

Use the hardware defaults, don't open code settings for things like
gains.  Your settings may not be appropriate for other systems.

> +static int rk3308_codec_prepare(struct rk3308_codec_priv *rk3308)
> +{
> +	/* Clear registers for ADC and DAC */
> +	rk3308_codec_dac_disable(rk3308);
> +	rk3308_codec_adc_ana_disable(rk3308, ADC_LR_GROUP_MAX);
> +	rk3308_codec_default_gains(rk3308);
> +	rk3308_codec_llp_down(rk3308);
> +	rk3308_codec_controls_prepare(rk3308);

This applies to settings in general, the exceptions are generally things
like zero cross where it's so overwhelmingly clear what makes sense and
the setting is more of a chicken bit than actually useful.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 5/8] ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk()
  2022-09-07 14:21 ` [PATCH 5/8] ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk() luca.ceresoli
@ 2022-09-08 16:36   ` Mark Brown
  0 siblings, 0 replies; 22+ messages in thread
From: Mark Brown @ 2022-09-08 16:36 UTC (permalink / raw)
  To: luca.ceresoli
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan


[-- Attachment #1.1: Type: text/plain, Size: 925 bytes --]

On Wed, Sep 07, 2022 at 04:21:21PM +0200, luca.ceresoli@bootlin.com wrote:

> -static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,
> +static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
>  				       unsigned int freq, int dir)
>  {
>  	struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai);
> @@ -978,15 +981,18 @@ static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,
>  	if (i2s_tdm->clk_trcm) {
>  		i2s_tdm->mclk_tx_freq = freq;
>  		i2s_tdm->mclk_rx_freq = freq;
> +
> +		dev_dbg(i2s_tdm->dev, "mclk freq: %u", freq);
>  	} else {
> -		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		if (clk_id == CLK_IDX_MCLK_TX)
>  			i2s_tdm->mclk_tx_freq = freq;
> -		else
> +		else if (clk_id == CLK_IDX_MCLK_RX)
>  			i2s_tdm->mclk_rx_freq = freq;
> -	}
> +		else
> +			return -ENOTSUPP;

This should be a switch statement for clarity and exensibility.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver
  2022-09-08 16:27   ` Mark Brown
@ 2022-09-09 17:11     ` Luca Ceresoli
  0 siblings, 0 replies; 22+ messages in thread
From: Luca Ceresoli @ 2022-09-09 17:11 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, linux-rockchip, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Rob Herring, Krzysztof Kozlowski,
	Heiko Stuebner, Jaroslav Kysela, Takashi Iwai,
	Nicolas Frattaroli, Philipp Zabel, Johan Jonker, Chris Morgan

Hello Mark,

On Thu, 8 Sep 2022 17:27:36 +0100
Mark Brown <broonie@kernel.org> wrote:

> On Wed, Sep 07, 2022 at 04:21:23PM +0200, luca.ceresoli@bootlin.com wrote:

Thank you for taking the time to review my patch in such detail! This
is my first contribution to ALSA, and it was not clear to me which
parts of the existing vendor driver needed even more cleanups than I
have already done. I will probably get back to you with specific
questions later on, while addressing your comments.

Best regards,
Luca
-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver
  2022-09-07 14:21 ` [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver luca.ceresoli
                     ` (2 preceding siblings ...)
  2022-09-08 16:27   ` Mark Brown
@ 2022-09-09 23:15   ` kernel test robot
  3 siblings, 0 replies; 22+ messages in thread
From: kernel test robot @ 2022-09-09 23:15 UTC (permalink / raw)
  To: luca.ceresoli, alsa-devel, linux-rockchip
  Cc: llvm, kbuild-all, Luca Ceresoli, devicetree, linux-arm-kernel,
	linux-kernel, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Heiko Stuebner, Jaroslav Kysela,
	Takashi Iwai, Nicolas Frattaroli, Philipp Zabel, Johan Jonker,
	Chris Morgan

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on rockchip/for-next tiwai-sound/for-next linus/master v6.0-rc4 next-20220909]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/luca-ceresoli-bootlin-com/Add-support-for-the-internal-RK3308-audio-codec/20220907-222555
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: hexagon-randconfig-r033-20220907 (https://download.01.org/0day-ci/archive/20220910/202209100733.bM1xaUdC-lkp@intel.com/config)
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 1546df49f5a6d09df78f569e4137ddb365a3e827)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/786c160ad64ae5a6c5266184b12ecf2674db2fbe
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review luca-ceresoli-bootlin-com/Add-support-for-the-internal-RK3308-audio-codec/20220907-222555
        git checkout 786c160ad64ae5a6c5266184b12ecf2674db2fbe
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   sound/soc/codecs/rk3308_codec.c:2007:6: warning: variable 'err' set but not used [-Wunused-but-set-variable]
           int err;
               ^
>> sound/soc/codecs/rk3308_codec.c:2104:34: warning: unused variable 'rk3308codec_of_match' [-Wunused-const-variable]
   static const struct of_device_id rk3308codec_of_match[] = {
                                    ^
   2 warnings generated.


vim +/rk3308codec_of_match +2104 sound/soc/codecs/rk3308_codec.c

  2103	
> 2104	static const struct of_device_id rk3308codec_of_match[] = {
  2105		{ .compatible = "rockchip,rk3308-codec", },
  2106		{},
  2107	};
  2108	MODULE_DEVICE_TABLE(of, rk3308codec_of_match);
  2109	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2022-09-09 23:17 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-07 14:21 [PATCH 0/8] Add support for the internal RK3308 audio codec luca.ceresoli
2022-09-07 14:21 ` [PATCH 1/8] ASoC: rockchip: rk3308: add internal audio codec bindings luca.ceresoli
2022-09-08 11:53   ` Krzysztof Kozlowski
2022-09-07 14:21 ` [PATCH 2/8] ASoC: rockchip: rk3308: add audio card bindings luca.ceresoli
2022-09-08 11:49   ` Krzysztof Kozlowski
2022-09-08 15:20     ` Luca Ceresoli
2022-09-08 15:28       ` Krzysztof Kozlowski
2022-09-07 14:21 ` [PATCH 3/8] arm64: dts: rockchip: add i2s_8ch_2 and i2s_8ch_3 luca.ceresoli
2022-09-07 14:21 ` [PATCH 4/8] arm64: dts: rockchip: add the internal audio codec luca.ceresoli
2022-09-08 11:53   ` Krzysztof Kozlowski
2022-09-07 14:21 ` [PATCH 5/8] ASoC: rockchip: i2s-tdm: Fix clk_id usage in .set_sysclk() luca.ceresoli
2022-09-08 16:36   ` Mark Brown
2022-09-07 14:21 ` [PATCH 6/8] ASoC: audio-graph: let dai_link->init be overridable luca.ceresoli
2022-09-07 14:21 ` [PATCH 7/8] ASoC: codecs: Add RK3308 internal audio codec driver luca.ceresoli
2022-09-07 19:53   ` kernel test robot
     [not found]   ` <202209082103.F4ICyyHT-lkp@intel.com>
2022-09-08 15:33     ` Luca Ceresoli
2022-09-08 16:27   ` Mark Brown
2022-09-09 17:11     ` Luca Ceresoli
2022-09-09 23:15   ` kernel test robot
2022-09-07 14:21 ` [PATCH 8/8] ASoC: rockchip: add new RK3308 sound card luca.ceresoli
2022-09-07 15:41 ` [PATCH 0/8] Add support for the internal RK3308 audio codec Mark Brown
2022-09-07 17:15   ` Luca Ceresoli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).