Selaa lähdekoodia

Merge tag 'asoc-v4.2' into asoc-next

ASoC: Updates for v4.2

The big thing this release has been Liam's addition of topology support
to the core.  We've also seen quite a bit of driver work and the
continuation of Lars' refactoring for component support.

 - Support for loading ASoC topology maps from firmware, intended to be
   used to allow self-describing DSP firmware images to be built which
   can map controls added by the DSP to userspace without the kernel
   needing to know about individual DSP firmwares.
 - Lots of refactoring to avoid direct access to snd_soc_codec where
   it's not needed supporting future refactoring.
 - Big refactoring and cleanup serieses for the Wolfson ADSP and TI
   TAS2552 drivers.
 - Support for TI TAS571x power amplifiers.
 - Support for Qualcomm APQ8016 and ZTE ZX296702 SoCs.
 - Support for x86 systems with RT5650 and Qualcomm Storm.

# gpg: Signature made Mon 08 Jun 2015 18:48:37 BST using RSA key ID 5D5487D0
# gpg: Oops: keyid_from_fingerprint: no pubkey
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
Mark Brown 10 vuotta sitten
vanhempi
commit
89fc594ba5
100 muutettua tiedostoa jossa 2843 lisäystä ja 850 poistoa
  1. 4 0
      Documentation/devicetree/bindings/sound/adi,adau1701.txt
  2. 13 0
      Documentation/devicetree/bindings/sound/bt-sco.txt
  3. 13 0
      Documentation/devicetree/bindings/sound/gtm601.txt
  4. 6 0
      Documentation/devicetree/bindings/sound/max98090.txt
  5. 12 1
      Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
  6. 1 1
      Documentation/devicetree/bindings/sound/renesas,rsnd.txt
  7. 2 0
      Documentation/devicetree/bindings/sound/rt5677.txt
  8. 41 0
      Documentation/devicetree/bindings/sound/tas571x.txt
  9. 11 0
      Documentation/devicetree/bindings/sound/wm8741.txt
  10. 44 0
      Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
  11. 28 0
      Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
  12. 1 0
      Documentation/devicetree/bindings/vendor-prefixes.txt
  13. 6 0
      MAINTAINERS
  14. 21 16
      drivers/dma/sh/rcar-dmac.c
  15. 0 5
      drivers/regulator/arizona-ldo1.c
  16. 9 0
      include/dt-bindings/sound/apq8016-lpass.h
  17. 9 0
      include/dt-bindings/sound/audio-jack-events.h
  18. 18 0
      include/dt-bindings/sound/tas2552.h
  19. 0 5
      include/sound/dmaengine_pcm.h
  20. 0 3
      include/sound/rt5645.h
  21. 49 0
      include/sound/soc-dapm.h
  22. 168 0
      include/sound/soc-topology.h
  23. 97 21
      include/sound/soc.h
  24. 1 14
      include/sound/tlv.h
  25. 388 0
      include/uapi/sound/asoc.h
  26. 31 0
      include/uapi/sound/tlv.h
  27. 1 0
      sound/soc/Kconfig
  28. 2 0
      sound/soc/Makefile
  29. 8 12
      sound/soc/atmel/Kconfig
  30. 3 5
      sound/soc/atmel/Makefile
  31. 1 2
      sound/soc/atmel/atmel-pcm-dma.c
  32. 3 7
      sound/soc/atmel/sam9g20_wm8731.c
  33. 1 1
      sound/soc/au1x/db1200.c
  34. 0 1
      sound/soc/cirrus/ep93xx-pcm.c
  35. 1 2
      sound/soc/codecs/88pm860x-codec.c
  36. 9 3
      sound/soc/codecs/Kconfig
  37. 2 0
      sound/soc/codecs/Makefile
  38. 11 9
      sound/soc/codecs/ab8500-codec.c
  39. 2 6
      sound/soc/codecs/ac97.c
  40. 1 1
      sound/soc/codecs/ad1836.c
  41. 0 1
      sound/soc/codecs/adau1373.c
  42. 110 16
      sound/soc/codecs/adau1701.c
  43. 12 15
      sound/soc/codecs/adau1761.c
  44. 4 6
      sound/soc/codecs/adau1781.c
  45. 10 10
      sound/soc/codecs/adau17x1.c
  46. 5 9
      sound/soc/codecs/adau1977.c
  47. 6 5
      sound/soc/codecs/adav80x.c
  48. 0 1
      sound/soc/codecs/ak4535.c
  49. 1 2
      sound/soc/codecs/ak4641.c
  50. 0 1
      sound/soc/codecs/ak4642.c
  51. 0 1
      sound/soc/codecs/ak4671.c
  52. 1 2
      sound/soc/codecs/alc5623.c
  53. 0 1
      sound/soc/codecs/alc5632.c
  54. 160 14
      sound/soc/codecs/arizona.c
  55. 15 2
      sound/soc/codecs/arizona.h
  56. 10 1
      sound/soc/codecs/bt-sco.c
  57. 0 1
      sound/soc/codecs/cq93vc.c
  58. 0 1
      sound/soc/codecs/cs35l32.c
  59. 0 1
      sound/soc/codecs/cs4265.c
  60. 2 3
      sound/soc/codecs/cs42l52.c
  61. 2 3
      sound/soc/codecs/cs42l56.c
  62. 1 2
      sound/soc/codecs/cs42l73.c
  63. 1 1
      sound/soc/codecs/cs42xx8.c
  64. 2 4
      sound/soc/codecs/cx20442.c
  65. 1 2
      sound/soc/codecs/da7213.c
  66. 1 3
      sound/soc/codecs/da732x.c
  67. 1 2
      sound/soc/codecs/da9055.c
  68. 1 2
      sound/soc/codecs/es8328.c
  69. 0 2
      sound/soc/codecs/isabelle.c
  70. 1 3
      sound/soc/codecs/jz4740.c
  71. 29 85
      sound/soc/codecs/lm4857.c
  72. 1 3
      sound/soc/codecs/lm49453.c
  73. 1 2
      sound/soc/codecs/max98088.c
  74. 21 13
      sound/soc/codecs/max98090.c
  75. 12 12
      sound/soc/codecs/max98095.c
  76. 1 2
      sound/soc/codecs/max98357a.c
  77. 1 2
      sound/soc/codecs/max9850.c
  78. 1 2
      sound/soc/codecs/ml26124.c
  79. 3 5
      sound/soc/codecs/pcm512x.c
  80. 17 16
      sound/soc/codecs/rt286.c
  81. 2 3
      sound/soc/codecs/rt5631.c
  82. 8 8
      sound/soc/codecs/rt5640.c
  83. 830 251
      sound/soc/codecs/rt5645.c
  84. 17 13
      sound/soc/codecs/rt5645.h
  85. 2 3
      sound/soc/codecs/rt5651.c
  86. 13 13
      sound/soc/codecs/rt5670.c
  87. 142 15
      sound/soc/codecs/rt5677.c
  88. 15 0
      sound/soc/codecs/rt5677.h
  89. 47 9
      sound/soc/codecs/sgtl5000.c
  90. 1 1
      sound/soc/codecs/sirf-audio-codec.c
  91. 8 4
      sound/soc/codecs/sn95031.c
  92. 2 7
      sound/soc/codecs/ssm2518.c
  93. 2 3
      sound/soc/codecs/ssm2602.c
  94. 2 7
      sound/soc/codecs/ssm4567.c
  95. 6 13
      sound/soc/codecs/sta32x.c
  96. 4 5
      sound/soc/codecs/sta350.c
  97. 1 7
      sound/soc/codecs/sta529.c
  98. 0 1
      sound/soc/codecs/stac9766.c
  99. 239 73
      sound/soc/codecs/tas2552.c
  100. 50 40
      sound/soc/codecs/tas2552.h

+ 4 - 0
Documentation/devicetree/bindings/sound/adi,adau1701.txt

@@ -20,6 +20,8 @@ Optional properties:
 			pin configurations as described in the datasheet,
 			pin configurations as described in the datasheet,
 			table 53. Note that the value of this property has
 			table 53. Note that the value of this property has
 			to be prefixed with '/bits/ 8'.
 			to be prefixed with '/bits/ 8'.
+ - avdd-supply: 	Power supply for AVDD, providing 3.3V
+ - dvdd-supply: 	Power supply for DVDD, providing 3.3V
 
 
 Examples:
 Examples:
 
 
@@ -28,6 +30,8 @@ Examples:
 			compatible = "adi,adau1701";
 			compatible = "adi,adau1701";
 			reg = <0x34>;
 			reg = <0x34>;
 			reset-gpio = <&gpio 23 0>;
 			reset-gpio = <&gpio 23 0>;
+			avdd-supply = <&vdd_3v3_reg>;
+			dvdd-supply = <&vdd_3v3_reg>;
 			adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
 			adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
 			adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
 			adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
                                                    0x4 0x4 0x4 0x4 0x4 0x4>;
                                                    0x4 0x4 0x4 0x4 0x4 0x4>;

+ 13 - 0
Documentation/devicetree/bindings/sound/bt-sco.txt

@@ -0,0 +1,13 @@
+Bluetooth-SCO audio CODEC
+
+This device support generic Bluetooth SCO link.
+
+Required properties:
+
+  - compatible : "delta,dfbmcs320"
+
+Example:
+
+codec: bt_sco {
+	compatible = "delta,dfbmcs320";
+};

+ 13 - 0
Documentation/devicetree/bindings/sound/gtm601.txt

@@ -0,0 +1,13 @@
+GTM601 UMTS modem audio interface CODEC
+
+This device has no configuration interface. Sample rate is fixed - 8kHz.
+
+Required properties:
+
+  - compatible : "option,gtm601"
+
+Example:
+
+codec: gtm601_codec {
+	compatible = "option,gtm601";
+};

+ 6 - 0
Documentation/devicetree/bindings/sound/max98090.txt

@@ -18,6 +18,12 @@ Optional properties:
 
 
 - maxim,dmic-freq: Frequency at which to clock DMIC
 - maxim,dmic-freq: Frequency at which to clock DMIC
 
 
+- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are:
+	0 - 2.2v
+	1 - 2.55v
+	2 - 2.4v
+	3 - 2.8v
+
 Pins on the device (for linking into audio routes):
 Pins on the device (for linking into audio routes):
 
 
   * MIC1
   * MIC1

+ 12 - 1
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt

@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
 
 
 Required properties:
 Required properties:
 
 
-- compatible		: "qcom,lpass-cpu"
+- compatible		: "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
 - clocks		: Must contain an entry for each entry in clock-names.
 - clocks		: Must contain an entry for each entry in clock-names.
 - clock-names		: A list which must include the following entries:
 - clock-names		: A list which must include the following entries:
 				* "ahbix-clk"
 				* "ahbix-clk"
 				* "mi2s-osr-clk"
 				* "mi2s-osr-clk"
 				* "mi2s-bit-clk"
 				* "mi2s-bit-clk"
+			: required clocks for "qcom,lpass-cpu-apq8016"
+				* "ahbix-clk"
+				* "mi2s-bit-clk0"
+				* "mi2s-bit-clk1"
+				* "mi2s-bit-clk2"
+				* "mi2s-bit-clk3"
+				* "pcnoc-mport-clk"
+				* "pcnoc-sway-clk"
+
 - interrupts		: Must contain an entry for each entry in
 - interrupts		: Must contain an entry for each entry in
 			  interrupt-names.
 			  interrupt-names.
 - interrupt-names	: A list which must include the following entries:
 - interrupt-names	: A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
 - reg-names		: A list which must include the following entries:
 - reg-names		: A list which must include the following entries:
 				* "lpass-lpaif"
 				* "lpass-lpaif"
 
 
+
+
 Optional properties:
 Optional properties:
 
 
 - qcom,adsp		: Phandle for the audio DSP node
 - qcom,adsp		: Phandle for the audio DSP node

+ 1 - 1
Documentation/devicetree/bindings/sound/renesas,rsnd.txt

@@ -48,7 +48,7 @@ DAI subnode properties:
 
 
 Example:
 Example:
 
 
-rcar_sound: rcar_sound@ec500000 {
+rcar_sound: sound@ec500000 {
 	#sound-dai-cells = <1>;
 	#sound-dai-cells = <1>;
 	compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
 	compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
 	reg =	<0 0xec500000 0 0x1000>, /* SCU */
 	reg =	<0 0xec500000 0 0x1000>, /* SCU */

+ 2 - 0
Documentation/devicetree/bindings/sound/rt5677.txt

@@ -18,6 +18,7 @@ Required properties:
 Optional properties:
 Optional properties:
 
 
 - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
 - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
+- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
 
 
 - realtek,in1-differential
 - realtek,in1-differential
 - realtek,in2-differential
 - realtek,in2-differential
@@ -70,6 +71,7 @@ rt5677 {
 
 
 	realtek,pow-ldo2-gpio =
 	realtek,pow-ldo2-gpio =
 		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
 		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+	realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
 	realtek,in1-differential = "true";
 	realtek,in1-differential = "true";
 	realtek,gpio-config = /bits/ 8  <0 0 0 0 0 2>;   /* pull up GPIO6 */
 	realtek,gpio-config = /bits/ 8  <0 0 0 0 0 2>;   /* pull up GPIO6 */
 	realtek,jd2-gpio = <3>;  /* Enables Jack detection for GPIO6 */
 	realtek,jd2-gpio = <3>;  /* Enables Jack detection for GPIO6 */

+ 41 - 0
Documentation/devicetree/bindings/sound/tas571x.txt

@@ -0,0 +1,41 @@
+Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
+
+The codec is controlled through an I2C interface.  It also has two other
+signals that can be wired up to GPIOs: reset (strongly recommended), and
+powerdown (optional).
+
+Required properties:
+
+- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
+- reg: The I2C address of the device
+- #sound-dai-cells: must be equal to 0
+
+Optional properties:
+
+- reset-gpios: GPIO specifier for the TAS571x's active low reset line
+- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line
+- clocks: clock phandle for the MCLK input
+- clock-names: should be "mclk"
+- AVDD-supply: regulator phandle for the AVDD supply (all chips)
+- DVDD-supply: regulator phandle for the DVDD supply (all chips)
+- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719)
+- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719)
+- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719)
+- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711)
+- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
+- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
+- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
+
+Example:
+
+	tas5717: audio-codec@2a {
+		compatible = "ti,tas5717";
+		reg = <0x2a>;
+		#sound-dai-cells = <0>;
+
+		reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+		pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+
+		clocks = <&clk_core CLK_I2S>;
+		clock-names = "mclk";
+	};

+ 11 - 0
Documentation/devicetree/bindings/sound/wm8741.txt

@@ -10,9 +10,20 @@ Required properties:
   - reg : the I2C address of the device for I2C, the chip select
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
           number for SPI.
 
 
+Optional properties:
+
+  - diff-mode: Differential output mode configuration. Default value for field
+    DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be:
+    0 = stereo
+    1 = mono left
+    2 = stereo reversed
+    3 = mono right
+
 Example:
 Example:
 
 
 codec: wm8741@1a {
 codec: wm8741@1a {
 	compatible = "wlf,wm8741";
 	compatible = "wlf,wm8741";
 	reg = <0x1a>;
 	reg = <0x1a>;
+
+	diff-mode = <3>;
 };
 };

+ 44 - 0
Documentation/devicetree/bindings/sound/zte,zx-i2s.txt

@@ -0,0 +1,44 @@
+ZTE ZX296702 I2S controller
+
+Required properties:
+ - compatible : Must be "zte,zx296702-i2s"
+ - reg : Must contain I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's clocks.
+ - clock-names: "tx" for the clock to the I2S interface.
+ - dmas: Pairs of phandle and specifier for the DMA channel that is used by
+   the core. The core expects two dma channels for transmit.
+ - dma-names : Must be "tx" and "rx"
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
+please check:
+	* resource-names.txt
+	* clock/clock-bindings.txt
+	* dma/dma.txt
+
+Example:
+	i2s0: i2s0@0b005000 {
+		#sound-dai-cells = <0>;
+		compatible = "zte,zx296702-i2s";
+		reg = <0x0b005000 0x1000>;
+		clocks = <&lsp0clk ZX296702_I2S0_DIV>;
+		clock-names = "tx";
+		interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+		dmas = <&dma 5>, <&dma 6>;
+		dma-names = "tx", "rx";
+		status = "okay";
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "zx296702_snd";
+		simple-audio-card,format = "left_j";
+		simple-audio-card,bitclock-master = <&sndcodec>;
+		simple-audio-card,frame-master = <&sndcodec>;
+		sndcpu: simple-audio-card,cpu {
+			sound-dai = <&i2s0>;
+		};
+
+		sndcodec: simple-audio-card,codec {
+			sound-dai = <&acodec>;
+		};
+	};

+ 28 - 0
Documentation/devicetree/bindings/sound/zte,zx-spdif.txt

@@ -0,0 +1,28 @@
+ZTE ZX296702 SPDIF controller
+
+Required properties:
+ - compatible : Must be "zte,zx296702-spdif"
+ - reg : Must contain SPDIF core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's clocks.
+ - clock-names: "tx" for the clock to the SPDIF interface.
+ - dmas: Pairs of phandle and specifier for the DMA channel that is used by
+   the core. The core expects one dma channel for transmit.
+ - dma-names : Must be "tx"
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
+please check:
+	* resource-names.txt
+	* clock/clock-bindings.txt
+	* dma/dma.txt
+
+Example:
+	spdif0: spdif0@0b004000 {
+		compatible = "zte,zx296702-spdif";
+		reg = <0x0b004000 0x1000>;
+		clocks = <&lsp0clk ZX296702_SPDIF0_DIV>;
+		clock-names = "tx";
+		interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+		dmas = <&dma 4>;
+		dma-names = "tx";
+		status = "okay";
+	};

+ 1 - 0
Documentation/devicetree/bindings/vendor-prefixes.txt

@@ -54,6 +54,7 @@ cosmic	Cosmic Circuits
 crystalfontz	Crystalfontz America, Inc.
 crystalfontz	Crystalfontz America, Inc.
 dallas	Maxim Integrated Products (formerly Dallas Semiconductor)
 dallas	Maxim Integrated Products (formerly Dallas Semiconductor)
 davicom	DAVICOM Semiconductor, Inc.
 davicom	DAVICOM Semiconductor, Inc.
+delta	Delta Electronics, Inc.
 denx	Denx Software Engineering
 denx	Denx Software Engineering
 digi	Digi International Inc.
 digi	Digi International Inc.
 digilent	Diglent, Inc.
 digilent	Diglent, Inc.

+ 6 - 0
MAINTAINERS

@@ -9924,6 +9924,12 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 S:	Maintained
 F:	drivers/net/ethernet/ti/netcp*
 F:	drivers/net/ethernet/ti/netcp*
 
 
+TI TAS571X FAMILY ASoC CODEC DRIVER
+M:	Kevin Cernekee <cernekee@chromium.org>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Odd Fixes
+F:	sound/soc/codecs/tas571x*
+
 TI TWL4030 SERIES SOC CODEC DRIVER
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
 M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)

+ 21 - 16
drivers/dma/sh/rcar-dmac.c

@@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
 static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 {
 {
 	struct rcar_dmac_desc_page *page;
 	struct rcar_dmac_desc_page *page;
+	unsigned long flags;
 	LIST_HEAD(list);
 	LIST_HEAD(list);
 	unsigned int i;
 	unsigned int i;
 
 
@@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 		list_add_tail(&desc->node, &list);
 		list_add_tail(&desc->node, &list);
 	}
 	}
 
 
-	spin_lock_irq(&chan->lock);
+	spin_lock_irqsave(&chan->lock, flags);
 	list_splice_tail(&list, &chan->desc.free);
 	list_splice_tail(&list, &chan->desc.free);
 	list_add_tail(&page->node, &chan->desc.pages);
 	list_add_tail(&page->node, &chan->desc.pages);
-	spin_unlock_irq(&chan->lock);
+	spin_unlock_irqrestore(&chan->lock, flags);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
 static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 {
 {
 	struct rcar_dmac_desc *desc, *_desc;
 	struct rcar_dmac_desc *desc, *_desc;
+	unsigned long flags;
 	LIST_HEAD(list);
 	LIST_HEAD(list);
 
 
 	/*
 	/*
@@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 	 * list_for_each_entry_safe, isn't safe if we release the channel lock
 	 * list_for_each_entry_safe, isn't safe if we release the channel lock
 	 * around the rcar_dmac_desc_put() call.
 	 * around the rcar_dmac_desc_put() call.
 	 */
 	 */
-	spin_lock_irq(&chan->lock);
+	spin_lock_irqsave(&chan->lock, flags);
 	list_splice_init(&chan->desc.wait, &list);
 	list_splice_init(&chan->desc.wait, &list);
-	spin_unlock_irq(&chan->lock);
+	spin_unlock_irqrestore(&chan->lock, flags);
 
 
 	list_for_each_entry_safe(desc, _desc, &list, node) {
 	list_for_each_entry_safe(desc, _desc, &list, node) {
 		if (async_tx_test_ack(&desc->async_tx)) {
 		if (async_tx_test_ack(&desc->async_tx)) {
@@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 		return;
 		return;
 
 
 	/* Put the remaining descriptors back in the wait list. */
 	/* Put the remaining descriptors back in the wait list. */
-	spin_lock_irq(&chan->lock);
+	spin_lock_irqsave(&chan->lock, flags);
 	list_splice(&list, &chan->desc.wait);
 	list_splice(&list, &chan->desc.wait);
-	spin_unlock_irq(&chan->lock);
+	spin_unlock_irqrestore(&chan->lock, flags);
 }
 }
 
 
 /*
 /*
@@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
 static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
 static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
 {
 {
 	struct rcar_dmac_desc *desc;
 	struct rcar_dmac_desc *desc;
+	unsigned long flags;
 	int ret;
 	int ret;
 
 
 	/* Recycle acked descriptors before attempting allocation. */
 	/* Recycle acked descriptors before attempting allocation. */
 	rcar_dmac_desc_recycle_acked(chan);
 	rcar_dmac_desc_recycle_acked(chan);
 
 
-	spin_lock_irq(&chan->lock);
+	spin_lock_irqsave(&chan->lock, flags);
 
 
 	while (list_empty(&chan->desc.free)) {
 	while (list_empty(&chan->desc.free)) {
 		/*
 		/*
@@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
 		 * allocated descriptors. If the allocation fails return an
 		 * allocated descriptors. If the allocation fails return an
 		 * error.
 		 * error.
 		 */
 		 */
-		spin_unlock_irq(&chan->lock);
+		spin_unlock_irqrestore(&chan->lock, flags);
 		ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
 		ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
 		if (ret < 0)
 		if (ret < 0)
 			return NULL;
 			return NULL;
-		spin_lock_irq(&chan->lock);
+		spin_lock_irqsave(&chan->lock, flags);
 	}
 	}
 
 
 	desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
 	desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
 	list_del(&desc->node);
 	list_del(&desc->node);
 
 
-	spin_unlock_irq(&chan->lock);
+	spin_unlock_irqrestore(&chan->lock, flags);
 
 
 	return desc;
 	return desc;
 }
 }
@@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
 static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 {
 {
 	struct rcar_dmac_desc_page *page;
 	struct rcar_dmac_desc_page *page;
+	unsigned long flags;
 	LIST_HEAD(list);
 	LIST_HEAD(list);
 	unsigned int i;
 	unsigned int i;
 
 
@@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
 		list_add_tail(&chunk->node, &list);
 		list_add_tail(&chunk->node, &list);
 	}
 	}
 
 
-	spin_lock_irq(&chan->lock);
+	spin_lock_irqsave(&chan->lock, flags);
 	list_splice_tail(&list, &chan->desc.chunks_free);
 	list_splice_tail(&list, &chan->desc.chunks_free);
 	list_add_tail(&page->node, &chan->desc.pages);
 	list_add_tail(&page->node, &chan->desc.pages);
-	spin_unlock_irq(&chan->lock);
+	spin_unlock_irqrestore(&chan->lock, flags);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk *
 rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
 rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
 {
 {
 	struct rcar_dmac_xfer_chunk *chunk;
 	struct rcar_dmac_xfer_chunk *chunk;
+	unsigned long flags;
 	int ret;
 	int ret;
 
 
-	spin_lock_irq(&chan->lock);
+	spin_lock_irqsave(&chan->lock, flags);
 
 
 	while (list_empty(&chan->desc.chunks_free)) {
 	while (list_empty(&chan->desc.chunks_free)) {
 		/*
 		/*
@@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
 		 * allocated descriptors. If the allocation fails return an
 		 * allocated descriptors. If the allocation fails return an
 		 * error.
 		 * error.
 		 */
 		 */
-		spin_unlock_irq(&chan->lock);
+		spin_unlock_irqrestore(&chan->lock, flags);
 		ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
 		ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
 		if (ret < 0)
 		if (ret < 0)
 			return NULL;
 			return NULL;
-		spin_lock_irq(&chan->lock);
+		spin_lock_irqsave(&chan->lock, flags);
 	}
 	}
 
 
 	chunk = list_first_entry(&chan->desc.chunks_free,
 	chunk = list_first_entry(&chan->desc.chunks_free,
 				 struct rcar_dmac_xfer_chunk, node);
 				 struct rcar_dmac_xfer_chunk, node);
 	list_del(&chunk->node);
 	list_del(&chunk->node);
 
 
-	spin_unlock_irq(&chan->lock);
+	spin_unlock_irqrestore(&chan->lock, flags);
 
 
 	return chunk;
 	return chunk;
 }
 }

+ 0 - 5
drivers/regulator/arizona-ldo1.c

@@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
 	if (ret != 0)
 	if (ret != 0)
 		return ret;
 		return ret;
 
 
-	ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
-				 ARIZONA_SUBSYS_MAX_FREQ, val);
-	if (ret != 0)
-		return ret;
-
 	if (val)
 	if (val)
 		return 0;
 		return 0;
 
 

+ 9 - 0
include/dt-bindings/sound/apq8016-lpass.h

@@ -0,0 +1,9 @@
+#ifndef __DT_APQ8016_LPASS_H
+#define __DT_APQ8016_LPASS_H
+
+#define MI2S_PRIMARY	0
+#define MI2S_SECONDARY	1
+#define MI2S_TERTIARY	2
+#define MI2S_QUATERNARY	3
+
+#endif /* __DT_APQ8016_LPASS_H */

+ 9 - 0
include/dt-bindings/sound/audio-jack-events.h

@@ -0,0 +1,9 @@
+#ifndef __AUDIO_JACK_EVENTS_H
+#define __AUDIO_JACK_EVENTS_H
+
+#define JACK_HEADPHONE		1
+#define JACK_MICROPHONE		2
+#define JACK_LINEOUT		3
+#define JACK_LINEIN		4
+
+#endif /* __AUDIO_JACK_EVENTS_H */

+ 18 - 0
include/dt-bindings/sound/tas2552.h

@@ -0,0 +1,18 @@
+#ifndef __DT_TAS2552_H
+#define __DT_TAS2552_H
+
+#define TAS2552_PLL_CLKIN		(0)
+#define TAS2552_PDM_CLK			(1)
+#define TAS2552_CLK_TARGET_MASK		(1)
+
+#define TAS2552_PLL_CLKIN_MCLK		((0 << 1) | TAS2552_PLL_CLKIN)
+#define TAS2552_PLL_CLKIN_BCLK		((1 << 1) | TAS2552_PLL_CLKIN)
+#define TAS2552_PLL_CLKIN_IVCLKIN	((2 << 1) | TAS2552_PLL_CLKIN)
+#define TAS2552_PLL_CLKIN_1_8_FIXED	((3 << 1) | TAS2552_PLL_CLKIN)
+
+#define TAS2552_PDM_CLK_PLL		((0 << 1) | TAS2552_PDM_CLK)
+#define TAS2552_PDM_CLK_IVCLKIN		((1 << 1) | TAS2552_PDM_CLK)
+#define TAS2552_PDM_CLK_BCLK		((2 << 1) | TAS2552_PDM_CLK)
+#define TAS2552_PDM_CLK_MCLK		((3 << 1) | TAS2552_PDM_CLK)
+
+#endif /* __DT_TAS2552_H */

+ 0 - 5
include/sound/dmaengine_pcm.h

@@ -90,11 +90,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
  * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
  * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
  */
  */
 #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
 #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
-/*
- * The platforms dmaengine driver does not support reporting the amount of
- * bytes that are still left to transfer.
- */
-#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2)
 /*
 /*
  * The PCM is half duplex and the DMA channel is shared between capture and
  * The PCM is half duplex and the DMA channel is shared between capture and
  * playback.
  * playback.

+ 0 - 3
include/sound/rt5645.h

@@ -15,7 +15,6 @@ struct rt5645_platform_data {
 	/* IN2 can optionally be differential */
 	/* IN2 can optionally be differential */
 	bool in2_diff;
 	bool in2_diff;
 
 
-	bool dmic_en;
 	unsigned int dmic1_data_pin;
 	unsigned int dmic1_data_pin;
 	/* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
 	/* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
 	unsigned int dmic2_data_pin;
 	unsigned int dmic2_data_pin;
@@ -24,8 +23,6 @@ struct rt5645_platform_data {
 	unsigned int hp_det_gpio;
 	unsigned int hp_det_gpio;
 	bool gpio_hp_det_active_high;
 	bool gpio_hp_det_active_high;
 
 
-	/* true if codec's jd function is used */
-	bool en_jd_func;
 	unsigned int jd_mode;
 	unsigned int jd_mode;
 };
 };
 
 

+ 49 - 0
include/sound/soc-dapm.h

@@ -15,6 +15,8 @@
 
 
 #include <linux/types.h>
 #include <linux/types.h>
 #include <sound/control.h>
 #include <sound/control.h>
+#include <sound/soc-topology.h>
+#include <sound/asoc.h>
 
 
 struct device;
 struct device;
 
 
@@ -107,6 +109,10 @@ struct device;
 {	.id = snd_soc_dapm_mux, .name = wname, \
 {	.id = snd_soc_dapm_mux, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 	.kcontrol_news = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
+{	.id = snd_soc_dapm_demux, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
@@ -444,11 +450,15 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
 	struct snd_kcontrol *kcontrol);
 	struct snd_kcontrol *kcontrol);
 
 
+int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
+	enum snd_soc_bias_level level);
+
 /* dapm widget types */
 /* dapm widget types */
 enum snd_soc_dapm_type {
 enum snd_soc_dapm_type {
 	snd_soc_dapm_input = 0,		/* input pin */
 	snd_soc_dapm_input = 0,		/* input pin */
 	snd_soc_dapm_output,		/* output pin */
 	snd_soc_dapm_output,		/* output pin */
 	snd_soc_dapm_mux,			/* selects 1 analog signal from many inputs */
 	snd_soc_dapm_mux,			/* selects 1 analog signal from many inputs */
+	snd_soc_dapm_demux,			/* connects the input to one of multiple outputs */
 	snd_soc_dapm_mixer,			/* mixes several analog signals together */
 	snd_soc_dapm_mixer,			/* mixes several analog signals together */
 	snd_soc_dapm_mixer_named_ctl,		/* mixer with named controls */
 	snd_soc_dapm_mixer_named_ctl,		/* mixer with named controls */
 	snd_soc_dapm_pga,			/* programmable gain/attenuation (volume) */
 	snd_soc_dapm_pga,			/* programmable gain/attenuation (volume) */
@@ -563,6 +573,7 @@ struct snd_soc_dapm_widget {
 	int num_kcontrols;
 	int num_kcontrols;
 	const struct snd_kcontrol_new *kcontrol_news;
 	const struct snd_kcontrol_new *kcontrol_news;
 	struct snd_kcontrol **kcontrols;
 	struct snd_kcontrol **kcontrols;
+	struct snd_soc_dobj dobj;
 
 
 	/* widget input and outputs */
 	/* widget input and outputs */
 	struct list_head sources;
 	struct list_head sources;
@@ -585,6 +596,10 @@ struct snd_soc_dapm_update {
 	int val;
 	int val;
 };
 };
 
 
+struct snd_soc_dapm_wcache {
+	struct snd_soc_dapm_widget *widget;
+};
+
 /* DAPM context */
 /* DAPM context */
 struct snd_soc_dapm_context {
 struct snd_soc_dapm_context {
 	enum snd_soc_bias_level bias_level;
 	enum snd_soc_bias_level bias_level;
@@ -606,6 +621,9 @@ struct snd_soc_dapm_context {
 	int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
 	int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
 			      enum snd_soc_bias_level level);
 			      enum snd_soc_bias_level level);
 
 
+	struct snd_soc_dapm_wcache path_sink_cache;
+	struct snd_soc_dapm_wcache path_source_cache;
+
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_dapm;
 	struct dentry *debugfs_dapm;
 #endif
 #endif
@@ -623,4 +641,35 @@ struct snd_soc_dapm_stats {
 	int neighbour_checks;
 	int neighbour_checks;
 };
 };
 
 
+/**
+ * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
+ * @dapm: The DAPM context to initialize
+ * @level: The DAPM level to initialize to
+ *
+ * This function only sets the driver internal state of the DAPM level and will
+ * not modify the state of the device. Hence it should not be used during normal
+ * operation, but only to synchronize the internal state to the device state.
+ * E.g. during driver probe to set the DAPM level to the one corresponding with
+ * the power-on reset state of the device.
+ *
+ * To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
+ */
+static inline void snd_soc_dapm_init_bias_level(
+	struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+	dapm->bias_level = level;
+}
+
+/**
+ * snd_soc_dapm_get_bias_level() - Get current DAPM bias level
+ * @dapm: The context for which to get the bias level
+ *
+ * Returns: The current bias level of the passed DAPM context.
+ */
+static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
+	struct snd_soc_dapm_context *dapm)
+{
+	return dapm->bias_level;
+}
+
 #endif
 #endif

+ 168 - 0
include/sound/soc-topology.h

@@ -0,0 +1,168 @@
+/*
+ * linux/sound/soc-topology.h -- ALSA SoC Firmware Controls and DAPM
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
+ * algorithms, equalisers, DAIs, widgets, FE caps, BE caps, codec link caps etc.
+ */
+
+#ifndef __LINUX_SND_SOC_TPLG_H
+#define __LINUX_SND_SOC_TPLG_H
+
+#include <sound/asoc.h>
+#include <linux/list.h>
+
+struct firmware;
+struct snd_kcontrol;
+struct snd_soc_tplg_pcm_be;
+struct snd_ctl_elem_value;
+struct snd_ctl_elem_info;
+struct snd_soc_dapm_widget;
+struct snd_soc_component;
+struct snd_soc_tplg_pcm_fe;
+struct snd_soc_dapm_context;
+struct snd_soc_card;
+
+/* object scan be loaded and unloaded in groups with identfying indexes */
+#define SND_SOC_TPLG_INDEX_ALL	0	/* ID that matches all FW objects */
+
+/* dynamic object type */
+enum snd_soc_dobj_type {
+	SND_SOC_DOBJ_NONE		= 0,	/* object is not dynamic */
+	SND_SOC_DOBJ_MIXER,
+	SND_SOC_DOBJ_ENUM,
+	SND_SOC_DOBJ_BYTES,
+	SND_SOC_DOBJ_PCM,
+	SND_SOC_DOBJ_DAI_LINK,
+	SND_SOC_DOBJ_CODEC_LINK,
+	SND_SOC_DOBJ_WIDGET,
+};
+
+/* dynamic control object */
+struct snd_soc_dobj_control {
+	struct snd_kcontrol *kcontrol;
+	char **dtexts;
+	unsigned long *dvalues;
+};
+
+/* dynamic widget object */
+struct snd_soc_dobj_widget {
+	unsigned int kcontrol_enum:1;	/* this widget is an enum kcontrol */
+};
+
+/* dynamic PCM DAI object */
+struct snd_soc_dobj_pcm_dai {
+	struct snd_soc_tplg_pcm_dai *pd;
+	unsigned int count;
+};
+
+/* generic dynamic object - all dynamic objects belong to this struct */
+struct snd_soc_dobj {
+	enum snd_soc_dobj_type type;
+	unsigned int index;	/* objects can belong in different groups */
+	struct list_head list;
+	struct snd_soc_tplg_ops *ops;
+	union {
+		struct snd_soc_dobj_control control;
+		struct snd_soc_dobj_widget widget;
+		struct snd_soc_dobj_pcm_dai pcm_dai;
+	};
+	void *private; /* core does not touch this */
+};
+
+/*
+ * Kcontrol operations - used to map handlers onto firmware based controls.
+ */
+struct snd_soc_tplg_kcontrol_ops {
+	u32 id;
+	int (*get)(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+	int (*put)(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+	int (*info)(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo);
+};
+
+/*
+ * DAPM widget event handlers - used to map handlers onto widgets.
+ */
+struct snd_soc_tplg_widget_events {
+	u16 type;
+	int (*event_handler)(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *k, int event);
+};
+
+/*
+ * Public API - Used by component drivers to load and unload dynamic objects
+ * and their resources.
+ */
+struct snd_soc_tplg_ops {
+
+	/* external kcontrol init - used for any driver specific init */
+	int (*control_load)(struct snd_soc_component *,
+		struct snd_kcontrol_new *, struct snd_soc_tplg_ctl_hdr *);
+	int (*control_unload)(struct snd_soc_component *,
+		struct snd_soc_dobj *);
+
+	/* external widget init - used for any driver specific init */
+	int (*widget_load)(struct snd_soc_component *,
+		struct snd_soc_dapm_widget *,
+		struct snd_soc_tplg_dapm_widget *);
+	int (*widget_unload)(struct snd_soc_component *,
+		struct snd_soc_dobj *);
+
+	/* FE - used for any driver specific init */
+	int (*pcm_dai_load)(struct snd_soc_component *,
+		struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe);
+	int (*pcm_dai_unload)(struct snd_soc_component *,
+		struct snd_soc_dobj *);
+
+	/* callback to handle vendor bespoke data */
+	int (*vendor_load)(struct snd_soc_component *,
+		struct snd_soc_tplg_hdr *);
+	int (*vendor_unload)(struct snd_soc_component *,
+		struct snd_soc_tplg_hdr *);
+
+	/* completion - called at completion of firmware loading */
+	void (*complete)(struct snd_soc_component *);
+
+	/* manifest - optional to inform component of manifest */
+	int (*manifest)(struct snd_soc_component *,
+		struct snd_soc_tplg_manifest *);
+
+	/* bespoke kcontrol handlers available for binding */
+	const struct snd_soc_tplg_kcontrol_ops *io_ops;
+	int io_ops_count;
+};
+
+/* gets a pointer to data from the firmware block header */
+static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
+{
+	const void *ptr = hdr;
+
+	return ptr + sizeof(*hdr);
+}
+
+/* Dynamic Object loading and removal for component drivers */
+int snd_soc_tplg_component_load(struct snd_soc_component *comp,
+	struct snd_soc_tplg_ops *ops, const struct firmware *fw,
+	u32 index);
+int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index);
+
+/* Widget removal - widgets also removed wth component API */
+void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w);
+void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
+	u32 index);
+
+/* Binds event handlers to dynamic widgets */
+int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
+	const struct snd_soc_tplg_widget_events *events, int num_events,
+	u16 event_type);
+
+#endif

+ 97 - 21
include/sound/soc.h

@@ -27,6 +27,7 @@
 #include <sound/compress_driver.h>
 #include <sound/compress_driver.h>
 #include <sound/control.h>
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 #include <sound/ac97_codec.h>
+#include <sound/soc-topology.h>
 
 
 /*
 /*
  * Convenience kcontrol builders
  * Convenience kcontrol builders
@@ -190,8 +191,12 @@
 #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
 #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
 	.mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
 	.mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
-#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
-	SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
+#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+	SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xitems, xtexts, xvalues)
+#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+{	.reg = xreg, .shift_l = xshift, .shift_r = xshift, \
+	.mask = xmask, .items = xitems, .texts = xtexts, \
+	.values = xvalues, .autodisable = 1}
 #define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
 #define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
 	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
 	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
 #define SOC_ENUM(xname, xenum) \
 #define SOC_ENUM(xname, xenum) \
@@ -312,6 +317,11 @@
 							ARRAY_SIZE(xtexts), xtexts, xvalues)
 							ARRAY_SIZE(xtexts), xtexts, xvalues)
 #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
 #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
 	SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
 	SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+
+#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
+	const struct soc_enum name = SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, \
+		xshift, xmask, ARRAY_SIZE(xtexts), xtexts, xvalues)
+
 #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
 #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
 	const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
 	const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
 
 
@@ -767,6 +777,9 @@ struct snd_soc_component {
 
 
 	struct mutex io_mutex;
 	struct mutex io_mutex;
 
 
+	/* attached dynamic objects */
+	struct list_head dobj_list;
+
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_root;
 	struct dentry *debugfs_root;
 #endif
 #endif
@@ -819,7 +832,7 @@ struct snd_soc_codec {
 	/* component */
 	/* component */
 	struct snd_soc_component component;
 	struct snd_soc_component component;
 
 
-	/* dapm */
+	/* Don't access this directly, use snd_soc_codec_get_dapm() */
 	struct snd_soc_dapm_context dapm;
 	struct snd_soc_dapm_context dapm;
 
 
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
@@ -961,6 +974,24 @@ struct snd_soc_dai_link {
 
 
 	enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
 	enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
 
 
+	/* codec/machine specific init - e.g. add machine controls */
+	int (*init)(struct snd_soc_pcm_runtime *rtd);
+
+	/* optional hw_params re-writing for BE and FE sync */
+	int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params);
+
+	/* machine stream operations */
+	const struct snd_soc_ops *ops;
+	const struct snd_soc_compr_ops *compr_ops;
+
+	/* For unidirectional dai links */
+	bool playback_only;
+	bool capture_only;
+
+	/* Mark this pcm with non atomic ops */
+	bool nonatomic;
+
 	/* Keep DAI active over suspend */
 	/* Keep DAI active over suspend */
 	unsigned int ignore_suspend:1;
 	unsigned int ignore_suspend:1;
 
 
@@ -969,9 +1000,6 @@ struct snd_soc_dai_link {
 	unsigned int symmetric_channels:1;
 	unsigned int symmetric_channels:1;
 	unsigned int symmetric_samplebits:1;
 	unsigned int symmetric_samplebits:1;
 
 
-	/* Mark this pcm with non atomic ops */
-	bool nonatomic;
-
 	/* Do not create a PCM for this DAI link (Backend link) */
 	/* Do not create a PCM for this DAI link (Backend link) */
 	unsigned int no_pcm:1;
 	unsigned int no_pcm:1;
 
 
@@ -982,23 +1010,11 @@ struct snd_soc_dai_link {
 	unsigned int dpcm_capture:1;
 	unsigned int dpcm_capture:1;
 	unsigned int dpcm_playback:1;
 	unsigned int dpcm_playback:1;
 
 
+	/* DPCM used FE & BE merged format */
+	unsigned int dpcm_merged_format:1;
+
 	/* pmdown_time is ignored at stop */
 	/* pmdown_time is ignored at stop */
 	unsigned int ignore_pmdown_time:1;
 	unsigned int ignore_pmdown_time:1;
-
-	/* codec/machine specific init - e.g. add machine controls */
-	int (*init)(struct snd_soc_pcm_runtime *rtd);
-
-	/* optional hw_params re-writing for BE and FE sync */
-	int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
-			struct snd_pcm_hw_params *params);
-
-	/* machine stream operations */
-	const struct snd_soc_ops *ops;
-	const struct snd_soc_compr_ops *compr_ops;
-
-	/* For unidirectional dai links */
-	bool playback_only;
-	bool capture_only;
 };
 };
 
 
 struct snd_soc_codec_conf {
 struct snd_soc_codec_conf {
@@ -1111,6 +1127,9 @@ struct snd_soc_card {
 	struct list_head dapm_list;
 	struct list_head dapm_list;
 	struct list_head dapm_dirty;
 	struct list_head dapm_dirty;
 
 
+	/* attached dynamic objects */
+	struct list_head dobj_list;
+
 	/* Generic DAPM context for the card */
 	/* Generic DAPM context for the card */
 	struct snd_soc_dapm_context dapm;
 	struct snd_soc_dapm_context dapm;
 	struct snd_soc_dapm_stats dapm_stats;
 	struct snd_soc_dapm_stats dapm_stats;
@@ -1170,6 +1189,7 @@ struct soc_mixer_control {
 	unsigned int sign_bit;
 	unsigned int sign_bit;
 	unsigned int invert:1;
 	unsigned int invert:1;
 	unsigned int autodisable:1;
 	unsigned int autodisable:1;
+	struct snd_soc_dobj dobj;
 };
 };
 
 
 struct soc_bytes {
 struct soc_bytes {
@@ -1180,6 +1200,8 @@ struct soc_bytes {
 
 
 struct soc_bytes_ext {
 struct soc_bytes_ext {
 	int max;
 	int max;
+	struct snd_soc_dobj dobj;
+
 	/* used for TLV byte control */
 	/* used for TLV byte control */
 	int (*get)(unsigned int __user *bytes, unsigned int size);
 	int (*get)(unsigned int __user *bytes, unsigned int size);
 	int (*put)(const unsigned int __user *bytes, unsigned int size);
 	int (*put)(const unsigned int __user *bytes, unsigned int size);
@@ -1200,6 +1222,8 @@ struct soc_enum {
 	unsigned int mask;
 	unsigned int mask;
 	const char * const *texts;
 	const char * const *texts;
 	const unsigned int *values;
 	const unsigned int *values;
+	unsigned int autodisable:1;
+	struct snd_soc_dobj dobj;
 };
 };
 
 
 /**
 /**
@@ -1281,6 +1305,58 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
 	return component->dapm_ptr;
 	return component->dapm_ptr;
 }
 }
 
 
+/**
+ * snd_soc_codec_get_dapm() - Returns the DAPM context for the CODEC
+ * @codec: The CODEC for which to get the DAPM context
+ *
+ * Note: Use this function instead of directly accessing the CODEC's dapm field
+ */
+static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
+	struct snd_soc_codec *codec)
+{
+	return &codec->dapm;
+}
+
+/**
+ * snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
+ * @dapm: The CODEC for which to initialize the DAPM bias level
+ * @level: The DAPM level to initialize to
+ *
+ * Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
+ */
+static inline void snd_soc_codec_init_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	snd_soc_dapm_init_bias_level(snd_soc_codec_get_dapm(codec), level);
+}
+
+/**
+ * snd_soc_dapm_get_bias_level() - Get current CODEC DAPM bias level
+ * @codec: The CODEC for which to get the DAPM bias level
+ *
+ * Returns: The current DAPM bias level of the CODEC.
+ */
+static inline enum snd_soc_bias_level snd_soc_codec_get_bias_level(
+	struct snd_soc_codec *codec)
+{
+	return snd_soc_dapm_get_bias_level(snd_soc_codec_get_dapm(codec));
+}
+
+/**
+ * snd_soc_codec_force_bias_level() - Set the CODEC DAPM bias level
+ * @codec: The CODEC for which to set the level
+ * @level: The level to set to
+ *
+ * Forces the CODEC bias level to a specific state. See
+ * snd_soc_dapm_force_bias_level().
+ */
+static inline int snd_soc_codec_force_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	return snd_soc_dapm_force_bias_level(snd_soc_codec_get_dapm(codec),
+		level);
+}
+
 /**
 /**
  * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
  * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
  * @kcontrol: The kcontrol
  * @kcontrol: The kcontrol

+ 1 - 14
include/sound/tlv.h

@@ -31,12 +31,7 @@
  *                       ~(sizeof(unsigned int) - 1)) ....
  *                       ~(sizeof(unsigned int) - 1)) ....
  */
  */
 
 
-#define SNDRV_CTL_TLVT_CONTAINER 0	/* one level down - group of TLVs */
-#define SNDRV_CTL_TLVT_DB_SCALE	1       /* dB scale */
-#define SNDRV_CTL_TLVT_DB_LINEAR 2	/* linear volume */
-#define SNDRV_CTL_TLVT_DB_RANGE 3	/* dB range container */
-#define SNDRV_CTL_TLVT_DB_MINMAX 4	/* dB scale with min/max */
-#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5	/* dB scale with min/max with mute */
+#include <uapi/sound/tlv.h>
 
 
 #define TLV_ITEM(type, ...) \
 #define TLV_ITEM(type, ...) \
 	(type), TLV_LENGTH(__VA_ARGS__), __VA_ARGS__
 	(type), TLV_LENGTH(__VA_ARGS__), __VA_ARGS__
@@ -90,12 +85,4 @@
 
 
 #define TLV_DB_GAIN_MUTE	-9999999
 #define TLV_DB_GAIN_MUTE	-9999999
 
 
-/*
- * channel-mapping TLV items
- *  TLV length must match with num_channels
- */
-#define SNDRV_CTL_TLVT_CHMAP_FIXED	0x101	/* fixed channel position */
-#define SNDRV_CTL_TLVT_CHMAP_VAR	0x102	/* channels freely swappable */
-#define SNDRV_CTL_TLVT_CHMAP_PAIRED	0x103	/* pair-wise swappable */
-
 #endif /* __SOUND_TLV_H */
 #endif /* __SOUND_TLV_H */

+ 388 - 0
include/uapi/sound/asoc.h

@@ -0,0 +1,388 @@
+/*
+ * uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
+ * algorithms, equalisers, DAIs, widgets etc.
+*/
+
+#ifndef __LINUX_UAPI_SND_ASOC_H
+#define __LINUX_UAPI_SND_ASOC_H
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+/*
+ * Maximum number of channels topology kcontrol can represent.
+ */
+#define SND_SOC_TPLG_MAX_CHAN		8
+
+/*
+ * Maximum number of PCM formats capability
+ */
+#define SND_SOC_TPLG_MAX_FORMATS	16
+
+/*
+ * Maximum number of PCM stream configs
+ */
+#define SND_SOC_TPLG_STREAM_CONFIG_MAX  8
+
+/* individual kcontrol info types - can be mixed with other types */
+#define SND_SOC_TPLG_CTL_VOLSW		1
+#define SND_SOC_TPLG_CTL_VOLSW_SX	2
+#define SND_SOC_TPLG_CTL_VOLSW_XR_SX	3
+#define SND_SOC_TPLG_CTL_ENUM		4
+#define SND_SOC_TPLG_CTL_BYTES		5
+#define SND_SOC_TPLG_CTL_ENUM_VALUE	6
+#define SND_SOC_TPLG_CTL_RANGE		7
+#define SND_SOC_TPLG_CTL_STROBE		8
+
+
+/* individual widget kcontrol info types - can be mixed with other types */
+#define SND_SOC_TPLG_DAPM_CTL_VOLSW		64
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE	65
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT		66
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE	67
+#define SND_SOC_TPLG_DAPM_CTL_PIN		68
+
+/* DAPM widget types - add new items to the end */
+#define SND_SOC_TPLG_DAPM_INPUT		0
+#define SND_SOC_TPLG_DAPM_OUTPUT	1
+#define SND_SOC_TPLG_DAPM_MUX		2
+#define SND_SOC_TPLG_DAPM_MIXER		3
+#define SND_SOC_TPLG_DAPM_PGA		4
+#define SND_SOC_TPLG_DAPM_OUT_DRV	5
+#define SND_SOC_TPLG_DAPM_ADC		6
+#define SND_SOC_TPLG_DAPM_DAC		7
+#define SND_SOC_TPLG_DAPM_SWITCH	8
+#define SND_SOC_TPLG_DAPM_PRE		9
+#define SND_SOC_TPLG_DAPM_POST		10
+#define SND_SOC_TPLG_DAPM_AIF_IN	11
+#define SND_SOC_TPLG_DAPM_AIF_OUT	12
+#define SND_SOC_TPLG_DAPM_DAI_IN	13
+#define SND_SOC_TPLG_DAPM_DAI_OUT	14
+#define SND_SOC_TPLG_DAPM_DAI_LINK	15
+#define SND_SOC_TPLG_DAPM_LAST		SND_SOC_TPLG_DAPM_DAI_LINK
+
+/* Header magic number and string sizes */
+#define SND_SOC_TPLG_MAGIC		0x41536F43 /* ASoC */
+
+/* string sizes */
+#define SND_SOC_TPLG_NUM_TEXTS		16
+
+/* ABI version */
+#define SND_SOC_TPLG_ABI_VERSION	0x2
+
+/* Max size of TLV data */
+#define SND_SOC_TPLG_TLV_SIZE		32
+
+/*
+ * File and Block header data types.
+ * Add new generic and vendor types to end of list.
+ * Generic types are handled by the core whilst vendors types are passed
+ * to the component drivers for handling.
+ */
+#define SND_SOC_TPLG_TYPE_MIXER		1
+#define SND_SOC_TPLG_TYPE_BYTES		2
+#define SND_SOC_TPLG_TYPE_ENUM		3
+#define SND_SOC_TPLG_TYPE_DAPM_GRAPH	4
+#define SND_SOC_TPLG_TYPE_DAPM_WIDGET	5
+#define SND_SOC_TPLG_TYPE_DAI_LINK	6
+#define SND_SOC_TPLG_TYPE_PCM		7
+#define SND_SOC_TPLG_TYPE_MANIFEST	8
+#define SND_SOC_TPLG_TYPE_CODEC_LINK	9
+#define SND_SOC_TPLG_TYPE_MAX	SND_SOC_TPLG_TYPE_CODEC_LINK
+
+/* vendor block IDs - please add new vendor types to end */
+#define SND_SOC_TPLG_TYPE_VENDOR_FW	1000
+#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG	1001
+#define SND_SOC_TPLG_TYPE_VENDOR_COEFF	1002
+#define SND_SOC_TPLG_TYPEVENDOR_CODEC	1003
+
+#define SND_SOC_TPLG_STREAM_PLAYBACK	0
+#define SND_SOC_TPLG_STREAM_CAPTURE	1
+
+/*
+ * Block Header.
+ * This header preceeds all object and object arrays below.
+ */
+struct snd_soc_tplg_hdr {
+	__le32 magic;		/* magic number */
+	__le32 abi;		/* ABI version */
+	__le32 version;		/* optional vendor specific version details */
+	__le32 type;		/* SND_SOC_TPLG_TYPE_ */
+	__le32 size;		/* size of this structure */
+	__le32 vendor_type;	/* optional vendor specific type info */
+	__le32 payload_size;	/* data bytes, excluding this header */
+	__le32 index;		/* identifier for block */
+	__le32 count;		/* number of elements in block */
+} __attribute__((packed));
+
+/*
+ * Private data.
+ * All topology objects may have private data that can be used by the driver or
+ * firmware. Core will ignore this data.
+ */
+struct snd_soc_tplg_private {
+	__le32 size;	/* in bytes of private data */
+	char data[0];
+} __attribute__((packed));
+
+/*
+ * Kcontrol TLV data.
+ */
+struct snd_soc_tplg_ctl_tlv {
+	__le32 size;	/* in bytes aligned to 4 */
+	__le32 numid;	/* control element numeric identification */
+	__le32 count;	/* number of elem in data array */
+	__le32 data[SND_SOC_TPLG_TLV_SIZE];
+} __attribute__((packed));
+
+/*
+ * Kcontrol channel data
+ */
+struct snd_soc_tplg_channel {
+	__le32 size;	/* in bytes of this structure */
+	__le32 reg;
+	__le32 shift;
+	__le32 id;	/* ID maps to Left, Right, LFE etc */
+} __attribute__((packed));
+
+/*
+ * Kcontrol Operations IDs
+ */
+struct snd_soc_tplg_kcontrol_ops_id {
+	__le32 get;
+	__le32 put;
+	__le32 info;
+} __attribute__((packed));
+
+/*
+ * kcontrol header
+ */
+struct snd_soc_tplg_ctl_hdr {
+	__le32 size;	/* in bytes of this structure */
+	__le32 type;
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	__le32 access;
+	struct snd_soc_tplg_kcontrol_ops_id ops;
+	__le32 tlv_size;	/* non zero means control has TLV data */
+} __attribute__((packed));
+
+/*
+ * Stream Capabilities
+ */
+struct snd_soc_tplg_stream_caps {
+	__le32 size;		/* in bytes of this structure */
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	__le64 formats[SND_SOC_TPLG_MAX_FORMATS];	/* supported formats SNDRV_PCM_FMTBIT_* */
+	__le32 rates;		/* supported rates SNDRV_PCM_RATE_* */
+	__le32 rate_min;	/* min rate */
+	__le32 rate_max;	/* max rate */
+	__le32 channels_min;	/* min channels */
+	__le32 channels_max;	/* max channels */
+	__le32 periods_min;	/* min number of periods */
+	__le32 periods_max;	/* max number of periods */
+	__le32 period_size_min;	/* min period size bytes */
+	__le32 period_size_max;	/* max period size bytes */
+	__le32 buffer_size_min;	/* min buffer size bytes */
+	__le32 buffer_size_max;	/* max buffer size bytes */
+} __attribute__((packed));
+
+/*
+ * FE or BE Stream configuration supported by SW/FW
+ */
+struct snd_soc_tplg_stream {
+	__le32 size;		/* in bytes of this structure */
+	__le64 format;		/* SNDRV_PCM_FMTBIT_* */
+	__le32 rate;		/* SNDRV_PCM_RATE_* */
+	__le32 period_bytes;	/* size of period in bytes */
+	__le32 buffer_bytes;	/* size of buffer in bytes */
+	__le32 channels;	/* channels */
+	__le32 tdm_slot;	/* optional BE bitmask of supported TDM slots */
+	__le32 dai_fmt;		/* SND_SOC_DAIFMT_  */
+} __attribute__((packed));
+
+/*
+ * Duplex stream configuration supported by SW/FW.
+ */
+struct snd_soc_tplg_stream_config {
+	__le32 size;		/* in bytes of this structure */
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	struct snd_soc_tplg_stream playback;
+	struct snd_soc_tplg_stream capture;
+} __attribute__((packed));
+
+/*
+ * Manifest. List totals for each payload type. Not used in parsing, but will
+ * be passed to the component driver before any other objects in order for any
+ * global componnent resource allocations.
+ *
+ * File block representation for manifest :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_manifest      |  1 |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_manifest {
+	__le32 size;		/* in bytes of this structure */
+	__le32 control_elems;	/* number of control elements */
+	__le32 widget_elems;	/* number of widget elements */
+	__le32 graph_elems;	/* number of graph elements */
+	__le32 dai_elems;	/* number of DAI elements */
+	__le32 dai_link_elems;	/* number of DAI link elements */
+} __attribute__((packed));
+
+/*
+ * Mixer kcontrol.
+ *
+ * File block representation for mixer kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_mixer_control |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_mixer_control {
+	struct snd_soc_tplg_ctl_hdr hdr;
+	__le32 size;	/* in bytes of this structure */
+	__le32 min;
+	__le32 max;
+	__le32 platform_max;
+	__le32 invert;
+	__le32 num_channels;
+	struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
+	struct snd_soc_tplg_ctl_tlv tlv;
+	struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Enumerated kcontrol
+ *
+ * File block representation for enum kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_enum_control  |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_enum_control {
+	struct snd_soc_tplg_ctl_hdr hdr;
+	__le32 size;	/* in bytes of this structure */
+	__le32 num_channels;
+	struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
+	__le32 items;
+	__le32 mask;
+	__le32 count;
+	char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	__le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4];
+	struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Bytes kcontrol
+ *
+ * File block representation for bytes kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_bytes_control |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_bytes_control {
+	struct snd_soc_tplg_ctl_hdr hdr;
+	__le32 size;	/* in bytes of this structure */
+	__le32 max;
+	__le32 mask;
+	__le32 base;
+	__le32 num_regs;
+	struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * DAPM Graph Element
+ *
+ * File block representation for DAPM graph elements :-
+ * +-------------------------------------+----+
+ * | struct snd_soc_tplg_hdr             |  1 |
+ * +-------------------------------------+----+
+ * | struct snd_soc_tplg_dapm_graph_elem |  N |
+ * +-------------------------------------+----+
+ */
+struct snd_soc_tplg_dapm_graph_elem {
+	char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+} __attribute__((packed));
+
+/*
+ * DAPM Widget.
+ *
+ * File block representation for DAPM widget :-
+ * +-------------------------------------+-----+
+ * | struct snd_soc_tplg_hdr             |  1  |
+ * +-------------------------------------+-----+
+ * | struct snd_soc_tplg_dapm_widget     |  N  |
+ * +-------------------------------------+-----+
+ * |   struct snd_soc_tplg_enum_control  | 0|1 |
+ * |   struct snd_soc_tplg_mixer_control | 0|N |
+ * +-------------------------------------+-----+
+ *
+ * Optional enum or mixer control can be appended to the end of each widget
+ * in the block.
+ */
+struct snd_soc_tplg_dapm_widget {
+	__le32 size;		/* in bytes of this structure */
+	__le32 id;		/* SND_SOC_DAPM_CTL */
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+	__le32 reg;		/* negative reg = no direct dapm */
+	__le32 shift;		/* bits to shift */
+	__le32 mask;		/* non-shifted mask */
+	__u32 invert;		/* invert the power bit */
+	__u32 ignore_suspend;	/* kept enabled over suspend */
+	__u16 event_flags;
+	__u16 event_type;
+	__u16 num_kcontrols;
+	struct snd_soc_tplg_private priv;
+	/*
+	 * kcontrols that relate to this widget
+	 * follow here after widget private data
+	 */
+} __attribute__((packed));
+
+struct snd_soc_tplg_pcm_cfg_caps {
+	struct snd_soc_tplg_stream_caps caps;
+	struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
+	__le32 num_configs;	/* number of configs */
+} __attribute__((packed));
+
+/*
+ * Describes SW/FW specific features of PCM or DAI link.
+ *
+ * File block representation for PCM/DAI-Link :-
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_hdr           |  1  |
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_dapm_pcm_dai  |  N  |
+ * +-----------------------------------+-----+
+ */
+struct snd_soc_tplg_pcm_dai {
+	__le32 size;		/* in bytes of this structure */
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	__le32 id;			/* unique ID - used to match */
+	__le32 playback;		/* supports playback mode */
+	__le32 capture;			/* supports capture mode */
+	__le32 compress;		/* 1 = compressed; 0 = PCM */
+	struct snd_soc_tplg_pcm_cfg_caps capconf[2];	/* capabilities and configs */
+} __attribute__((packed));
+
+#endif

+ 31 - 0
include/uapi/sound/tlv.h

@@ -0,0 +1,31 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#ifndef __UAPI_SOUND_TLV_H
+#define __UAPI_SOUND_TLV_H
+
+#define SNDRV_CTL_TLVT_CONTAINER 0	/* one level down - group of TLVs */
+#define SNDRV_CTL_TLVT_DB_SCALE	1       /* dB scale */
+#define SNDRV_CTL_TLVT_DB_LINEAR 2	/* linear volume */
+#define SNDRV_CTL_TLVT_DB_RANGE 3	/* dB range container */
+#define SNDRV_CTL_TLVT_DB_MINMAX 4	/* dB scale with min/max */
+#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5	/* dB scale with min/max with mute */
+
+/*
+ * channel-mapping TLV items
+ *  TLV length must match with num_channels
+ */
+#define SNDRV_CTL_TLVT_CHMAP_FIXED	0x101	/* fixed channel position */
+#define SNDRV_CTL_TLVT_CHMAP_VAR	0x102	/* channels freely swappable */
+#define SNDRV_CTL_TLVT_CHMAP_PAIRED	0x103	/* pair-wise swappable */
+
+#endif

+ 1 - 0
sound/soc/Kconfig

@@ -57,6 +57,7 @@ source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
 source "sound/soc/ux500/Kconfig"
 source "sound/soc/xtensa/Kconfig"
 source "sound/soc/xtensa/Kconfig"
+source "sound/soc/zte/Kconfig"
 
 
 # Supported codecs
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
 source "sound/soc/codecs/Kconfig"

+ 2 - 0
sound/soc/Makefile

@@ -1,5 +1,6 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
+snd-soc-core-objs += soc-topology.o
 
 
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
@@ -38,3 +39,4 @@ obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
 obj-$(CONFIG_SND_SOC)	+= txx9/
 obj-$(CONFIG_SND_SOC)	+= ux500/
 obj-$(CONFIG_SND_SOC)	+= ux500/
 obj-$(CONFIG_SND_SOC)	+= xtensa/
 obj-$(CONFIG_SND_SOC)	+= xtensa/
+obj-$(CONFIG_SND_SOC)	+= zte/

+ 8 - 12
sound/soc/atmel/Kconfig

@@ -6,27 +6,22 @@ config SND_ATMEL_SOC
 	  the ATMEL SSC interface. You will also need
 	  the ATMEL SSC interface. You will also need
 	  to select the audio interfaces to support below.
 	  to select the audio interfaces to support below.
 
 
+if SND_ATMEL_SOC
+
 config SND_ATMEL_SOC_PDC
 config SND_ATMEL_SOC_PDC
-	tristate
-	depends on SND_ATMEL_SOC
+	bool
 
 
 config SND_ATMEL_SOC_DMA
 config SND_ATMEL_SOC_DMA
-	tristate
-	depends on SND_ATMEL_SOC
+	bool
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 
 
 config SND_ATMEL_SOC_SSC
 config SND_ATMEL_SOC_SSC
 	tristate
 	tristate
-	depends on SND_ATMEL_SOC
-	help
-	  Say Y or M if you want to add support for codecs the
-	  ATMEL SSC interface. You will also needs to select the individual
-	  machine drivers to support below.
 
 
 config SND_AT91_SOC_SAM9G20_WM8731
 config SND_AT91_SOC_SAM9G20_WM8731
 	tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
 	tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
 	depends on ARCH_AT91 || COMPILE_TEST
 	depends on ARCH_AT91 || COMPILE_TEST
-	depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
+	depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
 	select SND_ATMEL_SOC_PDC
 	select SND_ATMEL_SOC_PDC
 	select SND_ATMEL_SOC_SSC
 	select SND_ATMEL_SOC_SSC
 	select SND_SOC_WM8731
 	select SND_SOC_WM8731
@@ -37,7 +32,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
 config SND_ATMEL_SOC_WM8904
 config SND_ATMEL_SOC_WM8904
 	tristate "Atmel ASoC driver for boards using WM8904 codec"
 	tristate "Atmel ASoC driver for boards using WM8904 codec"
 	depends on ARCH_AT91 || COMPILE_TEST
 	depends on ARCH_AT91 || COMPILE_TEST
-	depends on ATMEL_SSC && SND_ATMEL_SOC && I2C
+	depends on ATMEL_SSC && I2C
 	select SND_ATMEL_SOC_SSC
 	select SND_ATMEL_SOC_SSC
 	select SND_ATMEL_SOC_DMA
 	select SND_ATMEL_SOC_DMA
 	select SND_SOC_WM8904
 	select SND_SOC_WM8904
@@ -48,10 +43,11 @@ config SND_ATMEL_SOC_WM8904
 config SND_AT91_SOC_SAM9X5_WM8731
 config SND_AT91_SOC_SAM9X5_WM8731
 	tristate "SoC Audio support for WM8731-based at91sam9x5 board"
 	tristate "SoC Audio support for WM8731-based at91sam9x5 board"
 	depends on ARCH_AT91 || COMPILE_TEST
 	depends on ARCH_AT91 || COMPILE_TEST
-	depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
+	depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
 	select SND_ATMEL_SOC_SSC
 	select SND_ATMEL_SOC_SSC
 	select SND_ATMEL_SOC_DMA
 	select SND_ATMEL_SOC_DMA
 	select SND_SOC_WM8731
 	select SND_SOC_WM8731
 	help
 	help
 	  Say Y if you want to add support for audio SoC on an
 	  Say Y if you want to add support for audio SoC on an
 	  at91sam9x5 based board that is using WM8731 codec.
 	  at91sam9x5 based board that is using WM8731 codec.
+endif

+ 3 - 5
sound/soc/atmel/Makefile

@@ -1,10 +1,8 @@
 # AT91 Platform Support
 # AT91 Platform Support
-snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
-snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
-snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
+snd-soc-atmel-pcm-$(CONFIG_SND_ATMEL_SOC_PDC) := atmel-pcm-pdc.o
+snd-soc-atmel-pcm-$(CONFIG_SND_ATMEL_SOC_DMA) += atmel-pcm-dma.o
+snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o $(snd-soc-atmel-pcm-y)
 
 
-obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
-obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
 obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
 obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
 
 
 # AT91 Machine Support
 # AT91 Machine Support

+ 1 - 2
sound/soc/atmel/atmel-pcm-dma.c

@@ -124,8 +124,7 @@ static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
 
 
 int atmel_pcm_dma_platform_register(struct device *dev)
 int atmel_pcm_dma_platform_register(struct device *dev)
 {
 {
-	return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
-			SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+	return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, 0);
 }
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
 EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
 
 

+ 3 - 7
sound/soc/atmel/sam9g20_wm8731.c

@@ -95,8 +95,9 @@ static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
 
 
 static const struct snd_soc_dapm_route intercon[] = {
 static const struct snd_soc_dapm_route intercon[] = {
 
 
-	/* speaker connected to LHPOUT */
+	/* speaker connected to LHPOUT/RHPOUT */
 	{"Ext Spk", NULL, "LHPOUT"},
 	{"Ext Spk", NULL, "LHPOUT"},
+	{"Ext Spk", NULL, "RHPOUT"},
 
 
 	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
 	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
 	{"MICIN", NULL, "Mic Bias"},
 	{"MICIN", NULL, "Mic Bias"},
@@ -108,9 +109,7 @@ static const struct snd_soc_dapm_route intercon[] = {
  */
  */
 static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
 {
-	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 	int ret;
 
 
 	printk(KERN_DEBUG
 	printk(KERN_DEBUG
@@ -124,10 +123,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	/* not connected */
-	snd_soc_dapm_nc_pin(dapm, "RLINEIN");
-	snd_soc_dapm_nc_pin(dapm, "LLINEIN");
-
 #ifndef ENABLE_MIC_INPUT
 #ifndef ENABLE_MIC_INPUT
 	snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
 	snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
 #endif
 #endif
@@ -158,6 +153,7 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
 	.num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
 	.num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
 	.dapm_routes = intercon,
 	.dapm_routes = intercon,
 	.num_dapm_routes = ARRAY_SIZE(intercon),
 	.num_dapm_routes = ARRAY_SIZE(intercon),
+	.fully_routed = true,
 };
 };
 
 
 static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
 static int at91sam9g20ek_audio_probe(struct platform_device *pdev)

+ 1 - 1
sound/soc/au1x/db1200.c

@@ -21,7 +21,7 @@
 #include "../codecs/wm8731.h"
 #include "../codecs/wm8731.h"
 #include "psc.h"
 #include "psc.h"
 
 
-static struct platform_device_id db1200_pids[] = {
+static const struct platform_device_id db1200_pids[] = {
 	{
 	{
 		.name		= "db1200-ac97",
 		.name		= "db1200-ac97",
 		.driver_data	= 0,
 		.driver_data	= 0,

+ 0 - 1
sound/soc/cirrus/ep93xx-pcm.c

@@ -60,7 +60,6 @@ int devm_ep93xx_pcm_platform_register(struct device *dev)
 {
 {
 	return devm_snd_dmaengine_pcm_register(dev,
 	return devm_snd_dmaengine_pcm_register(dev,
 		&ep93xx_dmaengine_pcm_config,
 		&ep93xx_dmaengine_pcm_config,
-		SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
 		SND_DMAENGINE_PCM_FLAG_NO_DT |
 		SND_DMAENGINE_PCM_FLAG_NO_DT |
 		SND_DMAENGINE_PCM_FLAG_COMPAT);
 		SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 }

+ 1 - 2
sound/soc/codecs/88pm860x-codec.c

@@ -1140,7 +1140,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Enable Audio PLL & Audio section */
 			/* Enable Audio PLL & Audio section */
 			data = AUDIO_PLL | AUDIO_SECTION_ON;
 			data = AUDIO_PLL | AUDIO_SECTION_ON;
 			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
 			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
@@ -1156,7 +1156,6 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
 		pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
 		pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 9 - 3
sound/soc/codecs/Kconfig

@@ -16,7 +16,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_88PM860X if MFD_88PM860X
 	select SND_SOC_88PM860X if MFD_88PM860X
 	select SND_SOC_L3
 	select SND_SOC_L3
 	select SND_SOC_AB8500_CODEC if ABX500_CORE
 	select SND_SOC_AB8500_CODEC if ABX500_CORE
-	select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
+	select SND_SOC_AC97_CODEC
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD193X_SPI if SPI_MASTER
 	select SND_SOC_AD193X_SPI if SPI_MASTER
 	select SND_SOC_AD193X_I2C if I2C
 	select SND_SOC_AD193X_I2C if I2C
@@ -54,7 +54,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_CS4271_SPI if SPI_MASTER
 	select SND_SOC_CS4271_SPI if SPI_MASTER
 	select SND_SOC_CS42XX8_I2C if I2C
 	select SND_SOC_CS42XX8_I2C if I2C
 	select SND_SOC_CX20442 if TTY
 	select SND_SOC_CX20442 if TTY
-	select SND_SOC_DA7210 if I2C
+	select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_DA7213 if I2C
 	select SND_SOC_DA7213 if I2C
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA9055 if I2C
 	select SND_SOC_DA9055 if I2C
@@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TAS2552 if I2C
 	select SND_SOC_TAS2552 if I2C
 	select SND_SOC_TAS5086 if I2C
 	select SND_SOC_TAS5086 if I2C
+	select SND_SOC_TAS571X if I2C
 	select SND_SOC_TFA9879 if I2C
 	select SND_SOC_TFA9879 if I2C
 	select SND_SOC_TLV320AIC23_I2C if I2C
 	select SND_SOC_TLV320AIC23_I2C if I2C
 	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
 	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
@@ -211,8 +212,9 @@ config SND_SOC_AB8500_CODEC
 	tristate
 	tristate
 
 
 config SND_SOC_AC97_CODEC
 config SND_SOC_AC97_CODEC
-	tristate
+	tristate "Build generic ASoC AC97 CODEC driver"
 	select SND_AC97_CODEC
 	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
 
 
 config SND_SOC_AD1836
 config SND_SOC_AD1836
 	tristate
 	tristate
@@ -611,6 +613,10 @@ config SND_SOC_TAS5086
 	tristate "Texas Instruments TAS5086 speaker amplifier"
 	tristate "Texas Instruments TAS5086 speaker amplifier"
 	depends on I2C
 	depends on I2C
 
 
+config SND_SOC_TAS571X
+	tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
+	depends on I2C
+
 config SND_SOC_TFA9879
 config SND_SOC_TFA9879
 	tristate "NXP Semiconductors TFA9879 amplifier"
 	tristate "NXP Semiconductors TFA9879 amplifier"
 	depends on I2C
 	depends on I2C

+ 2 - 0
sound/soc/codecs/Makefile

@@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas5086-objs := tas5086.o
+snd-soc-tas571x-objs := tas571x.o
 snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
@@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS2552)	+= snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS2552)	+= snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TFA9879)	+= snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TFA9879)	+= snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o

+ 11 - 9
sound/soc/codecs/ab8500-codec.c

@@ -1209,6 +1209,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 				struct snd_ctl_elem_value *ucontrol)
 {
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 	struct device *dev = codec->dev;
 	struct device *dev = codec->dev;
 	bool apply_fir, apply_iir;
 	bool apply_fir, apply_iir;
@@ -1234,15 +1235,14 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 	apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
 	apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
 	apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
 	apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
 
 
-	status = snd_soc_dapm_force_enable_pin(&codec->dapm,
-					"ANC Configure Input");
+	status = snd_soc_dapm_force_enable_pin(dapm, "ANC Configure Input");
 	if (status < 0) {
 	if (status < 0) {
 		dev_err(dev,
 		dev_err(dev,
 			"%s: ERROR: Failed to enable power (status = %d)!\n",
 			"%s: ERROR: Failed to enable power (status = %d)!\n",
 			__func__, status);
 			__func__, status);
 		goto cleanup;
 		goto cleanup;
 	}
 	}
-	snd_soc_dapm_sync(&codec->dapm);
+	snd_soc_dapm_sync(dapm);
 
 
 	anc_configure(codec, apply_fir, apply_iir);
 	anc_configure(codec, apply_fir, apply_iir);
 
 
@@ -1259,8 +1259,8 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 			drvdata->anc_status =  ANC_IIR_CONFIGURED;
 			drvdata->anc_status =  ANC_IIR_CONFIGURED;
 	}
 	}
 
 
-	status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
-	snd_soc_dapm_sync(&codec->dapm);
+	status = snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
+	snd_soc_dapm_sync(dapm);
 
 
 cleanup:
 cleanup:
 	mutex_unlock(&drvdata->ctrl_lock);
 	mutex_unlock(&drvdata->ctrl_lock);
@@ -1947,6 +1947,7 @@ static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
 static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
 static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
 			struct amic_settings *amics)
 			struct amic_settings *amics)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	u8 value8;
 	u8 value8;
 	unsigned int value;
 	unsigned int value;
 	int status;
 	int status;
@@ -1973,15 +1974,15 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
 	dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
 	dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
 		amic_micbias_str(amics->mic1a_micbias));
 		amic_micbias_str(amics->mic1a_micbias));
 	route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
 	route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
-	status = snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+	status = snd_soc_dapm_add_routes(dapm, route, 1);
 	dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
 	dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
 		amic_micbias_str(amics->mic1b_micbias));
 		amic_micbias_str(amics->mic1b_micbias));
 	route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
 	route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
-	status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+	status |= snd_soc_dapm_add_routes(dapm, route, 1);
 	dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
 	dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
 		amic_micbias_str(amics->mic2_micbias));
 		amic_micbias_str(amics->mic2_micbias));
 	route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
 	route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
-	status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+	status |= snd_soc_dapm_add_routes(dapm, route, 1);
 	if (status < 0) {
 	if (status < 0) {
 		dev_err(codec->dev,
 		dev_err(codec->dev,
 			"%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
 			"%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
@@ -2461,6 +2462,7 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
 
 
 static int ab8500_codec_probe(struct snd_soc_codec *codec)
 static int ab8500_codec_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct device *dev = codec->dev;
 	struct device *dev = codec->dev;
 	struct device_node *np = dev->of_node;
 	struct device_node *np = dev->of_node;
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
@@ -2541,7 +2543,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 		&ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
 		&ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
 	drvdata->sid_fir_values = (long *)fc->value;
 	drvdata->sid_fir_values = (long *)fc->value;
 
 
-	(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
+	snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
 
 
 	mutex_init(&drvdata->ctrl_lock);
 	mutex_init(&drvdata->ctrl_lock);
 
 

+ 2 - 6
sound/soc/codecs/ac97.c

@@ -44,10 +44,6 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 	return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
 	return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
 }
 }
 
 
-#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
-		SNDRV_PCM_RATE_48000)
-
 static const struct snd_soc_dai_ops ac97_dai_ops = {
 static const struct snd_soc_dai_ops ac97_dai_ops = {
 	.prepare	= ac97_prepare,
 	.prepare	= ac97_prepare,
 };
 };
@@ -58,13 +54,13 @@ static struct snd_soc_dai_driver ac97_dai = {
 		.stream_name = "AC97 Playback",
 		.stream_name = "AC97 Playback",
 		.channels_min = 1,
 		.channels_min = 1,
 		.channels_max = 2,
 		.channels_max = 2,
-		.rates = STD_AC97_RATES,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SND_SOC_STD_AC97_FMTS,},
 		.formats = SND_SOC_STD_AC97_FMTS,},
 	.capture = {
 	.capture = {
 		.stream_name = "AC97 Capture",
 		.stream_name = "AC97 Capture",
 		.channels_min = 1,
 		.channels_min = 1,
 		.channels_max = 2,
 		.channels_max = 2,
-		.rates = STD_AC97_RATES,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SND_SOC_STD_AC97_FMTS,},
 		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &ac97_dai_ops,
 	.ops = &ac97_dai_ops,
 };
 };

+ 1 - 1
sound/soc/codecs/ad1836.c

@@ -251,7 +251,7 @@ static int ad1836_resume(struct snd_soc_codec *codec)
 static int ad1836_probe(struct snd_soc_codec *codec)
 static int ad1836_probe(struct snd_soc_codec *codec)
 {
 {
 	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
 	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	int num_dacs, num_adcs;
 	int num_dacs, num_adcs;
 	int ret = 0;
 	int ret = 0;
 	int i;
 	int i;

+ 0 - 1
sound/soc/codecs/adau1373.c

@@ -1444,7 +1444,6 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec,
 			ADAU1373_PWDN_CTRL3_PWR_EN, 0);
 			ADAU1373_PWDN_CTRL3_PWR_EN, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 110 - 16
sound/soc/codecs/adau1701.c

@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/regmap.h>
 #include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -101,6 +102,10 @@
 
 
 #define ADAU1701_FIRMWARE "adau1701.bin"
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
 
+static const char * const supply_names[] = {
+	"dvdd", "avdd"
+};
+
 struct adau1701 {
 struct adau1701 {
 	int gpio_nreset;
 	int gpio_nreset;
 	int gpio_pll_mode[2];
 	int gpio_pll_mode[2];
@@ -112,6 +117,7 @@ struct adau1701 {
 	u8 pin_config[12];
 	u8 pin_config[12];
 
 
 	struct sigmadsp *sigmadsp;
 	struct sigmadsp *sigmadsp;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 };
 
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -565,7 +571,6 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -669,6 +674,13 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
+	ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+				    adau1701->supplies);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
 	/*
 	/*
 	 * Let the pll_clkdiv variable default to something that won't happen
 	 * Let the pll_clkdiv variable default to something that won't happen
 	 * at runtime. That way, we can postpone the firmware download from
 	 * at runtime. That way, we can postpone the firmware download from
@@ -680,7 +692,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	/* initalize with pre-configured pll mode settings */
 	/* initalize with pre-configured pll mode settings */
 	ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
 	ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
 	if (ret < 0)
 	if (ret < 0)
-		return ret;
+		goto exit_regulators_disable;
 
 
 	/* set up pin config */
 	/* set up pin config */
 	val = 0;
 	val = 0;
@@ -696,10 +708,60 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
 	regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
 
 
 	return 0;
 	return 0;
+
+exit_regulators_disable:
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+	return ret;
 }
 }
 
 
+static int adau1701_remove(struct snd_soc_codec *codec)
+{
+	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+	if (gpio_is_valid(adau1701->gpio_nreset))
+		gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int adau1701_suspend(struct snd_soc_codec *codec)
+{
+	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies),
+			       adau1701->supplies);
+
+	return 0;
+}
+
+static int adau1701_resume(struct snd_soc_codec *codec)
+{
+	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+        ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+				    adau1701->supplies);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	return adau1701_reset(codec, adau1701->pll_clkdiv, 0);
+}
+#else
+#define adau1701_resume 	NULL
+#define adau1701_suspend 	NULL
+#endif /* CONFIG_PM */
+
 static struct snd_soc_codec_driver adau1701_codec_drv = {
 static struct snd_soc_codec_driver adau1701_codec_drv = {
 	.probe			= adau1701_probe,
 	.probe			= adau1701_probe,
+	.remove			= adau1701_remove,
+	.resume			= adau1701_resume,
+	.suspend		= adau1701_suspend,
 	.set_bias_level		= adau1701_set_bias_level,
 	.set_bias_level		= adau1701_set_bias_level,
 	.idle_bias_off		= true,
 	.idle_bias_off		= true,
 
 
@@ -730,32 +792,58 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 	struct device *dev = &client->dev;
 	struct device *dev = &client->dev;
 	int gpio_nreset = -EINVAL;
 	int gpio_nreset = -EINVAL;
 	int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
 	int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
-	int ret;
+	int ret, i;
 
 
 	adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
 	adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
 	if (!adau1701)
 	if (!adau1701)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		adau1701->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies),
+			adau1701->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+			adau1701->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
 	adau1701->client = client;
 	adau1701->client = client;
 	adau1701->regmap = devm_regmap_init(dev, NULL, client,
 	adau1701->regmap = devm_regmap_init(dev, NULL, client,
 					    &adau1701_regmap);
 					    &adau1701_regmap);
-	if (IS_ERR(adau1701->regmap))
-		return PTR_ERR(adau1701->regmap);
+	if (IS_ERR(adau1701->regmap)) {
+		ret = PTR_ERR(adau1701->regmap);
+		goto exit_regulators_disable;
+	}
+
 
 
 	if (dev->of_node) {
 	if (dev->of_node) {
 		gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
 		gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
-		if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
-			return gpio_nreset;
+		if (gpio_nreset < 0 && gpio_nreset != -ENOENT) {
+			ret = gpio_nreset;
+			goto exit_regulators_disable;
+		}
 
 
 		gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
 		gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
 						   "adi,pll-mode-gpios", 0);
 						   "adi,pll-mode-gpios", 0);
-		if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
-			return gpio_pll_mode[0];
+		if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) {
+			ret = gpio_pll_mode[0];
+			goto exit_regulators_disable;
+		}
 
 
 		gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
 		gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
 						   "adi,pll-mode-gpios", 1);
 						   "adi,pll-mode-gpios", 1);
-		if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
-			return gpio_pll_mode[1];
+		if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) {
+			ret = gpio_pll_mode[1];
+			goto exit_regulators_disable;
+		}
 
 
 		of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
 		of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
 				     &adau1701->pll_clkdiv);
 				     &adau1701->pll_clkdiv);
@@ -769,7 +857,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 		ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
 		ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
 					    "ADAU1701 Reset");
 					    "ADAU1701 Reset");
 		if (ret < 0)
 		if (ret < 0)
-			return ret;
+			goto exit_regulators_disable;
 	}
 	}
 
 
 	if (gpio_is_valid(gpio_pll_mode[0]) &&
 	if (gpio_is_valid(gpio_pll_mode[0]) &&
@@ -778,13 +866,13 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 					    GPIOF_OUT_INIT_LOW,
 					    GPIOF_OUT_INIT_LOW,
 					    "ADAU1701 PLL mode 0");
 					    "ADAU1701 PLL mode 0");
 		if (ret < 0)
 		if (ret < 0)
-			return ret;
+			goto exit_regulators_disable;
 
 
 		ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
 		ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
 					    GPIOF_OUT_INIT_LOW,
 					    GPIOF_OUT_INIT_LOW,
 					    "ADAU1701 PLL mode 1");
 					    "ADAU1701 PLL mode 1");
 		if (ret < 0)
 		if (ret < 0)
-			return ret;
+			goto exit_regulators_disable;
 	}
 	}
 
 
 	adau1701->gpio_nreset = gpio_nreset;
 	adau1701->gpio_nreset = gpio_nreset;
@@ -795,11 +883,17 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 
 
 	adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
 	adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
 		&adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
 		&adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
-	if (IS_ERR(adau1701->sigmadsp))
-		return PTR_ERR(adau1701->sigmadsp);
+	if (IS_ERR(adau1701->sigmadsp)) {
+		ret = PTR_ERR(adau1701->sigmadsp);
+		goto exit_regulators_disable;
+	}
 
 
 	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
 	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
 			&adau1701_dai, 1);
 			&adau1701_dai, 1);
+
+exit_regulators_disable:
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
 	return ret;
 	return ret;
 }
 }
 
 

+ 12 - 15
sound/soc/codecs/adau1761.c

@@ -466,7 +466,6 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -483,6 +482,7 @@ static enum adau1761_output_mode adau1761_get_lineout_mode(
 
 
 static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau1761_platform_data *pdata = codec->dev->platform_data;
 	struct adau1761_platform_data *pdata = codec->dev->platform_data;
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	enum adau1761_digmic_jackdet_pin_mode mode;
 	enum adau1761_digmic_jackdet_pin_mode mode;
@@ -515,21 +515,18 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
 	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau1761_no_dmic_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes,
 			ARRAY_SIZE(adau1761_no_dmic_routes));
 			ARRAY_SIZE(adau1761_no_dmic_routes));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 		break;
 		break;
 	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
 	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
-			adau1761_dmic_widgets,
+		ret = snd_soc_dapm_new_controls(dapm, adau1761_dmic_widgets,
 			ARRAY_SIZE(adau1761_dmic_widgets));
 			ARRAY_SIZE(adau1761_dmic_widgets));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 
 
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau1761_dmic_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau1761_dmic_routes,
 			ARRAY_SIZE(adau1761_dmic_routes));
 			ARRAY_SIZE(adau1761_dmic_routes));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
@@ -547,6 +544,7 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 
 
 static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
 static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau1761_platform_data *pdata = codec->dev->platform_data;
 	struct adau1761_platform_data *pdata = codec->dev->platform_data;
 	enum adau1761_output_mode mode;
 	enum adau1761_output_mode mode;
@@ -577,12 +575,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
 	}
 	}
 
 
 	if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
 	if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
+		ret = snd_soc_dapm_new_controls(dapm,
 			adau1761_capless_dapm_widgets,
 			adau1761_capless_dapm_widgets,
 			ARRAY_SIZE(adau1761_capless_dapm_widgets));
 			ARRAY_SIZE(adau1761_capless_dapm_widgets));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
+		ret = snd_soc_dapm_add_routes(dapm,
 			adau1761_capless_dapm_routes,
 			adau1761_capless_dapm_routes,
 			ARRAY_SIZE(adau1761_capless_dapm_routes));
 			ARRAY_SIZE(adau1761_capless_dapm_routes));
 	} else {
 	} else {
@@ -590,12 +588,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
 			ARRAY_SIZE(adau1761_mono_controls));
 			ARRAY_SIZE(adau1761_mono_controls));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
+		ret = snd_soc_dapm_new_controls(dapm,
 			adau1761_mono_dapm_widgets,
 			adau1761_mono_dapm_widgets,
 			ARRAY_SIZE(adau1761_mono_dapm_widgets));
 			ARRAY_SIZE(adau1761_mono_dapm_widgets));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
+		ret = snd_soc_dapm_add_routes(dapm,
 			adau1761_mono_dapm_routes,
 			adau1761_mono_dapm_routes,
 			ARRAY_SIZE(adau1761_mono_dapm_routes));
 			ARRAY_SIZE(adau1761_mono_dapm_routes));
 	}
 	}
@@ -640,6 +638,7 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg)
 
 
 static int adau1761_codec_probe(struct snd_soc_codec *codec)
 static int adau1761_codec_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau1761_platform_data *pdata = codec->dev->platform_data;
 	struct adau1761_platform_data *pdata = codec->dev->platform_data;
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
@@ -692,14 +691,12 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
 		return ret;
 		return ret;
 
 
 	if (adau->type == ADAU1761) {
 	if (adau->type == ADAU1761) {
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
-			adau1761_dapm_widgets,
+		ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets,
 			ARRAY_SIZE(adau1761_dapm_widgets));
 			ARRAY_SIZE(adau1761_dapm_widgets));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 
 
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau1761_dapm_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_routes,
 			ARRAY_SIZE(adau1761_dapm_routes));
 			ARRAY_SIZE(adau1761_dapm_routes));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;

+ 4 - 6
sound/soc/codecs/adau1781.c

@@ -339,7 +339,6 @@ static int adau1781_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -383,6 +382,7 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
 
 
 static int adau1781_codec_probe(struct snd_soc_codec *codec)
 static int adau1781_codec_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
 	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
@@ -403,19 +403,17 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
 	}
 	}
 
 
 	if (pdata && pdata->use_dmic) {
 	if (pdata && pdata->use_dmic) {
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
+		ret = snd_soc_dapm_new_controls(dapm,
 			adau1781_dmic_dapm_widgets,
 			adau1781_dmic_dapm_widgets,
 			ARRAY_SIZE(adau1781_dmic_dapm_widgets));
 			ARRAY_SIZE(adau1781_dmic_dapm_widgets));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau1781_dmic_dapm_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau1781_dmic_dapm_routes,
 			ARRAY_SIZE(adau1781_dmic_dapm_routes));
 			ARRAY_SIZE(adau1781_dmic_dapm_routes));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 	} else {
 	} else {
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau1781_adc_dapm_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau1781_adc_dapm_routes,
 			ARRAY_SIZE(adau1781_adc_dapm_routes));
 			ARRAY_SIZE(adau1781_adc_dapm_routes));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;

+ 10 - 10
sound/soc/codecs/adau17x1.c

@@ -155,6 +155,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 	struct snd_ctl_elem_value *ucontrol)
 {
 {
 	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	struct snd_soc_dapm_update update;
 	struct snd_soc_dapm_update update;
@@ -188,7 +189,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
 		update.reg = reg;
 		update.reg = reg;
 		update.val = val;
 		update.val = val;
 
 
-		snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
+		snd_soc_dapm_mux_update_power(dapm, kcontrol,
 				ucontrol->value.enumerated.item[0], e, &update);
 				ucontrol->value.enumerated.item[0], e, &update);
 	}
 	}
 
 
@@ -444,8 +445,8 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
 static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
 static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 		int clk_id, unsigned int freq, int dir)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
-	struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
 
 
 	switch (clk_id) {
 	switch (clk_id) {
 	case ADAU17X1_CLK_SRC_MCLK:
 	case ADAU17X1_CLK_SRC_MCLK:
@@ -804,6 +805,7 @@ EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
 
 
 int adau17x1_add_widgets(struct snd_soc_codec *codec)
 int adau17x1_add_widgets(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
 
 
@@ -811,14 +813,13 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
 		ARRAY_SIZE(adau17x1_controls));
 		ARRAY_SIZE(adau17x1_controls));
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
-	ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
+	ret = snd_soc_dapm_new_controls(dapm, adau17x1_dapm_widgets,
 		ARRAY_SIZE(adau17x1_dapm_widgets));
 		ARRAY_SIZE(adau17x1_dapm_widgets));
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
 	if (adau17x1_has_dsp(adau)) {
 	if (adau17x1_has_dsp(adau)) {
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
-			adau17x1_dsp_dapm_widgets,
+		ret = snd_soc_dapm_new_controls(dapm, adau17x1_dsp_dapm_widgets,
 			ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
 			ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
@@ -840,21 +841,20 @@ EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
 
 
 int adau17x1_add_routes(struct snd_soc_codec *codec)
 int adau17x1_add_routes(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
 
 
-	ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
+	ret = snd_soc_dapm_add_routes(dapm, adau17x1_dapm_routes,
 		ARRAY_SIZE(adau17x1_dapm_routes));
 		ARRAY_SIZE(adau17x1_dapm_routes));
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
 	if (adau17x1_has_dsp(adau)) {
 	if (adau17x1_has_dsp(adau)) {
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau17x1_dsp_dapm_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau17x1_dsp_dapm_routes,
 			ARRAY_SIZE(adau17x1_dsp_dapm_routes));
 			ARRAY_SIZE(adau17x1_dsp_dapm_routes));
 	} else {
 	} else {
-		ret = snd_soc_dapm_add_routes(&codec->dapm,
-			adau17x1_no_dsp_dapm_routes,
+		ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
 			ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
 			ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
 	}
 	}
 	return ret;
 	return ret;

+ 5 - 9
sound/soc/codecs/adau1977.c

@@ -202,7 +202,7 @@ static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
 		ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
 		ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
 
 
 #define ADAU1977_DC_SUB_SWITCH(x) \
 #define ADAU1977_DC_SUB_SWITCH(x) \
-	SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \
+	SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \
 		ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
 		ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
 
 
 static const struct snd_kcontrol_new adau1977_snd_controls[] = {
 static const struct snd_kcontrol_new adau1977_snd_controls[] = {
@@ -485,7 +485,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			ret = adau1977_power_enable(adau1977);
 			ret = adau1977_power_enable(adau1977);
 		break;
 		break;
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
@@ -493,12 +493,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	if (ret)
-		return ret;
-
-	codec->dapm.bias_level = level;
-
-	return 0;
+	return ret;
 }
 }
 
 
 static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -853,12 +848,13 @@ static int adau1977_set_sysclk(struct snd_soc_codec *codec,
 
 
 static int adau1977_codec_probe(struct snd_soc_codec *codec)
 static int adau1977_codec_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
 	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
 
 
 	switch (adau1977->type) {
 	switch (adau1977->type) {
 	case ADAU1977:
 	case ADAU1977:
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
+		ret = snd_soc_dapm_new_controls(dapm,
 			adau1977_micbias_dapm_widgets,
 			adau1977_micbias_dapm_widgets,
 			ARRAY_SIZE(adau1977_micbias_dapm_widgets));
 			ARRAY_SIZE(adau1977_micbias_dapm_widgets));
 		if (ret < 0)
 		if (ret < 0)

+ 6 - 5
sound/soc/codecs/adav80x.c

@@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
 			      unsigned int freq, int dir)
 			      unsigned int freq, int dir)
 {
 {
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
 
 	if (dir == SND_SOC_CLOCK_IN) {
 	if (dir == SND_SOC_CLOCK_IN) {
 		switch (clk_id) {
 		switch (clk_id) {
@@ -622,6 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
 static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
 static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	unsigned int pll_ctrl1 = 0;
 	unsigned int pll_ctrl1 = 0;
 	unsigned int pll_ctrl2 = 0;
 	unsigned int pll_ctrl2 = 0;
@@ -687,7 +688,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
 
 
 		adav80x->pll_src = source;
 		adav80x->pll_src = source;
 
 
-		snd_soc_dapm_sync(&codec->dapm);
+		snd_soc_dapm_sync(dapm);
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -714,7 +715,6 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -801,11 +801,12 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
 
 
 static int adav80x_probe(struct snd_soc_codec *codec)
 static int adav80x_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
 
 	/* Force PLLs on for SYSCLK output */
 	/* Force PLLs on for SYSCLK output */
-	snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
-	snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
+	snd_soc_dapm_force_enable_pin(dapm, "PLL1");
+	snd_soc_dapm_force_enable_pin(dapm, "PLL2");
 
 
 	/* Power down S/PDIF receiver, since it is currently not supported */
 	/* Power down S/PDIF receiver, since it is currently not supported */
 	regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
 	regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);

+ 0 - 1
sound/soc/codecs/ak4535.c

@@ -341,7 +341,6 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
 		snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
 		snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 2
sound/soc/codecs/ak4641.c

@@ -412,7 +412,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
 		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
 		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			if (pdata && gpio_is_valid(pdata->gpio_power))
 			if (pdata && gpio_is_valid(pdata->gpio_power))
 				gpio_set_value(pdata->gpio_power, 1);
 				gpio_set_value(pdata->gpio_power, 1);
 			mdelay(1);
 			mdelay(1);
@@ -439,7 +439,6 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
 		regcache_mark_dirty(ak4641->regmap);
 		regcache_mark_dirty(ak4641->regmap);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 0 - 1
sound/soc/codecs/ak4642.c

@@ -482,7 +482,6 @@ static int ak4642_set_bias_level(struct snd_soc_codec *codec,
 		snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
 		snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }

+ 0 - 1
sound/soc/codecs/ak4671.c

@@ -577,7 +577,6 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec,
 		snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
 		snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 2
sound/soc/codecs/alc5623.c

@@ -826,7 +826,6 @@ static int alc5623_set_bias_level(struct snd_soc_codec *codec,
 		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0);
 		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -894,7 +893,7 @@ static int alc5623_resume(struct snd_soc_codec *codec)
 static int alc5623_probe(struct snd_soc_codec *codec)
 static int alc5623_probe(struct snd_soc_codec *codec)
 {
 {
 	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
 	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
 
 	alc5623_reset(codec);
 	alc5623_reset(codec);
 
 

+ 0 - 1
sound/soc/codecs/alc5632.c

@@ -1000,7 +1000,6 @@ static int alc5632_set_bias_level(struct snd_soc_codec *codec,
 				ALC5632_PWR_MANAG_ADD1_MASK, 0);
 				ALC5632_PWR_MANAG_ADD1_MASK, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 160 - 14
sound/soc/codecs/arizona.c

@@ -208,11 +208,12 @@ static const struct snd_soc_dapm_widget arizona_spkr =
 
 
 int arizona_init_spk(struct snd_soc_codec *codec)
 int arizona_init_spk(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona *arizona = priv->arizona;
 	struct arizona *arizona = priv->arizona;
 	int ret;
 	int ret;
 
 
-	ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
+	ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
 	if (ret != 0)
 	if (ret != 0)
 		return ret;
 		return ret;
 
 
@@ -220,8 +221,7 @@ int arizona_init_spk(struct snd_soc_codec *codec)
 	case WM8997:
 	case WM8997:
 		break;
 		break;
 	default:
 	default:
-		ret = snd_soc_dapm_new_controls(&codec->dapm,
-						&arizona_spkr, 1);
+		ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
 		if (ret != 0)
 		if (ret != 0)
 			return ret;
 			return ret;
 		break;
 		break;
@@ -258,13 +258,14 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = {
 
 
 int arizona_init_mono(struct snd_soc_codec *codec)
 int arizona_init_mono(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona *arizona = priv->arizona;
 	struct arizona *arizona = priv->arizona;
 	int i;
 	int i;
 
 
 	for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
 	for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
 		if (arizona->pdata.out_mono[i])
 		if (arizona->pdata.out_mono[i])
-			snd_soc_dapm_add_routes(&codec->dapm,
+			snd_soc_dapm_add_routes(dapm,
 						&arizona_mono_routes[i], 1);
 						&arizona_mono_routes[i], 1);
 	}
 	}
 
 
@@ -274,6 +275,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono);
 
 
 int arizona_init_gpio(struct snd_soc_codec *codec)
 int arizona_init_gpio(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona *arizona = priv->arizona;
 	struct arizona *arizona = priv->arizona;
 	int i;
 	int i;
@@ -281,23 +283,21 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
 	switch (arizona->type) {
 	switch (arizona->type) {
 	case WM5110:
 	case WM5110:
 	case WM8280:
 	case WM8280:
-		snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
+		snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
 		break;
 		break;
 	default:
 	default:
 		break;
 		break;
 	}
 	}
 
 
-	snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
+	snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
 
 
 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
 		switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
 		switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
 		case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
 		case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
-			snd_soc_dapm_enable_pin(&codec->dapm,
-						"DRC1 Signal Activity");
+			snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
 			break;
 			break;
 		case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
 		case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
-			snd_soc_dapm_enable_pin(&codec->dapm,
-						"DRC2 Signal Activity");
+			snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
 			break;
 			break;
 		default:
 		default:
 			break;
 			break;
@@ -851,6 +851,134 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 }
 }
 EXPORT_SYMBOL_GPL(arizona_hp_ev);
 EXPORT_SYMBOL_GPL(arizona_hp_ev);
 
 
+static int arizona_dvfs_enable(struct snd_soc_codec *codec)
+{
+	const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+	int ret;
+
+	ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
+	if (ret) {
+		dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(arizona->regmap,
+				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
+				 ARIZONA_SUBSYS_MAX_FREQ,
+				 ARIZONA_SUBSYS_MAX_FREQ);
+	if (ret) {
+		dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
+		regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int arizona_dvfs_disable(struct snd_soc_codec *codec)
+{
+	const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+	int ret;
+
+	ret = regmap_update_bits(arizona->regmap,
+				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
+				 ARIZONA_SUBSYS_MAX_FREQ, 0);
+	if (ret) {
+		dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
+	if (ret) {
+		dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	mutex_lock(&priv->dvfs_lock);
+
+	if (!priv->dvfs_cached && !priv->dvfs_reqs) {
+		ret = arizona_dvfs_enable(codec);
+		if (ret)
+			goto err;
+	}
+
+	priv->dvfs_reqs |= flags;
+err:
+	mutex_unlock(&priv->dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_up);
+
+int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	unsigned int old_reqs;
+	int ret = 0;
+
+	mutex_lock(&priv->dvfs_lock);
+
+	old_reqs = priv->dvfs_reqs;
+	priv->dvfs_reqs &= ~flags;
+
+	if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
+		ret = arizona_dvfs_disable(codec);
+
+	mutex_unlock(&priv->dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_down);
+
+int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	mutex_lock(&priv->dvfs_lock);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (priv->dvfs_reqs)
+			ret = arizona_dvfs_enable(codec);
+
+		priv->dvfs_cached = false;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* We must ensure DVFS is disabled before the codec goes into
+		 * suspend so that we are never in an illegal state of DVFS
+		 * enabled without enough DCVDD
+		 */
+		priv->dvfs_cached = true;
+
+		if (priv->dvfs_reqs)
+			ret = arizona_dvfs_disable(codec);
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&priv->dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
+
+void arizona_init_dvfs(struct arizona_priv *priv)
+{
+	mutex_init(&priv->dvfs_lock);
+}
+EXPORT_SYMBOL_GPL(arizona_init_dvfs);
+
 static unsigned int arizona_sysclk_48k_rates[] = {
 static unsigned int arizona_sysclk_48k_rates[] = {
 	6144000,
 	6144000,
 	12288000,
 	12288000,
@@ -1266,7 +1394,7 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	int base = dai->driver->base;
 	int base = dai->driver->base;
-	int i, sr_val;
+	int i, sr_val, ret;
 
 
 	/*
 	/*
 	 * We will need to be more flexible than this in future,
 	 * We will need to be more flexible than this in future,
@@ -1282,6 +1410,23 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
 	}
 	}
 	sr_val = i;
 	sr_val = i;
 
 
+	switch (priv->arizona->type) {
+	case WM5102:
+	case WM8997:
+		if (arizona_sr_vals[sr_val] >= 88200)
+			ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
+		else
+			ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
+
+		if (ret) {
+			arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		break;
+	}
+
 	switch (dai_priv->clk) {
 	switch (dai_priv->clk) {
 	case ARIZONA_CLK_SYSCLK:
 	case ARIZONA_CLK_SYSCLK:
 		switch (priv->arizona->type) {
 		switch (priv->arizona->type) {
@@ -1474,6 +1619,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
 				  int clk_id, unsigned int freq, int dir)
 				  int clk_id, unsigned int freq, int dir)
 {
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	struct snd_soc_dapm_route routes[2];
 	struct snd_soc_dapm_route routes[2];
@@ -1504,15 +1650,15 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
 
 
 	routes[0].source = arizona_dai_clk_str(dai_priv->clk);
 	routes[0].source = arizona_dai_clk_str(dai_priv->clk);
 	routes[1].source = arizona_dai_clk_str(dai_priv->clk);
 	routes[1].source = arizona_dai_clk_str(dai_priv->clk);
-	snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
+	snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
 
 
 	routes[0].source = arizona_dai_clk_str(clk_id);
 	routes[0].source = arizona_dai_clk_str(clk_id);
 	routes[1].source = arizona_dai_clk_str(clk_id);
 	routes[1].source = arizona_dai_clk_str(clk_id);
-	snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
+	snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
 
 
 	dai_priv->clk = clk_id;
 	dai_priv->clk = clk_id;
 
 
-	return snd_soc_dapm_sync(&codec->dapm);
+	return snd_soc_dapm_sync(dapm);
 }
 }
 
 
 static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
 static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)

+ 15 - 2
sound/soc/codecs/arizona.h

@@ -60,6 +60,9 @@
 #define ARIZONA_MAX_DAI  6
 #define ARIZONA_MAX_DAI  6
 #define ARIZONA_MAX_ADSP 4
 #define ARIZONA_MAX_ADSP 4
 
 
+#define ARIZONA_DVFS_SR1_RQ	0x001
+#define ARIZONA_DVFS_ADSP1_RQ	0x100
+
 struct arizona;
 struct arizona;
 struct wm_adsp;
 struct wm_adsp;
 
 
@@ -84,6 +87,10 @@ struct arizona_priv {
 
 
 	unsigned int spk_ena:2;
 	unsigned int spk_ena:2;
 	unsigned int spk_ena_pending:1;
 	unsigned int spk_ena_pending:1;
+
+	unsigned int dvfs_reqs;
+	struct mutex dvfs_lock;
+	bool dvfs_cached;
 };
 };
 
 
 #define ARIZONA_NUM_MIXER_INPUTS 103
 #define ARIZONA_NUM_MIXER_INPUTS 103
@@ -107,8 +114,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 			     arizona_mixer_tlv)
 			     arizona_mixer_tlv)
 
 
 #define ARIZONA_MUX_ENUM_DECL(name, reg) \
 #define ARIZONA_MUX_ENUM_DECL(name, reg) \
-	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff,			\
-				   arizona_mixer_texts, arizona_mixer_values)
+	SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \
+		name, reg, 0, 0xff, arizona_mixer_texts, arizona_mixer_values)
 
 
 #define ARIZONA_MUX_CTL_DECL(name) \
 #define ARIZONA_MUX_CTL_DECL(name) \
 	const struct snd_kcontrol_new name##_mux =	\
 	const struct snd_kcontrol_new name##_mux =	\
@@ -245,6 +252,12 @@ struct arizona_fll {
 	char clock_ok_name[ARIZONA_FLL_NAME_LEN];
 	char clock_ok_name[ARIZONA_FLL_NAME_LEN];
 };
 };
 
 
+extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
+extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
+extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event);
+extern void arizona_init_dvfs(struct arizona_priv *priv);
+
 extern int arizona_init_fll(struct arizona *arizona, int id, int base,
 extern int arizona_init_fll(struct arizona *arizona, int id, int base,
 			    int lock_irq, int ok_irq, struct arizona_fll *fll);
 			    int lock_irq, int ok_irq, struct arizona_fll *fll);
 extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
 extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,

+ 10 - 1
sound/soc/codecs/bt-sco.c

@@ -63,7 +63,7 @@ static int bt_sco_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct platform_device_id bt_sco_driver_ids[] = {
+static const struct platform_device_id bt_sco_driver_ids[] = {
 	{
 	{
 		.name		= "dfbmcs320",
 		.name		= "dfbmcs320",
 	},
 	},
@@ -74,9 +74,18 @@ static struct platform_device_id bt_sco_driver_ids[] = {
 };
 };
 MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
 MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
 
 
+#if defined(CONFIG_OF)
+static const struct of_device_id bt_sco_codec_of_match[] = {
+	{ .compatible = "delta,dfbmcs320", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
+#endif
+
 static struct platform_driver bt_sco_driver = {
 static struct platform_driver bt_sco_driver = {
 	.driver = {
 	.driver = {
 		.name = "bt-sco",
 		.name = "bt-sco",
+		.of_match_table = of_match_ptr(bt_sco_codec_of_match),
 	},
 	},
 	.probe = bt_sco_probe,
 	.probe = bt_sco_probe,
 	.remove = bt_sco_remove,
 	.remove = bt_sco_remove,

+ 0 - 1
sound/soc/codecs/cq93vc.c

@@ -92,7 +92,6 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
 			     DAVINCI_VC_REG12_POWER_ALL_OFF);
 			     DAVINCI_VC_REG12_POWER_ALL_OFF);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }

+ 0 - 1
sound/soc/codecs/cs35l32.c

@@ -13,7 +13,6 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/delay.h>

+ 0 - 1
sound/soc/codecs/cs4265.c

@@ -503,7 +503,6 @@ static int cs4265_set_bias_level(struct snd_soc_codec *codec,
 			CS4265_PWRCTL_PDN);
 			CS4265_PWRCTL_PDN);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 3
sound/soc/codecs/cs42l52.c

@@ -897,7 +897,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
 				    CS42L52_PWRCTL1_PDN_CODEC, 0);
 				    CS42L52_PWRCTL1_PDN_CODEC, 0);
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l52->regmap, false);
 			regcache_cache_only(cs42l52->regmap, false);
 			regcache_sync(cs42l52->regmap);
 			regcache_sync(cs42l52->regmap);
 		}
 		}
@@ -908,7 +908,6 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
 		regcache_cache_only(cs42l52->regmap, true);
 		regcache_cache_only(cs42l52->regmap, true);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -956,7 +955,7 @@ static void cs42l52_beep_work(struct work_struct *work)
 	struct cs42l52_private *cs42l52 =
 	struct cs42l52_private *cs42l52 =
 		container_of(work, struct cs42l52_private, beep_work);
 		container_of(work, struct cs42l52_private, beep_work);
 	struct snd_soc_codec *codec = cs42l52->codec;
 	struct snd_soc_codec *codec = cs42l52->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	int i;
 	int i;
 	int val = 0;
 	int val = 0;
 	int best = 0;
 	int best = 0;

+ 2 - 3
sound/soc/codecs/cs42l56.c

@@ -953,7 +953,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
 				    CS42L56_PDN_ALL_MASK, 0);
 				    CS42L56_PDN_ALL_MASK, 0);
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l56->regmap, false);
 			regcache_cache_only(cs42l56->regmap, false);
 			regcache_sync(cs42l56->regmap);
 			regcache_sync(cs42l56->regmap);
 			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
 			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
@@ -978,7 +978,6 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
 						    cs42l56->supplies);
 						    cs42l56->supplies);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1026,7 +1025,7 @@ static void cs42l56_beep_work(struct work_struct *work)
 	struct cs42l56_private *cs42l56 =
 	struct cs42l56_private *cs42l56 =
 		container_of(work, struct cs42l56_private, beep_work);
 		container_of(work, struct cs42l56_private, beep_work);
 	struct snd_soc_codec *codec = cs42l56->codec;
 	struct snd_soc_codec *codec = cs42l56->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	int i;
 	int i;
 	int val = 0;
 	int val = 0;
 	int best = 0;
 	int best = 0;

+ 1 - 2
sound/soc/codecs/cs42l73.c

@@ -1208,7 +1208,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l73->regmap, false);
 			regcache_cache_only(cs42l73->regmap, false);
 			regcache_sync(cs42l73->regmap);
 			regcache_sync(cs42l73->regmap);
 		}
 		}
@@ -1228,7 +1228,6 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
 		snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
 		snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
sound/soc/codecs/cs42xx8.c

@@ -380,7 +380,7 @@ EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
 static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
 static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
 {
 {
 	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
 	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
 
 	switch (cs42xx8->drvdata->num_adcs) {
 	switch (cs42xx8->drvdata->num_adcs) {
 	case 3:
 	case 3:

+ 2 - 4
sound/soc/codecs/cx20442.c

@@ -333,7 +333,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
 
 
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
-		if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY)
+		if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_STANDBY)
 			break;
 			break;
 		if (IS_ERR(cx20442->por))
 		if (IS_ERR(cx20442->por))
 			err = PTR_ERR(cx20442->por);
 			err = PTR_ERR(cx20442->por);
@@ -341,7 +341,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
 			err = regulator_enable(cx20442->por);
 			err = regulator_enable(cx20442->por);
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE)
+		if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_PREPARE)
 			break;
 			break;
 		if (IS_ERR(cx20442->por))
 		if (IS_ERR(cx20442->por))
 			err = PTR_ERR(cx20442->por);
 			err = PTR_ERR(cx20442->por);
@@ -351,8 +351,6 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	if (!err)
-		codec->dapm.bias_level = level;
 
 
 	return err;
 	return err;
 }
 }

+ 1 - 2
sound/soc/codecs/da7213.c

@@ -1374,7 +1374,7 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Enable VMID reference & master bias */
 			/* Enable VMID reference & master bias */
 			snd_soc_update_bits(codec, DA7213_REFERENCES,
 			snd_soc_update_bits(codec, DA7213_REFERENCES,
 					    DA7213_VMID_EN | DA7213_BIAS_EN,
 					    DA7213_VMID_EN | DA7213_BIAS_EN,
@@ -1387,7 +1387,6 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 				    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
 				    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 3
sound/soc/codecs/da732x.c

@@ -1432,7 +1432,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Init Codec */
 			/* Init Codec */
 			snd_soc_write(codec, DA732X_REG_REF1,
 			snd_soc_write(codec, DA732X_REG_REF1,
 				      DA732X_VMID_FASTCHG);
 				      DA732X_VMID_FASTCHG);
@@ -1502,8 +1502,6 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 2
sound/soc/codecs/da9055.c

@@ -1364,7 +1364,7 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			/* Enable VMID reference & master bias */
 			/* Enable VMID reference & master bias */
 			snd_soc_update_bits(codec, DA9055_REFERENCES,
 			snd_soc_update_bits(codec, DA9055_REFERENCES,
 					    DA9055_VMID_EN | DA9055_BIAS_EN,
 					    DA9055_VMID_EN | DA9055_BIAS_EN,
@@ -1377,7 +1377,6 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
 				    DA9055_VMID_EN | DA9055_BIAS_EN, 0);
 				    DA9055_VMID_EN | DA9055_BIAS_EN, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 2
sound/soc/codecs/es8328.c

@@ -536,7 +536,7 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			snd_soc_update_bits(codec, ES8328_CONTROL1,
 			snd_soc_update_bits(codec, ES8328_CONTROL1,
 					ES8328_CONTROL1_VMIDSEL_MASK |
 					ES8328_CONTROL1_VMIDSEL_MASK |
 					ES8328_CONTROL1_ENREF,
 					ES8328_CONTROL1_ENREF,
@@ -566,7 +566,6 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
 				0);
 				0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 0 - 2
sound/soc/codecs/isabelle.c

@@ -909,8 +909,6 @@ static int isabelle_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 3
sound/soc/codecs/jz4740.c

@@ -258,7 +258,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		/* The only way to clear the suspend flag is to reset the codec */
 		/* The only way to clear the suspend flag is to reset the codec */
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			jz4740_codec_wakeup(regmap);
 			jz4740_codec_wakeup(regmap);
 
 
 		mask = JZ4740_CODEC_1_VREF_DISABLE |
 		mask = JZ4740_CODEC_1_VREF_DISABLE |
@@ -281,8 +281,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 29 - 85
sound/soc/codecs/lm4857.c

@@ -23,11 +23,6 @@
 #include <sound/soc.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
 
 
-struct lm4857 {
-	struct regmap *regmap;
-	uint8_t mode;
-};
-
 static const struct reg_default lm4857_default_regs[] = {
 static const struct reg_default lm4857_default_regs[] = {
 	{ 0x0, 0x00 },
 	{ 0x0, 0x00 },
 	{ 0x1, 0x00 },
 	{ 0x1, 0x00 },
@@ -46,66 +41,33 @@ static const struct reg_default lm4857_default_regs[] = {
 #define LM4857_WAKEUP 5
 #define LM4857_WAKEUP 5
 #define LM4857_EPGAIN 4
 #define LM4857_EPGAIN 4
 
 
-static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = lm4857->mode;
-
-	return 0;
-}
-
-static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-	uint8_t value = ucontrol->value.integer.value[0];
-
-	lm4857->mode = value;
-
-	if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-		regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6);
-
-	return 1;
-}
-
-static int lm4857_set_bias_level(struct snd_soc_codec *codec,
-				 enum snd_soc_bias_level level)
-{
-	struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-
-	switch (level) {
-	case SND_SOC_BIAS_ON:
-		regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F,
-			lm4857->mode + 6);
-		break;
-	case SND_SOC_BIAS_STANDBY:
-		regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0);
-		break;
-	default:
-		break;
-	}
-
-	codec->dapm.bias_level = level;
-
-	return 0;
-}
+static const unsigned int lm4857_mode_values[] = {
+	0,
+	6,
+	7,
+	8,
+	9,
+};
 
 
-static const char *lm4857_mode[] = {
+static const char * const lm4857_mode_texts[] = {
+	"Off",
 	"Earpiece",
 	"Earpiece",
 	"Loudspeaker",
 	"Loudspeaker",
 	"Loudspeaker + Headphone",
 	"Loudspeaker + Headphone",
 	"Headphone",
 	"Headphone",
 };
 };
 
 
-static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode);
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum,
+	LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values);
+
+static const struct snd_kcontrol_new lm4857_mode_ctrl =
+	SOC_DAPM_ENUM("Mode", lm4857_mode_enum);
 
 
 static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
 static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("IN"),
 	SND_SOC_DAPM_INPUT("IN"),
 
 
+	SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl),
+
 	SND_SOC_DAPM_OUTPUT("LS"),
 	SND_SOC_DAPM_OUTPUT("LS"),
 	SND_SOC_DAPM_OUTPUT("HP"),
 	SND_SOC_DAPM_OUTPUT("HP"),
 	SND_SOC_DAPM_OUTPUT("EP"),
 	SND_SOC_DAPM_OUTPUT("EP"),
@@ -127,24 +89,18 @@ static const struct snd_kcontrol_new lm4857_controls[] = {
 		LM4857_WAKEUP, 1, 0),
 		LM4857_WAKEUP, 1, 0),
 	SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL,
 	SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL,
 		LM4857_EPGAIN, 1, 0),
 		LM4857_EPGAIN, 1, 0),
-
-	SOC_ENUM_EXT("Mode", lm4857_mode_enum,
-		lm4857_get_mode, lm4857_set_mode),
 };
 };
 
 
-/* There is a demux between the input signal and the output signals.
- * Currently there is no easy way to model it in ASoC and since it does not make
- * much of a difference in practice simply connect the input direclty to the
- * outputs. */
 static const struct snd_soc_dapm_route lm4857_routes[] = {
 static const struct snd_soc_dapm_route lm4857_routes[] = {
-	{"LS", NULL, "IN"},
-	{"HP", NULL, "IN"},
-	{"EP", NULL, "IN"},
+	{ "Mode", NULL, "IN" },
+	{ "LS", "Loudspeaker", "Mode" },
+	{ "LS", "Loudspeaker + Headphone", "Mode" },
+	{ "HP", "Headphone", "Mode" },
+	{ "HP", "Loudspeaker + Headphone", "Mode" },
+	{ "EP", "Earpiece", "Mode" },
 };
 };
 
 
-static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
-	.set_bias_level = lm4857_set_bias_level,
-
+static struct snd_soc_component_driver lm4857_component_driver = {
 	.controls = lm4857_controls,
 	.controls = lm4857_controls,
 	.num_controls = ARRAY_SIZE(lm4857_controls),
 	.num_controls = ARRAY_SIZE(lm4857_controls),
 	.dapm_widgets = lm4857_dapm_widgets,
 	.dapm_widgets = lm4857_dapm_widgets,
@@ -167,25 +123,14 @@ static const struct regmap_config lm4857_regmap_config = {
 static int lm4857_i2c_probe(struct i2c_client *i2c,
 static int lm4857_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 			    const struct i2c_device_id *id)
 {
 {
-	struct lm4857 *lm4857;
-
-	lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
-	if (!lm4857)
-		return -ENOMEM;
-
-	i2c_set_clientdata(i2c, lm4857);
-
-	lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
-	if (IS_ERR(lm4857->regmap))
-		return PTR_ERR(lm4857->regmap);
+	struct regmap *regmap;
 
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
-}
+	regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
 
 
-static int lm4857_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
+	return devm_snd_soc_register_component(&i2c->dev,
+		&lm4857_component_driver, NULL, 0);
 }
 }
 
 
 static const struct i2c_device_id lm4857_i2c_id[] = {
 static const struct i2c_device_id lm4857_i2c_id[] = {
@@ -200,7 +145,6 @@ static struct i2c_driver lm4857_i2c_driver = {
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe = lm4857_i2c_probe,
 	.probe = lm4857_i2c_probe,
-	.remove = lm4857_i2c_remove,
 	.id_table = lm4857_i2c_id,
 	.id_table = lm4857_i2c_id,
 };
 };
 
 

+ 1 - 3
sound/soc/codecs/lm49453.c

@@ -1271,7 +1271,7 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			regcache_sync(lm49453->regmap);
 			regcache_sync(lm49453->regmap);
 
 
 		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
 		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
@@ -1284,8 +1284,6 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 2
sound/soc/codecs/max98088.c

@@ -1571,7 +1571,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			regcache_sync(max98088->regmap);
 			regcache_sync(max98088->regmap);
 
 
 		snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
 		snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
@@ -1584,7 +1584,6 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
 		regcache_mark_dirty(max98088->regmap);
 		regcache_mark_dirty(max98088->regmap);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 21 - 13
sound/soc/codecs/max98090.c

@@ -1500,7 +1500,7 @@ static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
 static int max98090_add_widgets(struct snd_soc_codec *codec)
 static int max98090_add_widgets(struct snd_soc_codec *codec)
 {
 {
 	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
 
 	snd_soc_add_codec_controls(codec, max98090_snd_controls,
 	snd_soc_add_codec_controls(codec, max98090_snd_controls,
 		ARRAY_SIZE(max98090_snd_controls));
 		ARRAY_SIZE(max98090_snd_controls));
@@ -1798,16 +1798,17 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 		 * away from ON. Disable the clock in that case, otherwise
 		 * away from ON. Disable the clock in that case, otherwise
 		 * enable it.
 		 * enable it.
 		 */
 		 */
-		if (!IS_ERR(max98090->mclk)) {
-			if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-				clk_disable_unprepare(max98090->mclk);
-			else
-				clk_prepare_enable(max98090->mclk);
-		}
+		if (IS_ERR(max98090->mclk))
+			break;
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
+			clk_disable_unprepare(max98090->mclk);
+		else
+			clk_prepare_enable(max98090->mclk);
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(max98090->regmap);
 			ret = regcache_sync(max98090->regmap);
 			if (ret != 0) {
 			if (ret != 0) {
 				dev_err(codec->dev,
 				dev_err(codec->dev,
@@ -1824,7 +1825,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 		regcache_mark_dirty(max98090->regmap);
 		regcache_mark_dirty(max98090->regmap);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2187,7 +2187,6 @@ static void max98090_jack_work(struct work_struct *work)
 		struct max98090_priv,
 		struct max98090_priv,
 		jack_work.work);
 		jack_work.work);
 	struct snd_soc_codec *codec = max98090->codec;
 	struct snd_soc_codec *codec = max98090->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int status = 0;
 	int status = 0;
 	int reg;
 	int reg;
 
 
@@ -2266,8 +2265,6 @@ static void max98090_jack_work(struct work_struct *work)
 
 
 	snd_soc_jack_report(max98090->jack, status,
 	snd_soc_jack_report(max98090->jack, status,
 			    SND_JACK_HEADSET | SND_JACK_BTN_0);
 			    SND_JACK_HEADSET | SND_JACK_BTN_0);
-
-	snd_soc_dapm_sync(dapm);
 }
 }
 
 
 static irqreturn_t max98090_interrupt(int irq, void *data)
 static irqreturn_t max98090_interrupt(int irq, void *data)
@@ -2422,6 +2419,8 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	struct max98090_cdata *cdata;
 	struct max98090_cdata *cdata;
 	enum max98090_type devtype;
 	enum max98090_type devtype;
 	int ret = 0;
 	int ret = 0;
+	int err;
+	unsigned int micbias;
 
 
 	dev_dbg(codec->dev, "max98090_probe\n");
 	dev_dbg(codec->dev, "max98090_probe\n");
 
 
@@ -2506,8 +2505,17 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
 	snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
 		M98090_VCM_MODE_MASK);
 		M98090_VCM_MODE_MASK);
 
 
+	err = device_property_read_u32(codec->dev, "maxim,micbias", &micbias);
+	if (err) {
+		micbias = M98090_MBVSEL_2V8;
+		dev_info(codec->dev, "use default 2.8v micbias\n");
+	} else if (micbias < M98090_MBVSEL_2V2 || micbias > M98090_MBVSEL_2V8) {
+		dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
+		micbias = M98090_MBVSEL_2V8;
+	}
+
 	snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
 	snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
-		M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
+		M98090_MBVSEL_MASK, micbias);
 
 
 	max98090_add_widgets(codec);
 	max98090_add_widgets(codec);
 
 

+ 12 - 12
sound/soc/codecs/max98095.c

@@ -1650,16 +1650,17 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
 		 * away from ON. Disable the clock in that case, otherwise
 		 * away from ON. Disable the clock in that case, otherwise
 		 * enable it.
 		 * enable it.
 		 */
 		 */
-		if (!IS_ERR(max98095->mclk)) {
-			if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-				clk_disable_unprepare(max98095->mclk);
-			else
-				clk_prepare_enable(max98095->mclk);
-		}
+		if (IS_ERR(max98095->mclk))
+			break;
+
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
+			clk_disable_unprepare(max98095->mclk);
+		else
+			clk_prepare_enable(max98095->mclk);
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(max98095->regmap);
 			ret = regcache_sync(max98095->regmap);
 
 
 			if (ret != 0) {
 			if (ret != 0) {
@@ -1678,7 +1679,6 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
 		regcache_mark_dirty(max98095->regmap);
 		regcache_mark_dirty(max98095->regmap);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2198,7 +2198,7 @@ static int max98095_suspend(struct snd_soc_codec *codec)
 	if (max98095->headphone_jack || max98095->mic_jack)
 	if (max98095->headphone_jack || max98095->mic_jack)
 		max98095_jack_detect_disable(codec);
 		max98095_jack_detect_disable(codec);
 
 
-	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2208,7 +2208,7 @@ static int max98095_resume(struct snd_soc_codec *codec)
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct i2c_client *client = to_i2c_client(codec->dev);
 	struct i2c_client *client = to_i2c_client(codec->dev);
 
 
-	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 
 	if (max98095->headphone_jack || max98095->mic_jack) {
 	if (max98095->headphone_jack || max98095->mic_jack) {
 		max98095_jack_detect_enable(codec);
 		max98095_jack_detect_enable(codec);
@@ -2301,8 +2301,8 @@ static int max98095_probe(struct snd_soc_codec *codec)
 		/* register an audio interrupt */
 		/* register an audio interrupt */
 		ret = request_threaded_irq(client->irq, NULL,
 		ret = request_threaded_irq(client->irq, NULL,
 			max98095_report_jack,
 			max98095_report_jack,
-			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-			"max98095", codec);
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+			IRQF_ONESHOT, "max98095", codec);
 		if (ret) {
 		if (ret) {
 			dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
 			dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
 			goto err_access;
 			goto err_access;

+ 1 - 2
sound/soc/codecs/max98357a.c

@@ -60,13 +60,12 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec)
 {
 {
 	struct gpio_desc *sdmode;
 	struct gpio_desc *sdmode;
 
 
-	sdmode = devm_gpiod_get(codec->dev, "sdmode");
+	sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW);
 	if (IS_ERR(sdmode)) {
 	if (IS_ERR(sdmode)) {
 		dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
 		dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
 				__func__, PTR_ERR(sdmode));
 				__func__, PTR_ERR(sdmode));
 		return PTR_ERR(sdmode);
 		return PTR_ERR(sdmode);
 	}
 	}
-	gpiod_direction_output(sdmode, 0);
 	snd_soc_codec_set_drvdata(codec, sdmode);
 	snd_soc_codec_set_drvdata(codec, sdmode);
 
 
 	return 0;
 	return 0;

+ 1 - 2
sound/soc/codecs/max9850.c

@@ -252,7 +252,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(max9850->regmap);
 			ret = regcache_sync(max9850->regmap);
 			if (ret) {
 			if (ret) {
 				dev_err(codec->dev,
 				dev_err(codec->dev,
@@ -264,7 +264,6 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 2
sound/soc/codecs/ml26124.c

@@ -523,7 +523,7 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		/* VMID ON */
 		/* VMID ON */
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
 			snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
 					    ML26124_VMID, ML26124_VMID);
 					    ML26124_VMID, ML26124_VMID);
 			msleep(500);
 			msleep(500);
@@ -536,7 +536,6 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
 				    ML26124_VMID, 0);
 				    ML26124_VMID, 0);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 3 - 5
sound/soc/codecs/pcm512x.c

@@ -242,7 +242,7 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 
 
-	switch (codec->dapm.bias_level) {
+	switch (snd_soc_codec_get_bias_level(codec)) {
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		break;
 		break;
@@ -270,7 +270,7 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 
 
-	switch (codec->dapm.bias_level) {
+	switch (snd_soc_codec_get_bias_level(codec)) {
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		break;
 		break;
@@ -298,7 +298,7 @@ static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
 
 
-	switch (codec->dapm.bias_level) {
+	switch (snd_soc_codec_get_bias_level(codec)) {
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		break;
 		break;
@@ -641,8 +641,6 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 17 - 16
sound/soc/codecs/rt286.c

@@ -301,6 +301,7 @@ static int rt286_support_power_controls[] = {
 
 
 static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 {
 {
+	struct snd_soc_dapm_context *dapm;
 	unsigned int val, buf;
 	unsigned int val, buf;
 
 
 	*hp = false;
 	*hp = false;
@@ -308,6 +309,9 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 
 
 	if (!rt286->codec)
 	if (!rt286->codec)
 		return -EINVAL;
 		return -EINVAL;
+
+	dapm = snd_soc_codec_get_dapm(rt286->codec);
+
 	if (rt286->pdata.cbj_en) {
 	if (rt286->pdata.cbj_en) {
 		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
 		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
 		*hp = buf & 0x80000000;
 		*hp = buf & 0x80000000;
@@ -316,14 +320,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 			regmap_update_bits(rt286->regmap,
 			regmap_update_bits(rt286->regmap,
 				RT286_DC_GAIN, 0x200, 0x200);
 				RT286_DC_GAIN, 0x200, 0x200);
 
 
-			snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
-							"HV");
-			snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
-							"VREF");
+			snd_soc_dapm_force_enable_pin(dapm, "HV");
+			snd_soc_dapm_force_enable_pin(dapm, "VREF");
 			/* power LDO1 */
 			/* power LDO1 */
-			snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
-							"LDO1");
-			snd_soc_dapm_sync(&rt286->codec->dapm);
+			snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+			snd_soc_dapm_sync(dapm);
 
 
 			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
 			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
 			msleep(50);
 			msleep(50);
@@ -360,11 +361,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 		*mic = buf & 0x80000000;
 		*mic = buf & 0x80000000;
 	}
 	}
 
 
-	snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
-	snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
+	snd_soc_dapm_disable_pin(dapm, "HV");
+	snd_soc_dapm_disable_pin(dapm, "VREF");
 	if (!*hp)
 	if (!*hp)
-		snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
-	snd_soc_dapm_sync(&rt286->codec->dapm);
+		snd_soc_dapm_disable_pin(dapm, "LDO1");
+	snd_soc_dapm_sync(dapm);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -391,6 +392,7 @@ static void rt286_jack_detect_work(struct work_struct *work)
 
 
 int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 
 
 	rt286->jack = jack;
 	rt286->jack = jack;
@@ -398,7 +400,7 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 	if (jack) {
 	if (jack) {
 		/* enable IRQ */
 		/* enable IRQ */
 		if (rt286->jack->status & SND_JACK_HEADPHONE)
 		if (rt286->jack->status & SND_JACK_HEADPHONE)
-			snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
+			snd_soc_dapm_force_enable_pin(dapm, "LDO1");
 		regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
 		regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
 		/* Send an initial empty report */
 		/* Send an initial empty report */
 		snd_soc_jack_report(rt286->jack, rt286->jack->status,
 		snd_soc_jack_report(rt286->jack, rt286->jack->status,
@@ -406,9 +408,9 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 	} else {
 	} else {
 		/* disable IRQ */
 		/* disable IRQ */
 		regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
 		regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
-		snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
+		snd_soc_dapm_disable_pin(dapm, "LDO1");
 	}
 	}
-	snd_soc_dapm_sync(&codec->dapm);
+	snd_soc_dapm_sync(dapm);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -985,7 +987,7 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
 {
 {
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
 			snd_soc_write(codec,
 			snd_soc_write(codec,
 				RT286_SET_AUDIO_POWER, AC_PWRST_D0);
 				RT286_SET_AUDIO_POWER, AC_PWRST_D0);
 			snd_soc_update_bits(codec,
 			snd_soc_update_bits(codec,
@@ -1012,7 +1014,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }

+ 2 - 3
sound/soc/codecs/rt5631.c

@@ -1546,7 +1546,7 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
 			snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
 				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
 				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
 				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
 				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
@@ -1569,7 +1569,6 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1615,7 +1614,7 @@ static int rt5631_probe(struct snd_soc_codec *codec)
 			RT5631_DMIC_R_CH_LATCH_RISING);
 			RT5631_DMIC_R_CH_LATCH_RISING);
 	}
 	}
 
 
-	codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+	snd_soc_codec_init_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 
 	return 0;
 	return 0;
 }
 }

+ 8 - 8
sound/soc/codecs/rt5640.c

@@ -1870,7 +1870,7 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 {
 {
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+		if (SND_SOC_BIAS_OFF == snd_soc_codec_get_bias_level(codec)) {
 			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
 			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
 				RT5640_PWR_VREF1 | RT5640_PWR_MB |
 				RT5640_PWR_VREF1 | RT5640_PWR_MB |
 				RT5640_PWR_BG | RT5640_PWR_VREF2,
 				RT5640_PWR_BG | RT5640_PWR_VREF2,
@@ -1902,7 +1902,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1935,11 +1934,12 @@ EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
 
 
 static int rt5640_probe(struct snd_soc_codec *codec)
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
 
 	rt5640->codec = codec;
 	rt5640->codec = codec;
 
 
-	rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 
 	snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
 	snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
 	snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
 	snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
@@ -1951,18 +1951,18 @@ static int rt5640_probe(struct snd_soc_codec *codec)
 		snd_soc_add_codec_controls(codec,
 		snd_soc_add_codec_controls(codec,
 			rt5640_specific_snd_controls,
 			rt5640_specific_snd_controls,
 			ARRAY_SIZE(rt5640_specific_snd_controls));
 			ARRAY_SIZE(rt5640_specific_snd_controls));
-		snd_soc_dapm_new_controls(&codec->dapm,
+		snd_soc_dapm_new_controls(dapm,
 			rt5640_specific_dapm_widgets,
 			rt5640_specific_dapm_widgets,
 			ARRAY_SIZE(rt5640_specific_dapm_widgets));
 			ARRAY_SIZE(rt5640_specific_dapm_widgets));
-		snd_soc_dapm_add_routes(&codec->dapm,
+		snd_soc_dapm_add_routes(dapm,
 			rt5640_specific_dapm_routes,
 			rt5640_specific_dapm_routes,
 			ARRAY_SIZE(rt5640_specific_dapm_routes));
 			ARRAY_SIZE(rt5640_specific_dapm_routes));
 		break;
 		break;
 	case RT5640_ID_5639:
 	case RT5640_ID_5639:
-		snd_soc_dapm_new_controls(&codec->dapm,
+		snd_soc_dapm_new_controls(dapm,
 			rt5639_specific_dapm_widgets,
 			rt5639_specific_dapm_widgets,
 			ARRAY_SIZE(rt5639_specific_dapm_widgets));
 			ARRAY_SIZE(rt5639_specific_dapm_widgets));
-		snd_soc_dapm_add_routes(&codec->dapm,
+		snd_soc_dapm_add_routes(dapm,
 			rt5639_specific_dapm_routes,
 			rt5639_specific_dapm_routes,
 			ARRAY_SIZE(rt5639_specific_dapm_routes));
 			ARRAY_SIZE(rt5639_specific_dapm_routes));
 		break;
 		break;
@@ -1991,7 +1991,7 @@ static int rt5640_suspend(struct snd_soc_codec *codec)
 {
 {
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
 
-	rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 	rt5640_reset(codec);
 	rt5640_reset(codec);
 	regcache_cache_only(rt5640->regmap, true);
 	regcache_cache_only(rt5640->regmap, true);
 	regcache_mark_dirty(rt5640->regmap);
 	regcache_mark_dirty(rt5640->regmap);

+ 830 - 251
sound/soc/codecs/rt5645.c

@@ -18,7 +18,9 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/acpi.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/pcm_params.h>
@@ -415,9 +417,9 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
 }
 }
 
 
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
@@ -432,30 +434,6 @@ static unsigned int bst_tlv[] = {
 	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
 	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
 };
 };
 
 
-static const char * const rt5645_tdm_data_swap_select[] = {
-	"L/R", "R/L", "L/L", "R/R"
-};
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
-	RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
-	RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
-	RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum,
-	RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select);
-
-static const char * const rt5645_tdm_adc_data_select[] = {
-	"1/2/R", "2/1/R", "R/1/2", "R/2/1"
-};
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum,
-				RT5645_TDM_CTRL_1, 8,
-				rt5645_tdm_adc_data_select);
-
 static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 	/* Speaker Output Volume */
 	/* Speaker Output Volume */
 	SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
 	SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
@@ -481,9 +459,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 	SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL,
 	SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL,
 		RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1),
 		RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1),
 	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL,
 	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL,
-		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
 	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL,
 	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL,
-		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
 
 
 	/* IN1/IN2 Control */
 	/* IN1/IN2 Control */
 	SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
 	SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
@@ -499,11 +477,11 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 	SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL,
 	SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL,
 		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
 		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
 	SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL,
-		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
 	SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL,
 	SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL,
 		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
 		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
 	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL,
-		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
 
 
 	/* ADC Boost Volume Control */
 	/* ADC Boost Volume Control */
 	SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1,
 	SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1,
@@ -516,17 +494,6 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 	/* I2S2 function select */
 	/* I2S2 function select */
 	SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
 	SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
 		1, 1),
 		1, 1),
-
-	/* TDM */
-	SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum),
-	SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum),
-	SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum),
-	SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum),
-	SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum),
-	SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0),
-	SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0),
-	SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0),
-	SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0),
 };
 };
 
 
 /**
 /**
@@ -1093,7 +1060,8 @@ static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux =
 
 
 /* MX-77 [9:8] */
 /* MX-77 [9:8] */
 static const char * const rt5645_if1_adc_in_src[] = {
 static const char * const rt5645_if1_adc_in_src[] = {
-	"IF_ADC1", "IF_ADC2", "VAD_ADC"
+	"IF_ADC1/IF_ADC2/VAD_ADC", "IF_ADC2/IF_ADC1/VAD_ADC",
+	"VAD_ADC/IF_ADC1/IF_ADC2", "VAD_ADC/IF_ADC2/IF_ADC1"
 };
 };
 
 
 static SOC_ENUM_SINGLE_DECL(
 static SOC_ENUM_SINGLE_DECL(
@@ -1103,6 +1071,140 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
 	SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 	SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 
 
+/* MX-78 [4:0] */
+static const char * const rt5650_if1_adc_in_src[] = {
+	"IF_ADC1/IF_ADC2/DAC_REF/Null",
+	"IF_ADC1/IF_ADC2/Null/DAC_REF",
+	"IF_ADC1/DAC_REF/IF_ADC2/Null",
+	"IF_ADC1/DAC_REF/Null/IF_ADC2",
+	"IF_ADC1/Null/DAC_REF/IF_ADC2",
+	"IF_ADC1/Null/IF_ADC2/DAC_REF",
+
+	"IF_ADC2/IF_ADC1/DAC_REF/Null",
+	"IF_ADC2/IF_ADC1/Null/DAC_REF",
+	"IF_ADC2/DAC_REF/IF_ADC1/Null",
+	"IF_ADC2/DAC_REF/Null/IF_ADC1",
+	"IF_ADC2/Null/DAC_REF/IF_ADC1",
+	"IF_ADC2/Null/IF_ADC1/DAC_REF",
+
+	"DAC_REF/IF_ADC1/IF_ADC2/Null",
+	"DAC_REF/IF_ADC1/Null/IF_ADC2",
+	"DAC_REF/IF_ADC2/IF_ADC1/Null",
+	"DAC_REF/IF_ADC2/Null/IF_ADC1",
+	"DAC_REF/Null/IF_ADC1/IF_ADC2",
+	"DAC_REF/Null/IF_ADC2/IF_ADC1",
+
+	"Null/IF_ADC1/IF_ADC2/DAC_REF",
+	"Null/IF_ADC1/DAC_REF/IF_ADC2",
+	"Null/IF_ADC2/IF_ADC1/DAC_REF",
+	"Null/IF_ADC2/DAC_REF/IF_ADC1",
+	"Null/DAC_REF/IF_ADC1/IF_ADC2",
+	"Null/DAC_REF/IF_ADC2/IF_ADC1",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_if1_adc_in_enum, RT5645_TDM_CTRL_2,
+	0, rt5650_if1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5650_if1_adc_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC IN source", rt5650_if1_adc_in_enum);
+
+/* MX-78 [15:14][13:12][11:10] */
+static const char * const rt5645_tdm_adc_swap_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot0_1_enum,
+	RT5645_TDM_CTRL_2, 14, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc1_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5650_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot2_3_enum,
+	RT5645_TDM_CTRL_2, 12, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc2_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5650_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot4_5_enum,
+	RT5645_TDM_CTRL_2, 10, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc3_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5650_tdm_adc_slot4_5_enum);
+
+/* MX-77 [7:6][5:4][3:2] */
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
+	RT5645_TDM_CTRL_1, 6, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc1_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5645_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
+	RT5645_TDM_CTRL_1, 4, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc2_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5645_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
+	RT5645_TDM_CTRL_1, 2, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc3_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5645_tdm_adc_slot4_5_enum);
+
+/* MX-79 [14:12][10:8][6:4][2:0] */
+static const char * const rt5645_tdm_dac_swap_select[] = {
+	"Slot0", "Slot1", "Slot2", "Slot3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac0_enum,
+	RT5645_TDM_CTRL_3, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC0 source", rt5645_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac1_enum,
+	RT5645_TDM_CTRL_3, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC1 source", rt5645_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac2_enum,
+	RT5645_TDM_CTRL_3, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC2 source", rt5645_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac3_enum,
+	RT5645_TDM_CTRL_3, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC3 source", rt5645_tdm_dac3_enum);
+
+/* MX-7a [14:12][10:8][6:4][2:0] */
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac0_enum,
+	RT5650_TDM_CTRL_4, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC0 source", rt5650_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac1_enum,
+	RT5650_TDM_CTRL_4, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC1 source", rt5650_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac2_enum,
+	RT5650_TDM_CTRL_4, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC2 source", rt5650_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac3_enum,
+	RT5650_TDM_CTRL_4, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC3 source", rt5650_tdm_dac3_enum);
+
 /* MX-2d [3] [2] */
 /* MX-2d [3] [2] */
 static const char * const rt5650_a_dac1_src[] = {
 static const char * const rt5650_a_dac1_src[] = {
 	"DAC1", "Stereo DAC Mixer"
 	"DAC1", "Stereo DAC Mixer"
@@ -1227,52 +1329,79 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 
 
 	if (on) {
 	if (on) {
 		if (hp_amp_power_count <= 0) {
 		if (hp_amp_power_count <= 0) {
-			/* depop parameters */
-			snd_soc_update_bits(codec, RT5645_DEPOP_M2,
-				RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
-			snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
-			regmap_write(rt5645->regmap, RT5645_PR_BASE +
-				RT5645_HP_DCC_INT1, 0x9f01);
-			mdelay(150);
-			/* headphone amp power on */
-			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-				RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0);
-			snd_soc_update_bits(codec, RT5645_PWR_VOL,
-				RT5645_PWR_HV_L | RT5645_PWR_HV_R,
-				RT5645_PWR_HV_L | RT5645_PWR_HV_R);
-			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-				RT5645_PWR_HP_L | RT5645_PWR_HP_R |
-				RT5645_PWR_HA,
-				RT5645_PWR_HP_L | RT5645_PWR_HP_R |
-				RT5645_PWR_HA);
-			mdelay(5);
-			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-				RT5645_PWR_FV1 | RT5645_PWR_FV2,
-				RT5645_PWR_FV1 | RT5645_PWR_FV2);
-
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-				RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
-				RT5645_HP_CO_EN | RT5645_HP_SG_EN);
-			regmap_write(rt5645->regmap, RT5645_PR_BASE +
-				0x14, 0x1aaa);
-			regmap_write(rt5645->regmap, RT5645_PR_BASE +
-				0x24, 0x0430);
+			if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+				snd_soc_write(codec, RT5645_CHARGE_PUMP,
+					0x0e06);
+				snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x3e, 0x7400);
+				snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_MAMP_INT_REG2, 0xfc00);
+				snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+			} else {
+				/* depop parameters */
+				snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+					RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
+				snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_HP_DCC_INT1, 0x9f01);
+				mdelay(150);
+				/* headphone amp power on */
+				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+					RT5645_PWR_FV1 | RT5645_PWR_FV2, 0);
+				snd_soc_update_bits(codec, RT5645_PWR_VOL,
+					RT5645_PWR_HV_L | RT5645_PWR_HV_R,
+					RT5645_PWR_HV_L | RT5645_PWR_HV_R);
+				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+					RT5645_PWR_HA,
+					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+					RT5645_PWR_HA);
+				mdelay(5);
+				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+					RT5645_PWR_FV1 | RT5645_PWR_FV2,
+					RT5645_PWR_FV1 | RT5645_PWR_FV2);
+
+				snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+					RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
+					RT5645_HP_CO_EN | RT5645_HP_SG_EN);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x14, 0x1aaa);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x24, 0x0430);
+			}
 		}
 		}
 		hp_amp_power_count++;
 		hp_amp_power_count++;
 	} else {
 	} else {
 		hp_amp_power_count--;
 		hp_amp_power_count--;
 		if (hp_amp_power_count <= 0) {
 		if (hp_amp_power_count <= 0) {
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-				RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
-				RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
-				RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
-			/* headphone amp power down */
-			snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
-			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
-				RT5645_PWR_HP_L | RT5645_PWR_HP_R |
-				RT5645_PWR_HA, 0);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M2,
-				RT5645_DEPOP_MASK, 0);
+			if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x3e, 0x7400);
+				snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_MAMP_INT_REG2, 0xfc00);
+				snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+				msleep(100);
+				snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001);
+
+			} else {
+				snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+					RT5645_HP_SG_MASK |
+					RT5645_HP_L_SMT_MASK |
+					RT5645_HP_R_SMT_MASK,
+					RT5645_HP_SG_DIS |
+					RT5645_HP_L_SMT_DIS |
+					RT5645_HP_R_SMT_DIS);
+				/* headphone amp power down */
+				snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
+				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+					RT5645_PWR_HA, 0);
+				snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+					RT5645_DEPOP_MASK, 0);
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -1287,56 +1416,52 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMU:
 		hp_amp_power(codec, 1);
 		hp_amp_power(codec, 1);
 		/* headphone unmute sequence */
 		/* headphone unmute sequence */
-		if (rt5645->codec_type == CODEC_TYPE_RT5650) {
-			snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
-		} else {
+		if (rt5645->codec_type == CODEC_TYPE_RT5645) {
 			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
 			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
 				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
 				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
 				RT5645_CP_FQ3_MASK,
 				RT5645_CP_FQ3_MASK,
 				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
 				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
 				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
 				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
 				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
 				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+			regmap_write(rt5645->regmap, RT5645_PR_BASE +
+				RT5645_MAMP_INT_REG2, 0xfc00);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_RSTN_MASK, RT5645_RSTN_EN);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
+				RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
+				RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+			msleep(40);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
+				RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
+				RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
 		}
 		}
-		regmap_write(rt5645->regmap,
-			RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_RSTN_MASK, RT5645_RSTN_EN);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
-			RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
-			RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
-		msleep(40);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
-			RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
-			RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
 		break;
 		break;
 
 
 	case SND_SOC_DAPM_PRE_PMD:
 	case SND_SOC_DAPM_PRE_PMD:
 		/* headphone mute sequence */
 		/* headphone mute sequence */
-		if (rt5645->codec_type == CODEC_TYPE_RT5650) {
-			snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
-		} else {
+		if (rt5645->codec_type == CODEC_TYPE_RT5645) {
 			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
 			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
 				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
 				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
 				RT5645_CP_FQ3_MASK,
 				RT5645_CP_FQ3_MASK,
 				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
 				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
 				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
 				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
 				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
 				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+			regmap_write(rt5645->regmap, RT5645_PR_BASE +
+				RT5645_MAMP_INT_REG2, 0xfc00);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_RSTP_MASK, RT5645_RSTP_EN);
+			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
+				RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
+				RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+			msleep(30);
 		}
 		}
-		regmap_write(rt5645->regmap,
-			RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_RSTP_MASK, RT5645_RSTP_EN);
-		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
-			RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
-			RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
-			RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
-		msleep(30);
 		hp_amp_power(codec, 0);
 		hp_amp_power(codec, 0);
 		break;
 		break;
 
 
@@ -1571,20 +1696,50 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 
 	/* IF1 2 Mux */
 	/* IF1 2 Mux */
-	SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM,
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc1_in_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc2_in_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc3_in_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM,
 		0, 0, &rt5645_if1_adc_in_mux),
 		0, 0, &rt5645_if1_adc_in_mux),
+
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc1_in_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc2_in_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc3_in_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc_in_mux),
+
 	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
 	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
 		0, 0, &rt5645_if2_adc_in_mux),
 		0, 0, &rt5645_if2_adc_in_mux),
 
 
 	/* Digital Interface */
 	/* Digital Interface */
 	SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1,
 	SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1,
 		RT5645_PWR_I2S1_BIT, 0, NULL, 0),
 		RT5645_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac3_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac3_tdm_sel_mux),
 	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1848,42 +2003,32 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 	{ "IF_ADC2", NULL, "Mono ADC MIXR" },
 	{ "IF_ADC2", NULL, "Mono ADC MIXR" },
 	{ "VAD_ADC", NULL, "VAD ADC Mux" },
 	{ "VAD_ADC", NULL, "VAD ADC Mux" },
 
 
-	{ "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" },
-	{ "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" },
-	{ "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" },
-
 	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
 	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
 	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
 	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
 	{ "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
 	{ "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
 
 
 	{ "IF1 ADC", NULL, "I2S1" },
 	{ "IF1 ADC", NULL, "I2S1" },
-	{ "IF1 ADC", NULL, "IF1 ADC Mux" },
 	{ "IF2 ADC", NULL, "I2S2" },
 	{ "IF2 ADC", NULL, "I2S2" },
 	{ "IF2 ADC", NULL, "IF2 ADC Mux" },
 	{ "IF2 ADC", NULL, "IF2 ADC Mux" },
 
 
-	{ "AIF1TX", NULL, "IF1 ADC" },
-	{ "AIF1TX", NULL, "IF2 ADC" },
 	{ "AIF2TX", NULL, "IF2 ADC" },
 	{ "AIF2TX", NULL, "IF2 ADC" },
 
 
+	{ "IF1 DAC0", NULL, "AIF1RX" },
 	{ "IF1 DAC1", NULL, "AIF1RX" },
 	{ "IF1 DAC1", NULL, "AIF1RX" },
 	{ "IF1 DAC2", NULL, "AIF1RX" },
 	{ "IF1 DAC2", NULL, "AIF1RX" },
+	{ "IF1 DAC3", NULL, "AIF1RX" },
 	{ "IF2 DAC", NULL, "AIF2RX" },
 	{ "IF2 DAC", NULL, "AIF2RX" },
 
 
+	{ "IF1 DAC0", NULL, "I2S1" },
 	{ "IF1 DAC1", NULL, "I2S1" },
 	{ "IF1 DAC1", NULL, "I2S1" },
 	{ "IF1 DAC2", NULL, "I2S1" },
 	{ "IF1 DAC2", NULL, "I2S1" },
+	{ "IF1 DAC3", NULL, "I2S1" },
 	{ "IF2 DAC", NULL, "I2S2" },
 	{ "IF2 DAC", NULL, "I2S2" },
 
 
-	{ "IF1 DAC2 L", NULL, "IF1 DAC2" },
-	{ "IF1 DAC2 R", NULL, "IF1 DAC2" },
-	{ "IF1 DAC1 L", NULL, "IF1 DAC1" },
-	{ "IF1 DAC1 R", NULL, "IF1 DAC1" },
 	{ "IF2 DAC L", NULL, "IF2 DAC" },
 	{ "IF2 DAC L", NULL, "IF2 DAC" },
 	{ "IF2 DAC R", NULL, "IF2 DAC" },
 	{ "IF2 DAC R", NULL, "IF2 DAC" },
 
 
-	{ "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" },
 	{ "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
 	{ "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
-
-	{ "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" },
 	{ "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
 	{ "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
 
 
 	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
 	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
@@ -1893,14 +2038,12 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
 	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
 	{ "DAC1 MIXR", NULL, "dac stereo1 filter" },
 	{ "DAC1 MIXR", NULL, "dac stereo1 filter" },
 
 
-	{ "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" },
 	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
 	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
 	{ "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" },
 	{ "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" },
 	{ "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
 	{ "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
 	{ "DAC L2 Volume", NULL, "DAC L2 Mux" },
 	{ "DAC L2 Volume", NULL, "DAC L2 Mux" },
 	{ "DAC L2 Volume", NULL, "dac mono left filter" },
 	{ "DAC L2 Volume", NULL, "dac mono left filter" },
 
 
-	{ "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" },
 	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
 	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
 	{ "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" },
 	{ "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" },
 	{ "DAC R2 Mux", "Haptic", "Haptic Generator" },
 	{ "DAC R2 Mux", "Haptic", "Haptic Generator" },
@@ -2038,6 +2181,80 @@ static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
 	{ "DAC R1", NULL, "A DAC1 R Mux" },
 	{ "DAC R1", NULL, "A DAC1 R Mux" },
 	{ "DAC L2", NULL, "A DAC2 L Mux" },
 	{ "DAC L2", NULL, "A DAC2 L Mux" },
 	{ "DAC R2", NULL, "A DAC2 R Mux" },
 	{ "DAC R2", NULL, "A DAC2 R Mux" },
+
+	{ "RT5650 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+	{ "RT5650 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+	{ "RT5650 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+	{ "RT5650 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+	{ "RT5650 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+	{ "RT5650 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+	{ "RT5650 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+	{ "RT5650 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+	{ "RT5650 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+	{ "RT5650 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+	{ "RT5650 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+	{ "RT5650 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+	{ "IF1 ADC", NULL, "RT5650 IF1 ADC1 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5650 IF1 ADC2 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5650 IF1 ADC3 Swap Mux" },
+
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/DAC_REF/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/Null/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/IF_ADC2/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/Null/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/Null/DAC_REF/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/Null/IF_ADC2/DAC_REF", "IF1 ADC" },
+
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/DAC_REF/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/Null/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/IF_ADC1/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/Null/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/Null/DAC_REF/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/Null/IF_ADC1/DAC_REF", "IF1 ADC" },
+
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/IF_ADC2/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/Null/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/IF_ADC1/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/Null/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC1/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC2/IF_ADC1", "IF1 ADC" },
+
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC1/IF_ADC2/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC1/DAC_REF/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC2/IF_ADC1/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC2/DAC_REF/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC1/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC2/IF_ADC1", "IF1 ADC" },
+	{ "AIF1TX", NULL, "RT5650 IF1 ADC Mux" },
+
+	{ "RT5650 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5650 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5650 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5650 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "DAC1 L Mux", "IF1 DAC", "RT5650 IF1 DAC1 L Mux" },
+	{ "DAC1 R Mux", "IF1 DAC", "RT5650 IF1 DAC1 R Mux" },
+
+	{ "DAC L2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 L Mux" },
+	{ "DAC R2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 R Mux" },
 };
 };
 
 
 static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
 static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
@@ -2045,6 +2262,57 @@ static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
 	{ "DAC R1", NULL, "Stereo DAC MIXR" },
 	{ "DAC R1", NULL, "Stereo DAC MIXR" },
 	{ "DAC L2", NULL, "Mono DAC MIXL" },
 	{ "DAC L2", NULL, "Mono DAC MIXL" },
 	{ "DAC R2", NULL, "Mono DAC MIXR" },
 	{ "DAC R2", NULL, "Mono DAC MIXR" },
+
+	{ "RT5645 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+	{ "RT5645 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+	{ "RT5645 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+	{ "RT5645 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+	{ "RT5645 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+	{ "RT5645 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+	{ "RT5645 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+	{ "RT5645 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+	{ "RT5645 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+	{ "RT5645 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+	{ "RT5645 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+	{ "RT5645 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+	{ "IF1 ADC", NULL, "RT5645 IF1 ADC1 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5645 IF1 ADC2 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5645 IF1 ADC3 Swap Mux" },
+
+	{ "RT5645 IF1 ADC Mux", "IF_ADC1/IF_ADC2/VAD_ADC", "IF1 ADC" },
+	{ "RT5645 IF1 ADC Mux", "IF_ADC2/IF_ADC1/VAD_ADC", "IF1 ADC" },
+	{ "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC1/IF_ADC2", "IF1 ADC" },
+	{ "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC2/IF_ADC1", "IF1 ADC" },
+	{ "AIF1TX", NULL, "RT5645 IF1 ADC Mux" },
+
+	{ "RT5645 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5645 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5645 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5645 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "DAC1 L Mux", "IF1 DAC", "RT5645 IF1 DAC1 L Mux" },
+	{ "DAC1 R Mux", "IF1 DAC", "RT5645 IF1 DAC1 R Mux" },
+
+	{ "DAC L2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 L Mux" },
+	{ "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" },
 };
 };
 
 
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
@@ -2102,9 +2370,8 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
 
 
 	switch (dai->id) {
 	switch (dai->id) {
 	case RT5645_AIF1:
 	case RT5645_AIF1:
-		mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK;
-		val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT |
-			pre_div << RT5645_I2S_PD1_SFT;
+		mask_clk = RT5645_I2S_PD1_MASK;
+		val_clk = pre_div << RT5645_I2S_PD1_SFT;
 		snd_soc_update_bits(codec, RT5645_I2S1_SDP,
 		snd_soc_update_bits(codec, RT5645_I2S1_SDP,
 			(0x3 << dl_sft), (val_len << dl_sft));
 			(0x3 << dl_sft), (val_len << dl_sft));
 		snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
 		snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
@@ -2369,6 +2636,8 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 			enum snd_soc_bias_level level)
 {
 {
+	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
 		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
@@ -2399,8 +2668,9 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 
 
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 		snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
 		snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
-				RT5645_DIG_GATE_CTRL, 0);
+		if (!rt5645->en_button_func)
+			snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+					RT5645_DIG_GATE_CTRL, 0);
 		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
 		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_BG | RT5645_PWR_VREF2 |
 				RT5645_PWR_BG | RT5645_PWR_VREF2 |
@@ -2410,72 +2680,222 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int rt5645_jack_detect(struct snd_soc_codec *codec)
+static int rt5650_calibration(struct rt5645_priv *rt5645)
 {
 {
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
-	int gpio_state, jack_type = 0;
-	unsigned int val;
+	int val, i;
+	int ret = -1;
 
 
-	if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
-		dev_err(codec->dev, "invalid gpio\n");
-		return -EINVAL;
+	regcache_cache_bypass(rt5645->regmap, true);
+	regmap_write(rt5645->regmap, RT5645_RESET, 0);
+	regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800);
+	regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC,
+		0x3600);
+	regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000);
+	regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008);
+	/* headset type */
+	regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061);
+	regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
+	regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012);
+	regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002);
+	regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020);
+	regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+	regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
+	regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827);
+	regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827);
+	msleep(400);
+	/* Inline command */
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001);
+	regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
+	regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
+	/* Calbration */
+	regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000);
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
+	regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
+	regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
+	regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800);
+	regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa);
+	regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04);
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100);
+	regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+	regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13);
+	regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820);
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d);
+	/* Power on and Calbration */
+	regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1,
+		0x9f01);
+	msleep(200);
+	for (i = 0; i < 5; i++) {
+		regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val);
+		if (val != 0 && val != 0x3f3f) {
+			ret = 0;
+			break;
+		}
+		msleep(50);
 	}
 	}
-	gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+	pr_debug("%s: PR-7A = 0x%x\n", __func__, val);
+
+	/* mute */
+	regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400);
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737);
+	regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2,
+		0xfc00);
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140);
+	regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
+	regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020);
+	regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006);
+	regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000);
+	msleep(350);
+
+	regcache_cache_bypass(rt5645->regmap, false);
+
+	return ret;
+}
 
 
-	dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
-		gpio_state);
+static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
+	bool enable)
+{
+	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
 
-	if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
-		(!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) {
-		snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1");
-		snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2");
-		snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
-		snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power");
-		snd_soc_dapm_sync(&codec->dapm);
+	if (enable) {
+		snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+							"ADC L power");
+		snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+							"ADC R power");
+		snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+							"LDO2");
+		snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+							"Mic Det Power");
+		snd_soc_dapm_sync_unlocked(&codec->dapm);
+		snd_soc_update_bits(codec,
+					RT5645_INT_IRQ_ST, 0x8, 0x8);
+		snd_soc_update_bits(codec,
+					RT5650_4BTN_IL_CMD2, 0x8000, 0x8000);
+		snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+		pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
+			snd_soc_read(codec, RT5650_4BTN_IL_CMD1));
+	} else {
+		snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
+		snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0);
+		snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+							"ADC L power");
+		snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+							"ADC R power");
+		if (rt5645->pdata.jd_mode == 0)
+			snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+								"LDO2");
+		snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+							"Mic Det Power");
+		snd_soc_dapm_sync_unlocked(&codec->dapm);
+	}
+}
 
 
-		snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
-		snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
+static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val;
 
 
-		snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
-			RT5645_CBJ_MN_JD, 0);
-		snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
-			RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+	if (jack_insert) {
+		regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
+
+		if (codec->component.card->instantiated) {
+			/* for jack type detect */
+			snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+			snd_soc_dapm_force_enable_pin(&codec->dapm,
+				"Mic Det Power");
+			snd_soc_dapm_sync(&codec->dapm);
+		} else {
+			/* Power up necessary bits for JD if dapm is
+			   not ready yet */
+			regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1,
+				RT5645_PWR_MB | RT5645_PWR_VREF2,
+				RT5645_PWR_MB | RT5645_PWR_VREF2);
+			regmap_update_bits(rt5645->regmap, RT5645_PWR_MIXER,
+				RT5645_PWR_LDO2, RT5645_PWR_LDO2);
+			regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL,
+				RT5645_PWR_MIC_DET, RT5645_PWR_MIC_DET);
+		}
 
 
-		msleep(400);
-		val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
+		regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+		regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
+		regmap_update_bits(rt5645->regmap,
+				   RT5645_IN1_CTRL2, 0x1000, 0x1000);
+		msleep(100);
+		regmap_update_bits(rt5645->regmap,
+				   RT5645_IN1_CTRL2, 0x1000, 0x0000);
+
+		msleep(450);
+		regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
+		val &= 0x7;
 		dev_dbg(codec->dev, "val = %d\n", val);
 		dev_dbg(codec->dev, "val = %d\n", val);
 
 
-		if (val == 1 || val == 2)
-			jack_type = SND_JACK_HEADSET;
-		else
-			jack_type = SND_JACK_HEADPHONE;
+		if (val == 1 || val == 2) {
+			rt5645->jack_type = SND_JACK_HEADSET;
+			if (rt5645->en_button_func) {
+				rt5645_enable_push_button_irq(codec, true);
+			}
+		} else {
+			if (codec->component.card->instantiated) {
+				snd_soc_dapm_disable_pin(&codec->dapm,
+					"Mic Det Power");
+				snd_soc_dapm_sync(&codec->dapm);
+			} else
+				regmap_update_bits(rt5645->regmap,
+					RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+			rt5645->jack_type = SND_JACK_HEADPHONE;
+		}
 
 
-		snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
-		snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
-		if (rt5645->pdata.jd_mode == 0)
-			snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
-		snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
-		snd_soc_dapm_sync(&codec->dapm);
+	} else { /* jack out */
+		rt5645->jack_type = 0;
+		if (rt5645->en_button_func)
+			rt5645_enable_push_button_irq(codec, false);
+		else {
+			if (codec->component.card->instantiated) {
+				if (rt5645->pdata.jd_mode == 0)
+					snd_soc_dapm_disable_pin(&codec->dapm,
+						"LDO2");
+				snd_soc_dapm_disable_pin(&codec->dapm,
+					"Mic Det Power");
+				snd_soc_dapm_sync(&codec->dapm);
+			} else {
+				if (rt5645->pdata.jd_mode == 0)
+					regmap_update_bits(rt5645->regmap,
+						RT5645_PWR_MIXER,
+						RT5645_PWR_LDO2, 0);
+				regmap_update_bits(rt5645->regmap,
+					RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+			}
+		}
 	}
 	}
 
 
-	snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
-	snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
-	return 0;
+	return rt5645->jack_type;
 }
 }
 
 
+static int rt5645_irq_detection(struct rt5645_priv *rt5645);
+static irqreturn_t rt5645_irq(int irq, void *data);
+
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+	struct snd_soc_jack *btn_jack)
 {
 {
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
 
 	rt5645->hp_jack = hp_jack;
 	rt5645->hp_jack = hp_jack;
 	rt5645->mic_jack = mic_jack;
 	rt5645->mic_jack = mic_jack;
-	rt5645_jack_detect(codec);
+	rt5645->btn_jack = btn_jack;
+	if (rt5645->btn_jack && rt5645->codec_type == CODEC_TYPE_RT5650) {
+		rt5645->en_button_func = true;
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+				RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+		regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1,
+				RT5645_HP_CB_MASK, RT5645_HP_CB_PU);
+		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1,
+				RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+	}
+	rt5645_irq(0, rt5645);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2486,7 +2906,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
 	struct rt5645_priv *rt5645 =
 	struct rt5645_priv *rt5645 =
 		container_of(work, struct rt5645_priv, jack_detect_work.work);
 		container_of(work, struct rt5645_priv, jack_detect_work.work);
 
 
-	rt5645_jack_detect(rt5645->codec);
+	rt5645_irq_detection(rt5645);
 }
 }
 
 
 static irqreturn_t rt5645_irq(int irq, void *data)
 static irqreturn_t rt5645_irq(int irq, void *data)
@@ -2499,6 +2919,126 @@ static irqreturn_t rt5645_irq(int irq, void *data)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
+static int rt5645_button_detect(struct snd_soc_codec *codec)
+{
+	int btn_type, val;
+
+	val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+	pr_debug("val=0x%x\n", val);
+	btn_type = val & 0xfff0;
+	snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val);
+
+	return btn_type;
+}
+
+static int rt5645_irq_detection(struct rt5645_priv *rt5645)
+{
+	int val, btn_type, gpio_state = 0, report = 0;
+
+	switch (rt5645->pdata.jd_mode) {
+	case 0: /* Not using rt5645 JD */
+		if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
+			gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+			dev_dbg(rt5645->codec->dev, "gpio = %d(%d)\n",
+				rt5645->pdata.hp_det_gpio, gpio_state);
+		}
+		if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
+			(!rt5645->pdata.gpio_hp_det_active_high &&
+			 !gpio_state)) {
+			report = rt5645_jack_detect(rt5645->codec, 1);
+		} else {
+			report = rt5645_jack_detect(rt5645->codec, 0);
+		}
+		snd_soc_jack_report(rt5645->hp_jack,
+				    report, SND_JACK_HEADPHONE);
+		snd_soc_jack_report(rt5645->mic_jack,
+				    report, SND_JACK_MICROPHONE);
+		return report;
+	case 1: /* 2 port */
+		val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070;
+		break;
+	default: /* 1 port */
+		val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020;
+		break;
+
+	}
+
+	switch (val) {
+	/* jack in */
+	case 0x30: /* 2 port */
+	case 0x0: /* 1 port or 2 port */
+		if (rt5645->jack_type == 0) {
+			report = rt5645_jack_detect(rt5645->codec, 1);
+			/* for push button and jack out */
+			break;
+		}
+		btn_type = 0;
+		if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) {
+			/* button pressed */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5645_button_detect(rt5645->codec);
+			/* rt5650 can report three kinds of button behavior,
+			   one click, double click and hold. However,
+			   currently we will report button pressed/released
+			   event. So all the three button behaviors are
+			   treated as button pressed. */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				report |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				report |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				dev_err(rt5645->codec->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+		if (btn_type == 0)/* button release */
+			report =  rt5645->jack_type;
+
+		break;
+	/* jack out */
+	case 0x70: /* 2 port */
+	case 0x10: /* 2 port */
+	case 0x20: /* 1 port */
+		report = 0;
+		snd_soc_update_bits(rt5645->codec,
+				    RT5645_INT_IRQ_ST, 0x1, 0x0);
+		rt5645_jack_detect(rt5645->codec, 0);
+		break;
+	default:
+		break;
+	}
+
+	snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
+	snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
+	if (rt5645->en_button_func)
+		snd_soc_jack_report(rt5645->btn_jack,
+			report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+	return report;
+}
+
 static int rt5645_probe(struct snd_soc_codec *codec)
 static int rt5645_probe(struct snd_soc_codec *codec)
 {
 {
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
@@ -2521,12 +3061,10 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 		break;
 		break;
 	}
 	}
 
 
-	rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 
 	/* for JD function */
 	/* for JD function */
-	if (rt5645->pdata.en_jd_func) {
+	if (rt5645->pdata.jd_mode) {
 		snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
 		snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
 		snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
 		snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
 		snd_soc_dapm_sync(&codec->dapm);
 		snd_soc_dapm_sync(&codec->dapm);
@@ -2666,6 +3204,32 @@ static struct acpi_device_id rt5645_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
 MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
 #endif
 #endif
 
 
+static struct rt5645_platform_data *rt5645_pdata;
+
+static struct rt5645_platform_data strago_platform_data = {
+	.dmic1_data_pin = RT5645_DMIC1_DISABLE,
+	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+	.jd_mode = 3,
+};
+
+static int strago_quirk_cb(const struct dmi_system_id *id)
+{
+	rt5645_pdata = &strago_platform_data;
+
+	return 1;
+}
+
+static struct dmi_system_id dmi_platform_intel_braswell[] = {
+	{
+		.ident = "Intel Strago",
+		.callback = strago_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
+		},
+	},
+	{ }
+};
+
 static int rt5645_i2c_probe(struct i2c_client *i2c,
 static int rt5645_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 		    const struct i2c_device_id *id)
 {
 {
@@ -2673,6 +3237,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 	struct rt5645_priv *rt5645;
 	struct rt5645_priv *rt5645;
 	int ret;
 	int ret;
 	unsigned int val;
 	unsigned int val;
+	struct gpio_desc *gpiod;
 
 
 	rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
 	rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
 				GFP_KERNEL);
 				GFP_KERNEL);
@@ -2682,8 +3247,23 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 	rt5645->i2c = i2c;
 	rt5645->i2c = i2c;
 	i2c_set_clientdata(i2c, rt5645);
 	i2c_set_clientdata(i2c, rt5645);
 
 
-	if (pdata)
+	if (pdata) {
 		rt5645->pdata = *pdata;
 		rt5645->pdata = *pdata;
+	} else {
+		if (dmi_check_system(dmi_platform_intel_braswell)) {
+			rt5645->pdata = *rt5645_pdata;
+			gpiod = devm_gpiod_get_index(&i2c->dev, "rt5645", 0);
+
+			if (IS_ERR(gpiod) || gpiod_direction_input(gpiod)) {
+				rt5645->pdata.hp_det_gpio = -1;
+				dev_err(&i2c->dev, "failed to initialize gpiod\n");
+			} else {
+				rt5645->pdata.hp_det_gpio = desc_to_gpio(gpiod);
+				rt5645->pdata.gpio_hp_det_active_high
+						= !gpiod_is_active_low(gpiod);
+			}
+		}
+	}
 
 
 	rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
 	rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
 	if (IS_ERR(rt5645->regmap)) {
 	if (IS_ERR(rt5645->regmap)) {
@@ -2709,6 +3289,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
+	if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+		ret = rt5650_calibration(rt5645);
+
+		if (ret < 0)
+			pr_err("calibration failed!\n");
+	}
+
 	regmap_write(rt5645->regmap, RT5645_RESET, 0);
 	regmap_write(rt5645->regmap, RT5645_RESET, 0);
 
 
 	ret = regmap_register_patch(rt5645->regmap, init_list,
 	ret = regmap_register_patch(rt5645->regmap, init_list,
@@ -2728,84 +3315,76 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 		regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
 		regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
 					RT5645_IN_DF2, RT5645_IN_DF2);
 					RT5645_IN_DF2, RT5645_IN_DF2);
 
 
-	if (rt5645->pdata.dmic_en) {
+	if (rt5645->pdata.dmic1_data_pin || rt5645->pdata.dmic2_data_pin) {
 		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
 		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
 			RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
 			RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
+	}
+	switch (rt5645->pdata.dmic1_data_pin) {
+	case RT5645_DMIC_DATA_IN2N:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
+		break;
 
 
-		switch (rt5645->pdata.dmic1_data_pin) {
-		case RT5645_DMIC_DATA_IN2N:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
-			break;
-
-		case RT5645_DMIC_DATA_GPIO5:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
-			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-				RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
-			break;
-
-		case RT5645_DMIC_DATA_GPIO11:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
-			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-				RT5645_GP11_PIN_MASK,
-				RT5645_GP11_PIN_DMIC1_SDA);
-			break;
+	case RT5645_DMIC_DATA_GPIO5:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
+		break;
 
 
-		default:
-			break;
-		}
+	case RT5645_DMIC_DATA_GPIO11:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP11_PIN_MASK,
+			RT5645_GP11_PIN_DMIC1_SDA);
+		break;
 
 
-		switch (rt5645->pdata.dmic2_data_pin) {
-		case RT5645_DMIC_DATA_IN2P:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
-			break;
+	default:
+		break;
+	}
 
 
-		case RT5645_DMIC_DATA_GPIO6:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
-			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-				RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
-			break;
+	switch (rt5645->pdata.dmic2_data_pin) {
+	case RT5645_DMIC_DATA_IN2P:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
+		break;
 
 
-		case RT5645_DMIC_DATA_GPIO10:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
-			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-				RT5645_GP10_PIN_MASK,
-				RT5645_GP10_PIN_DMIC2_SDA);
-			break;
+	case RT5645_DMIC_DATA_GPIO6:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
+		break;
 
 
-		case RT5645_DMIC_DATA_GPIO12:
-			regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
-				RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
-			regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
-				RT5645_GP12_PIN_MASK,
-				RT5645_GP12_PIN_DMIC2_SDA);
-			break;
+	case RT5645_DMIC_DATA_GPIO10:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP10_PIN_MASK,
+			RT5645_GP10_PIN_DMIC2_SDA);
+		break;
 
 
-		default:
-			break;
-		}
+	case RT5645_DMIC_DATA_GPIO12:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP12_PIN_MASK,
+			RT5645_GP12_PIN_DMIC2_SDA);
+		break;
 
 
+	default:
+		break;
 	}
 	}
 
 
-	if (rt5645->pdata.en_jd_func) {
+	if (rt5645->pdata.jd_mode) {
 		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
 		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
-			RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
-			RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
+				   RT5645_IRQ_CLK_GATE_CTRL,
+				   RT5645_IRQ_CLK_GATE_CTRL);
 		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
 		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
-			RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
-		regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
-			RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
-			RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
+				   RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
 		regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
 		regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
-			RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
-	}
-
-	if (rt5645->pdata.jd_mode) {
+				   RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
 		regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
 		regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
 				   RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
 				   RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
 		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
 		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,

+ 17 - 13
sound/soc/codecs/rt5645.h

@@ -105,6 +105,7 @@
 #define RT5645_TDM_CTRL_1			0x77
 #define RT5645_TDM_CTRL_1			0x77
 #define RT5645_TDM_CTRL_2			0x78
 #define RT5645_TDM_CTRL_2			0x78
 #define RT5645_TDM_CTRL_3			0x79
 #define RT5645_TDM_CTRL_3			0x79
+#define RT5650_TDM_CTRL_4			0x7a
 
 
 /* Function - Analog */
 /* Function - Analog */
 #define RT5645_GLB_CLK				0x80
 #define RT5645_GLB_CLK				0x80
@@ -942,10 +943,6 @@
 #define RT5645_I2S2_SDI_I2S2			(0x1 << 6)
 #define RT5645_I2S2_SDI_I2S2			(0x1 << 6)
 
 
 /* ADC/DAC Clock Control 1 (0x73) */
 /* ADC/DAC Clock Control 1 (0x73) */
-#define RT5645_I2S_BCLK_MS1_MASK		(0x1 << 15)
-#define RT5645_I2S_BCLK_MS1_SFT			15
-#define RT5645_I2S_BCLK_MS1_32			(0x0 << 15)
-#define RT5645_I2S_BCLK_MS1_64			(0x1 << 15)
 #define RT5645_I2S_PD1_MASK			(0x7 << 12)
 #define RT5645_I2S_PD1_MASK			(0x7 << 12)
 #define RT5645_I2S_PD1_SFT			12
 #define RT5645_I2S_PD1_SFT			12
 #define RT5645_I2S_PD1_1			(0x0 << 12)
 #define RT5645_I2S_PD1_1			(0x0 << 12)
@@ -1067,13 +1064,14 @@
 #define RT5645_SCLK_SRC_SFT			14
 #define RT5645_SCLK_SRC_SFT			14
 #define RT5645_SCLK_SRC_MCLK			(0x0 << 14)
 #define RT5645_SCLK_SRC_MCLK			(0x0 << 14)
 #define RT5645_SCLK_SRC_PLL1			(0x1 << 14)
 #define RT5645_SCLK_SRC_PLL1			(0x1 << 14)
-#define RT5645_SCLK_SRC_RCCLK			(0x2 << 14) /* 15MHz */
-#define RT5645_PLL1_SRC_MASK			(0x3 << 12)
-#define RT5645_PLL1_SRC_SFT			12
-#define RT5645_PLL1_SRC_MCLK			(0x0 << 12)
-#define RT5645_PLL1_SRC_BCLK1			(0x1 << 12)
-#define RT5645_PLL1_SRC_BCLK2			(0x2 << 12)
-#define RT5645_PLL1_SRC_BCLK3			(0x3 << 12)
+#define RT5645_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5645_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5645_PLL1_SRC_SFT			11
+#define RT5645_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5645_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5645_PLL1_SRC_BCLK2			(0x2 << 11)
+#define RT5645_PLL1_SRC_BCLK3			(0x3 << 11)
+#define RT5645_PLL1_SRC_RCCLK			(0x4 << 11)
 #define RT5645_PLL1_PD_MASK			(0x1 << 3)
 #define RT5645_PLL1_PD_MASK			(0x1 << 3)
 #define RT5645_PLL1_PD_SFT			3
 #define RT5645_PLL1_PD_SFT			3
 #define RT5645_PLL1_PD_1			(0x0 << 3)
 #define RT5645_PLL1_PD_1			(0x0 << 3)
@@ -2147,6 +2145,7 @@ enum {
 };
 };
 
 
 enum {
 enum {
+	RT5645_DMIC1_DISABLE,
 	RT5645_DMIC_DATA_IN2P,
 	RT5645_DMIC_DATA_IN2P,
 	RT5645_DMIC_DATA_GPIO6,
 	RT5645_DMIC_DATA_GPIO6,
 	RT5645_DMIC_DATA_GPIO10,
 	RT5645_DMIC_DATA_GPIO10,
@@ -2154,6 +2153,7 @@ enum {
 };
 };
 
 
 enum {
 enum {
+	RT5645_DMIC2_DISABLE,
 	RT5645_DMIC_DATA_IN2N,
 	RT5645_DMIC_DATA_IN2N,
 	RT5645_DMIC_DATA_GPIO5,
 	RT5645_DMIC_DATA_GPIO5,
 	RT5645_DMIC_DATA_GPIO11,
 	RT5645_DMIC_DATA_GPIO11,
@@ -2184,6 +2184,7 @@ struct rt5645_priv {
 	struct i2c_client *i2c;
 	struct i2c_client *i2c;
 	struct snd_soc_jack *hp_jack;
 	struct snd_soc_jack *hp_jack;
 	struct snd_soc_jack *mic_jack;
 	struct snd_soc_jack *mic_jack;
+	struct snd_soc_jack *btn_jack;
 	struct delayed_work jack_detect_work;
 	struct delayed_work jack_detect_work;
 
 
 	int codec_type;
 	int codec_type;
@@ -2196,9 +2197,12 @@ struct rt5645_priv {
 	int pll_src;
 	int pll_src;
 	int pll_in;
 	int pll_in;
 	int pll_out;
 	int pll_out;
+
+	int jack_type;
+	bool en_button_func;
 };
 };
 
 
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
-
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+	struct snd_soc_jack *btn_jack);
 #endif /* __RT5645_H__ */
 #endif /* __RT5645_H__ */

+ 2 - 3
sound/soc/codecs/rt5651.c

@@ -1571,7 +1571,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
 {
 {
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
 			snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
 			snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
 				RT5651_PWR_VREF1 | RT5651_PWR_MB |
 				RT5651_PWR_VREF1 | RT5651_PWR_MB |
 				RT5651_PWR_BG | RT5651_PWR_VREF2,
 				RT5651_PWR_BG | RT5651_PWR_VREF2,
@@ -1604,7 +1604,6 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1625,7 +1624,7 @@ static int rt5651_probe(struct snd_soc_codec *codec)
 		RT5651_PWR_FV1 | RT5651_PWR_FV2,
 		RT5651_PWR_FV1 | RT5651_PWR_FV2,
 		RT5651_PWR_FV1 | RT5651_PWR_FV2);
 		RT5651_PWR_FV1 | RT5651_PWR_FV2);
 
 
-	rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 
 	return 0;
 	return 0;
 }
 }

+ 13 - 13
sound/soc/codecs/rt5670.c

@@ -416,12 +416,12 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
 static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 {
 {
 	int val;
 	int val;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
 
 	if (jack_insert) {
 	if (jack_insert) {
-		snd_soc_dapm_force_enable_pin(&codec->dapm,
-						       "Mic Det Power");
-		snd_soc_dapm_sync(&codec->dapm);
+		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
 		snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0);
 		snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0);
 		snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
 		snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
 			RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
 			RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
@@ -447,15 +447,15 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 		} else {
 		} else {
 			snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
 			snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
 			rt5670->jack_type = SND_JACK_HEADPHONE;
 			rt5670->jack_type = SND_JACK_HEADPHONE;
-			snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
-			snd_soc_dapm_sync(&codec->dapm);
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_sync(dapm);
 		}
 		}
 	} else {
 	} else {
 		snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0);
 		snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0);
 		snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
 		snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
 		rt5670->jack_type = 0;
 		rt5670->jack_type = 0;
-		snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
-		snd_soc_dapm_sync(&codec->dapm);
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
 	}
 	}
 
 
 	return rt5670->jack_type;
 	return rt5670->jack_type;
@@ -2603,7 +2603,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 
 
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
 			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
 			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
 				RT5670_PWR_VREF1 | RT5670_PWR_MB |
 				RT5670_PWR_VREF1 | RT5670_PWR_MB |
 				RT5670_PWR_BG | RT5670_PWR_VREF2,
 				RT5670_PWR_BG | RT5670_PWR_VREF2,
@@ -2647,30 +2647,30 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static int rt5670_probe(struct snd_soc_codec *codec)
 static int rt5670_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
 
 	switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
 	switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
 	case RT5670_ID_5670:
 	case RT5670_ID_5670:
 	case RT5670_ID_5671:
 	case RT5670_ID_5671:
-		snd_soc_dapm_new_controls(&codec->dapm,
+		snd_soc_dapm_new_controls(dapm,
 			rt5670_specific_dapm_widgets,
 			rt5670_specific_dapm_widgets,
 			ARRAY_SIZE(rt5670_specific_dapm_widgets));
 			ARRAY_SIZE(rt5670_specific_dapm_widgets));
-		snd_soc_dapm_add_routes(&codec->dapm,
+		snd_soc_dapm_add_routes(dapm,
 			rt5670_specific_dapm_routes,
 			rt5670_specific_dapm_routes,
 			ARRAY_SIZE(rt5670_specific_dapm_routes));
 			ARRAY_SIZE(rt5670_specific_dapm_routes));
 		break;
 		break;
 	case RT5670_ID_5672:
 	case RT5670_ID_5672:
-		snd_soc_dapm_new_controls(&codec->dapm,
+		snd_soc_dapm_new_controls(dapm,
 			rt5672_specific_dapm_widgets,
 			rt5672_specific_dapm_widgets,
 			ARRAY_SIZE(rt5672_specific_dapm_widgets));
 			ARRAY_SIZE(rt5672_specific_dapm_widgets));
-		snd_soc_dapm_add_routes(&codec->dapm,
+		snd_soc_dapm_add_routes(dapm,
 			rt5672_specific_dapm_routes,
 			rt5672_specific_dapm_routes,
 			ARRAY_SIZE(rt5672_specific_dapm_routes));
 			ARRAY_SIZE(rt5672_specific_dapm_routes));
 		break;
 		break;

+ 142 - 15
sound/soc/codecs/rt5677.c

@@ -820,7 +820,7 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
 
 
 	rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
 	rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
 
 
-	if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+	if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 		rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
 		rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
 
 
 	return 0;
 	return 0;
@@ -1060,6 +1060,7 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
 	unsigned int asrc5_mask = 0, asrc5_value = 0;
 	unsigned int asrc5_mask = 0, asrc5_value = 0;
 	unsigned int asrc6_mask = 0, asrc6_value = 0;
 	unsigned int asrc6_mask = 0, asrc6_value = 0;
 	unsigned int asrc7_mask = 0, asrc7_value = 0;
 	unsigned int asrc7_mask = 0, asrc7_value = 0;
+	unsigned int asrc8_mask = 0, asrc8_value = 0;
 
 
 	switch (clk_src) {
 	switch (clk_src) {
 	case RT5677_CLK_SEL_SYS:
 	case RT5677_CLK_SEL_SYS:
@@ -1196,10 +1197,108 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
 		regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
 		regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
 			asrc7_value);
 			asrc7_value);
 
 
+	/* ASRC 8 */
+	if (filter_mask & RT5677_I2S1_SOURCE) {
+		asrc8_mask |= RT5677_I2S1_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S1_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_I2S2_SOURCE) {
+		asrc8_mask |= RT5677_I2S2_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S2_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S2_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_I2S3_SOURCE) {
+		asrc8_mask |= RT5677_I2S3_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S3_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S3_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_I2S4_SOURCE) {
+		asrc8_mask |= RT5677_I2S4_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S4_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S4_CLK_SEL_SFT);
+	}
+
+	if (asrc8_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_8, asrc8_mask,
+			asrc8_value);
+
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
 EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
 
 
+static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	unsigned int asrc_setting;
+
+	switch (source->shift) {
+	case 11:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >>
+				RT5677_AD_STO1_CLK_SEL_SFT;
+		if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+			asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+			return 1;
+		break;
+
+	case 10:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >>
+				RT5677_AD_STO2_CLK_SEL_SFT;
+		if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+			asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+			return 1;
+		break;
+
+	case 9:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >>
+				RT5677_AD_STO3_CLK_SEL_SFT;
+		if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+			asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+			return 1;
+		break;
+
+	case 8:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >>
+			RT5677_AD_STO4_CLK_SEL_SFT;
+		if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+			asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+			return 1;
+		break;
+
+	case 7:
+		regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >>
+			RT5677_AD_MONOL_CLK_SEL_SFT;
+		if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+			asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+			return 1;
+		break;
+
+	case 6:
+		regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >>
+			RT5677_AD_MONOR_CLK_SEL_SFT;
+		if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+			asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+			return 1;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 /* Digital Mixer */
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
 static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
@@ -2479,7 +2578,7 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
 
 
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMU:
-		if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
+		if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON &&
 			!rt5677->is_vref_slow) {
 			!rt5677->is_vref_slow) {
 			mdelay(20);
 			mdelay(20);
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@ -3057,12 +3156,12 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 };
 };
 
 
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
-	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
-	{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
-	{ "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
-	{ "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
-	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
-	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", rt5677_dmic_use_asrc },
+	{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", rt5677_dmic_use_asrc },
+	{ "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", rt5677_dmic_use_asrc },
+	{ "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", rt5677_dmic_use_asrc },
+	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", rt5677_dmic_use_asrc },
+	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", rt5677_dmic_use_asrc },
 	{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
 	{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
 	{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
 	{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
 	{ "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
 	{ "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
@@ -4353,7 +4452,7 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			rt5677_set_dsp_vad(codec, false);
 			rt5677_set_dsp_vad(codec, false);
 
 
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@ -4395,7 +4494,6 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 	default:
 	default:
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -4606,22 +4704,23 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
 
 
 static int rt5677_probe(struct snd_soc_codec *codec)
 static int rt5677_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	int i;
 	int i;
 
 
 	rt5677->codec = codec;
 	rt5677->codec = codec;
 
 
 	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
 	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
-		snd_soc_dapm_add_routes(&codec->dapm,
+		snd_soc_dapm_add_routes(dapm,
 			rt5677_dmic2_clk_2,
 			rt5677_dmic2_clk_2,
 			ARRAY_SIZE(rt5677_dmic2_clk_2));
 			ARRAY_SIZE(rt5677_dmic2_clk_2));
 	} else { /*use dmic1 clock by default*/
 	} else { /*use dmic1 clock by default*/
-		snd_soc_dapm_add_routes(&codec->dapm,
+		snd_soc_dapm_add_routes(dapm,
 			rt5677_dmic2_clk_1,
 			rt5677_dmic2_clk_1,
 			ARRAY_SIZE(rt5677_dmic2_clk_1));
 			ARRAY_SIZE(rt5677_dmic2_clk_1));
 	}
 	}
 
 
-	rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
 
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
 	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
 	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
@@ -4667,6 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
 	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
 	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
 	if (gpio_is_valid(rt5677->pow_ldo2))
 	if (gpio_is_valid(rt5677->pow_ldo2))
 		gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 		gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+	if (gpio_is_valid(rt5677->reset_pin))
+		gpio_set_value_cansleep(rt5677->reset_pin, 0);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -4682,6 +4783,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 
 
 		if (gpio_is_valid(rt5677->pow_ldo2))
 		if (gpio_is_valid(rt5677->pow_ldo2))
 			gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 			gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+		if (gpio_is_valid(rt5677->reset_pin))
+			gpio_set_value_cansleep(rt5677->reset_pin, 0);
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -4692,10 +4795,13 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 
 	if (!rt5677->dsp_vad_en) {
 	if (!rt5677->dsp_vad_en) {
-		if (gpio_is_valid(rt5677->pow_ldo2)) {
+		if (gpio_is_valid(rt5677->pow_ldo2))
 			gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
 			gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+		if (gpio_is_valid(rt5677->reset_pin))
+			gpio_set_value_cansleep(rt5677->reset_pin, 1);
+		if (gpio_is_valid(rt5677->pow_ldo2) ||
+		    gpio_is_valid(rt5677->reset_pin))
 			msleep(10);
 			msleep(10);
-		}
 
 
 		regcache_cache_only(rt5677->regmap, false);
 		regcache_cache_only(rt5677->regmap, false);
 		regcache_sync(rt5677->regmap);
 		regcache_sync(rt5677->regmap);
@@ -4933,6 +5039,8 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
 
 
 	rt5677->pow_ldo2 = of_get_named_gpio(np,
 	rt5677->pow_ldo2 = of_get_named_gpio(np,
 					"realtek,pow-ldo2-gpio", 0);
 					"realtek,pow-ldo2-gpio", 0);
+	rt5677->reset_pin = of_get_named_gpio(np,
+					"realtek,reset-gpio", 0);
 
 
 	/*
 	/*
 	 * POW_LDO2 is optional (it may be statically tied on the board).
 	 * POW_LDO2 is optional (it may be statically tied on the board).
@@ -4943,6 +5051,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
 	if (!gpio_is_valid(rt5677->pow_ldo2) &&
 	if (!gpio_is_valid(rt5677->pow_ldo2) &&
 			(rt5677->pow_ldo2 != -ENOENT))
 			(rt5677->pow_ldo2 != -ENOENT))
 		return rt5677->pow_ldo2;
 		return rt5677->pow_ldo2;
+	if (!gpio_is_valid(rt5677->reset_pin) &&
+			(rt5677->reset_pin != -ENOENT))
+		return rt5677->reset_pin;
 
 
 	of_property_read_u8_array(np, "realtek,gpio-config",
 	of_property_read_u8_array(np, "realtek,gpio-config",
 		rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
 		rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
@@ -5044,6 +5155,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 		}
 		}
 	} else {
 	} else {
 		rt5677->pow_ldo2 = -EINVAL;
 		rt5677->pow_ldo2 = -EINVAL;
+		rt5677->reset_pin = -EINVAL;
 	}
 	}
 
 
 	if (gpio_is_valid(rt5677->pow_ldo2)) {
 	if (gpio_is_valid(rt5677->pow_ldo2)) {
@@ -5055,6 +5167,21 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 				rt5677->pow_ldo2, ret);
 				rt5677->pow_ldo2, ret);
 			return ret;
 			return ret;
 		}
 		}
+	}
+
+	if (gpio_is_valid(rt5677->reset_pin)) {
+		ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin,
+					    GPIOF_OUT_INIT_HIGH,
+					    "RT5677 RESET");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request RESET %d: %d\n",
+				rt5677->reset_pin, ret);
+			return ret;
+		}
+	}
+
+	if (gpio_is_valid(rt5677->pow_ldo2) ||
+	    gpio_is_valid(rt5677->reset_pin)) {
 		/* Wait a while until I2C bus becomes available. The datasheet
 		/* Wait a while until I2C bus becomes available. The datasheet
 		 * does not specify the exact we should wait but startup
 		 * does not specify the exact we should wait but startup
 		 * sequence mentiones at least a few milliseconds.
 		 * sequence mentiones at least a few milliseconds.

+ 15 - 0
sound/soc/codecs/rt5677.h

@@ -1446,6 +1446,16 @@
 #define RT5677_DSP_OB_4_7_CLK_SEL_MASK		(0xf << 8)
 #define RT5677_DSP_OB_4_7_CLK_SEL_MASK		(0xf << 8)
 #define RT5677_DSP_OB_4_7_CLK_SEL_SFT		8
 #define RT5677_DSP_OB_4_7_CLK_SEL_SFT		8
 
 
+/* ASRC Control 8 (0x8a) */
+#define RT5677_I2S1_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_I2S1_CLK_SEL_SFT			12
+#define RT5677_I2S2_CLK_SEL_MASK		(0xf << 8)
+#define RT5677_I2S2_CLK_SEL_SFT			8
+#define RT5677_I2S3_CLK_SEL_MASK		(0xf << 4)
+#define RT5677_I2S3_CLK_SEL_SFT			4
+#define RT5677_I2S4_CLK_SEL_MASK		(0xf)
+#define RT5677_I2S4_CLK_SEL_SFT			0
+
 /* VAD Function Control 4 (0x9f) */
 /* VAD Function Control 4 (0x9f) */
 #define RT5677_VAD_SRC_MASK			(0x7 << 8)
 #define RT5677_VAD_SRC_MASK			(0x7 << 8)
 #define RT5677_VAD_SRC_SFT			8
 #define RT5677_VAD_SRC_SFT			8
@@ -1744,6 +1754,10 @@ enum {
 	RT5677_AD_MONO_R_FILTER = (0x1 << 12),
 	RT5677_AD_MONO_R_FILTER = (0x1 << 12),
 	RT5677_DSP_OB_0_3_FILTER = (0x1 << 13),
 	RT5677_DSP_OB_0_3_FILTER = (0x1 << 13),
 	RT5677_DSP_OB_4_7_FILTER = (0x1 << 14),
 	RT5677_DSP_OB_4_7_FILTER = (0x1 << 14),
+	RT5677_I2S1_SOURCE = (0x1 << 15),
+	RT5677_I2S2_SOURCE = (0x1 << 16),
+	RT5677_I2S3_SOURCE = (0x1 << 17),
+	RT5677_I2S4_SOURCE = (0x1 << 18),
 };
 };
 
 
 struct rt5677_priv {
 struct rt5677_priv {
@@ -1762,6 +1776,7 @@ struct rt5677_priv {
 	int pll_in;
 	int pll_in;
 	int pll_out;
 	int pll_out;
 	int pow_ldo2; /* POW_LDO2 pin */
 	int pow_ldo2; /* POW_LDO2 pin */
+	int reset_pin; /* RESET pin */
 	enum rt5677_type type;
 	enum rt5677_type type;
 #ifdef CONFIG_GPIOLIB
 #ifdef CONFIG_GPIOLIB
 	struct gpio_chip gpio_chip;
 	struct gpio_chip gpio_chip;

+ 47 - 9
sound/soc/codecs/sgtl5000.c

@@ -948,7 +948,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(
 			ret = regulator_bulk_enable(
 						ARRAY_SIZE(sgtl5000->supplies),
 						ARRAY_SIZE(sgtl5000->supplies),
 						sgtl5000->supplies);
 						sgtl5000->supplies);
@@ -979,7 +979,6 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1091,6 +1090,19 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
 	}
 	}
 }
 }
 
 
+/*
+ * This precalculated table contains all (vag_val * 100 / lo_calcntrl) results
+ * to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL
+ * The calculatation was done for all possible register values which
+ * is the array index and the following formula: 10^((idx−15)/40) * 100
+ */
+static const u8 vol_quot_table[] = {
+	42, 45, 47, 50, 53, 56, 60, 63,
+	67, 71, 75, 79, 84, 89, 94, 100,
+	106, 112, 119, 126, 133, 141, 150, 158,
+	168, 178, 188, 200, 211, 224, 237, 251
+};
+
 /*
 /*
  * sgtl5000 has 3 internal power supplies:
  * sgtl5000 has 3 internal power supplies:
  * 1. VAG, normally set to vdda/2
  * 1. VAG, normally set to vdda/2
@@ -1111,6 +1123,10 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 	u16 ana_pwr;
 	u16 ana_pwr;
 	u16 lreg_ctrl;
 	u16 lreg_ctrl;
 	int vag;
 	int vag;
+	int lo_vag;
+	int vol_quot;
+	int lo_vol;
+	size_t i;
 	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
 
 	vdda  = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
 	vdda  = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
@@ -1198,23 +1214,45 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 			SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
 			SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
 
 
 	/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
 	/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
-	vag = vddio / 2;
-	if (vag <= SGTL5000_LINE_OUT_GND_BASE)
-		vag = 0;
-	else if (vag >= SGTL5000_LINE_OUT_GND_BASE +
+	lo_vag = vddio / 2;
+	if (lo_vag <= SGTL5000_LINE_OUT_GND_BASE)
+		lo_vag = 0;
+	else if (lo_vag >= SGTL5000_LINE_OUT_GND_BASE +
 		SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX)
 		SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX)
-		vag = SGTL5000_LINE_OUT_GND_MAX;
+		lo_vag = SGTL5000_LINE_OUT_GND_MAX;
 	else
 	else
-		vag = (vag - SGTL5000_LINE_OUT_GND_BASE) /
+		lo_vag = (lo_vag - SGTL5000_LINE_OUT_GND_BASE) /
 		    SGTL5000_LINE_OUT_GND_STP;
 		    SGTL5000_LINE_OUT_GND_STP;
 
 
 	snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
 	snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
 			SGTL5000_LINE_OUT_CURRENT_MASK |
 			SGTL5000_LINE_OUT_CURRENT_MASK |
 			SGTL5000_LINE_OUT_GND_MASK,
 			SGTL5000_LINE_OUT_GND_MASK,
-			vag << SGTL5000_LINE_OUT_GND_SHIFT |
+			lo_vag << SGTL5000_LINE_OUT_GND_SHIFT |
 			SGTL5000_LINE_OUT_CURRENT_360u <<
 			SGTL5000_LINE_OUT_CURRENT_360u <<
 				SGTL5000_LINE_OUT_CURRENT_SHIFT);
 				SGTL5000_LINE_OUT_CURRENT_SHIFT);
 
 
+	/*
+	 * Set lineout output level in range (0..31)
+	 * the same value is used for right and left channel
+	 *
+	 * Searching for a suitable index solving this formula:
+	 * idx = 40 * log10(vag_val / lo_cagcntrl) + 15
+	 */
+	vol_quot = (vag * 100) / lo_vag;
+	lo_vol = 0;
+	for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
+		if (vol_quot >= vol_quot_table[i])
+			lo_vol = i;
+		else
+			break;
+	}
+
+	snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_VOL,
+		SGTL5000_LINE_OUT_VOL_RIGHT_MASK |
+		SGTL5000_LINE_OUT_VOL_LEFT_MASK,
+		lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT |
+		lo_vol << SGTL5000_LINE_OUT_VOL_LEFT_SHIFT);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
sound/soc/codecs/sirf-audio-codec.c

@@ -395,7 +395,7 @@ struct snd_soc_dai_driver sirf_audio_codec_dai = {
 
 
 static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
 static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
 {
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 
 
 	pm_runtime_enable(codec->dev);
 	pm_runtime_enable(codec->dev);
 
 

+ 8 - 4
sound/soc/codecs/sn95031.c

@@ -194,7 +194,7 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
 			pr_debug("vaud_bias powering up pll\n");
 			pr_debug("vaud_bias powering up pll\n");
 			/* power up the pll */
 			/* power up the pll */
 			snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
 			snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
@@ -205,17 +205,22 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		switch (snd_soc_codec_get_bias_level(codec)) {
+		case SND_SOC_BIAS_OFF:
 			pr_debug("vaud_bias power up rail\n");
 			pr_debug("vaud_bias power up rail\n");
 			/* power up the rail */
 			/* power up the rail */
 			snd_soc_write(codec, SN95031_VAUD,
 			snd_soc_write(codec, SN95031_VAUD,
 					BIT(2)|BIT(1)|BIT(0));
 					BIT(2)|BIT(1)|BIT(0));
 			msleep(1);
 			msleep(1);
-		} else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+			break;
+		case SND_SOC_BIAS_PREPARE:
 			/* turn off pcm */
 			/* turn off pcm */
 			pr_debug("vaud_bias power dn pcm\n");
 			pr_debug("vaud_bias power dn pcm\n");
 			snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
 			snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
 			snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
 			snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
+			break;
+		default:
+			break;
 		}
 		}
 		break;
 		break;
 
 
@@ -226,7 +231,6 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 7
sound/soc/codecs/ssm2518.c

@@ -510,7 +510,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			ret = ssm2518_set_power(ssm2518, true);
 			ret = ssm2518_set_power(ssm2518, true);
 		break;
 		break;
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
@@ -518,12 +518,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	if (ret)
-		return ret;
-
-	codec->dapm.bias_level = level;
-
-	return 0;
+	return ret;
 }
 }
 
 
 static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,

+ 2 - 3
sound/soc/codecs/ssm2602.c

@@ -473,7 +473,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -524,8 +523,8 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
 
 
 static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 	int ret;
 
 
 	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
 	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
@@ -549,7 +548,7 @@ static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 
 
 static int ssm2604_codec_probe(struct snd_soc_codec *codec)
 static int ssm2604_codec_probe(struct snd_soc_codec *codec)
 {
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	int ret;
 	int ret;
 
 
 	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
 	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,

+ 2 - 7
sound/soc/codecs/ssm4567.c

@@ -353,7 +353,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			ret = ssm4567_set_power(ssm4567, true);
 			ret = ssm4567_set_power(ssm4567, true);
 		break;
 		break;
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
@@ -361,12 +361,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
-	if (ret)
-		return ret;
-
-	codec->dapm.bias_level = level;
-
-	return 0;
+	return ret;
 }
 }
 
 
 static const struct snd_soc_dai_ops ssm4567_dai_ops = {
 static const struct snd_soc_dai_ops ssm4567_dai_ops = {

+ 6 - 13
sound/soc/codecs/sta32x.c

@@ -819,7 +819,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
 			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
 						    sta32x->supplies);
 						    sta32x->supplies);
 			if (ret != 0) {
 			if (ret != 0) {
@@ -854,7 +854,6 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
 				       sta32x->supplies);
 				       sta32x->supplies);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -970,7 +969,7 @@ static int sta32x_probe(struct snd_soc_codec *codec)
 	if (sta32x->pdata->needs_esd_watchdog)
 	if (sta32x->pdata->needs_esd_watchdog)
 		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
 		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
 
 
-	sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	/* Bias level configuration will have done an extra enable */
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 
 
@@ -1096,16 +1095,10 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
 #endif
 #endif
 
 
 	/* GPIOs */
 	/* GPIOs */
-	sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
-	if (IS_ERR(sta32x->gpiod_nreset)) {
-		ret = PTR_ERR(sta32x->gpiod_nreset);
-		if (ret != -ENOENT && ret != -ENOSYS)
-			return ret;
-
-		sta32x->gpiod_nreset = NULL;
-	} else {
-		gpiod_direction_output(sta32x->gpiod_nreset, 0);
-	}
+	sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+						       GPIOD_OUT_LOW);
+	if (IS_ERR(sta32x->gpiod_nreset))
+		return PTR_ERR(sta32x->gpiod_nreset);
 
 
 	/* regulators */
 	/* regulators */
 	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
 	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)

+ 4 - 5
sound/soc/codecs/sta350.c

@@ -853,7 +853,7 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(
 			ret = regulator_bulk_enable(
 				ARRAY_SIZE(sta350->supplies),
 				ARRAY_SIZE(sta350->supplies),
 				sta350->supplies);
 				sta350->supplies);
@@ -890,7 +890,6 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
 				       sta350->supplies);
 				       sta350->supplies);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1037,7 +1036,7 @@ static int sta350_probe(struct snd_soc_codec *codec)
 	sta350->coef_shadow[60] = 0x400000;
 	sta350->coef_shadow[60] = 0x400000;
 	sta350->coef_shadow[61] = 0x400000;
 	sta350->coef_shadow[61] = 0x400000;
 
 
-	sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	/* Bias level configuration will have done an extra enable */
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
 	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
 
 
@@ -1218,8 +1217,8 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(sta350->gpiod_nreset))
 	if (IS_ERR(sta350->gpiod_nreset))
 		return PTR_ERR(sta350->gpiod_nreset);
 		return PTR_ERR(sta350->gpiod_nreset);
 
 
-	sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
-						  GPIOD_OUT_LOW);
+	sta350->gpiod_power_down = devm_gpiod_get_optional(dev, "power-down",
+							   GPIOD_OUT_LOW);
 	if (IS_ERR(sta350->gpiod_power_down))
 	if (IS_ERR(sta350->gpiod_power_down))
 		return PTR_ERR(sta350->gpiod_power_down);
 		return PTR_ERR(sta350->gpiod_power_down);
 
 

+ 1 - 7
sound/soc/codecs/sta529.c

@@ -165,7 +165,7 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
 				FFX_CLK_ENB);
 				FFX_CLK_ENB);
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
 			regcache_sync(sta529->regmap);
 			regcache_sync(sta529->regmap);
 		snd_soc_update_bits(codec, STA529_FFXCFG0,
 		snd_soc_update_bits(codec, STA529_FFXCFG0,
 					POWER_CNTLMSAK, POWER_STDBY);
 					POWER_CNTLMSAK, POWER_STDBY);
@@ -179,12 +179,6 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
 		break;
 		break;
 	}
 	}
 
 
-	/*
-	 * store the label for powers down audio subsystem for suspend.This is
-	 * used by soc core layer
-	 */
-	codec->dapm.bias_level = level;
-
 	return 0;
 	return 0;
 
 
 }
 }

+ 0 - 1
sound/soc/codecs/stac9766.c

@@ -236,7 +236,6 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
 		stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
 		stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
 		break;
 		break;
 	}
 	}
-	codec->dapm.bias_level = level;
 	return 0;
 	return 0;
 }
 }
 
 

+ 239 - 73
sound/soc/codecs/tas2552.c

@@ -34,6 +34,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
 #include <sound/tas2552-plat.h>
 #include <sound/tas2552-plat.h>
+#include <dt-bindings/sound/tas2552.h>
 
 
 #include "tas2552.h"
 #include "tas2552.h"
 
 
@@ -45,7 +46,7 @@ static struct reg_default tas2552_reg_defs[] = {
 	{TAS2552_PDM_CFG, 0x01},
 	{TAS2552_PDM_CFG, 0x01},
 	{TAS2552_PGA_GAIN, 0x00},
 	{TAS2552_PGA_GAIN, 0x00},
 	{TAS2552_BOOST_PT_CTRL, 0x0f},
 	{TAS2552_BOOST_PT_CTRL, 0x0f},
-	{TAS2552_RESERVED_0D, 0x00},
+	{TAS2552_RESERVED_0D, 0xbe},
 	{TAS2552_LIMIT_RATE_HYS, 0x08},
 	{TAS2552_LIMIT_RATE_HYS, 0x08},
 	{TAS2552_CFG_2, 0xef},
 	{TAS2552_CFG_2, 0xef},
 	{TAS2552_SER_CTRL_1, 0x00},
 	{TAS2552_SER_CTRL_1, 0x00},
@@ -75,20 +76,45 @@ struct tas2552_data {
 	struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
 	struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
 	struct gpio_desc *enable_gpio;
 	struct gpio_desc *enable_gpio;
 	unsigned char regs[TAS2552_VBAT_DATA];
 	unsigned char regs[TAS2552_VBAT_DATA];
-	unsigned int mclk;
-};
+	unsigned int pll_clkin;
+	unsigned int pdm_clk;
 
 
-/* Input mux controls */
-static const char *tas2552_input_texts[] = {
-	"Digital", "Analog"
+	unsigned int dai_fmt;
+	unsigned int tdm_delay;
 };
 };
 
 
+static int tas2552_post_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0);
+		snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5),
+				    (1 << 5));
+		snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0);
+		snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS,
+				    TAS2552_SWS);
+		snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1);
+		snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
+		snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe);
+		break;
+	}
+	return 0;
+}
+
+/* Input mux controls */
+static const char * const tas2552_input_texts[] = {
+	"Digital", "Analog" };
 static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
 static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
 			    tas2552_input_texts);
 			    tas2552_input_texts);
 
 
-static const struct snd_kcontrol_new tas2552_input_mux_control[] = {
-	SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum)
-};
+static const struct snd_kcontrol_new tas2552_input_mux_control =
+	SOC_DAPM_ENUM("Route", tas2552_input_mux_enum);
 
 
 static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
 static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
 {
 {
@@ -96,12 +122,13 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
 
 
 	/* MUX Controls */
 	/* MUX Controls */
 	SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
-				tas2552_input_mux_control),
+			 &tas2552_input_mux_control),
 
 
 	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
 	SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
 
 
 	SND_SOC_DAPM_OUTPUT("OUT")
 	SND_SOC_DAPM_OUTPUT("OUT")
 };
 };
@@ -118,15 +145,16 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
 static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
 {
 {
-	u8 cfg1_reg;
+	u8 cfg1_reg = 0;
+
+	if (!tas_data->codec)
+		return;
 
 
 	if (sw_shutdown)
 	if (sw_shutdown)
-		cfg1_reg = 0;
-	else
-		cfg1_reg = TAS2552_SWS_MASK;
+		cfg1_reg = TAS2552_SWS;
 
 
-	snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1,
-						 TAS2552_SWS_MASK, cfg1_reg);
+	snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, TAS2552_SWS,
+			    cfg1_reg);
 }
 }
 #endif
 #endif
 
 
@@ -138,15 +166,92 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
 	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
 	int sample_rate, pll_clk;
 	int sample_rate, pll_clk;
 	int d;
 	int d;
+	int cpf;
 	u8 p, j;
 	u8 p, j;
+	u8 ser_ctrl1_reg, wclk_rate;
 
 
-	if (!tas2552->mclk)
+	switch (params_width(params)) {
+	case 16:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_16BIT;
+		cpf = 32 + tas2552->tdm_delay;
+		break;
+	case 20:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_20BIT;
+		cpf = 64 + tas2552->tdm_delay;
+		break;
+	case 24:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_24BIT;
+		cpf = 64 + tas2552->tdm_delay;
+		break;
+	case 32:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_32BIT;
+		cpf = 64 + tas2552->tdm_delay;
+		break;
+	default:
+		dev_err(codec->dev, "Not supported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	if (cpf <= 32)
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_32;
+	else if (cpf <= 64)
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_64;
+	else if (cpf <= 128)
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_128;
+	else
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256;
+
+	snd_soc_update_bits(codec, TAS2552_SER_CTRL_1,
+			    TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK,
+			    ser_ctrl1_reg);
+
+	switch (params_rate(params)) {
+	case 8000:
+		wclk_rate = TAS2552_WCLK_FREQ_8KHZ;
+		break;
+	case 11025:
+	case 12000:
+		wclk_rate = TAS2552_WCLK_FREQ_11_12KHZ;
+		break;
+	case 16000:
+		wclk_rate = TAS2552_WCLK_FREQ_16KHZ;
+		break;
+	case 22050:
+	case 24000:
+		wclk_rate = TAS2552_WCLK_FREQ_22_24KHZ;
+		break;
+	case 32000:
+		wclk_rate = TAS2552_WCLK_FREQ_32KHZ;
+		break;
+	case 44100:
+	case 48000:
+		wclk_rate = TAS2552_WCLK_FREQ_44_48KHZ;
+		break;
+	case 88200:
+	case 96000:
+		wclk_rate = TAS2552_WCLK_FREQ_88_96KHZ;
+		break;
+	case 176400:
+	case 192000:
+		wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ;
+		break;
+	default:
+		dev_err(codec->dev, "Not supported sample rate: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
+			    wclk_rate);
+
+	if (!tas2552->pll_clkin)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
 	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
 
 
-	if (tas2552->mclk == TAS2552_245MHZ_CLK ||
-		tas2552->mclk == TAS2552_225MHZ_CLK) {
+	if (tas2552->pll_clkin == TAS2552_245MHZ_CLK ||
+	    tas2552->pll_clkin == TAS2552_225MHZ_CLK) {
 		/* By pass the PLL configuration */
 		/* By pass the PLL configuration */
 		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
 		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
 				    TAS2552_PLL_BYPASS_MASK,
 				    TAS2552_PLL_BYPASS_MASK,
@@ -170,8 +275,8 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
-		j = (pll_clk * 2 * (1 << p)) / tas2552->mclk;
-		d = (pll_clk * 2 * (1 << p)) % tas2552->mclk;
+		j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin;
+		d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin;
 
 
 		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
 		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
 				TAS2552_PLL_J_MASK, j);
 				TAS2552_PLL_J_MASK, j);
@@ -185,56 +290,74 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 	return 0;
 }
 }
 
 
+#define TAS2552_DAI_FMT_MASK	(TAS2552_BCLKDIR | \
+				 TAS2552_WCLKDIR | \
+				 TAS2552_DATAFORMAT_MASK)
+static int tas2552_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	int delay = 0;
+
+	/* TDM slot selection only valid in DSP_A/_B mode */
+	if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A)
+		delay += (tas2552->tdm_delay + 1);
+	else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B)
+		delay += tas2552->tdm_delay;
+
+	/* Configure data delay */
+	snd_soc_write(codec, TAS2552_SER_CTRL_2, delay);
+
+	return 0;
+}
+
 static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
+	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
 	u8 serial_format;
 	u8 serial_format;
-	u8 serial_control_mask;
 
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 	case SND_SOC_DAIFMT_CBS_CFS:
 		serial_format = 0x00;
 		serial_format = 0x00;
 		break;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFM:
 	case SND_SOC_DAIFMT_CBS_CFM:
-		serial_format = TAS2552_WORD_CLK_MASK;
+		serial_format = TAS2552_WCLKDIR;
 		break;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFS:
 	case SND_SOC_DAIFMT_CBM_CFS:
-		serial_format = TAS2552_BIT_CLK_MASK;
+		serial_format = TAS2552_BCLKDIR;
 		break;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 	case SND_SOC_DAIFMT_CBM_CFM:
-		serial_format = (TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK);
+		serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
 		break;
 		break;
 	default:
 	default:
 		dev_vdbg(codec->dev, "DAI Format master is not found\n");
 		dev_vdbg(codec->dev, "DAI Format master is not found\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	serial_control_mask = TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK;
-
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		serial_format &= TAS2552_DAIFMT_I2S_MASK;
+	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+		       SND_SOC_DAIFMT_INV_MASK)) {
+	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
 		break;
 		break;
-	case SND_SOC_DAIFMT_DSP_A:
-		serial_format |= TAS2552_DAIFMT_DSP;
+	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
+	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
+		serial_format |= TAS2552_DATAFORMAT_DSP;
 		break;
 		break;
-	case SND_SOC_DAIFMT_RIGHT_J:
-		serial_format |= TAS2552_DAIFMT_RIGHT_J;
+	case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
+		serial_format |= TAS2552_DATAFORMAT_RIGHT_J;
 		break;
 		break;
-	case SND_SOC_DAIFMT_LEFT_J:
-		serial_format |= TAS2552_DAIFMT_LEFT_J;
+	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
+		serial_format |= TAS2552_DATAFORMAT_LEFT_J;
 		break;
 		break;
 	default:
 	default:
 		dev_vdbg(codec->dev, "DAI Format is not found\n");
 		dev_vdbg(codec->dev, "DAI Format is not found\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+	tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
 
-	if (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
-		serial_control_mask |= TAS2552_DATA_FORMAT_MASK;
-
-	snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, serial_control_mask,
-						serial_format);
-
+	snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
+			    serial_format);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -243,23 +366,75 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 {
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
 	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
 	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+	u8 reg, mask, val;
+
+	switch (clk_id) {
+	case TAS2552_PLL_CLKIN_MCLK:
+	case TAS2552_PLL_CLKIN_BCLK:
+	case TAS2552_PLL_CLKIN_IVCLKIN:
+	case TAS2552_PLL_CLKIN_1_8_FIXED:
+		mask = TAS2552_PLL_SRC_MASK;
+		val = (clk_id << 3) & mask; /* bit 4:5 in the register */
+		reg = TAS2552_CFG_1;
+		tas2552->pll_clkin = freq;
+		break;
+	case TAS2552_PDM_CLK_PLL:
+	case TAS2552_PDM_CLK_IVCLKIN:
+	case TAS2552_PDM_CLK_BCLK:
+	case TAS2552_PDM_CLK_MCLK:
+		mask = TAS2552_PDM_CLK_SEL_MASK;
+		val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
+		reg = TAS2552_PDM_CFG;
+		tas2552->pdm_clk = freq;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid clk id: %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, reg, mask, val);
+
+	return 0;
+}
+
+static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	unsigned int lsb;
+
+	if (unlikely(!tx_mask)) {
+		dev_err(codec->dev, "tx masks need to be non 0\n");
+		return -EINVAL;
+	}
+
+	/* TDM based on DSP mode requires slots to be adjacent */
+	lsb = __ffs(tx_mask);
+	if ((lsb + 1) != __fls(tx_mask)) {
+		dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
+		return -EINVAL;
+	}
+
+	tas2552->tdm_delay = lsb * slot_width;
 
 
-	tas2552->mclk = freq;
+	/* DOUT in high-impedance on inactive bit clocks */
+	snd_soc_update_bits(codec, TAS2552_DOUT,
+			    TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static int tas2552_mute(struct snd_soc_dai *dai, int mute)
 static int tas2552_mute(struct snd_soc_dai *dai, int mute)
 {
 {
-	u8 cfg1_reg;
+	u8 cfg1_reg = 0;
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
 
 
 	if (mute)
 	if (mute)
-		cfg1_reg = TAS2552_MUTE_MASK;
-	else
-		cfg1_reg = ~TAS2552_MUTE_MASK;
+		cfg1_reg |= TAS2552_MUTE;
 
 
-	snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK, cfg1_reg);
+	snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -269,7 +444,7 @@ static int tas2552_runtime_suspend(struct device *dev)
 {
 {
 	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
 	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
 
 
-	tas2552_sw_shutdown(tas2552, 0);
+	tas2552_sw_shutdown(tas2552, 1);
 
 
 	regcache_cache_only(tas2552->regmap, true);
 	regcache_cache_only(tas2552->regmap, true);
 	regcache_mark_dirty(tas2552->regmap);
 	regcache_mark_dirty(tas2552->regmap);
@@ -287,7 +462,7 @@ static int tas2552_runtime_resume(struct device *dev)
 	if (tas2552->enable_gpio)
 	if (tas2552->enable_gpio)
 		gpiod_set_value(tas2552->enable_gpio, 1);
 		gpiod_set_value(tas2552->enable_gpio, 1);
 
 
-	tas2552_sw_shutdown(tas2552, 1);
+	tas2552_sw_shutdown(tas2552, 0);
 
 
 	regcache_cache_only(tas2552->regmap, false);
 	regcache_cache_only(tas2552->regmap, false);
 	regcache_sync(tas2552->regmap);
 	regcache_sync(tas2552->regmap);
@@ -303,8 +478,10 @@ static const struct dev_pm_ops tas2552_pm = {
 
 
 static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
 static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
 	.hw_params	= tas2552_hw_params,
 	.hw_params	= tas2552_hw_params,
+	.prepare	= tas2552_prepare,
 	.set_sysclk	= tas2552_set_dai_sysclk,
 	.set_sysclk	= tas2552_set_dai_sysclk,
 	.set_fmt	= tas2552_set_dai_fmt,
 	.set_fmt	= tas2552_set_dai_fmt,
+	.set_tdm_slot	= tas2552_set_dai_tdm_slot,
 	.digital_mute = tas2552_mute,
 	.digital_mute = tas2552_mute,
 };
 };
 
 
@@ -330,16 +507,11 @@ static struct snd_soc_dai_driver tas2552_dai[] = {
 /*
 /*
  * DAC digital volumes. From -7 to 24 dB in 1 dB steps
  * DAC digital volumes. From -7 to 24 dB in 1 dB steps
  */
  */
-static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24);
+static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 0);
 
 
 static const struct snd_kcontrol_new tas2552_snd_controls[] = {
 static const struct snd_kcontrol_new tas2552_snd_controls[] = {
 	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
 	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
-			 TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv),
-	SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0),
-};
-
-static const struct reg_default tas2552_init_regs[] = {
-	{ TAS2552_RESERVED_0D, 0xc0 },
+			 TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
 };
 };
 
 
 static int tas2552_codec_probe(struct snd_soc_codec *codec)
 static int tas2552_codec_probe(struct snd_soc_codec *codec)
@@ -368,31 +540,19 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
 		goto probe_fail;
 		goto probe_fail;
 	}
 	}
 
 
-	snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK |
-				TAS2552_PLL_SRC_BCLK);
+	snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
 	snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
 	snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
-				TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ);
+					    TAS2552_DIN_SRC_SEL_AVG_L_R);
 	snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
 	snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
 	snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8);
 	snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8);
-	snd_soc_write(codec, TAS2552_PDM_CFG, TAS2552_PDM_BCLK_SEL);
 	snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
 	snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
 				TAS2552_APT_THRESH_2_1_7);
 				TAS2552_APT_THRESH_2_1_7);
 
 
-	ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs,
-					    ARRAY_SIZE(tas2552_init_regs));
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to write init registers: %d\n",
-			ret);
-		goto patch_fail;
-	}
-
 	snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
 	snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
 				  TAS2552_APT_EN | TAS2552_LIM_EN);
 				  TAS2552_APT_EN | TAS2552_LIM_EN);
 
 
 	return 0;
 	return 0;
 
 
-patch_fail:
-	pm_runtime_put(codec->dev);
 probe_fail:
 probe_fail:
 	if (tas2552->enable_gpio)
 	if (tas2552->enable_gpio)
 		gpiod_set_value(tas2552->enable_gpio, 0);
 		gpiod_set_value(tas2552->enable_gpio, 0);
@@ -454,6 +614,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
 	.remove = tas2552_codec_remove,
 	.remove = tas2552_codec_remove,
 	.suspend =	tas2552_suspend,
 	.suspend =	tas2552_suspend,
 	.resume = tas2552_resume,
 	.resume = tas2552_resume,
+	.ignore_pmdown_time = true,
+
 	.controls = tas2552_snd_controls,
 	.controls = tas2552_snd_controls,
 	.num_controls = ARRAY_SIZE(tas2552_snd_controls),
 	.num_controls = ARRAY_SIZE(tas2552_snd_controls),
 	.dapm_widgets = tas2552_dapm_widgets,
 	.dapm_widgets = tas2552_dapm_widgets,
@@ -486,8 +648,12 @@ static int tas2552_probe(struct i2c_client *client,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 	data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
-	if (IS_ERR(data->enable_gpio))
-		return PTR_ERR(data->enable_gpio);
+	if (IS_ERR(data->enable_gpio)) {
+		if (PTR_ERR(data->enable_gpio) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+
+		data->enable_gpio = NULL;;
+	}
 
 
 	data->tas2552_client = client;
 	data->tas2552_client = client;
 	data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
 	data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);

+ 50 - 40
sound/soc/codecs/tas2552.h

@@ -45,10 +45,14 @@
 #define TAS2552_MAX_REG			0x20
 #define TAS2552_MAX_REG			0x20
 
 
 /* CFG1 Register Masks */
 /* CFG1 Register Masks */
-#define TAS2552_MUTE_MASK		(1 << 2)
-#define TAS2552_SWS_MASK		(1 << 1)
-#define TAS2552_WCLK_MASK		0x07
-#define TAS2552_CLASSD_EN_MASK	(1 << 7)
+#define TAS2552_DEV_RESET		(1 << 0)
+#define TAS2552_SWS			(1 << 1)
+#define TAS2552_MUTE			(1 << 2)
+#define TAS2552_PLL_SRC_MCLK		(0x0 << 4)
+#define TAS2552_PLL_SRC_BCLK		(0x1 << 4)
+#define TAS2552_PLL_SRC_IVCLKIN		(0x2 << 4)
+#define TAS2552_PLL_SRC_1_8_FIXED 	(0x3 << 4)
+#define TAS2552_PLL_SRC_MASK	 	TAS2552_PLL_SRC_1_8_FIXED
 
 
 /* CFG2 Register Masks */
 /* CFG2 Register Masks */
 #define TAS2552_CLASSD_EN		(1 << 7)
 #define TAS2552_CLASSD_EN		(1 << 7)
@@ -59,38 +63,44 @@
 #define TAS2552_IVSENSE_EN		(1 << 1)
 #define TAS2552_IVSENSE_EN		(1 << 1)
 
 
 /* CFG3 Register Masks */
 /* CFG3 Register Masks */
-#define TAS2552_WORD_CLK_MASK		(1 << 7)
-#define TAS2552_BIT_CLK_MASK		(1 << 6)
-#define TAS2552_DATA_FORMAT_MASK	(0x11 << 2)
-
-#define TAS2552_DAIFMT_I2S_MASK		0xf3
-#define TAS2552_DAIFMT_DSP			(1 << 3)
-#define TAS2552_DAIFMT_RIGHT_J		(1 << 4)
-#define TAS2552_DAIFMT_LEFT_J		(0x11 << 3)
-
-#define TAS2552_PLL_SRC_MCLK	0x00
-#define TAS2552_PLL_SRC_BCLK	(1 << 3)
-#define TAS2552_PLL_SRC_IVCLKIN	(1 << 4)
-#define TAS2552_PLL_SRC_1_8_FIXED (0x11 << 3)
-
-#define TAS2552_DIN_SRC_SEL_MUTED	0x00
-#define TAS2552_DIN_SRC_SEL_LEFT	(1 << 4)
-#define TAS2552_DIN_SRC_SEL_RIGHT	(1 << 5)
-#define TAS2552_DIN_SRC_SEL_AVG_L_R	(0x11 << 4)
-
+#define TAS2552_WCLK_FREQ_8KHZ		(0x0 << 0)
+#define TAS2552_WCLK_FREQ_11_12KHZ	(0x1 << 0)
+#define TAS2552_WCLK_FREQ_16KHZ		(0x2 << 0)
+#define TAS2552_WCLK_FREQ_22_24KHZ	(0x3 << 0)
+#define TAS2552_WCLK_FREQ_32KHZ		(0x4 << 0)
+#define TAS2552_WCLK_FREQ_44_48KHZ	(0x5 << 0)
+#define TAS2552_WCLK_FREQ_88_96KHZ	(0x6 << 0)
+#define TAS2552_WCLK_FREQ_176_192KHZ	(0x7 << 0)
+#define TAS2552_WCLK_FREQ_MASK		TAS2552_WCLK_FREQ_176_192KHZ
+#define TAS2552_DIN_SRC_SEL_MUTED	(0x0 << 3)
+#define TAS2552_DIN_SRC_SEL_LEFT	(0x1 << 3)
+#define TAS2552_DIN_SRC_SEL_RIGHT	(0x2 << 3)
+#define TAS2552_DIN_SRC_SEL_AVG_L_R	(0x3 << 3)
 #define TAS2552_PDM_IN_SEL		(1 << 5)
 #define TAS2552_PDM_IN_SEL		(1 << 5)
 #define TAS2552_I2S_OUT_SEL		(1 << 6)
 #define TAS2552_I2S_OUT_SEL		(1 << 6)
-#define TAS2552_ANALOG_IN_SEL	(1 << 7)
-
-/* CFG3 WCLK Dividers */
-#define TAS2552_8KHZ		0x00
-#define TAS2552_11_12KHZ	(1 << 1)
-#define TAS2552_16KHZ		(1 << 2)
-#define TAS2552_22_24KHZ	(1 << 3)
-#define TAS2552_32KHZ		(1 << 4)
-#define TAS2552_44_48KHZ	(1 << 5)
-#define TAS2552_88_96KHZ	(1 << 6)
-#define TAS2552_176_192KHZ	(1 << 7)
+#define TAS2552_ANALOG_IN_SEL		(1 << 7)
+
+/* DOUT Register Masks */
+#define TAS2552_SDOUT_TRISTATE		(1 << 2)
+
+/* Serial Interface Control Register Masks */
+#define TAS2552_WORDLENGTH_16BIT	(0x0 << 0)
+#define TAS2552_WORDLENGTH_20BIT	(0x1 << 0)
+#define TAS2552_WORDLENGTH_24BIT	(0x2 << 0)
+#define TAS2552_WORDLENGTH_32BIT	(0x3 << 0)
+#define TAS2552_WORDLENGTH_MASK		TAS2552_WORDLENGTH_32BIT
+#define TAS2552_DATAFORMAT_I2S		(0x0 << 2)
+#define TAS2552_DATAFORMAT_DSP		(0x1 << 2)
+#define TAS2552_DATAFORMAT_RIGHT_J	(0x2 << 2)
+#define TAS2552_DATAFORMAT_LEFT_J	(0x3 << 2)
+#define TAS2552_DATAFORMAT_MASK		TAS2552_DATAFORMAT_LEFT_J
+#define TAS2552_CLKSPERFRAME_32		(0x0 << 4)
+#define TAS2552_CLKSPERFRAME_64		(0x1 << 4)
+#define TAS2552_CLKSPERFRAME_128	(0x2 << 4)
+#define TAS2552_CLKSPERFRAME_256	(0x3 << 4)
+#define TAS2552_CLKSPERFRAME_MASK	TAS2552_CLKSPERFRAME_256
+#define TAS2552_BCLKDIR			(1 << 6)
+#define TAS2552_WCLKDIR			(1 << 7)
 
 
 /* OUTPUT_DATA register */
 /* OUTPUT_DATA register */
 #define TAS2552_PDM_DATA_I		0x00
 #define TAS2552_PDM_DATA_I		0x00
@@ -99,12 +109,12 @@
 #define TAS2552_PDM_DATA_V_I	(0x11 << 6)
 #define TAS2552_PDM_DATA_V_I	(0x11 << 6)
 
 
 /* PDM CFG Register */
 /* PDM CFG Register */
-#define TAS2552_PDM_DATA_ES_RISE 0x4
-
-#define TAS2552_PDM_PLL_CLK_SEL 0x00
-#define TAS2552_PDM_IV_CLK_SEL	(1 << 1)
-#define TAS2552_PDM_BCLK_SEL	(1 << 2)
-#define TAS2552_PDM_MCLK_SEL	(1 << 3)
+#define TAS2552_PDM_CLK_SEL_PLL		(0x0 << 0)
+#define TAS2552_PDM_CLK_SEL_IVCLKIN	(0x1 << 0)
+#define TAS2552_PDM_CLK_SEL_BCLK	(0x2 << 0)
+#define TAS2552_PDM_CLK_SEL_MCLK	(0x3 << 0)
+#define TAS2552_PDM_CLK_SEL_MASK	TAS2552_PDM_CLK_SEL_MCLK
+#define TAS2552_PDM_DATA_ES	 	(1 << 2)
 
 
 /* Boost pass-through register */
 /* Boost pass-through register */
 #define TAS2552_APT_DELAY_50	0x00
 #define TAS2552_APT_DELAY_50	0x00

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä