Browse Source

Merge tag 'asoc-v3.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Updates for v3.20

More updates for v3.20:

 - Lots of refactoring from Lars-Peter Clausen, moving drivers to more
   data driven initialization and rationalizing a lot of DAPM usage.
 - Much improved handling of CDCLK clocks on Samsung I2S controllers.
 - Lots of driver specific cleanups and feature improvements.
 - CODEC support for TI PCM514x and TLV320AIC3104 devices.
 - Board support for Tegra systems with Realtek RT5677.

Conflicts:
	sound/soc/intel/sst-mfld-platform-pcm.c
Takashi Iwai 10 years ago
parent
commit
a3ae255e37
100 changed files with 2932 additions and 822 deletions
  1. 18 0
      Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt
  2. 31 0
      Documentation/devicetree/bindings/sound/designware-i2s.txt
  3. 67 0
      Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt
  4. 23 2
      Documentation/devicetree/bindings/sound/pcm512x.txt
  5. 22 0
      Documentation/devicetree/bindings/sound/samsung-i2s.txt
  6. 5 0
      Documentation/devicetree/bindings/sound/simple-card.txt
  7. 92 0
      Documentation/devicetree/bindings/sound/st,sta32x.txt
  8. 9 1
      Documentation/devicetree/bindings/sound/tlv320aic3x.txt
  9. 5 0
      Documentation/devicetree/bindings/sound/ts3a227e.txt
  10. 1 1
      Documentation/devicetree/bindings/sound/wm8904.txt
  11. 11 0
      MAINTAINERS
  12. 8 0
      include/dt-bindings/sound/samsung-i2s.h
  13. 12 0
      include/sound/pcm.h
  14. 1 0
      include/sound/rcar_snd.h
  15. 3 0
      include/sound/rt5677.h
  16. 1 0
      include/sound/simple_card.h
  17. 1 2
      include/sound/soc-dapm.h
  18. 4 0
      include/sound/soc.h
  19. 13 5
      include/sound/sta32x.h
  20. 85 0
      sound/core/pcm_lib.c
  21. 1 0
      sound/soc/Kconfig
  22. 1 0
      sound/soc/Makefile
  23. 1 1
      sound/soc/atmel/Kconfig
  24. 5 7
      sound/soc/atmel/atmel-pcm-dma.c
  25. 78 54
      sound/soc/atmel/atmel_ssc_dai.c
  26. 2 29
      sound/soc/atmel/sam9g20_wm8731.c
  27. 3 16
      sound/soc/au1x/db1200.c
  28. 0 6
      sound/soc/au1x/dbdma2.c
  29. 0 6
      sound/soc/au1x/dma.c
  30. 2 2
      sound/soc/codecs/88pm860x-codec.c
  31. 4 2
      sound/soc/codecs/Kconfig
  32. 2 2
      sound/soc/codecs/ad193x.c
  33. 1 1
      sound/soc/codecs/ak4671.c
  34. 5 3
      sound/soc/codecs/alc5623.c
  35. 7 5
      sound/soc/codecs/alc5632.c
  36. 69 9
      sound/soc/codecs/arizona.c
  37. 5 0
      sound/soc/codecs/arizona.h
  38. 1 1
      sound/soc/codecs/bt-sco.c
  39. 2 2
      sound/soc/codecs/cs35l32.c
  40. 2 2
      sound/soc/codecs/cs42l52.c
  41. 2 2
      sound/soc/codecs/cs42l56.c
  42. 2 2
      sound/soc/codecs/cs42l73.c
  43. 2 2
      sound/soc/codecs/da732x.c
  44. 5 5
      sound/soc/codecs/mc13783.c
  45. 2 2
      sound/soc/codecs/pcm3008.c
  46. 915 17
      sound/soc/codecs/pcm512x.c
  47. 104 5
      sound/soc/codecs/pcm512x.h
  48. 13 38
      sound/soc/codecs/rt286.c
  49. 18 10
      sound/soc/codecs/rt5631.c
  50. 7 5
      sound/soc/codecs/rt5640.c
  51. 150 24
      sound/soc/codecs/rt5645.c
  52. 15 0
      sound/soc/codecs/rt5645.h
  53. 10 8
      sound/soc/codecs/rt5651.c
  54. 92 7
      sound/soc/codecs/rt5670.c
  55. 39 41
      sound/soc/codecs/rt5670.h
  56. 36 14
      sound/soc/codecs/rt5677.c
  57. 16 11
      sound/soc/codecs/sgtl5000.c
  58. 20 13
      sound/soc/codecs/sn95031.c
  59. 338 196
      sound/soc/codecs/sta32x.c
  60. 1 1
      sound/soc/codecs/sta32x.h
  61. 5 4
      sound/soc/codecs/tlv320aic31xx.c
  62. 246 103
      sound/soc/codecs/tlv320aic3x.c
  63. 5 4
      sound/soc/codecs/tlv320dac33.c
  64. 32 3
      sound/soc/codecs/ts3a227e.c
  65. 34 21
      sound/soc/codecs/twl4030.c
  66. 2 2
      sound/soc/codecs/twl6040.c
  67. 1 1
      sound/soc/codecs/wm2000.c
  68. 3 2
      sound/soc/codecs/wm5100.c
  69. 14 9
      sound/soc/codecs/wm5102.c
  70. 13 7
      sound/soc/codecs/wm5110.c
  71. 1 1
      sound/soc/codecs/wm8350.c
  72. 5 4
      sound/soc/codecs/wm8400.c
  73. 4 1
      sound/soc/codecs/wm8731.c
  74. 2 6
      sound/soc/codecs/wm8770.c
  75. 2 2
      sound/soc/codecs/wm8804.c
  76. 1 1
      sound/soc/codecs/wm8900.c
  77. 1 1
      sound/soc/codecs/wm8903.c
  78. 32 3
      sound/soc/codecs/wm8904.c
  79. 1 1
      sound/soc/codecs/wm8955.c
  80. 1 1
      sound/soc/codecs/wm8958-dsp2.c
  81. 48 3
      sound/soc/codecs/wm8960.c
  82. 2 2
      sound/soc/codecs/wm8961.c
  83. 3 3
      sound/soc/codecs/wm8962.c
  84. 3 3
      sound/soc/codecs/wm8988.c
  85. 5 4
      sound/soc/codecs/wm8990.c
  86. 5 4
      sound/soc/codecs/wm8991.c
  87. 1 1
      sound/soc/codecs/wm8993.c
  88. 12 11
      sound/soc/codecs/wm8994.c
  89. 8 12
      sound/soc/codecs/wm8995.c
  90. 5 3
      sound/soc/codecs/wm8996.c
  91. 7 4
      sound/soc/codecs/wm8997.c
  92. 1 1
      sound/soc/codecs/wm9081.c
  93. 1 1
      sound/soc/codecs/wm9090.c
  94. 10 6
      sound/soc/codecs/wm9705.c
  95. 8 4
      sound/soc/codecs/wm9712.c
  96. 9 5
      sound/soc/codecs/wm9713.c
  97. 3 3
      sound/soc/codecs/wm_adsp.c
  98. 5 5
      sound/soc/codecs/wm_hubs.c
  99. 1 2
      sound/soc/davinci/Kconfig
  100. 0 6
      sound/soc/davinci/davinci-evm.c

+ 18 - 0
Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt

@@ -0,0 +1,18 @@
+Bindings for I2S controller built into xtfpga Xtensa bitstreams.
+
+Required properties:
+- compatible: shall be "cdns,xtfpga-i2s".
+- reg: memory region (address and length) with device registers.
+- interrupts: interrupt for the device.
+- clocks: phandle to the clk used as master clock. I2S bus clock
+  is derived from it.
+
+Examples:
+
+	i2s0: xtfpga-i2s@0d080000 {
+		#sound-dai-cells = <0>;
+		compatible = "cdns,xtfpga-i2s";
+		reg = <0x0d080000 0x40>;
+		interrupts = <2 1>;
+		clocks = <&cdce706 4>;
+	};

+ 31 - 0
Documentation/devicetree/bindings/sound/designware-i2s.txt

@@ -0,0 +1,31 @@
+DesignWare I2S controller
+
+Required properties:
+ - compatible : Must be "snps,designware-i2s"
+ - reg : Must contain the I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's
+   clocks. The controller expects one clock: the clock used as the sampling
+   rate reference clock sample.
+ - clock-names : "i2sclk" for the sample rate reference clock.
+ - dmas: Pairs of phandle and specifier for the DMA channels that are used by
+   the core. The core expects one or two dma channels: one for transmit and
+   one for receive.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+
+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:
+
+	soc_i2s: i2s@7ff90000 {
+		compatible = "snps,designware-i2s";
+		reg = <0x0 0x7ff90000 0x0 0x1000>;
+		clocks = <&scpi_i2sclk 0>;
+		clock-names = "i2sclk";
+		#sound-dai-cells = <0>;
+		dmas = <&dma0 5>;
+		dma-names = "tx";
+	};

+ 67 - 0
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt

@@ -0,0 +1,67 @@
+NVIDIA Tegra audio complex, with RT5677 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-rt5677"
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  - pll_a
+  - pll_a_out0
+  - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the RT5677's pins (as documented in its binding), and the jacks
+  on the board:
+
+  * Headphone
+  * Speaker
+  * Headset Mic
+  * Internal Mic 1
+  * Internal Mic 2
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding
+  assumes that AIF1 on the CODEC is connected to Tegra.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
+- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier
+- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in
+- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-rt5677-ryu",
+	        "nvidia,tegra-audio-rt5677";
+	nvidia,model = "NVIDIA Tegra Ryu";
+
+	nvidia,audio-routing =
+		"Headphone", "LOUT2",
+		"Headphone", "LOUT1",
+		"Headset Mic", "MICBIAS1",
+		"IN1P", "Headset Mic",
+		"IN1N", "Headset Mic",
+		"DMIC L1", "Internal Mic 1",
+		"DMIC R1", "Internal Mic 1",
+		"DMIC L2", "Internal Mic 2",
+		"DMIC R2", "Internal Mic 2",
+		"Speaker", "PDM1L",
+		"Speaker", "PDM1R";
+
+	nvidia,i2s-controller = <&tegra_i2s1>;
+	nvidia,audio-codec = <&rt5677>;
+
+	nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>;
+	nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
+	nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>;
+	nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>;
+
+	clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
+	         <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
+	         <&tegra_car TEGRA124_CLK_EXTERN1>;
+	clock-names = "pll_a", "pll_a_out0", "mclk";
+};

+ 23 - 2
Documentation/devicetree/bindings/sound/pcm512x.txt

@@ -17,9 +17,16 @@ Required properties:
 Optional properties:
 
   - clocks : A clock specifier for the clock connected as SCLK.  If this
-    is absent the device will be configured to clock from BCLK.
+    is absent the device will be configured to clock from BCLK.  If pll-in
+    and pll-out are specified in addition to a clock, the device is
+    configured to accept clock input on a specified gpio pin.
 
-Example:
+  - pll-in, pll-out : gpio pins used to connect the pll using <1>
+    through <6>.  The device will be configured for clock input on the
+    given pll-in pin and PLL output on the given pll-out pin.  An
+    external connection from the pll-out pin to the SCLK pin is assumed.
+
+Examples:
 
 	pcm5122: pcm5122@4c {
 		compatible = "ti,pcm5122";
@@ -29,3 +36,17 @@ Example:
 		DVDD-supply = <&reg_1v8>;
 		CPVDD-supply = <&reg_3v3>;
 	};
+
+
+	pcm5142: pcm5142@4c {
+		compatible = "ti,pcm5142";
+		reg = <0x4c>;
+
+		AVDD-supply = <&reg_3v3_analog>;
+		DVDD-supply = <&reg_1v8>;
+		CPVDD-supply = <&reg_3v3>;
+
+		clocks = <&sck>;
+		pll-in = <3>;
+		pll-out = <6>;
+	};

+ 22 - 0
Documentation/devicetree/bindings/sound/samsung-i2s.txt

@@ -33,6 +33,25 @@ Required SoC Specific Properties:
   "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
   clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
   doesn't have any such mux.
+- #clock-cells: should be 1, this property must be present if the I2S device
+  is a clock provider in terms of the common clock bindings, described in
+  ../clock/clock-bindings.txt.
+- clock-output-names: from the common clock bindings, names of the CDCLK
+  I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
+  "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
+
+There are following clocks available at the I2S device nodes:
+ CLK_I2S_CDCLK    - the CDCLK (CODECLKO) gate clock,
+ CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
+		    IISPSR register),
+ CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
+		    IISMOD register).
+
+Refer to the SoC datasheet for availability of the above clocks.
+The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
+in the IIS Multi Audio Interface (I2S0).
+Note: Old DTs may not have the #clock-cells, clock-output-names properties
+and then not use the I2S node as a clock supplier.
 
 Optional SoC Specific Properties:
 
@@ -41,6 +60,7 @@ Optional SoC Specific Properties:
 - pinctrl-0: Should specify pin control groups used for this controller.
 - pinctrl-names: Should contain only one value - "default".
 
+
 Example:
 
 i2s0: i2s@03830000 {
@@ -54,6 +74,8 @@ i2s0: i2s@03830000 {
 		<&clock_audss EXYNOS_I2S_BUS>,
 		<&clock_audss EXYNOS_SCLK_I2S>;
 	clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+	#clock-cells;
+	clock-output-names = "i2s_cdclk0";
 	samsung,idma-addr = <0x03000000>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2s0_bus>;

+ 5 - 0
Documentation/devicetree/bindings/sound/simple-card.txt

@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties:
 					  it can be specified via "clocks" if system has
 					  clock node (= common clock), or "system-clock-frequency"
 					  (if system doens't support common clock)
+					  If a clock is specified, it is
+					  enabled with clk_prepare_enable()
+					  in dai startup() and disabled with
+					  clk_disable_unprepare() in dai
+					  shutdown().
 
 Example 1 - single DAI link:
 

+ 92 - 0
Documentation/devicetree/bindings/sound/st,sta32x.txt

@@ -0,0 +1,92 @@
+STA32X audio CODEC
+
+The driver for this device only supports I2C.
+
+Required properties:
+
+  - compatible: "st,sta32x"
+  - reg: the I2C address of the device for I2C
+  - reset-gpios: a GPIO spec for the reset pin. If specified, it will be
+		 deasserted before communication to the codec starts.
+
+  - power-down-gpios: a GPIO spec for the power down pin. If specified,
+		      it will be deasserted before communication to the codec
+		      starts.
+
+  - Vdda-supply: regulator spec, providing 3.3V
+  - Vdd3-supply: regulator spec, providing 3.3V
+  - Vcc-supply: regulator spec, providing 5V - 26V
+
+Optional properties:
+
+  -  st,output-conf: number, Selects the output configuration:
+	0: 2-channel (full-bridge) power, 2-channel data-out
+	1: 2 (half-bridge). 1 (full-bridge) on-board power
+	2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
+	3: 1 Channel Mono-Parallel
+	If parameter is missing, mode 0 will be enabled.
+	This property has to be specified as '/bits/ 8' value.
+
+  -  st,ch1-output-mapping: Channel 1 output mapping
+  -  st,ch2-output-mapping: Channel 2 output mapping
+  -  st,ch3-output-mapping: Channel 3 output mapping
+	0: Channel 1
+	1: Channel 2
+	2: Channel 3
+	If parameter is missing, channel 1 is chosen.
+	This properties have to be specified as '/bits/ 8' values.
+
+  -  st,thermal-warning-recover:
+	If present, thermal warning recovery is enabled.
+
+  -  st,thermal-warning-adjustment:
+	If present, thermal warning adjustment is enabled.
+
+  -  st,fault-detect-recovery:
+	If present, then fault recovery will be enabled.
+
+  -  st,drop-compensation-ns: number
+	Only required for "st,ffx-power-output-mode" ==
+	"variable-drop-compensation".
+	Specifies the drop compensation in nanoseconds.
+	The value must be in the range of 0..300, and only
+	multiples of 20 are allowed. Default is 140ns.
+
+  -  st,max-power-use-mpcc:
+	If present, then MPCC bits are used for MPC coefficients,
+	otherwise standard MPC coefficients are used.
+
+  -  st,max-power-corr:
+	If present, power bridge correction for THD reduction near maximum
+	power output is enabled.
+
+  -  st,am-reduction-mode:
+	If present, FFX mode runs in AM reduction mode, otherwise normal
+	FFX mode is used.
+
+  -  st,odd-pwm-speed-mode:
+	If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
+	channels. If not present, normal PWM spped mode (384 kHz) will be used.
+
+  -  st,invalid-input-detect-mute:
+	If present, automatic invalid input detect mute is enabled.
+
+Example:
+
+codec: sta32x@38 {
+	compatible = "st,sta32x";
+	reg = <0x1c>;
+	reset-gpios = <&gpio1 19 0>;
+	power-down-gpios = <&gpio1 16 0>;
+	st,output-conf = /bits/ 8  <0x3>;	// set output to 2-channel
+						// (full-bridge) power,
+						// 2-channel data-out
+	st,ch1-output-mapping = /bits/ 8 <0>;	// set channel 1 output ch 1
+	st,ch2-output-mapping = /bits/ 8 <0>;	// set channel 2 output ch 1
+	st,ch3-output-mapping = /bits/ 8 <0>;	// set channel 3 output ch 1
+	st,max-power-correction;		// enables power bridge
+						// correction for THD reduction
+						// near maximum power output
+	st,invalid-input-detect-mute;		// mute if no valid digital
+						// audio signal is provided.
+};

+ 9 - 1
Documentation/devicetree/bindings/sound/tlv320aic3x.txt

@@ -9,6 +9,7 @@ Required properties:
     "ti,tlv320aic33" - TLV320AIC33
     "ti,tlv320aic3007" - TLV320AIC3007
     "ti,tlv320aic3106" - TLV320AIC3106
+    "ti,tlv320aic3104" - TLV320AIC3104
 
 
 - reg - <int> -  I2C slave address
@@ -18,6 +19,7 @@ Optional properties:
 
 - gpio-reset - gpio pin number used for codec reset
 - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+				    - Not supported on tlv320aic3104
 - ai3x-micbias-vg - MicBias Voltage required.
 	1 - MICBIAS output is powered to 2.0V,
 	2 - MICBIAS output is powered to 2.5V,
@@ -36,7 +38,13 @@ CODEC output pins:
   * HPLCOM
   * HPRCOM
 
-CODEC input pins:
+CODEC input pins for TLV320AIC3104:
+  * MIC2L
+  * MIC2R
+  * LINE1L
+  * LINE1R
+
+CODEC input pins for other compatible codecs:
   * MIC3L
   * MIC3R
   * LINE1L

+ 5 - 0
Documentation/devicetree/bindings/sound/ts3a227e.txt

@@ -13,6 +13,11 @@ Required properties:
  - interrupt-parent:	The parent interrupt controller
  - interrupts:		Interrupt number for /INT pin from the 227e
 
+Optional properies:
+ - ti,micbias:   Intended MICBIAS voltage (datasheet section 9.6.7).
+      Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
+      2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
+      Default value is "1" (2.2V).
 
 Examples:
 

+ 1 - 1
Documentation/devicetree/bindings/sound/wm8904.txt

@@ -3,7 +3,7 @@ WM8904 audio CODEC
 This device supports I2C only.
 
 Required properties:
-  - compatible: "wlf,wm8904"
+  - compatible: "wlf,wm8904" or "wlf,wm8912"
   - reg: the I2C address of the device.
   - clock-names: "mclk"
   - clocks: reference to

+ 11 - 0
MAINTAINERS

@@ -4953,6 +4953,16 @@ F:	Documentation/input/multi-touch-protocol.txt
 F:	drivers/input/input-mt.c
 K:	\b(ABS|SYN)_MT_
 
+INTEL ASoC BDW/HSW DRIVERS
+M:	Jie Yang <yang.jie@linux.intel.com>
+L:	alsa-devel@alsa-project.org
+S:	Supported
+F:	sound/soc/intel/sst-haswell*
+F:	sound/soc/intel/sst-dsp*
+F:	sound/soc/intel/sst-firmware.c
+F:	sound/soc/intel/broadwell.c
+F:	sound/soc/intel/haswell.c
+
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:	Intel SCU Linux support <intel-linux-scu@intel.com>
 M:	Artur Paszkiewicz <artur.paszkiewicz@intel.com>
@@ -10659,6 +10669,7 @@ M:	Max Filippov <jcmvbkbc@gmail.com>
 L:	linux-xtensa@linux-xtensa.org
 S:	Maintained
 F:	drivers/spi/spi-xtensa-xtfpga.c
+F:	sound/soc/xtensa/xtfpga-i2s.c
 
 YAM DRIVER FOR AX.25
 M:	Jean-Paul Roubelat <jpr@f6fbb.org>

+ 8 - 0
include/dt-bindings/sound/samsung-i2s.h

@@ -0,0 +1,8 @@
+#ifndef _DT_BINDINGS_SAMSUNG_I2S_H
+#define _DT_BINDINGS_SAMSUNG_I2S_H
+
+#define CLK_I2S_CDCLK		0
+#define CLK_I2S_RCLK_SRC	1
+#define CLK_I2S_RCLK_PSR	2
+
+#endif /* _DT_BINDINGS_SAMSUNG_I2S_H */

+ 12 - 0
include/sound/pcm.h

@@ -273,6 +273,12 @@ struct snd_pcm_hw_constraint_list {
 	unsigned int mask;
 };
 
+struct snd_pcm_hw_constraint_ranges {
+	unsigned int count;
+	const struct snd_interval *ranges;
+	unsigned int mask;
+};
+
 struct snd_pcm_hwptr_log;
 
 struct snd_pcm_runtime {
@@ -907,6 +913,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
 			  const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
 		      const unsigned int *list, unsigned int mask);
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+			const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
 			unsigned int rats_count, struct snd_ratnum *rats,
 			unsigned int *nump, unsigned int *denp);
@@ -931,6 +939,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
 			       unsigned int cond,
 			       snd_pcm_hw_param_t var,
 			       const struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+				 unsigned int cond,
+				 snd_pcm_hw_param_t var,
+				 const struct snd_pcm_hw_constraint_ranges *r);
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
 				  unsigned int cond,
 				  snd_pcm_hw_param_t var,

+ 1 - 0
include/sound/rcar_snd.h

@@ -55,6 +55,7 @@ struct rsnd_ssi_platform_info {
 struct rsnd_src_platform_info {
 	u32 convert_rate; /* sampling rate convert */
 	int dma_id; /* for Gen2 SCU */
+	int irq;
 };
 
 /*

+ 3 - 0
include/sound/rt5677.h

@@ -37,6 +37,9 @@ struct rt5677_platform_data {
 		OFF, GPIO4, GPIO5 and GPIO6 respectively */
 	unsigned int jd2_gpio;
 	unsigned int jd3_gpio;
+
+	/* Set MICBIAS1 VDD 1v8 or 3v3 */
+	bool micbias1_vdd_3v3;
 };
 
 #endif

+ 1 - 0
include/sound/simple_card.h

@@ -20,6 +20,7 @@ struct asoc_simple_dai {
 	unsigned int sysclk;
 	int slots;
 	int slot_width;
+	struct clk *clk;
 };
 
 struct asoc_simple_card_info {

+ 1 - 2
include/sound/soc-dapm.h

@@ -405,7 +405,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
 		struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
-int snd_soc_dapm_sys_add(struct device *dev);
+extern struct attribute *soc_dapm_dev_attrs[];
 void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
 				struct dentry *parent);
 
@@ -525,7 +525,6 @@ struct snd_soc_dapm_widget {
 	enum snd_soc_dapm_type id;
 	const char *name;		/* widget name */
 	const char *sname;	/* stream name */
-	struct snd_soc_codec *codec;
 	struct list_head list;
 	struct snd_soc_dapm_context *dapm;
 

+ 4 - 0
include/sound/soc.h

@@ -429,6 +429,9 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
 void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
 void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
 
+int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
+	unsigned int dai_fmt);
+
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -498,6 +501,7 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
 				unsigned int mask, unsigned int value);
 
 #ifdef CONFIG_SND_SOC_AC97_BUS
+struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
 struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
 void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
 

+ 13 - 5
include/sound/sta32x.h

@@ -24,12 +24,20 @@
 #define STA32X_THERMAL_RECOVERY_ENABLE		2
 
 struct sta32x_platform_data {
-	int output_conf;
-	int ch1_output_mapping;
-	int ch2_output_mapping;
-	int ch3_output_mapping;
-	int thermal_conf;
+	u8 output_conf;
+	u8 ch1_output_mapping;
+	u8 ch2_output_mapping;
+	u8 ch3_output_mapping;
 	int needs_esd_watchdog;
+	u8 drop_compensation_ns;
+	unsigned int thermal_warning_recovery:1;
+	unsigned int thermal_warning_adjustment:1;
+	unsigned int fault_detect_recovery:1;
+	unsigned int max_power_use_mpcc:1;
+	unsigned int max_power_correction:1;
+	unsigned int am_reduction_mode:1;
+	unsigned int odd_pwm_speed_mode:1;
+	unsigned int invalid_input_detect_mute:1;
 };
 
 #endif /* __LINUX_SND__STA32X_H */

+ 85 - 0
sound/core/pcm_lib.c

@@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
+/**
+ * snd_interval_ranges - refine the interval value from the list of ranges
+ * @i: the interval value to refine
+ * @count: the number of elements in the list of ranges
+ * @ranges: the ranges list
+ * @mask: the bit-mask to evaluate
+ *
+ * Refines the interval value from the list of ranges.
+ * When mask is non-zero, only the elements corresponding to bit 1 are
+ * evaluated.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+			const struct snd_interval *ranges, unsigned int mask)
+{
+	unsigned int k;
+	struct snd_interval range_union;
+	struct snd_interval range;
+
+	if (!count) {
+		snd_interval_none(i);
+		return -EINVAL;
+	}
+	snd_interval_any(&range_union);
+	range_union.min = UINT_MAX;
+	range_union.max = 0;
+	for (k = 0; k < count; k++) {
+		if (mask && !(mask & (1 << k)))
+			continue;
+		snd_interval_copy(&range, &ranges[k]);
+		if (snd_interval_refine(&range, i) < 0)
+			continue;
+		if (snd_interval_empty(&range))
+			continue;
+
+		if (range.min < range_union.min) {
+			range_union.min = range.min;
+			range_union.openmin = 1;
+		}
+		if (range.min == range_union.min && !range.openmin)
+			range_union.openmin = 0;
+		if (range.max > range_union.max) {
+			range_union.max = range.max;
+			range_union.openmax = 1;
+		}
+		if (range.max == range_union.max && !range.openmax)
+			range_union.openmax = 0;
+	}
+	return snd_interval_refine(i, &range_union);
+}
+EXPORT_SYMBOL(snd_interval_ranges);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
 	unsigned int n;
@@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
 
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
+static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
+				  struct snd_pcm_hw_rule *rule)
+{
+	struct snd_pcm_hw_constraint_ranges *r = rule->private;
+	return snd_interval_ranges(hw_param_interval(params, rule->var),
+				   r->count, r->ranges, r->mask);
+}
+
+
+/**
+ * snd_pcm_hw_constraint_ranges - apply list of range constraints to a parameter
+ * @runtime: PCM runtime instance
+ * @cond: condition bits
+ * @var: hw_params variable to apply the list of range constraints
+ * @r: ranges
+ *
+ * Apply the list of range constraints to an interval parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+				 unsigned int cond,
+				 snd_pcm_hw_param_t var,
+				 const struct snd_pcm_hw_constraint_ranges *r)
+{
+	return snd_pcm_hw_rule_add(runtime, cond, var,
+				   snd_pcm_hw_rule_ranges, (void *)r,
+				   var, -1);
+}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
+
 static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
 				   struct snd_pcm_hw_rule *rule)
 {

+ 1 - 0
sound/soc/Kconfig

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

+ 1 - 0
sound/soc/Makefile

@@ -36,3 +36,4 @@ obj-$(CONFIG_SND_SOC)	+= spear/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
 obj-$(CONFIG_SND_SOC)	+= ux500/
+obj-$(CONFIG_SND_SOC)	+= xtensa/

+ 1 - 1
sound/soc/atmel/Kconfig

@@ -45,7 +45,7 @@ config SND_ATMEL_SOC_WM8904
 
 config SND_AT91_SOC_SAM9X5_WM8731
 	tristate "SoC Audio support for WM8731-based at91sam9x5 board"
-	depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5
+	depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
 	select SND_ATMEL_SOC_SSC
 	select SND_ATMEL_SOC_DMA
 	select SND_SOC_WM8731

+ 5 - 7
sound/soc/atmel/atmel-pcm-dma.c

@@ -105,13 +105,11 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config->dst_addr = ssc->phybase + SSC_THR;
-		slave_config->dst_maxburst = 1;
-	} else {
-		slave_config->src_addr = ssc->phybase + SSC_RHR;
-		slave_config->src_maxburst = 1;
-	}
+	slave_config->dst_addr = ssc->phybase + SSC_THR;
+	slave_config->dst_maxburst = 1;
+
+	slave_config->src_addr = ssc->phybase + SSC_RHR;
+	slave_config->src_maxburst = 1;
 
 	prtd->dma_intr_handler = atmel_pcm_dma_irq;
 

+ 78 - 54
sound/soc/atmel/atmel_ssc_dai.c

@@ -204,6 +204,13 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 	pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
 		ssc_readl(ssc_p->ssc->regs, SR));
 
+	/* Enable PMC peripheral clock for this SSC */
+	pr_debug("atmel_ssc_dai: Starting clock\n");
+	clk_enable(ssc_p->ssc->clk);
+
+	/* Reset the SSC to keep it at a clean status */
+	ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		dir = 0;
 		dir_mask = SSC_DIR_MASK_PLAYBACK;
@@ -250,11 +257,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 	dma_params = ssc_p->dma_params[dir];
 
 	if (dma_params != NULL) {
-		ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
-		pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n",
-			(dir ? "receive" : "transmit"),
-			ssc_readl(ssc_p->ssc->regs, SR));
-
 		dma_params->ssc = NULL;
 		dma_params->substream = NULL;
 		ssc_p->dma_params[dir] = NULL;
@@ -266,10 +268,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 	ssc_p->dir_mask &= ~dir_mask;
 	if (!ssc_p->dir_mask) {
 		if (ssc_p->initialized) {
-			/* Shutdown the SSC clock. */
-			pr_debug("atmel_ssc_dai: Stopping clock\n");
-			clk_disable(ssc_p->ssc->clk);
-
 			free_irq(ssc_p->ssc->irq, ssc_p);
 			ssc_p->initialized = 0;
 		}
@@ -280,6 +278,10 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 		ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
 	}
 	spin_unlock_irq(&ssc_p->lock);
+
+	/* Shutdown the SSC clock. */
+	pr_debug("atmel_ssc_dai: Stopping clock\n");
+	clk_disable(ssc_p->ssc->clk);
 }
 
 
@@ -348,7 +350,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 	struct atmel_pcm_dma_params *dma_params;
 	int dir, channels, bits;
 	u32 tfmr, rfmr, tcmr, rcmr;
-	int start_event;
 	int ret;
 	int fslen, fslen_ext;
 
@@ -451,25 +452,10 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		break;
 
 	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-		/*
-		 * I2S format, CODEC supplies BCLK and LRC clocks.
-		 *
-		 * The SSC transmit clock is obtained from the BCLK signal on
-		 * on the TK line, and the SSC receive clock is
-		 * generated from the transmit clock.
-		 *
-		 *  For single channel data, one sample is transferred
-		 * on the falling edge of the LRC clock.
-		 * For two channel data, one sample is
-		 * transferred on both edges of the LRC clock.
-		 */
-		start_event = ((channels == 1)
-				? SSC_START_FALLING_RF
-				: SSC_START_EDGE_RF);
-
+		/* I2S format, CODEC supplies BCLK and LRC clocks. */
 		rcmr =	  SSC_BF(RCMR_PERIOD, 0)
 			| SSC_BF(RCMR_STTDLY, START_DELAY)
-			| SSC_BF(RCMR_START, start_event)
+			| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
 			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
 			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
 			| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
@@ -478,14 +464,14 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		rfmr =	  SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
 			| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
 			| SSC_BF(RFMR_FSLEN, 0)
-			| SSC_BF(RFMR_DATNB, 0)
+			| SSC_BF(RFMR_DATNB, (channels - 1))
 			| SSC_BIT(RFMR_MSBF)
 			| SSC_BF(RFMR_LOOP, 0)
 			| SSC_BF(RFMR_DATLEN, (bits - 1));
 
 		tcmr =	  SSC_BF(TCMR_PERIOD, 0)
 			| SSC_BF(TCMR_STTDLY, START_DELAY)
-			| SSC_BF(TCMR_START, start_event)
+			| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
 			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
 			| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
 			| SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
@@ -495,7 +481,55 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 			| SSC_BF(TFMR_FSDEN, 0)
 			| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
 			| SSC_BF(TFMR_FSLEN, 0)
-			| SSC_BF(TFMR_DATNB, 0)
+			| SSC_BF(TFMR_DATNB, (channels - 1))
+			| SSC_BIT(TFMR_MSBF)
+			| SSC_BF(TFMR_DATDEF, 0)
+			| SSC_BF(TFMR_DATLEN, (bits - 1));
+		break;
+
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS:
+		/* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */
+		if (bits > 16 && !ssc->pdata->has_fslen_ext) {
+			dev_err(dai->dev,
+				"sample size %d is too large for SSC device\n",
+				bits);
+			return -EINVAL;
+		}
+
+		fslen_ext = (bits - 1) / 16;
+		fslen = (bits - 1) % 16;
+
+		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+			| SSC_BF(RCMR_STTDLY, START_DELAY)
+			| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
+			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+					   SSC_CKS_PIN : SSC_CKS_CLOCK);
+
+		rfmr =    SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
+			| SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
+			| SSC_BF(RFMR_FSLEN, fslen)
+			| SSC_BF(RFMR_DATNB, (channels - 1))
+			| SSC_BIT(RFMR_MSBF)
+			| SSC_BF(RFMR_LOOP, 0)
+			| SSC_BF(RFMR_DATLEN, (bits - 1));
+
+		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+			| SSC_BF(TCMR_STTDLY, START_DELAY)
+			| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
+			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+			| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
+					   SSC_CKS_CLOCK : SSC_CKS_PIN);
+
+		tfmr =    SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
+			| SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE)
+			| SSC_BF(TFMR_FSDEN, 0)
+			| SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
+			| SSC_BF(TFMR_FSLEN, fslen)
+			| SSC_BF(TFMR_DATNB, (channels - 1))
 			| SSC_BIT(TFMR_MSBF)
 			| SSC_BF(TFMR_DATDEF, 0)
 			| SSC_BF(TFMR_DATLEN, (bits - 1));
@@ -512,7 +546,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
 			| SSC_BF(RCMR_STTDLY, 1)
 			| SSC_BF(RCMR_START, SSC_START_RISING_RF)
-			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKI, SSC_CKI_FALLING)
 			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
 			| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
 
@@ -527,7 +561,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
 			| SSC_BF(TCMR_STTDLY, 1)
 			| SSC_BF(TCMR_START, SSC_START_RISING_RF)
-			| SSC_BF(TCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
 			| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
 			| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
 
@@ -545,10 +579,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		/*
 		 * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
 		 *
-		 * The SSC transmit clock is obtained from the BCLK signal on
-		 * on the TK line, and the SSC receive clock is
-		 * generated from the transmit clock.
-		 *
 		 * Data is transferred on first BCLK after LRC pulse rising
 		 * edge.If stereo, the right channel data is contiguous with
 		 * the left channel data.
@@ -556,7 +586,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		rcmr =	  SSC_BF(RCMR_PERIOD, 0)
 			| SSC_BF(RCMR_STTDLY, START_DELAY)
 			| SSC_BF(RCMR_START, SSC_START_RISING_RF)
-			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKI, SSC_CKI_FALLING)
 			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
 			| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
 					   SSC_CKS_PIN : SSC_CKS_CLOCK);
@@ -597,23 +627,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 			rcmr, rfmr, tcmr, tfmr);
 
 	if (!ssc_p->initialized) {
-
-		/* Enable PMC peripheral clock for this SSC */
-		pr_debug("atmel_ssc_dai: Starting clock\n");
-		clk_enable(ssc_p->ssc->clk);
-
-		/* Reset the SSC and its PDC registers */
-		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-		ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
-
-		ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+		if (!ssc_p->ssc->pdata->use_dma) {
+			ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+			ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+		}
 
 		ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
 				ssc_p->name, ssc_p);

+ 2 - 29
sound/soc/atmel/sam9g20_wm8731.c

@@ -47,7 +47,6 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 #include "../codecs/wm8731.h"
 #include "atmel-pcm.h"
@@ -64,33 +63,6 @@
 
 static struct clk *mclk;
 
-static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int ret;
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static struct snd_soc_ops at91sam9g20ek_ops = {
-	.hw_params = at91sam9g20ek_hw_params,
-};
-
 static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
 					struct snd_soc_dapm_context *dapm,
 					enum snd_soc_bias_level level)
@@ -173,7 +145,8 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
 	.init = at91sam9g20ek_wm8731_init,
 	.platform_name = "at91rm9200_ssc.0",
 	.codec_name = "wm8731.0-001b",
-	.ops = &at91sam9g20ek_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBM_CFM,
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {

+ 3 - 16
sound/soc/au1x/db1200.c

@@ -91,27 +91,12 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int ret;
 
 	/* WM8731 has its own 12MHz crystal */
 	snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
 				12000000, SND_SOC_CLOCK_IN);
 
-	/* codec is bitclock and lrclk master */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		goto out;
-
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J |
-			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		goto out;
-
-	ret = 0;
-out:
-	return ret;
+	return 0;
 }
 
 static struct snd_soc_ops db1200_i2s_wm8731_ops = {
@@ -125,6 +110,8 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
 	.cpu_dai_name	= "au1xpsc_i2s.1",
 	.platform_name	= "au1xpsc-pcm.1",
 	.codec_name	= "wm8731.0-001b",
+	.dai_fmt	= SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF |
+			  SND_SOC_DAIFMT_CBM_CFM,
 	.ops		= &db1200_i2s_wm8731_ops,
 };
 

+ 0 - 6
sound/soc/au1x/dbdma2.c

@@ -315,11 +315,6 @@ static struct snd_pcm_ops au1xpsc_pcm_ops = {
 	.pointer	= au1xpsc_pcm_pointer,
 };
 
-static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
@@ -335,7 +330,6 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver au1xpsc_soc_platform = {
 	.ops		= &au1xpsc_pcm_ops,
 	.pcm_new	= au1xpsc_pcm_new,
-	.pcm_free	= au1xpsc_pcm_free_dma_buffers,
 };
 
 static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)

+ 0 - 6
sound/soc/au1x/dma.c

@@ -287,11 +287,6 @@ static struct snd_pcm_ops alchemy_pcm_ops = {
 	.pointer		= alchemy_pcm_pointer,
 };
 
-static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_pcm *pcm = rtd->pcm;
@@ -305,7 +300,6 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
 	.ops		= &alchemy_pcm_ops,
 	.pcm_new	= alchemy_pcm_new,
-	.pcm_free	= alchemy_pcm_free_dma_buffers,
 };
 
 static int alchemy_pcm_drvprobe(struct platform_device *pdev)

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

@@ -386,7 +386,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	/*
 	 * In order to avoid current on the load, mute power-on and power-off
@@ -403,7 +403,7 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int dac = 0;
 	int data;
 

+ 4 - 2
sound/soc/codecs/Kconfig

@@ -525,7 +525,7 @@ config SND_SOC_RT5677
 
 config SND_SOC_RT5677_SPI
 	tristate
-	default SND_SOC_RT5677
+	default SND_SOC_RT5677 && SPI
 
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
@@ -580,7 +580,9 @@ config SND_SOC_SSM4567
 	depends on I2C
 
 config SND_SOC_STA32X
-	tristate
+	tristate "STA326, STA328 and STA329 speaker amplifier"
+	depends on I2C
+	select REGMAP_I2C
 
 config SND_SOC_STA350
 	tristate "STA350 speaker amplifier"

+ 2 - 2
sound/soc/codecs/ad193x.c

@@ -333,8 +333,8 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
 	regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
 	/* de-emphasis: 48kHz, powedown dac */
 	regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
-	/* powerdown dac, dac in tdm mode */
-	regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41);
+	/* dac in tdm mode */
+	regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40);
 	/* high-pass filter enable */
 	regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
 	/* sata delay=1, adc aux mode */

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

@@ -163,7 +163,7 @@ static const struct snd_kcontrol_new ak4671_snd_controls[] = {
 static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:

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

@@ -55,18 +55,20 @@ static inline int alc5623_reset(struct snd_soc_codec *codec)
 static int amp_mixer_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);
+
 	/* to power-on/off class-d amp generators/speaker */
 	/* need to write to 'index-46h' register :        */
 	/* so write index num (here 0x46) to reg 0x6a     */
 	/* and then 0xffff/0 to reg 0x6c                  */
-	snd_soc_write(w->codec, ALC5623_HID_CTRL_INDEX, 0x46);
+	snd_soc_write(codec, ALC5623_HID_CTRL_INDEX, 0x46);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
+		snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0);
+		snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0);
 		break;
 	}
 

+ 7 - 5
sound/soc/codecs/alc5632.c

@@ -116,18 +116,20 @@ static inline int alc5632_reset(struct regmap *map)
 static int amp_mixer_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);
+
 	/* to power-on/off class-d amp generators/speaker */
 	/* need to write to 'index-46h' register :        */
 	/* so write index num (here 0x46) to reg 0x6a     */
 	/* and then 0xffff/0 to reg 0x6c                  */
-	snd_soc_write(w->codec, ALC5632_HID_CTRL_INDEX, 0x46);
+	snd_soc_write(codec, ALC5632_HID_CTRL_INDEX, 0x46);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
+		snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0);
+		snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0);
 		break;
 	}
 
@@ -1066,7 +1068,7 @@ static int alc5632_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
+static const struct snd_soc_codec_driver soc_codec_device_alc5632 = {
 	.probe = alc5632_probe,
 	.resume = alc5632_resume,
 	.set_bias_level = alc5632_set_bias_level,
@@ -1080,7 +1082,7 @@ static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
 	.num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
 };
 
-static struct regmap_config alc5632_regmap = {
+static const struct regmap_config alc5632_regmap = {
 	.reg_bits = 8,
 	.val_bits = 16,
 

+ 69 - 9
sound/soc/codecs/arizona.c

@@ -84,7 +84,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	bool manual_ena = false;
@@ -692,7 +692,8 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		  int event)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	unsigned int reg;
 
 	if (w->shift % 2)
@@ -705,25 +706,25 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		priv->in_pending++;
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
+		snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
 
 		/* If this is the last input pending then allow VU */
 		priv->in_pending--;
 		if (priv->in_pending == 0) {
 			msleep(1);
-			arizona_in_set_vu(w->codec, 1);
+			arizona_in_set_vu(codec, 1);
 		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(w->codec, reg,
+		snd_soc_update_bits(codec, reg,
 				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
 				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Disable volume updates if no inputs are enabled */
-		reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
+		reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
 		if (reg == 0)
-			arizona_in_set_vu(w->codec, 0);
+			arizona_in_set_vu(codec, 0);
 	}
 
 	return 0;
@@ -734,7 +735,25 @@ int arizona_out_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);
+
 	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+			priv->out_up_pending++;
+			priv->out_up_delay += 17;
+			break;
+		default:
+			break;
+		}
+		break;
 	case SND_SOC_DAPM_POST_PMU:
 		switch (w->shift) {
 		case ARIZONA_OUT1L_ENA_SHIFT:
@@ -743,13 +762,50 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		case ARIZONA_OUT2R_ENA_SHIFT:
 		case ARIZONA_OUT3L_ENA_SHIFT:
 		case ARIZONA_OUT3R_ENA_SHIFT:
-			msleep(17);
+			priv->out_up_pending--;
+			if (!priv->out_up_pending) {
+				msleep(priv->out_up_delay);
+				priv->out_up_delay = 0;
+			}
 			break;
 
 		default:
 			break;
 		}
 		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+			priv->out_down_pending++;
+			priv->out_down_delay++;
+			break;
+		default:
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+			priv->out_down_pending--;
+			if (!priv->out_down_pending) {
+				msleep(priv->out_down_delay);
+				priv->out_down_delay = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
 	}
 
 	return 0;
@@ -760,7 +816,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
 	struct arizona *arizona = priv->arizona;
 	unsigned int mask = 1 << w->shift;
 	unsigned int val;
@@ -772,6 +829,9 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_PRE_PMD:
 		val = 0;
 		break;
+	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		return arizona_out_ev(w, kcontrol, event);
 	default:
 		return -EINVAL;
 	}

+ 5 - 0
sound/soc/codecs/arizona.h

@@ -77,6 +77,11 @@ struct arizona_priv {
 	int num_inputs;
 	unsigned int in_pending;
 
+	unsigned int out_up_pending;
+	unsigned int out_up_delay;
+	unsigned int out_down_pending;
+	unsigned int out_down_delay;
+
 	unsigned int spk_ena:2;
 	unsigned int spk_ena_pending:1;
 };

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

@@ -86,5 +86,5 @@ static struct platform_driver bt_sco_driver = {
 module_platform_driver(bt_sco_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver");
+MODULE_DESCRIPTION("ASoC generic bluetooth sco link driver");
 MODULE_LICENSE("GPL");

+ 2 - 2
sound/soc/codecs/cs35l32.c

@@ -264,7 +264,7 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
 			CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
 	.set_sysclk = cs35l32_codec_set_sysclk,
 
 	.dapm_widgets = cs35l32_dapm_widgets,
@@ -288,7 +288,7 @@ static const struct reg_default cs35l32_monitor_patch[] = {
 	{ 0x00, 0x00 },
 };
 
-static struct regmap_config cs35l32_regmap = {
+static const struct regmap_config cs35l32_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 

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

@@ -1103,7 +1103,7 @@ static int cs42l52_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
 	.probe = cs42l52_probe,
 	.remove = cs42l52_remove,
 	.set_bias_level = cs42l52_set_bias_level,
@@ -1130,7 +1130,7 @@ static const struct reg_default cs42l52_threshold_patch[] = {
 
 };
 
-static struct regmap_config cs42l52_regmap = {
+static const struct regmap_config cs42l52_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 

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

@@ -1164,7 +1164,7 @@ static int cs42l56_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
 	.probe = cs42l56_probe,
 	.remove = cs42l56_remove,
 	.set_bias_level = cs42l56_set_bias_level,
@@ -1179,7 +1179,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
 	.num_controls = ARRAY_SIZE(cs42l56_snd_controls),
 };
 
-static struct regmap_config cs42l56_regmap = {
+static const struct regmap_config cs42l56_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 

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

@@ -1347,7 +1347,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
 	.probe = cs42l73_probe,
 	.set_bias_level = cs42l73_set_bias_level,
 	.suspend_bias_off = true,
@@ -1361,7 +1361,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
 	.num_controls = ARRAY_SIZE(cs42l73_snd_controls),
 };
 
-static struct regmap_config cs42l73_regmap = {
+static const struct regmap_config cs42l73_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
 

+ 2 - 2
sound/soc/codecs/da732x.c

@@ -609,7 +609,7 @@ static const struct snd_kcontrol_new da732x_snd_controls[] = {
 static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -663,7 +663,7 @@ static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 static int da732x_out_pga_event(struct snd_soc_dapm_widget *w,
 				struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:

+ 5 - 5
sound/soc/codecs/mc13783.c

@@ -328,16 +328,16 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
 	}
 
 	switch (rx_mask) {
-	case 0xfffffffc:
+	case 0x03:
 		val |= SSI_NETWORK_DAC_RXSLOT_0_1;
 		break;
-	case 0xfffffff3:
+	case 0x0c:
 		val |= SSI_NETWORK_DAC_RXSLOT_2_3;
 		break;
-	case 0xffffffcf:
+	case 0x30:
 		val |= SSI_NETWORK_DAC_RXSLOT_4_5;
 		break;
-	case 0xffffff3f:
+	case 0xc0:
 		val |= SSI_NETWORK_DAC_RXSLOT_6_7;
 		break;
 	default:
@@ -360,7 +360,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
 	if (slots != 4)
 		return -EINVAL;
 
-	if (tx_mask != 0xfffffffc)
+	if (tx_mask != 0x3)
 		return -EINVAL;
 
 	val |= (0x00 << 2);	/* primary timeslot RX/TX(?) is 0 */

+ 2 - 2
sound/soc/codecs/pcm3008.c

@@ -32,7 +32,7 @@ static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
 	gpio_set_value_cansleep(setup->pdda_pin,
@@ -45,7 +45,7 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
 	gpio_set_value_cansleep(setup->pdad_pin,

+ 915 - 17
sound/soc/codecs/pcm512x.c

@@ -21,12 +21,19 @@
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gcd.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
 #include <sound/tlv.h>
 
 #include "pcm512x.h"
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+	({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#define DIV_ROUND_CLOSEST_ULL(ll, d) \
+	({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+
 #define PCM512x_NUM_SUPPLIES 3
 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
 	"AVDD",
@@ -39,6 +46,14 @@ struct pcm512x_priv {
 	struct clk *sclk;
 	struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
 	struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+	int fmt;
+	int pll_in;
+	int pll_out;
+	int pll_r;
+	int pll_j;
+	int pll_d;
+	int pll_p;
+	unsigned long real_pll;
 };
 
 /*
@@ -69,6 +84,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
 	{ PCM512x_MUTE,              0x00 },
 	{ PCM512x_DSP,               0x00 },
 	{ PCM512x_PLL_REF,           0x00 },
+	{ PCM512x_DAC_REF,           0x00 },
 	{ PCM512x_DAC_ROUTING,       0x11 },
 	{ PCM512x_DSP_PROGRAM,       0x01 },
 	{ PCM512x_CLKDET,            0x00 },
@@ -87,6 +103,25 @@ static const struct reg_default pcm512x_reg_defaults[] = {
 	{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
 	{ PCM512x_VCOM_CTRL_1,       0x00 },
 	{ PCM512x_VCOM_CTRL_2,       0x01 },
+	{ PCM512x_BCLK_LRCLK_CFG,    0x00 },
+	{ PCM512x_MASTER_MODE,       0x7c },
+	{ PCM512x_GPIO_DACIN,        0x00 },
+	{ PCM512x_GPIO_PLLIN,        0x00 },
+	{ PCM512x_SYNCHRONIZE,       0x10 },
+	{ PCM512x_PLL_COEFF_0,       0x00 },
+	{ PCM512x_PLL_COEFF_1,       0x00 },
+	{ PCM512x_PLL_COEFF_2,       0x00 },
+	{ PCM512x_PLL_COEFF_3,       0x00 },
+	{ PCM512x_PLL_COEFF_4,       0x00 },
+	{ PCM512x_DSP_CLKDIV,        0x00 },
+	{ PCM512x_DAC_CLKDIV,        0x00 },
+	{ PCM512x_NCP_CLKDIV,        0x00 },
+	{ PCM512x_OSR_CLKDIV,        0x00 },
+	{ PCM512x_MASTER_CLKDIV_1,   0x00 },
+	{ PCM512x_MASTER_CLKDIV_2,   0x00 },
+	{ PCM512x_FS_SPEED_MODE,     0x00 },
+	{ PCM512x_IDAC_1,            0x01 },
+	{ PCM512x_IDAC_2,            0x00 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -103,6 +138,10 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
 	case PCM512x_DSP_GPIO_INPUT:
 	case PCM512x_MASTER_MODE:
 	case PCM512x_PLL_REF:
+	case PCM512x_DAC_REF:
+	case PCM512x_GPIO_DACIN:
+	case PCM512x_GPIO_PLLIN:
+	case PCM512x_SYNCHRONIZE:
 	case PCM512x_PLL_COEFF_0:
 	case PCM512x_PLL_COEFF_1:
 	case PCM512x_PLL_COEFF_2:
@@ -143,6 +182,7 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
 	case PCM512x_RATE_DET_2:
 	case PCM512x_RATE_DET_3:
 	case PCM512x_RATE_DET_4:
+	case PCM512x_CLOCK_STATUS:
 	case PCM512x_ANALOG_MUTE_DET:
 	case PCM512x_GPIN:
 	case PCM512x_DIGITAL_MUTE_DET:
@@ -154,6 +194,8 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
 	case PCM512x_VCOM_CTRL_1:
 	case PCM512x_VCOM_CTRL_2:
 	case PCM512x_CRAM_CTRL:
+	case PCM512x_FLEX_A:
+	case PCM512x_FLEX_B:
 		return true;
 	default:
 		/* There are 256 raw register addresses */
@@ -170,6 +212,7 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
 	case PCM512x_RATE_DET_2:
 	case PCM512x_RATE_DET_3:
 	case PCM512x_RATE_DET_4:
+	case PCM512x_CLOCK_STATUS:
 	case PCM512x_ANALOG_MUTE_DET:
 	case PCM512x_GPIN:
 	case PCM512x_DIGITAL_MUTE_DET:
@@ -277,7 +320,7 @@ SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r),
 SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3,
 	   PCM512x_ACTL_SHIFT, 1, 0),
 SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
-	   PCM512x_AMLR_SHIFT, 1, 0),
+	   PCM512x_AMRE_SHIFT, 1, 0),
 
 SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf),
 SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds),
@@ -303,6 +346,136 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
 	{ "OUTR", NULL, "DACR" },
 };
 
+static const u32 pcm512x_dai_rates[] = {
+	8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+	88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+	.count = ARRAY_SIZE(pcm512x_dai_rates),
+	.list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
+				struct snd_pcm_hw_rule *rule)
+{
+	struct snd_interval ranges[2];
+	int frame_size;
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0)
+		return frame_size;
+
+	switch (frame_size) {
+	case 32:
+		/* No hole when the frame size is 32. */
+		return 0;
+	case 48:
+	case 64:
+		/* There is only one hole in the range of supported
+		 * rates, but it moves with the frame size.
+		 */
+		memset(ranges, 0, sizeof(ranges));
+		ranges[0].min = 8000;
+		ranges[0].max = 25000000 / frame_size / 2;
+		ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
+		ranges[1].max = 384000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_interval_ranges(hw_param_interval(params, rule->var),
+				   ARRAY_SIZE(ranges), ranges, 0);
+}
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct device *dev = dai->dev;
+	struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+	struct snd_ratnum *rats_no_pll;
+
+	if (IS_ERR(pcm512x->sclk)) {
+		dev_err(dev, "Need SCLK for master mode: %ld\n",
+			PTR_ERR(pcm512x->sclk));
+		return PTR_ERR(pcm512x->sclk);
+	}
+
+	if (pcm512x->pll_out)
+		return snd_pcm_hw_rule_add(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_RATE,
+					   pcm512x_hw_rule_rate,
+					   NULL,
+					   SNDRV_PCM_HW_PARAM_FRAME_BITS,
+					   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+	constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+					  GFP_KERNEL);
+	if (!constraints_no_pll)
+		return -ENOMEM;
+	constraints_no_pll->nrats = 1;
+	rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+	if (!rats_no_pll)
+		return -ENOMEM;
+	constraints_no_pll->rats = rats_no_pll;
+	rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
+	rats_no_pll->den_min = 1;
+	rats_no_pll->den_max = 128;
+	rats_no_pll->den_step = 1;
+
+	return snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+					     SNDRV_PCM_HW_PARAM_RATE,
+					     constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct device *dev = dai->dev;
+	struct regmap *regmap = pcm512x->regmap;
+
+	if (IS_ERR(pcm512x->sclk)) {
+		dev_info(dev, "No SCLK, using BCLK: %ld\n",
+			 PTR_ERR(pcm512x->sclk));
+
+		/* Disable reporting of missing SCLK as an error */
+		regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
+				   PCM512x_IDCH, PCM512x_IDCH);
+
+		/* Switch PLL input to BCLK */
+		regmap_update_bits(regmap, PCM512x_PLL_REF,
+				   PCM512x_SREF, PCM512x_SREF_BCK);
+	}
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &constraints_slave);
+}
+
+static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+	switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+		return pcm512x_dai_startup_master(substream, dai);
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		return pcm512x_dai_startup_slave(substream, dai);
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
 				  enum snd_soc_bias_level level)
 {
@@ -340,17 +513,717 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
+static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
+				      unsigned long bclk_rate)
+{
+	struct device *dev = dai->dev;
+	unsigned long sck_rate;
+	int pow2;
+
+	/* 64 MHz <= pll_rate <= 100 MHz, VREF mode */
+	/* 16 MHz <= sck_rate <=  25 MHz, VREF mode */
+
+	/* select sck_rate as a multiple of bclk_rate but still with
+	 * as many factors of 2 as possible, as that makes it easier
+	 * to find a fast DAC rate
+	 */
+	pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
+	for (; pow2; pow2 >>= 1) {
+		sck_rate = rounddown(25000000, bclk_rate * pow2);
+		if (sck_rate >= 16000000)
+			break;
+	}
+	if (!pow2) {
+		dev_err(dev, "Impossible to generate a suitable SCK\n");
+		return 0;
+	}
+
+	dev_dbg(dev, "sck_rate %lu\n", sck_rate);
+	return sck_rate;
+}
+
+/* pll_rate = pllin_rate * R * J.D / P
+ * 1 <= R <= 16
+ * 1 <= J <= 63
+ * 0 <= D <= 9999
+ * 1 <= P <= 15
+ * 64 MHz <= pll_rate <= 100 MHz
+ * if D == 0
+ *     1 MHz <= pllin_rate / P <= 20 MHz
+ * else if D > 0
+ *     6.667 MHz <= pllin_rate / P <= 20 MHz
+ *     4 <= J <= 11
+ *     R = 1
+ */
+static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai,
+				  unsigned long pllin_rate,
+				  unsigned long pll_rate)
+{
+	struct device *dev = dai->dev;
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	unsigned long common;
+	int R, J, D, P;
+	unsigned long K; /* 10000 * J.D */
+	unsigned long num;
+	unsigned long den;
+
+	common = gcd(pll_rate, pllin_rate);
+	dev_dbg(dev, "pll %lu pllin %lu common %lu\n",
+		pll_rate, pllin_rate, common);
+	num = pll_rate / common;
+	den = pllin_rate / common;
+
+	/* pllin_rate / P (or here, den) cannot be greater than 20 MHz */
+	if (pllin_rate / den > 20000000 && num < 8) {
+		num *= 20000000 / (pllin_rate / den);
+		den *= 20000000 / (pllin_rate / den);
+	}
+	dev_dbg(dev, "num / den = %lu / %lu\n", num, den);
+
+	P = den;
+	if (den <= 15 && num <= 16 * 63
+	    && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) {
+		/* Try the case with D = 0 */
+		D = 0;
+		/* factor 'num' into J and R, such that R <= 16 and J <= 63 */
+		for (R = 16; R; R--) {
+			if (num % R)
+				continue;
+			J = num / R;
+			if (J == 0 || J > 63)
+				continue;
+
+			dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P);
+			pcm512x->real_pll = pll_rate;
+			goto done;
+		}
+		/* no luck */
+	}
+
+	R = 1;
+
+	if (num > 0xffffffffUL / 10000)
+		goto fallback;
+
+	/* Try to find an exact pll_rate using the D > 0 case */
+	common = gcd(10000 * num, den);
+	num = 10000 * num / common;
+	den /= common;
+	dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common);
+
+	for (P = den; P <= 15; P++) {
+		if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P)
+			continue;
+		if (num * P % den)
+			continue;
+		K = num * P / den;
+		/* J == 12 is ok if D == 0 */
+		if (K < 40000 || K > 120000)
+			continue;
+
+		J = K / 10000;
+		D = K % 10000;
+		dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P);
+		pcm512x->real_pll = pll_rate;
+		goto done;
+	}
+
+	/* Fall back to an approximate pll_rate */
+
+fallback:
+	/* find smallest possible P */
+	P = DIV_ROUND_UP(pllin_rate, 20000000);
+	if (!P)
+		P = 1;
+	else if (P > 15) {
+		dev_err(dev, "Need a slower clock as pll-input\n");
+		return -EINVAL;
+	}
+	if (pllin_rate / P < 6667000) {
+		dev_err(dev, "Need a faster clock as pll-input\n");
+		return -EINVAL;
+	}
+	K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate);
+	if (K < 40000)
+		K = 40000;
+	/* J == 12 is ok if D == 0 */
+	if (K > 120000)
+		K = 120000;
+	J = K / 10000;
+	D = K % 10000;
+	dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P);
+	pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P);
+
+done:
+	pcm512x->pll_r = R;
+	pcm512x->pll_j = J;
+	pcm512x->pll_d = D;
+	pcm512x->pll_p = P;
+	return 0;
+}
+
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+					    unsigned long osr_rate,
+					    unsigned long pllin_rate)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	unsigned long dac_rate;
+
+	if (!pcm512x->pll_out)
+		return 0; /* no PLL to bypass, force SCK as DAC input */
+
+	if (pllin_rate % osr_rate)
+		return 0; /* futile, quit early */
+
+	/* run DAC no faster than 6144000 Hz */
+	for (dac_rate = rounddown(6144000, osr_rate);
+	     dac_rate;
+	     dac_rate -= osr_rate) {
+
+		if (pllin_rate / dac_rate > 128)
+			return 0; /* DAC divider would be too big */
+
+		if (!(pllin_rate % dac_rate))
+			return dac_rate;
+
+		dac_rate -= osr_rate;
+	}
+
+	return 0;
+}
+
+static int pcm512x_set_dividers(struct snd_soc_dai *dai,
+				struct snd_pcm_hw_params *params)
+{
+	struct device *dev = dai->dev;
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	unsigned long pllin_rate = 0;
+	unsigned long pll_rate;
+	unsigned long sck_rate;
+	unsigned long mck_rate;
+	unsigned long bclk_rate;
+	unsigned long sample_rate;
+	unsigned long osr_rate;
+	unsigned long dacsrc_rate;
+	int bclk_div;
+	int lrclk_div;
+	int dsp_div;
+	int dac_div;
+	unsigned long dac_rate;
+	int ncp_div;
+	int osr_div;
+	int ret;
+	int idac;
+	int fssp;
+	int gpio;
+
+	lrclk_div = snd_soc_params_to_frame_size(params);
+	if (lrclk_div == 0) {
+		dev_err(dev, "No LRCLK?\n");
+		return -EINVAL;
+	}
+
+	if (!pcm512x->pll_out) {
+		sck_rate = clk_get_rate(pcm512x->sclk);
+		bclk_div = params->rate_den * 64 / lrclk_div;
+		bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div);
+
+		mck_rate = sck_rate;
+	} else {
+		ret = snd_soc_params_to_bclk(params);
+		if (ret < 0) {
+			dev_err(dev, "Failed to find suitable BCLK: %d\n", ret);
+			return ret;
+		}
+		if (ret == 0) {
+			dev_err(dev, "No BCLK?\n");
+			return -EINVAL;
+		}
+		bclk_rate = ret;
+
+		pllin_rate = clk_get_rate(pcm512x->sclk);
+
+		sck_rate = pcm512x_find_sck(dai, bclk_rate);
+		if (!sck_rate)
+			return -EINVAL;
+		pll_rate = 4 * sck_rate;
+
+		ret = pcm512x_find_pll_coeff(dai, pllin_rate, pll_rate);
+		if (ret != 0)
+			return ret;
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_0, pcm512x->pll_p - 1);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL P: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_1, pcm512x->pll_j);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL J: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_2, pcm512x->pll_d >> 8);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL D msb: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_3, pcm512x->pll_d & 0xff);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL D lsb: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_4, pcm512x->pll_r - 1);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL R: %d\n", ret);
+			return ret;
+		}
+
+		mck_rate = pcm512x->real_pll;
+
+		bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate);
+	}
+
+	if (bclk_div > 128) {
+		dev_err(dev, "Failed to find BCLK divider\n");
+		return -EINVAL;
+	}
+
+	/* the actual rate */
+	sample_rate = sck_rate / bclk_div / lrclk_div;
+	osr_rate = 16 * sample_rate;
+
+	/* run DSP no faster than 50 MHz */
+	dsp_div = mck_rate > 50000000 ? 2 : 1;
+
+	dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+	if (dac_rate) {
+		/* the desired clock rate is "compatible" with the pll input
+		 * clock, so use that clock as dac input instead of the pll
+		 * output clock since the pll will introduce jitter and thus
+		 * noise.
+		 */
+		dev_dbg(dev, "using pll input as dac input\n");
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+					 PCM512x_SDAC, PCM512x_SDAC_GPIO);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to set gpio as dacref: %d\n", ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN,
+					 PCM512x_GREF, gpio);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to set gpio %d as dacin: %d\n",
+				pcm512x->pll_in, ret);
+			return ret;
+		}
+
+		dacsrc_rate = pllin_rate;
+	} else {
+		/* run DAC no faster than 6144000 Hz */
+		unsigned long dac_mul = 6144000 / osr_rate;
+		unsigned long sck_mul = sck_rate / osr_rate;
+
+		for (; dac_mul; dac_mul--) {
+			if (!(sck_mul % dac_mul))
+				break;
+		}
+		if (!dac_mul) {
+			dev_err(dev, "Failed to find DAC rate\n");
+			return -EINVAL;
+		}
+
+		dac_rate = dac_mul * osr_rate;
+		dev_dbg(dev, "dac_rate %lu sample_rate %lu\n",
+			dac_rate, sample_rate);
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+					 PCM512x_SDAC, PCM512x_SDAC_SCK);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to set sck as dacref: %d\n", ret);
+			return ret;
+		}
+
+		dacsrc_rate = sck_rate;
+	}
+
+	dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
+	if (dac_div > 128) {
+		dev_err(dev, "Failed to find DAC divider\n");
+		return -EINVAL;
+	}
+
+	ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
+	if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
+		/* run NCP no faster than 2048000 Hz, but why? */
+		ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+		if (ncp_div > 128) {
+			dev_err(dev, "Failed to find NCP divider\n");
+			return -EINVAL;
+		}
+	}
+
+	osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+	if (osr_div > 128) {
+		dev_err(dev, "Failed to find OSR divider\n");
+		return -EINVAL;
+	}
+
+	idac = mck_rate / (dsp_div * sample_rate);
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write DSP divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write DAC divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write NCP divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write OSR divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap,
+			   PCM512x_MASTER_CLKDIV_1, bclk_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write BCLK divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap,
+			   PCM512x_MASTER_CLKDIV_2, lrclk_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write LRCLK divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret);
+		return ret;
+	}
+
+	if (sample_rate <= 48000)
+		fssp = PCM512x_FSSP_48KHZ;
+	else if (sample_rate <= 96000)
+		fssp = PCM512x_FSSP_96KHZ;
+	else if (sample_rate <= 192000)
+		fssp = PCM512x_FSSP_192KHZ;
+	else
+		fssp = PCM512x_FSSP_384KHZ;
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE,
+				 PCM512x_FSSP, fssp);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set fs speed: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "DSP divider %d\n", dsp_div);
+	dev_dbg(codec->dev, "DAC divider %d\n", dac_div);
+	dev_dbg(codec->dev, "NCP divider %d\n", ncp_div);
+	dev_dbg(codec->dev, "OSR divider %d\n", osr_div);
+	dev_dbg(codec->dev, "BCK divider %d\n", bclk_div);
+	dev_dbg(codec->dev, "LRCK divider %d\n", lrclk_div);
+	dev_dbg(codec->dev, "IDAC %d\n", idac);
+	dev_dbg(codec->dev, "1<<FSSP %d\n", 1 << fssp);
+
+	return 0;
+}
+
+static int pcm512x_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	int alen;
+	int gpio;
+	int clock_output;
+	int master_mode;
+	int ret;
+
+	dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n",
+		params_rate(params),
+		params_channels(params));
+
+	switch (snd_pcm_format_width(params_format(params))) {
+	case 16:
+		alen = PCM512x_ALEN_16;
+		break;
+	case 20:
+		alen = PCM512x_ALEN_20;
+		break;
+	case 24:
+		alen = PCM512x_ALEN_24;
+		break;
+	case 32:
+		alen = PCM512x_ALEN_32;
+		break;
+	default:
+		dev_err(codec->dev, "Bad frame size: %d\n",
+			snd_pcm_format_width(params_format(params)));
+		return -EINVAL;
+	}
+
+	switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ret = regmap_update_bits(pcm512x->regmap,
+					 PCM512x_BCLK_LRCLK_CFG,
+					 PCM512x_BCKP
+					 | PCM512x_BCKO | PCM512x_LRKO,
+					 0);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to enable slave mode: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+					 PCM512x_DCAS, 0);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to enable clock divider autoset: %d\n",
+				ret);
+			return ret;
+		}
+		return 0;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clock_output = PCM512x_BCKO | PCM512x_LRKO;
+		master_mode = PCM512x_RLRK | PCM512x_RBCK;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		clock_output = PCM512x_BCKO;
+		master_mode = PCM512x_RBCK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+				 PCM512x_ALEN, alen);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set frame size: %d\n", ret);
+		return ret;
+	}
+
+	if (pcm512x->pll_out) {
+		ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to set FLEX_A: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to set FLEX_B: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_IDCM | PCM512x_DCAS
+					 | PCM512x_IPLK,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_DCAS);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to ignore auto-clock failures: %d\n",
+				ret);
+			return ret;
+		}
+	} else {
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_IDCM | PCM512x_DCAS
+					 | PCM512x_IPLK,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_DCAS | PCM512x_IPLK);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to ignore auto-clock failures: %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+					 PCM512x_PLLE, 0);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to disable pll: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = pcm512x_set_dividers(dai, params);
+	if (ret != 0)
+		return ret;
+
+	if (pcm512x->pll_out) {
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
+					 PCM512x_SREF, PCM512x_SREF_GPIO);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to set gpio as pllref: %d\n", ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN,
+					 PCM512x_GREF, gpio);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to set gpio %d as pllin: %d\n",
+				pcm512x->pll_in, ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+					 PCM512x_PLLE, PCM512x_PLLE);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to enable pll: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+				 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+				 clock_output);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to enable clock output: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+				 PCM512x_RLRK | PCM512x_RBCK,
+				 master_mode);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to enable master mode: %d\n", ret);
+		return ret;
+	}
+
+	if (pcm512x->pll_out) {
+		gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+					 gpio, gpio);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+				pcm512x->pll_out, ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1;
+		ret = regmap_update_bits(pcm512x->regmap, gpio,
+					 PCM512x_GxSL, PCM512x_GxSL_PLLCK);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to output pll on %d: %d\n",
+				ret, pcm512x->pll_out);
+			return ret;
+		}
+
+		gpio = PCM512x_G1OE << (4 - 1);
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+					 gpio, gpio);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+				4, ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1;
+		ret = regmap_update_bits(pcm512x->regmap, gpio,
+					 PCM512x_GxSL, PCM512x_GxSL_PLLLK);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to output pll lock on %d: %d\n",
+				ret, 4);
+			return ret;
+		}
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+				 PCM512x_RQSY, PCM512x_RQSY_HALT);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to halt clocks: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+				 PCM512x_RQSY, PCM512x_RQSY_RESUME);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to resume clocks: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+	pcm512x->fmt = fmt;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm512x_dai_ops = {
+	.startup = pcm512x_dai_startup,
+	.hw_params = pcm512x_hw_params,
+	.set_fmt = pcm512x_set_fmt,
+};
+
 static struct snd_soc_dai_driver pcm512x_dai = {
 	.name = "pcm512x-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_8000_192000,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 8000,
+		.rate_max = 384000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			   SNDRV_PCM_FMTBIT_S24_LE |
 			   SNDRV_PCM_FMTBIT_S32_LE
 	},
+	.ops = &pcm512x_dai_ops,
 };
 
 static struct snd_soc_codec_driver pcm512x_codec_driver = {
@@ -448,21 +1321,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
 	}
 
 	pcm512x->sclk = devm_clk_get(dev, NULL);
-	if (IS_ERR(pcm512x->sclk)) {
-		if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		dev_info(dev, "No SCLK, using BCLK: %ld\n",
-			 PTR_ERR(pcm512x->sclk));
-
-		/* Disable reporting of missing SCLK as an error */
-		regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
-				   PCM512x_IDCH, PCM512x_IDCH);
-
-		/* Switch PLL input to BCLK */
-		regmap_update_bits(regmap, PCM512x_PLL_REF,
-				   PCM512x_SREF, PCM512x_SREF);
-	} else {
+	if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (!IS_ERR(pcm512x->sclk)) {
 		ret = clk_prepare_enable(pcm512x->sclk);
 		if (ret != 0) {
 			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
@@ -483,6 +1344,43 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
 	pm_runtime_enable(dev);
 	pm_runtime_idle(dev);
 
+#ifdef CONFIG_OF
+	if (dev->of_node) {
+		const struct device_node *np = dev->of_node;
+		u32 val;
+
+		if (of_property_read_u32(np, "pll-in", &val) >= 0) {
+			if (val > 6) {
+				dev_err(dev, "Invalid pll-in\n");
+				ret = -EINVAL;
+				goto err_clk;
+			}
+			pcm512x->pll_in = val;
+		}
+
+		if (of_property_read_u32(np, "pll-out", &val) >= 0) {
+			if (val > 6) {
+				dev_err(dev, "Invalid pll-out\n");
+				ret = -EINVAL;
+				goto err_clk;
+			}
+			pcm512x->pll_out = val;
+		}
+
+		if (!pcm512x->pll_in != !pcm512x->pll_out) {
+			dev_err(dev,
+				"Error: both pll-in and pll-out, or none\n");
+			ret = -EINVAL;
+			goto err_clk;
+		}
+		if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) {
+			dev_err(dev, "Error: pll-in == pll-out\n");
+			ret = -EINVAL;
+			goto err_clk;
+		}
+	}
+#endif
+
 	ret = snd_soc_register_codec(dev, &pcm512x_codec_driver,
 				    &pcm512x_dai, 1);
 	if (ret != 0) {

+ 104 - 5
sound/soc/codecs/pcm512x.h

@@ -37,6 +37,10 @@
 #define PCM512x_DSP_GPIO_INPUT    (PCM512x_PAGE_BASE(0) +  10)
 #define PCM512x_MASTER_MODE       (PCM512x_PAGE_BASE(0) +  12)
 #define PCM512x_PLL_REF           (PCM512x_PAGE_BASE(0) +  13)
+#define PCM512x_DAC_REF           (PCM512x_PAGE_BASE(0) +  14)
+#define PCM512x_GPIO_DACIN        (PCM512x_PAGE_BASE(0) +  16)
+#define PCM512x_GPIO_PLLIN        (PCM512x_PAGE_BASE(0) +  18)
+#define PCM512x_SYNCHRONIZE       (PCM512x_PAGE_BASE(0) +  19)
 #define PCM512x_PLL_COEFF_0       (PCM512x_PAGE_BASE(0) +  20)
 #define PCM512x_PLL_COEFF_1       (PCM512x_PAGE_BASE(0) +  21)
 #define PCM512x_PLL_COEFF_2       (PCM512x_PAGE_BASE(0) +  22)
@@ -77,6 +81,7 @@
 #define PCM512x_RATE_DET_2        (PCM512x_PAGE_BASE(0) +  92)
 #define PCM512x_RATE_DET_3        (PCM512x_PAGE_BASE(0) +  93)
 #define PCM512x_RATE_DET_4        (PCM512x_PAGE_BASE(0) +  94)
+#define PCM512x_CLOCK_STATUS      (PCM512x_PAGE_BASE(0) +  95)
 #define PCM512x_ANALOG_MUTE_DET   (PCM512x_PAGE_BASE(0) + 108)
 #define PCM512x_GPIN              (PCM512x_PAGE_BASE(0) + 119)
 #define PCM512x_DIGITAL_MUTE_DET  (PCM512x_PAGE_BASE(0) + 120)
@@ -91,7 +96,10 @@
 
 #define PCM512x_CRAM_CTRL         (PCM512x_PAGE_BASE(44) +  1)
 
-#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(44) +  1)
+#define PCM512x_FLEX_A            (PCM512x_PAGE_BASE(253) + 63)
+#define PCM512x_FLEX_B            (PCM512x_PAGE_BASE(253) + 64)
+
+#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(253) + 64)
 
 /* Page 0, Register 1 - reset */
 #define PCM512x_RSTR (1 << 0)
@@ -108,8 +116,8 @@
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
-#define PCM512x_PLCE       (1 << 0)
-#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLLE       (1 << 0)
+#define PCM512x_PLLE_SHIFT 0
 #define PCM512x_PLCK       (1 << 4)
 #define PCM512x_PLCK_SHIFT 4
 
@@ -119,8 +127,66 @@
 #define PCM512x_DEMP       (1 << 4)
 #define PCM512x_DEMP_SHIFT 4
 
+/* Page 0, Register 8 - GPIO output enable */
+#define PCM512x_G1OE       (1 << 0)
+#define PCM512x_G2OE       (1 << 1)
+#define PCM512x_G3OE       (1 << 2)
+#define PCM512x_G4OE       (1 << 3)
+#define PCM512x_G5OE       (1 << 4)
+#define PCM512x_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define PCM512x_LRKO       (1 << 0)
+#define PCM512x_LRKO_SHIFT 0
+#define PCM512x_BCKO       (1 << 4)
+#define PCM512x_BCKO_SHIFT 4
+#define PCM512x_BCKP       (1 << 5)
+#define PCM512x_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define PCM512x_RLRK       (1 << 0)
+#define PCM512x_RLRK_SHIFT 0
+#define PCM512x_RBCK       (1 << 1)
+#define PCM512x_RBCK_SHIFT 1
+
 /* Page 0, Register 13 - PLL reference */
-#define PCM512x_SREF (1 << 4)
+#define PCM512x_SREF        (7 << 4)
+#define PCM512x_SREF_SHIFT  4
+#define PCM512x_SREF_SCK    (0 << 4)
+#define PCM512x_SREF_BCK    (1 << 4)
+#define PCM512x_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define PCM512x_SDAC        (7 << 4)
+#define PCM512x_SDAC_SHIFT  4
+#define PCM512x_SDAC_MCK    (0 << 4)
+#define PCM512x_SDAC_PLL    (1 << 4)
+#define PCM512x_SDAC_SCK    (3 << 4)
+#define PCM512x_SDAC_BCK    (4 << 4)
+#define PCM512x_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define PCM512x_GREF        (7 << 0)
+#define PCM512x_GREF_SHIFT  0
+#define PCM512x_GREF_GPIO1  (0 << 0)
+#define PCM512x_GREF_GPIO2  (1 << 0)
+#define PCM512x_GREF_GPIO3  (2 << 0)
+#define PCM512x_GREF_GPIO4  (3 << 0)
+#define PCM512x_GREF_GPIO5  (4 << 0)
+#define PCM512x_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define PCM512x_RQSY        (1 << 0)
+#define PCM512x_RQSY_RESUME (0 << 0)
+#define PCM512x_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define PCM512x_FSSP        (3 << 0)
+#define PCM512x_FSSP_SHIFT  0
+#define PCM512x_FSSP_48KHZ  (0 << 0)
+#define PCM512x_FSSP_96KHZ  (1 << 0)
+#define PCM512x_FSSP_192KHZ (2 << 0)
+#define PCM512x_FSSP_384KHZ (3 << 0)
 
 /* Page 0, Register 37 - Error detection */
 #define PCM512x_IPLK (1 << 0)
@@ -131,6 +197,20 @@
 #define PCM512x_IDBK (1 << 5)
 #define PCM512x_IDFS (1 << 6)
 
+/* Page 0, Register 40 - I2S configuration */
+#define PCM512x_ALEN       (3 << 0)
+#define PCM512x_ALEN_SHIFT 0
+#define PCM512x_ALEN_16    (0 << 0)
+#define PCM512x_ALEN_20    (1 << 0)
+#define PCM512x_ALEN_24    (2 << 0)
+#define PCM512x_ALEN_32    (3 << 0)
+#define PCM512x_AFMT       (3 << 4)
+#define PCM512x_AFMT_SHIFT 4
+#define PCM512x_AFMT_I2S   (0 << 4)
+#define PCM512x_AFMT_DSP   (1 << 4)
+#define PCM512x_AFMT_RTJ   (2 << 4)
+#define PCM512x_AFMT_LTJ   (3 << 4)
+
 /* Page 0, Register 42 - DAC routing */
 #define PCM512x_AUPR_SHIFT 0
 #define PCM512x_AUPL_SHIFT 4
@@ -152,7 +232,26 @@
 /* Page 0, Register 65 - Digital mute enables */
 #define PCM512x_ACTL_SHIFT 2
 #define PCM512x_AMLE_SHIFT 1
-#define PCM512x_AMLR_SHIFT 0
+#define PCM512x_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define PCM512x_GxSL       (31 << 0)
+#define PCM512x_GxSL_SHIFT 0
+#define PCM512x_GxSL_OFF   (0 << 0)
+#define PCM512x_GxSL_DSP   (1 << 0)
+#define PCM512x_GxSL_REG   (2 << 0)
+#define PCM512x_GxSL_AMUTB (3 << 0)
+#define PCM512x_GxSL_AMUTL (4 << 0)
+#define PCM512x_GxSL_AMUTR (5 << 0)
+#define PCM512x_GxSL_CLKI  (6 << 0)
+#define PCM512x_GxSL_SDOUT (7 << 0)
+#define PCM512x_GxSL_ANMUL (8 << 0)
+#define PCM512x_GxSL_ANMUR (9 << 0)
+#define PCM512x_GxSL_PLLLK (10 << 0)
+#define PCM512x_GxSL_CPCLK (11 << 0)
+#define PCM512x_GxSL_UV0_7 (14 << 0)
+#define PCM512x_GxSL_UV0_3 (15 << 0)
+#define PCM512x_GxSL_PLLCK (16 << 0)
 
 /* Page 1, Register 2 - analog volume control */
 #define PCM512x_RAGN_SHIFT 0

+ 13 - 38
sound/soc/codecs/rt286.c

@@ -403,7 +403,8 @@ EXPORT_SYMBOL_GPL(rt286_mic_detect);
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 
 	if (rt286->clk_id == RT286_SCLK_S_MCLK)
 		return 1;
@@ -417,6 +418,8 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
 static const struct snd_kcontrol_new rt286_snd_controls[] = {
 	SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN,
 			    RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R("ADC0 Capture Switch", RT286_ADCL_GAIN,
+			    RT286_ADCR_GAIN, 7, 1, 1),
 	SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN,
 			    RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
 	SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN,
@@ -500,7 +503,7 @@ SOC_DAPM_ENUM("SPO source", rt286_spo_enum);
 static int rt286_spk_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -522,7 +525,7 @@ static int rt286_spk_event(struct snd_soc_dapm_widget *w,
 static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -538,36 +541,10 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static int rt286_adc_event(struct snd_soc_dapm_widget *w,
-			     struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	unsigned int nid;
-
-	nid = (w->reg >> 20) & 0xff;
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec,
-			VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
-			0x7080, 0x7000);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec,
-			VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
-			0x7080, 0x7080);
-		break;
-	default:
-		return 0;
-	}
-
-	return 0;
-}
-
 static int rt286_vref_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -585,7 +562,7 @@ static int rt286_vref_event(struct snd_soc_dapm_widget *w,
 static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -604,7 +581,7 @@ static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
 static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -667,12 +644,10 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
 	SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
 
 	/* ADC Mux */
-	SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
-		&rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
-		&rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
+		&rt286_adc0_mux),
+	SND_SOC_DAPM_MUX("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
+		&rt286_adc1_mux),
 
 	/* Audio Interface */
 	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),

+ 18 - 10
sound/soc/codecs/rt5631.c

@@ -287,70 +287,78 @@ static const struct snd_kcontrol_new rt5631_snd_controls[] = {
 static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_GLOBAL_CLK_CTRL);
+	reg = snd_soc_read(codec, RT5631_GLOBAL_CLK_CTRL);
 	return reg & RT5631_SYSCLK_SOUR_SEL_PLL;
 }
 
 static int check_dmic_used(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(source->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 	return rt5631->dmic_used_flag;
 }
 
 static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL);
+	reg = snd_soc_read(codec, RT5631_OUTMIXER_L_CTRL);
 	return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L);
 }
 
 static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL);
+	reg = snd_soc_read(codec, RT5631_OUTMIXER_R_CTRL);
 	return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R);
 }
 
 static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+	reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
 	return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L);
 }
 
 static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+	reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
 	return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R);
 }
 
 static int check_adcl_select(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+	reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
 	return !(reg & RT5631_M_MIC1_TO_RECMIXER_L);
 }
 
 static int check_adcr_select(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+	reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
 	return !(reg & RT5631_M_MIC2_TO_RECMIXER_R);
 }
 
@@ -556,7 +564,7 @@ static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable)
 static int hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -590,7 +598,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int set_dmic_params(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
 	switch (rt5631->rx_rate) {

+ 7 - 5
sound/soc/codecs/rt5640.c

@@ -458,7 +458,7 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 	int idx = -EINVAL;
 
@@ -475,9 +475,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(source->codec, RT5640_GLB_CLK);
+	val = snd_soc_read(codec, RT5640_GLB_CLK);
 	val &= RT5640_SCLK_SRC_MASK;
 	if (val == RT5640_SCLK_SRC_PLL1)
 		return 1;
@@ -963,7 +964,7 @@ static void rt5640_pmu_depop(struct snd_soc_codec *codec)
 static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -987,7 +988,7 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1003,7 +1004,7 @@ static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -2124,6 +2125,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
 static struct acpi_device_id rt5640_acpi_match[] = {
 	{ "INT33CA", 0 },
 	{ "10EC5640", 0 },
+	{ "10EC5642", 0 },
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);

+ 150 - 24
sound/soc/codecs/rt5645.c

@@ -31,6 +31,7 @@
 #include "rt5645.h"
 
 #define RT5645_DEVICE_ID 0x6308
+#define RT5650_DEVICE_ID 0x6419
 
 #define RT5645_PR_RANGE_BASE (0xff + 1)
 #define RT5645_PR_SPACING 0x100
@@ -59,6 +60,10 @@ static const struct reg_default init_list[] = {
 };
 #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
+static const struct reg_default rt5650_init_list[] = {
+	{0xf6,	0x0100},
+};
+
 static const struct reg_default rt5645_reg[] = {
 	{ 0x00, 0x0000 },
 	{ 0x01, 0xc8c8 },
@@ -86,6 +91,7 @@ static const struct reg_default rt5645_reg[] = {
 	{ 0x2a, 0x5656 },
 	{ 0x2b, 0x5454 },
 	{ 0x2c, 0xaaa0 },
+	{ 0x2d, 0x0000 },
 	{ 0x2f, 0x1002 },
 	{ 0x31, 0x5000 },
 	{ 0x32, 0x0000 },
@@ -193,6 +199,8 @@ static const struct reg_default rt5645_reg[] = {
 	{ 0xdb, 0x0003 },
 	{ 0xdc, 0x0049 },
 	{ 0xdd, 0x001b },
+	{ 0xdf, 0x0008 },
+	{ 0xe0, 0x4000 },
 	{ 0xe6, 0x8000 },
 	{ 0xe7, 0x0200 },
 	{ 0xec, 0xb300 },
@@ -242,6 +250,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
 	case RT5645_IRQ_CTRL3:
 	case RT5645_INT_IRQ_ST:
 	case RT5645_IL_CMD:
+	case RT5650_4BTN_IL_CMD1:
 	case RT5645_VENDOR_ID:
 	case RT5645_VENDOR_ID1:
 	case RT5645_VENDOR_ID2:
@@ -287,6 +296,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
 	case RT5645_STO_DAC_MIXER:
 	case RT5645_MONO_DAC_MIXER:
 	case RT5645_DIG_MIXER:
+	case RT5650_A_DAC_SOUR:
 	case RT5645_DIG_INF1_DATA:
 	case RT5645_PDM_OUT_CTRL:
 	case RT5645_REC_L1_MIXER:
@@ -378,6 +388,8 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
 	case RT5645_IL_CMD:
 	case RT5645_IL_CMD2:
 	case RT5645_IL_CMD3:
+	case RT5650_4BTN_IL_CMD1:
+	case RT5650_4BTN_IL_CMD2:
 	case RT5645_DRC1_HL_CTRL1:
 	case RT5645_DRC2_HL_CTRL1:
 	case RT5645_ADC_MONO_HP_CTRL1:
@@ -527,7 +539,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 	int idx = -EINVAL;
 
@@ -544,9 +556,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(source->codec, RT5645_GLB_CLK);
+	val = snd_soc_read(codec, RT5645_GLB_CLK);
 	val &= RT5645_SCLK_SRC_MASK;
 	if (val == RT5645_SCLK_SRC_PLL1)
 		return 1;
@@ -557,6 +570,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_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);
 	unsigned int reg, shift, val;
 
 	switch (source->shift) {
@@ -588,7 +602,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 		return 0;
 	}
 
-	val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
 	switch (val) {
 	case 1:
 	case 2:
@@ -1007,6 +1021,44 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
 	SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 
+/* MX-2d [3] [2] */
+static const char * const rt5650_a_dac1_src[] = {
+	"DAC1", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_l_mux =
+	SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_r_mux =
+	SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum);
+
+/* MX-2d [1] [0] */
+static const char * const rt5650_a_dac2_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_l_mux =
+	SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_r_mux =
+	SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum);
+
 /* MX-2F [13:12] */
 static const char * const rt5645_if2_adc_in_src[] = {
 	"IF_ADC1", "IF_ADC2", "VAD_ADC"
@@ -1144,18 +1196,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		hp_amp_power(codec, 1);
 		/* headphone unmute sequence */
-		snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK |
-			RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK,
-			(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
-			(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-			(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+		if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+			snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+		} else {
+			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+				RT5645_CP_FQ3_MASK,
+				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_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,
@@ -1175,12 +1232,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* headphone mute sequence */
-		snd_soc_update_bits(codec, RT5645_DEPOP_M3,
-			RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
-			RT5645_CP_FQ3_MASK,
-			(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
-			(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-			(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+		if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+			snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+		} else {
+			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+				RT5645_CP_FQ3_MASK,
+				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_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,
@@ -1205,7 +1266,7 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1232,7 +1293,7 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1262,7 +1323,7 @@ static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
 static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1574,6 +1635,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("SPOR"),
 };
 
+static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac1_l_mux),
+	SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac1_r_mux),
+	SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac2_l_mux),
+	SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac2_r_mux),
+};
+
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 	{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
 	{ "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1779,13 +1851,9 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 	{ "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
 	{ "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
 
-	{ "DAC L1", NULL, "Stereo DAC MIXL" },
 	{ "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
-	{ "DAC R1", NULL, "Stereo DAC MIXR" },
 	{ "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
-	{ "DAC L2", NULL, "Mono DAC MIXL" },
 	{ "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
-	{ "DAC R2", NULL, "Mono DAC MIXR" },
 	{ "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
 
 	{ "SPK MIXL", "BST1 Switch", "BST1" },
@@ -1874,6 +1942,30 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 	{ "SPOR", NULL, "SPK amp" },
 };
 
+static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
+	{ "A DAC1 L Mux", "DAC1",  "DAC1 MIXL"},
+	{ "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+	{ "A DAC1 R Mux", "DAC1",  "DAC1 MIXR"},
+	{ "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+
+	{ "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+	{ "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"},
+	{ "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+	{ "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+	{ "DAC L1", NULL, "A DAC1 L Mux" },
+	{ "DAC R1", NULL, "A DAC1 R Mux" },
+	{ "DAC L2", NULL, "A DAC2 L Mux" },
+	{ "DAC R2", NULL, "A DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+	{ "DAC L2", NULL, "Mono DAC MIXL" },
+	{ "DAC R2", NULL, "Mono DAC MIXR" },
+};
+
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -2293,6 +2385,22 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 
 	rt5645->codec = codec;
 
+	switch (rt5645->codec_type) {
+	case CODEC_TYPE_RT5645:
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5645_specific_dapm_routes,
+			ARRAY_SIZE(rt5645_specific_dapm_routes));
+		break;
+	case CODEC_TYPE_RT5650:
+		snd_soc_dapm_new_controls(&codec->dapm,
+			rt5650_specific_dapm_widgets,
+			ARRAY_SIZE(rt5650_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5650_specific_dapm_routes,
+			ARRAY_SIZE(rt5650_specific_dapm_routes));
+		break;
+	}
+
 	rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
@@ -2424,6 +2532,7 @@ static const struct regmap_config rt5645_regmap = {
 
 static const struct i2c_device_id rt5645_i2c_id[] = {
 	{ "rt5645", 0 },
+	{ "rt5650", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
@@ -2456,9 +2565,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 	}
 
 	regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
-	if (val != RT5645_DEVICE_ID) {
+
+	switch (val) {
+	case RT5645_DEVICE_ID:
+		rt5645->codec_type = CODEC_TYPE_RT5645;
+		break;
+	case RT5650_DEVICE_ID:
+		rt5645->codec_type = CODEC_TYPE_RT5650;
+		break;
+	default:
 		dev_err(&i2c->dev,
-			"Device with ID register %x is not rt5645\n", val);
+			"Device with ID register %x is not rt5645 or rt5650\n",
+			val);
 		return -ENODEV;
 	}
 
@@ -2469,6 +2587,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 	if (ret != 0)
 		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
+	if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+		ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+				    ARRAY_SIZE(rt5650_init_list));
+		if (ret != 0)
+			dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
+					   ret);
+	}
+
 	if (rt5645->pdata.in2_diff)
 		regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
 					RT5645_IN_DF2, RT5645_IN_DF2);

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

@@ -47,6 +47,7 @@
 #define RT5645_STO_DAC_MIXER			0x2a
 #define RT5645_MONO_DAC_MIXER			0x2b
 #define RT5645_DIG_MIXER			0x2c
+#define RT5650_A_DAC_SOUR			0x2d
 #define RT5645_DIG_INF1_DATA			0x2f
 /* Mixer - PDM */
 #define RT5645_PDM_OUT_CTRL			0x31
@@ -150,6 +151,8 @@
 #define RT5645_IL_CMD				0xdb
 #define RT5645_IL_CMD2				0xdc
 #define RT5645_IL_CMD3				0xdd
+#define RT5650_4BTN_IL_CMD1			0xdf
+#define RT5650_4BTN_IL_CMD2			0xe0
 #define RT5645_DRC1_HL_CTRL1			0xe7
 #define RT5645_DRC2_HL_CTRL1			0xe9
 #define RT5645_MUTI_DRC_CTRL1			0xea
@@ -472,6 +475,12 @@
 #define RT5645_DAC_L2_DAC_R_VOL_MASK		(0x1 << 4)
 #define RT5645_DAC_L2_DAC_R_VOL_SFT		4
 
+/* Analog DAC1/2 Input Source Control (0x2d) */
+#define RT5650_A_DAC1_L_IN_SFT			3
+#define RT5650_A_DAC1_R_IN_SFT			2
+#define RT5650_A_DAC2_L_IN_SFT			1
+#define RT5650_A_DAC2_R_IN_SFT			0
+
 /* Digital Interface Data Control (0x2f) */
 #define RT5645_IF1_ADC2_IN_SEL			(0x1 << 15)
 #define RT5645_IF1_ADC2_IN_SFT			15
@@ -2175,6 +2184,11 @@ enum {
 	RT5645_DMIC_DATA_GPIO11,
 };
 
+enum {
+	CODEC_TYPE_RT5645,
+	CODEC_TYPE_RT5650,
+};
+
 struct rt5645_priv {
 	struct snd_soc_codec *codec;
 	struct rt5645_platform_data pdata;
@@ -2184,6 +2198,7 @@ struct rt5645_priv {
 	struct snd_soc_jack *mic_jack;
 	struct delayed_work jack_detect_work;
 
+	int codec_type;
 	int sysclk;
 	int sysclk_src;
 	int lrck[RT5645_AIFS];

+ 10 - 8
sound/soc/codecs/rt5651.c

@@ -376,7 +376,7 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 	int idx = -EINVAL;
 
@@ -394,9 +394,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(source->codec, RT5651_GLB_CLK);
+	val = snd_soc_read(codec, RT5651_GLB_CLK);
 	val &= RT5651_SCLK_SRC_MASK;
 	if (val == RT5651_SCLK_SRC_PLL1)
 		return 1;
@@ -731,7 +732,7 @@ static const struct snd_kcontrol_new rt5651_pdm_r_mux =
 static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -769,7 +770,7 @@ static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -813,7 +814,8 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -833,7 +835,7 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -856,7 +858,7 @@ static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -879,7 +881,7 @@ static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:

+ 92 - 7
sound/soc/codecs/rt5670.c

@@ -500,7 +500,7 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 	int idx = -EINVAL;
 
@@ -517,9 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(source->codec, RT5670_GLB_CLK);
+	val = snd_soc_read(codec, RT5670_GLB_CLK);
 	val &= RT5670_SCLK_SRC_MASK;
 	if (val == RT5670_SCLK_SRC_PLL1)
 		return 1;
@@ -530,6 +531,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_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);
 	unsigned int reg, shift, val;
 
 	switch (source->shift) {
@@ -565,7 +567,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 		return 0;
 	}
 
-	val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
 	switch (val) {
 	case 1:
 	case 2:
@@ -590,6 +592,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
 	return 0;
 }
 
+
+/**
+ * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+			    unsigned int filter_mask, unsigned int clk_src)
+{
+	unsigned int asrc2_mask = 0, asrc2_value = 0;
+	unsigned int asrc3_mask = 0, asrc3_value = 0;
+
+	if (clk_src > RT5670_CLK_SEL_SYS3)
+		return -EINVAL;
+
+	if (filter_mask & RT5670_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DA_STO_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DA_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DA_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_AD_STEREO_FILTER) {
+		asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_AD_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_AD_MONO_L_FILTER) {
+		asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_AD_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_AD_MONO_R_FILTER)  {
+		asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_AD_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_UP_RATE_FILTER) {
+		asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_UP_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_DOWN_RATE_FILTER) {
+		asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DOWN_CLK_SEL_SFT);
+	}
+
+	if (asrc2_mask)
+		snd_soc_update_bits(codec, RT5670_ASRC_2,
+				    asrc2_mask, asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_update_bits(codec, RT5670_ASRC_3,
+				    asrc3_mask, asrc3_value);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@ -1148,7 +1233,7 @@ static const struct snd_kcontrol_new rt5670_vad_adc_mux =
 static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -1184,7 +1269,7 @@ static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -1234,7 +1319,7 @@ static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1257,7 +1342,7 @@ static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:

+ 39 - 41
sound/soc/codecs/rt5670.h

@@ -1023,50 +1023,33 @@
 #define RT5670_DMIC_2_M_NOR			(0x0 << 8)
 #define RT5670_DMIC_2_M_ASYN			(0x1 << 8)
 
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5670_CLK_SEL_SYS			(0x0)
+#define RT5670_CLK_SEL_I2S1_ASRC		(0x1)
+#define RT5670_CLK_SEL_I2S2_ASRC		(0x2)
+#define RT5670_CLK_SEL_I2S3_ASRC		(0x3)
+#define RT5670_CLK_SEL_SYS2			(0x5)
+#define RT5670_CLK_SEL_SYS3			(0x6)
+
 /* ASRC Control 2 (0x84) */
-#define RT5670_MDA_L_M_MASK			(0x1 << 15)
-#define RT5670_MDA_L_M_SFT			15
-#define RT5670_MDA_L_M_NOR			(0x0 << 15)
-#define RT5670_MDA_L_M_ASYN			(0x1 << 15)
-#define RT5670_MDA_R_M_MASK			(0x1 << 14)
-#define RT5670_MDA_R_M_SFT			14
-#define RT5670_MDA_R_M_NOR			(0x0 << 14)
-#define RT5670_MDA_R_M_ASYN			(0x1 << 14)
-#define RT5670_MAD_L_M_MASK			(0x1 << 13)
-#define RT5670_MAD_L_M_SFT			13
-#define RT5670_MAD_L_M_NOR			(0x0 << 13)
-#define RT5670_MAD_L_M_ASYN			(0x1 << 13)
-#define RT5670_MAD_R_M_MASK			(0x1 << 12)
-#define RT5670_MAD_R_M_SFT			12
-#define RT5670_MAD_R_M_NOR			(0x0 << 12)
-#define RT5670_MAD_R_M_ASYN			(0x1 << 12)
-#define RT5670_ADC_M_MASK			(0x1 << 11)
-#define RT5670_ADC_M_SFT			11
-#define RT5670_ADC_M_NOR			(0x0 << 11)
-#define RT5670_ADC_M_ASYN			(0x1 << 11)
-#define RT5670_STO_DAC_M_MASK			(0x1 << 5)
-#define RT5670_STO_DAC_M_SFT			5
-#define RT5670_STO_DAC_M_NOR			(0x0 << 5)
-#define RT5670_STO_DAC_M_ASYN			(0x1 << 5)
-#define RT5670_I2S1_R_D_MASK			(0x1 << 4)
-#define RT5670_I2S1_R_D_SFT			4
-#define RT5670_I2S1_R_D_DIS			(0x0 << 4)
-#define RT5670_I2S1_R_D_EN			(0x1 << 4)
-#define RT5670_I2S2_R_D_MASK			(0x1 << 3)
-#define RT5670_I2S2_R_D_SFT			3
-#define RT5670_I2S2_R_D_DIS			(0x0 << 3)
-#define RT5670_I2S2_R_D_EN			(0x1 << 3)
-#define RT5670_PRE_SCLK_MASK			(0x3)
-#define RT5670_PRE_SCLK_SFT			0
-#define RT5670_PRE_SCLK_512			(0x0)
-#define RT5670_PRE_SCLK_1024			(0x1)
-#define RT5670_PRE_SCLK_2048			(0x2)
+#define RT5670_DA_STO_CLK_SEL_MASK		(0xf << 12)
+#define RT5670_DA_STO_CLK_SEL_SFT		12
+#define RT5670_DA_MONOL_CLK_SEL_MASK		(0xf << 8)
+#define RT5670_DA_MONOL_CLK_SEL_SFT		8
+#define RT5670_DA_MONOR_CLK_SEL_MASK		(0xf << 4)
+#define RT5670_DA_MONOR_CLK_SEL_SFT		4
+#define RT5670_AD_STO1_CLK_SEL_MASK		(0xf << 0)
+#define RT5670_AD_STO1_CLK_SEL_SFT		0
 
 /* ASRC Control 3 (0x85) */
-#define RT5670_I2S1_RATE_MASK			(0xf << 12)
-#define RT5670_I2S1_RATE_SFT			12
-#define RT5670_I2S2_RATE_MASK			(0xf << 8)
-#define RT5670_I2S2_RATE_SFT			8
+#define RT5670_UP_CLK_SEL_MASK			(0xf << 12)
+#define RT5670_UP_CLK_SEL_SFT			12
+#define RT5670_DOWN_CLK_SEL_MASK		(0xf << 8)
+#define RT5670_DOWN_CLK_SEL_SFT			8
+#define RT5670_AD_MONOL_CLK_SEL_MASK		(0xf << 4)
+#define RT5670_AD_MONOL_CLK_SEL_SFT		4
+#define RT5670_AD_MONOR_CLK_SEL_MASK		(0xf << 0)
+#define RT5670_AD_MONOR_CLK_SEL_SFT		0
 
 /* ASRC Control 4 (0x89) */
 #define RT5670_I2S1_PD_MASK			(0x7 << 12)
@@ -1983,6 +1966,21 @@ enum {
 	RT5670_DMIC_DATA_GPIO5,
 };
 
+/* filter mask */
+enum {
+	RT5670_DA_STEREO_FILTER = 0x1,
+	RT5670_DA_MONO_L_FILTER = (0x1 << 1),
+	RT5670_DA_MONO_R_FILTER = (0x1 << 2),
+	RT5670_AD_STEREO_FILTER = (0x1 << 3),
+	RT5670_AD_MONO_L_FILTER = (0x1 << 4),
+	RT5670_AD_MONO_R_FILTER = (0x1 << 5),
+	RT5670_UP_RATE_FILTER   = (0x1 << 6),
+	RT5670_DOWN_RATE_FILTER = (0x1 << 7),
+};
+
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+			    unsigned int filter_mask, unsigned int clk_src);
+
 struct rt5670_priv {
 	struct snd_soc_codec *codec;
 	struct rt5670_platform_data pdata;

+ 36 - 14
sound/soc/codecs/rt5677.c

@@ -702,6 +702,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
 	static bool activity;
 	int ret;
 
+	if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI))
+		return -ENXIO;
+
 	if (on && !activity) {
 		activity = true;
 
@@ -896,7 +899,7 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	int idx = rl6231_calc_dmic_clk(rt5677->sysclk);
 
@@ -911,7 +914,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(source->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	unsigned int val;
 
 	regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val);
@@ -925,6 +929,8 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_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 reg, shift, val;
 
 	if (source->reg == RT5677_ASRC_1) {
@@ -991,7 +997,9 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 		}
 	}
 
-	val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+	regmap_read(rt5677->regmap, reg, &val);
+	val = (val >> shift) & 0xf;
+
 	switch (val) {
 	case 1 ... 6:
 		return 1;
@@ -2122,7 +2130,7 @@ static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
 static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -2146,7 +2154,7 @@ static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -2170,7 +2178,7 @@ static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -2192,7 +2200,7 @@ static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -2214,7 +2222,7 @@ static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -2241,7 +2249,7 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	unsigned int value;
 
@@ -2264,7 +2272,7 @@ static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	unsigned int value;
 
@@ -2287,7 +2295,7 @@ static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -4098,7 +4106,8 @@ static int rt5677_set_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;
-	unsigned int val = 0;
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0, slot_width_25 = 0;
 
 	if (rx_mask || tx_mask)
 		val |= (1 << 12);
@@ -4122,6 +4131,8 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	case 20:
 		val |= (1 << 8);
 		break;
+	case 25:
+		slot_width_25 = 0x8080;
 	case 24:
 		val |= (2 << 8);
 		break;
@@ -4135,10 +4146,16 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
 	switch (dai->id) {
 	case RT5677_AIF1:
-		snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val);
+		regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, 0x1f00,
+			val);
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x8000,
+			slot_width_25);
 		break;
 	case RT5677_AIF2:
-		snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val);
+		regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, 0x1f00,
+			val);
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x80,
+			slot_width_25);
 		break;
 	default:
 		break;
@@ -4923,6 +4940,11 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 					RT5677_GPIO5_DIR_OUT);
 	}
 
+	if (rt5677->pdata.micbias1_vdd_3v3)
+		regmap_update_bits(rt5677->regmap, RT5677_MICBIAS,
+			RT5677_MICBIAS1_CTRL_VDD_MASK,
+			RT5677_MICBIAS1_CTRL_VDD_3_3V);
+
 	rt5677_init_gpio(i2c);
 	rt5677_init_irq(i2c);
 

+ 16 - 11
sound/soc/codecs/sgtl5000.c

@@ -155,18 +155,19 @@ struct sgtl5000_priv {
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* change mic bias resistor */
-		snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+		snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
 			SGTL5000_BIAS_R_MASK,
 			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+		snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
 				SGTL5000_BIAS_R_MASK, 0);
 		break;
 	}
@@ -181,11 +182,12 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
 static int power_vag_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);
 	const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
 			SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
 		break;
 
@@ -195,9 +197,9 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
 		 * operational to prevent inadvertently starving the
 		 * other one of them.
 		 */
-		if ((snd_soc_read(w->codec, SGTL5000_CHIP_ANA_POWER) &
+		if ((snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER) &
 				mask) != mask) {
-			snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+			snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
 				SGTL5000_VAG_POWERUP, 0);
 			msleep(400);
 		}
@@ -483,21 +485,21 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	/* setting i2s data format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_DSP_A:
-		i2sctl |= SGTL5000_I2S_MODE_PCM;
+		i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT;
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		i2sctl |= SGTL5000_I2S_MODE_PCM;
+		i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT;
 		i2sctl |= SGTL5000_I2S_LRALIGN;
 		break;
 	case SND_SOC_DAIFMT_I2S:
-		i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
+		i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
-		i2sctl |= SGTL5000_I2S_MODE_RJ;
+		i2sctl |= SGTL5000_I2S_MODE_RJ << SGTL5000_I2S_MODE_SHIFT;
 		i2sctl |= SGTL5000_I2S_LRPOL;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
+		i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT;
 		i2sctl |= SGTL5000_I2S_LRALIGN;
 		break;
 	default:
@@ -1462,6 +1464,9 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 	if (ret)
 		return ret;
 
+	/* Need 8 clocks before I2C accesses */
+	udelay(1);
+
 	/* read chip information */
 	ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
 	if (ret)

+ 20 - 13
sound/soc/codecs/sn95031.c

@@ -233,16 +233,18 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
 static int sn95031_vhs_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);
+
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
 		/* power up the rail */
-		snd_soc_write(w->codec, SN95031_VHSP, 0x3D);
-		snd_soc_write(w->codec, SN95031_VHSN, 0x3F);
+		snd_soc_write(codec, SN95031_VHSP, 0x3D);
+		snd_soc_write(codec, SN95031_VHSN, 0x3F);
 		msleep(1);
 	} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-		snd_soc_write(w->codec, SN95031_VHSP, 0xC4);
-		snd_soc_write(w->codec, SN95031_VHSN, 0x04);
+		snd_soc_write(codec, SN95031_VHSP, 0xC4);
+		snd_soc_write(codec, SN95031_VHSN, 0x04);
 	}
 	return 0;
 }
@@ -250,14 +252,16 @@ static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
 static int sn95031_vihf_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);
+
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
 		/* power up the rail */
-		snd_soc_write(w->codec, SN95031_VIHF, 0x27);
+		snd_soc_write(codec, SN95031_VIHF, 0x27);
 		msleep(1);
 	} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-		snd_soc_write(w->codec, SN95031_VIHF, 0x24);
+		snd_soc_write(codec, SN95031_VIHF, 0x24);
 	}
 	return 0;
 }
@@ -265,6 +269,7 @@ static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
 static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *k, int event)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -273,15 +278,16 @@ static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
 		data_dir = BIT(7);
 	}
 	/* program DMIC LDO, clock and set clock */
-	snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
-	snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
-	snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(7), data_dir);
+	snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+	snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
+	snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir);
 	return 0;
 }
 
 static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *k, int event)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -290,22 +296,23 @@ static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
 		data_dir = BIT(1);
 	}
 	/* program DMIC LDO, clock and set clock */
-	snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
-	snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
-	snd_soc_update_bits(w->codec, SN95031_DMICBUF45, BIT(1), data_dir);
+	snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+	snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
+	snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir);
 	return 0;
 }
 
 static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *k, int event)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int ldo = 0;
 
 	if (SND_SOC_DAPM_EVENT_ON(event))
 		ldo = BIT(7)|BIT(6);
 
 	/* program DMIC LDO */
-	snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
+	snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
 	return 0;
 }
 

+ 338 - 196
sound/soc/codecs/sta32x.c

@@ -24,8 +24,11 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
@@ -102,6 +105,35 @@ static const struct reg_default sta32x_regs[] = {
 	{ 0x2c, 0x0c },
 };
 
+static const struct regmap_range sta32x_write_regs_range[] = {
+	regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
+	regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_read_regs_range[] = {
+	regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
+	regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_volatile_regs_range[] = {
+	regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
+};
+
+static const struct regmap_access_table sta32x_write_regs = {
+	.yes_ranges =	sta32x_write_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta32x_write_regs_range),
+};
+
+static const struct regmap_access_table sta32x_read_regs = {
+	.yes_ranges =	sta32x_read_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta32x_read_regs_range),
+};
+
+static const struct regmap_access_table sta32x_volatile_regs = {
+	.yes_ranges =	sta32x_volatile_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta32x_volatile_regs_range),
+};
+
 /* regulator power supply names */
 static const char *sta32x_supply_names[] = {
 	"Vdda",	/* analog supply, 3.3VV */
@@ -122,6 +154,8 @@ struct sta32x_priv {
 	u32 coef_shadow[STA32X_COEF_COUNT];
 	struct delayed_work watchdog_work;
 	int shutdown;
+	struct gpio_desc *gpiod_nreset;
+	struct mutex coeff_lock;
 };
 
 static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
@@ -155,37 +189,32 @@ static const char *sta32x_limiter_release_rate[] = {
 	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
 	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
 	"0.0134", "0.0117", "0.0110", "0.0104" };
-
-static const unsigned int sta32x_limiter_ac_attack_tlv[] = {
-	TLV_DB_RANGE_HEAD(2),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
 	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
 	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_ac_release_tlv[] = {
-	TLV_DB_RANGE_HEAD(5),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
 	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
 	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
 	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
 	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_drc_attack_tlv[] = {
-	TLV_DB_RANGE_HEAD(3),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
 	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
 	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
 	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_drc_release_tlv[] = {
-	TLV_DB_RANGE_HEAD(5),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
 	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
 	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
 	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
 	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
-};
+);
 
 static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
 			    STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
@@ -244,29 +273,42 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
-	unsigned int cfud;
-	int i;
+	unsigned int cfud, val;
+	int i, ret = 0;
+
+	mutex_lock(&sta32x->coeff_lock);
 
 	/* preserve reserved bits in STA32X_CFUD */
-	cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
-	/* chip documentation does not say if the bits are self clearing,
-	 * so do it explicitly */
-	snd_soc_write(codec, STA32X_CFUD, cfud);
+	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	cfud &= 0xf0;
+	/*
+	 * chip documentation does not say if the bits are self clearing,
+	 * so do it explicitly
+	 */
+	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
 
-	snd_soc_write(codec, STA32X_CFADDR2, index);
-	if (numcoef == 1)
-		snd_soc_write(codec, STA32X_CFUD, cfud | 0x04);
-	else if (numcoef == 5)
-		snd_soc_write(codec, STA32X_CFUD, cfud | 0x08);
-	else
-		return -EINVAL;
-	for (i = 0; i < 3 * numcoef; i++)
-		ucontrol->value.bytes.data[i] =
-			snd_soc_read(codec, STA32X_B1CF1 + i);
+	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
+	if (numcoef == 1) {
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
+	} else if (numcoef == 5) {
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
+	} else {
+		ret = -EINVAL;
+		goto exit_unlock;
+	}
 
-	return 0;
+	for (i = 0; i < 3 * numcoef; i++) {
+		regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
+		ucontrol->value.bytes.data[i] = val;
+	}
+
+exit_unlock:
+	mutex_unlock(&sta32x->coeff_lock);
+
+	return ret;
 }
 
 static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
@@ -280,24 +322,27 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
 	int i;
 
 	/* preserve reserved bits in STA32X_CFUD */
-	cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
-	/* chip documentation does not say if the bits are self clearing,
-	 * so do it explicitly */
-	snd_soc_write(codec, STA32X_CFUD, cfud);
+	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	cfud &= 0xf0;
+	/*
+	 * chip documentation does not say if the bits are self clearing,
+	 * so do it explicitly
+	 */
+	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
 
-	snd_soc_write(codec, STA32X_CFADDR2, index);
+	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
 	for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
 		sta32x->coef_shadow[index + i] =
 			  (ucontrol->value.bytes.data[3 * i] << 16)
 			| (ucontrol->value.bytes.data[3 * i + 1] << 8)
 			| (ucontrol->value.bytes.data[3 * i + 2]);
 	for (i = 0; i < 3 * numcoef; i++)
-		snd_soc_write(codec, STA32X_B1CF1 + i,
-			      ucontrol->value.bytes.data[i]);
+		regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
+			     ucontrol->value.bytes.data[i]);
 	if (numcoef == 1)
-		snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
 	else if (numcoef == 5)
-		snd_soc_write(codec, STA32X_CFUD, cfud | 0x02);
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
 	else
 		return -EINVAL;
 
@@ -311,20 +356,23 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
 	int i;
 
 	/* preserve reserved bits in STA32X_CFUD */
-	cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
+	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	cfud &= 0xf0;
 
 	for (i = 0; i < STA32X_COEF_COUNT; i++) {
-		snd_soc_write(codec, STA32X_CFADDR2, i);
-		snd_soc_write(codec, STA32X_B1CF1,
-			      (sta32x->coef_shadow[i] >> 16) & 0xff);
-		snd_soc_write(codec, STA32X_B1CF2,
-			      (sta32x->coef_shadow[i] >> 8) & 0xff);
-		snd_soc_write(codec, STA32X_B1CF3,
-			      (sta32x->coef_shadow[i]) & 0xff);
-		/* chip documentation does not say if the bits are
-		 * self-clearing, so do it explicitly */
-		snd_soc_write(codec, STA32X_CFUD, cfud);
-		snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+		regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
+		regmap_write(sta32x->regmap, STA32X_B1CF1,
+			     (sta32x->coef_shadow[i] >> 16) & 0xff);
+		regmap_write(sta32x->regmap, STA32X_B1CF2,
+			     (sta32x->coef_shadow[i] >> 8) & 0xff);
+		regmap_write(sta32x->regmap, STA32X_B1CF3,
+			     (sta32x->coef_shadow[i]) & 0xff);
+		/*
+		 * chip documentation does not say if the bits are
+		 * self-clearing, so do it explicitly
+		 */
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
 	}
 	return 0;
 }
@@ -336,11 +384,11 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec)
 	int rc;
 
 	/* mute during register sync */
-	mute = snd_soc_read(codec, STA32X_MMUTE);
-	snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
+	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
+	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
 	sta32x_sync_coef_shadow(codec);
 	rc = regcache_sync(sta32x->regmap);
-	snd_soc_write(codec, STA32X_MMUTE, mute);
+	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
 	return rc;
 }
 
@@ -508,17 +556,12 @@ static struct {
 };
 
 /* MCLK to fs clock ratios */
-static struct {
-	int ratio;
-	int mcs;
-} mclk_ratios[3][7] = {
-	{ { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 },
-	  { 128, 4 }, { 576, 5 }, { 0, 0 } },
-	{ { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
-	{ { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
+static int mcs_ratio_table[3][7] = {
+	{ 768, 512, 384, 256, 128, 576, 0 },
+	{ 384, 256, 192, 128,  64,   0 },
+	{ 384, 256, 192, 128,  64,   0 },
 };
 
-
 /**
  * sta32x_set_dai_sysclk - configure MCLK
  * @codec_dai: the codec DAI
@@ -543,46 +586,10 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-	int i, j, ir, fs;
-	unsigned int rates = 0;
-	unsigned int rate_min = -1;
-	unsigned int rate_max = 0;
 
-	pr_debug("mclk=%u\n", freq);
+	dev_dbg(codec->dev, "mclk=%u\n", freq);
 	sta32x->mclk = freq;
 
-	if (sta32x->mclk) {
-		for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
-			ir = interpolation_ratios[i].ir;
-			fs = interpolation_ratios[i].fs;
-			for (j = 0; mclk_ratios[ir][j].ratio; j++) {
-				if (mclk_ratios[ir][j].ratio * fs == freq) {
-					rates |= snd_pcm_rate_to_rate_bit(fs);
-					if (fs < rate_min)
-						rate_min = fs;
-					if (fs > rate_max)
-						rate_max = fs;
-					break;
-				}
-			}
-		}
-		/* FIXME: soc should support a rate list */
-		rates &= ~SNDRV_PCM_RATE_KNOT;
-
-		if (!rates) {
-			dev_err(codec->dev, "could not find a valid sample rate\n");
-			return -EINVAL;
-		}
-	} else {
-		/* enable all possible rates */
-		rates = STA32X_RATES;
-		rate_min = 32000;
-		rate_max = 192000;
-	}
-
-	codec_dai->driver->playback.rates = rates;
-	codec_dai->driver->playback.rate_min = rate_min;
-	codec_dai->driver->playback.rate_max = rate_max;
 	return 0;
 }
 
@@ -599,10 +606,7 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-	u8 confb = snd_soc_read(codec, STA32X_CONFB);
-
-	pr_debug("\n");
-	confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM);
+	u8 confb = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
@@ -632,8 +636,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, STA32X_CONFB, confb);
-	return 0;
+	return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+				  STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
 }
 
 /**
@@ -651,39 +655,55 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-	unsigned int rate;
-	int i, mcs = -1, ir = -1;
-	u8 confa, confb;
+	int i, mcs = -EINVAL, ir = -EINVAL;
+	unsigned int confa, confb;
+	unsigned int rate, ratio;
+	int ret;
+
+	if (!sta32x->mclk) {
+		dev_err(codec->dev,
+			"sta32x->mclk is unset. Unable to determine ratio\n");
+		return -EIO;
+	}
 
 	rate = params_rate(params);
-	pr_debug("rate: %u\n", rate);
-	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
+	ratio = sta32x->mclk / rate;
+	dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
 		if (interpolation_ratios[i].fs == rate) {
 			ir = interpolation_ratios[i].ir;
 			break;
 		}
-	if (ir < 0)
+	}
+
+	if (ir < 0) {
+		dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
 		return -EINVAL;
-	for (i = 0; mclk_ratios[ir][i].ratio; i++)
-		if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
-			mcs = mclk_ratios[ir][i].mcs;
+	}
+
+	for (i = 0; i < 6; i++) {
+		if (mcs_ratio_table[ir][i] == ratio) {
+			mcs = i;
 			break;
 		}
-	if (mcs < 0)
+	}
+
+	if (mcs < 0) {
+		dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
 		return -EINVAL;
+	}
 
-	confa = snd_soc_read(codec, STA32X_CONFA);
-	confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK);
-	confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT);
+	confa = (ir << STA32X_CONFA_IR_SHIFT) |
+		(mcs << STA32X_CONFA_MCS_SHIFT);
+	confb = 0;
 
-	confb = snd_soc_read(codec, STA32X_CONFB);
-	confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB);
 	switch (params_width(params)) {
 	case 24:
-		pr_debug("24bit\n");
+		dev_dbg(codec->dev, "24bit\n");
 		/* fall through */
 	case 32:
-		pr_debug("24bit or 32bit\n");
+		dev_dbg(codec->dev, "24bit or 32bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x0;
@@ -698,7 +718,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 20:
-		pr_debug("20bit\n");
+		dev_dbg(codec->dev, "20bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x4;
@@ -713,7 +733,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 18:
-		pr_debug("18bit\n");
+		dev_dbg(codec->dev, "18bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x8;
@@ -728,7 +748,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 16:
-		pr_debug("16bit\n");
+		dev_dbg(codec->dev, "16bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x0;
@@ -746,8 +766,30 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, STA32X_CONFA, confa);
-	snd_soc_write(codec, STA32X_CONFB, confb);
+	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+				 STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
+				 confa);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+				 STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
+				 confb);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
+{
+	if (sta32x->gpiod_nreset) {
+		gpiod_set_value(sta32x->gpiod_nreset, 0);
+		mdelay(1);
+		gpiod_set_value(sta32x->gpiod_nreset, 1);
+		mdelay(1);
+	}
+
 	return 0;
 }
 
@@ -766,14 +808,14 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
 	int ret;
 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 
-	pr_debug("level = %d\n", level);
+	dev_dbg(codec->dev, "level = %d\n", level);
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
 		/* Full power on */
-		snd_soc_update_bits(codec, STA32X_CONFF,
+		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
 		break;
@@ -788,25 +830,28 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
 				return ret;
 			}
 
+			sta32x_startup_sequence(sta32x);
 			sta32x_cache_sync(codec);
 			sta32x_watchdog_start(sta32x);
 		}
 
-		/* Power up to mute */
-		/* FIXME */
-		snd_soc_update_bits(codec, STA32X_CONFF,
-				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
+		/* Power down */
+		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+				   0);
 
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* The chip runs through the power down sequence for us. */
-		snd_soc_update_bits(codec, STA32X_CONFF,
-				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-				    STA32X_CONFF_PWDN);
+		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
 		msleep(300);
 		sta32x_watchdog_stop(sta32x);
+
+		if (sta32x->gpiod_nreset)
+			gpiod_set_value(sta32x->gpiod_nreset, 0);
+
 		regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
 				       sta32x->supplies);
 		break;
@@ -822,7 +867,7 @@ static const struct snd_soc_dai_ops sta32x_dai_ops = {
 };
 
 static struct snd_soc_dai_driver sta32x_dai = {
-	.name = "STA32X",
+	.name = "sta32x-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
@@ -836,11 +881,8 @@ static struct snd_soc_dai_driver sta32x_dai = {
 static int sta32x_probe(struct snd_soc_codec *codec)
 {
 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct sta32x_platform_data *pdata = sta32x->pdata;
 	int i, ret = 0, thermal = 0;
-
-	sta32x->codec = codec;
-	sta32x->pdata = dev_get_platdata(codec->dev);
-
 	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
 				    sta32x->supplies);
 	if (ret != 0) {
@@ -848,50 +890,73 @@ static int sta32x_probe(struct snd_soc_codec *codec)
 		return ret;
 	}
 
-	/* Chip documentation explicitly requires that the reset values
-	 * of reserved register bits are left untouched.
-	 * Write the register default value to cache for reserved registers,
-	 * so the write to the these registers are suppressed by the cache
-	 * restore code when it skips writes of default registers.
-	 */
-	regcache_cache_only(sta32x->regmap, true);
-	snd_soc_write(codec, STA32X_CONFC, 0xc2);
-	snd_soc_write(codec, STA32X_CONFE, 0xc2);
-	snd_soc_write(codec, STA32X_CONFF, 0x5c);
-	snd_soc_write(codec, STA32X_MMUTE, 0x10);
-	snd_soc_write(codec, STA32X_AUTO1, 0x60);
-	snd_soc_write(codec, STA32X_AUTO3, 0x00);
-	snd_soc_write(codec, STA32X_C3CFG, 0x40);
-	regcache_cache_only(sta32x->regmap, false);
-
-	/* set thermal warning adjustment and recovery */
-	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
+	ret = sta32x_startup_sequence(sta32x);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to startup device\n");
+		return ret;
+	}
+
+	/* CONFA */
+	if (!pdata->thermal_warning_recovery)
 		thermal |= STA32X_CONFA_TWAB;
-	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE))
+	if (!pdata->thermal_warning_adjustment)
 		thermal |= STA32X_CONFA_TWRB;
-	snd_soc_update_bits(codec, STA32X_CONFA,
-			    STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
-			    thermal);
+	if (!pdata->fault_detect_recovery)
+		thermal |= STA32X_CONFA_FDRB;
+	regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+			   STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
+			   STA32X_CONFA_FDRB,
+			   thermal);
+
+	/* CONFC */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFC,
+			   STA32X_CONFC_CSZ_MASK,
+			   pdata->drop_compensation_ns
+				<< STA32X_CONFC_CSZ_SHIFT);
+
+	/* CONFE */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_MPCV,
+			   pdata->max_power_use_mpcc ?
+				STA32X_CONFE_MPCV : 0);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_MPC,
+			   pdata->max_power_correction ?
+				STA32X_CONFE_MPC : 0);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_AME,
+			   pdata->am_reduction_mode ?
+				STA32X_CONFE_AME : 0);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_PWMS,
+			   pdata->odd_pwm_speed_mode ?
+				STA32X_CONFE_PWMS : 0);
+
+	/*  CONFF */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+			   STA32X_CONFF_IDE,
+			   pdata->invalid_input_detect_mute ?
+				STA32X_CONFF_IDE : 0);
 
 	/* select output configuration  */
-	snd_soc_update_bits(codec, STA32X_CONFF,
-			    STA32X_CONFF_OCFG_MASK,
-			    sta32x->pdata->output_conf
-			    << STA32X_CONFF_OCFG_SHIFT);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+			   STA32X_CONFF_OCFG_MASK,
+			   pdata->output_conf
+				<< STA32X_CONFF_OCFG_SHIFT);
 
 	/* channel to output mapping */
-	snd_soc_update_bits(codec, STA32X_C1CFG,
-			    STA32X_CxCFG_OM_MASK,
-			    sta32x->pdata->ch1_output_mapping
-			    << STA32X_CxCFG_OM_SHIFT);
-	snd_soc_update_bits(codec, STA32X_C2CFG,
-			    STA32X_CxCFG_OM_MASK,
-			    sta32x->pdata->ch2_output_mapping
-			    << STA32X_CxCFG_OM_SHIFT);
-	snd_soc_update_bits(codec, STA32X_C3CFG,
-			    STA32X_CxCFG_OM_MASK,
-			    sta32x->pdata->ch3_output_mapping
-			    << STA32X_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
+			   STA32X_CxCFG_OM_MASK,
+			   pdata->ch1_output_mapping
+				<< STA32X_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
+			   STA32X_CxCFG_OM_MASK,
+			   pdata->ch2_output_mapping
+				<< STA32X_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
+			   STA32X_CxCFG_OM_MASK,
+			   pdata->ch3_output_mapping
+				<< STA32X_CxCFG_OM_SHIFT);
 
 	/* initialize coefficient shadow RAM with reset values */
 	for (i = 4; i <= 49; i += 5)
@@ -924,16 +989,6 @@ static int sta32x_remove(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
-{
-	switch (reg) {
-	case STA32X_CONFA ... STA32X_L2ATRT:
-	case STA32X_MPCC1 ... STA32X_FDRC2:
-		return 0;
-	}
-	return 1;
-}
-
 static const struct snd_soc_codec_driver sta32x_codec = {
 	.probe =		sta32x_probe,
 	.remove =		sta32x_remove,
@@ -954,12 +1009,75 @@ static const struct regmap_config sta32x_regmap = {
 	.reg_defaults =		sta32x_regs,
 	.num_reg_defaults =	ARRAY_SIZE(sta32x_regs),
 	.cache_type =		REGCACHE_RBTREE,
-	.volatile_reg =		sta32x_reg_is_volatile,
+	.wr_table =		&sta32x_write_regs,
+	.rd_table =		&sta32x_read_regs,
+	.volatile_table =	&sta32x_volatile_regs,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id st32x_dt_ids[] = {
+	{ .compatible = "st,sta32x", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, st32x_dt_ids);
+
+static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
+{
+	struct device_node *np = dev->of_node;
+	struct sta32x_platform_data *pdata;
+	u16 tmp;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	of_property_read_u8(np, "st,output-conf",
+			    &pdata->output_conf);
+	of_property_read_u8(np, "st,ch1-output-mapping",
+			    &pdata->ch1_output_mapping);
+	of_property_read_u8(np, "st,ch2-output-mapping",
+			    &pdata->ch2_output_mapping);
+	of_property_read_u8(np, "st,ch3-output-mapping",
+			    &pdata->ch3_output_mapping);
+
+	if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+		pdata->thermal_warning_recovery = 1;
+	if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+		pdata->thermal_warning_adjustment = 1;
+	if (of_get_property(np, "st,needs_esd_watchdog", NULL))
+		pdata->needs_esd_watchdog = 1;
+
+	tmp = 140;
+	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+	/* CONFE */
+	if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+		pdata->max_power_use_mpcc = 1;
+
+	if (of_get_property(np, "st,max-power-correction", NULL))
+		pdata->max_power_correction = 1;
+
+	if (of_get_property(np, "st,am-reduction-mode", NULL))
+		pdata->am_reduction_mode = 1;
+
+	if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+		pdata->odd_pwm_speed_mode = 1;
+
+	/* CONFF */
+	if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+		pdata->invalid_input_detect_mute = 1;
+
+	sta32x->pdata = pdata;
+
+	return 0;
+}
+#endif
+
 static int sta32x_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
+	struct device *dev = &i2c->dev;
 	struct sta32x_priv *sta32x;
 	int ret, i;
 
@@ -968,6 +1086,29 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
 	if (!sta32x)
 		return -ENOMEM;
 
+	mutex_init(&sta32x->coeff_lock);
+	sta32x->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+	if (dev->of_node) {
+		ret = sta32x_probe_dt(dev, sta32x);
+		if (ret < 0)
+			return ret;
+	}
+#endif
+
+	/* 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);
+	}
+
 	/* regulators */
 	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
 		sta32x->supplies[i].supply = sta32x_supply_names[i];
@@ -982,15 +1123,15 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
 	sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
 	if (IS_ERR(sta32x->regmap)) {
 		ret = PTR_ERR(sta32x->regmap);
-		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		dev_err(dev, "Failed to init regmap: %d\n", ret);
 		return ret;
 	}
 
 	i2c_set_clientdata(i2c, sta32x);
 
-	ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
-	if (ret != 0)
-		dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+	ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
+	if (ret < 0)
+		dev_err(dev, "Failed to register codec (%d)\n", ret);
 
 	return ret;
 }
@@ -1013,6 +1154,7 @@ static struct i2c_driver sta32x_i2c_driver = {
 	.driver = {
 		.name = "sta32x",
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(st32x_dt_ids),
 	},
 	.probe =    sta32x_i2c_probe,
 	.remove =   sta32x_i2c_remove,

+ 1 - 1
sound/soc/codecs/sta32x.h

@@ -131,7 +131,7 @@
 #define STA32X_CONFF_OCFG_MASK	0x03
 #define STA32X_CONFF_OCFG_SHIFT	0
 #define STA32X_CONFF_IDE	0x04
-#define STA32X_CONFF_IDE_SHIFT	3
+#define STA32X_CONFF_IDE_SHIFT	2
 #define STA32X_CONFF_BCLE	0x08
 #define STA32X_CONFF_ECLE	0x20
 #define STA32X_CONFF_PWDN	0x40

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

@@ -349,7 +349,8 @@ static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
 static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 				    struct snd_kcontrol *kcontrol, int event)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 	unsigned int reg = AIC31XX_DACFLAG1;
 	unsigned int mask;
 
@@ -377,7 +378,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 		reg = AIC31XX_ADCFLAG;
 		break;
 	default:
-		dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n",
+		dev_err(codec->dev, "Unknown widget '%s' calling %s\n",
 			w->name, __func__);
 		return -EINVAL;
 	}
@@ -388,7 +389,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMD:
 		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
 	default:
-		dev_dbg(w->codec->dev,
+		dev_dbg(codec->dev,
 			"Unhandled dapm widget event %d from %s\n",
 			event, w->name);
 	}
@@ -433,7 +434,7 @@ static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {

+ 246 - 103
sound/soc/codecs/tlv320aic3x.c

@@ -87,6 +87,7 @@ struct aic3x_priv {
 #define AIC3X_MODEL_3X 0
 #define AIC3X_MODEL_33 1
 #define AIC3X_MODEL_3007 2
+#define AIC3X_MODEL_3104 3
 	u16 model;
 
 	/* Selects the micbias voltage */
@@ -197,7 +198,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -316,52 +317,37 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 	 * only for swapped L-to-R and R-to-L routes. See below stereo controls
 	 * for direct L-to-L and R-to-R routes.
 	 */
-	SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
-		       LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
 		       PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
 		       DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
 
-	SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
-		       LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
 		       PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
 		       DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
 
-	SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
-		       LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
 		       PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
 		       DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
 
-	SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
-		       LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
 		       PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
 		       DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
 
-	SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
-		       LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
 		       PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
 		       DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
 
-	SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
-		       LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
 		       PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
 	SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
 		       DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
 
 	/* Stereo output controls for direct L-to-L and R-to-R routes */
-	SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
-			 LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
-			 0, 118, 1, output_stage_tlv),
 	SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
 			 PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
 			 0, 118, 1, output_stage_tlv),
@@ -369,9 +355,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 			 DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
 			 0, 118, 1, output_stage_tlv),
 
-	SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
-			 LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
-			 0, 118, 1, output_stage_tlv),
 	SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
 			 PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
 			 0, 118, 1, output_stage_tlv),
@@ -379,9 +362,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 			 DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
 			 0, 118, 1, output_stage_tlv),
 
-	SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
-			 LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
-			 0, 118, 1, output_stage_tlv),
 	SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
 			 PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
 			 0, 118, 1, output_stage_tlv),
@@ -424,6 +404,45 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 	SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum),
 };
 
+/* For other than tlv320aic3104 */
+static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = {
+	/*
+	 * Output controls that map to output mixer switches. Note these are
+	 * only for swapped L-to-R and R-to-L routes. See below stereo controls
+	 * for direct L-to-L and R-to-R routes.
+	 */
+	SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+		       LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+		       LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+		       LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+		       LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+		       LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+		       LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+	/* Stereo output controls for direct L-to-L and R-to-R routes */
+	SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+			 LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+			 LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+			 LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+			 0, 118, 1, output_stage_tlv),
+};
+
 static const struct snd_kcontrol_new aic3x_mono_controls[] = {
 	SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
 			 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
@@ -464,22 +483,24 @@ SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum);
 
 /* Left Line Mixer */
 static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
 };
 
 /* Right Line Mixer */
 static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
 };
 
 /* Mono Mixer */
@@ -494,42 +515,46 @@ static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
 
 /* Left HP Mixer */
 static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
 };
 
 /* Right HP Mixer */
 static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
 };
 
 /* Left HPCOM Mixer */
 static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
 };
 
 /* Right HPCOM Mixer */
 static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left PGA Mixer */
@@ -550,6 +575,22 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
 	SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
 };
 
+/* Left PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
+};
+
+/* Right PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
+};
+
 /* Left Line1 Mux */
 static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum);
@@ -593,26 +634,56 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 
 	/* Inputs to Left ADC */
 	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
-	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
-			   &aic3x_left_pga_mixer_controls[0],
-			   ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
 	SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_left_line1l_mux_controls),
 	SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_left_line1r_mux_controls),
-	SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
-			 &aic3x_left_line2_mux_controls),
 
 	/* Inputs to Right ADC */
 	SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
 			 LINE1R_2_RADC_CTRL, 2, 0),
-	SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
-			   &aic3x_right_pga_mixer_controls[0],
-			   ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
 	SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_right_line1l_mux_controls),
 	SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_right_line1r_mux_controls),
+
+	/* Mic Bias */
+	SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
+			 mic_bias_event,
+			 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_OUTPUT("LLOUT"),
+	SND_SOC_DAPM_OUTPUT("RLOUT"),
+	SND_SOC_DAPM_OUTPUT("HPLOUT"),
+	SND_SOC_DAPM_OUTPUT("HPROUT"),
+	SND_SOC_DAPM_OUTPUT("HPLCOM"),
+	SND_SOC_DAPM_OUTPUT("HPRCOM"),
+
+	SND_SOC_DAPM_INPUT("LINE1L"),
+	SND_SOC_DAPM_INPUT("LINE1R"),
+
+	/*
+	 * Virtual output pin to detection block inside codec. This can be
+	 * used to keep codec bias on if gpio or detection features are needed.
+	 * Force pin on or construct a path with an input jack and mic bias
+	 * widgets.
+	 */
+	SND_SOC_DAPM_OUTPUT("Detection"),
+};
+
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = {
+	/* Inputs to Left ADC */
+	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
+	SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_line2_mux_controls),
+
+	/* Inputs to Right ADC */
+	SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
 	SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_right_line2_mux_controls),
 
@@ -637,11 +708,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
 			 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
 
-	/* Mic Bias */
-	SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
-			 mic_bias_event,
-			 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
 	/* Output mixers */
 	SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
 			   &aic3x_left_line_mixer_controls[0],
@@ -662,27 +728,46 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 			   &aic3x_right_hpcom_mixer_controls[0],
 			   ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
 
-	SND_SOC_DAPM_OUTPUT("LLOUT"),
-	SND_SOC_DAPM_OUTPUT("RLOUT"),
-	SND_SOC_DAPM_OUTPUT("HPLOUT"),
-	SND_SOC_DAPM_OUTPUT("HPROUT"),
-	SND_SOC_DAPM_OUTPUT("HPLCOM"),
-	SND_SOC_DAPM_OUTPUT("HPRCOM"),
-
 	SND_SOC_DAPM_INPUT("MIC3L"),
 	SND_SOC_DAPM_INPUT("MIC3R"),
-	SND_SOC_DAPM_INPUT("LINE1L"),
-	SND_SOC_DAPM_INPUT("LINE1R"),
 	SND_SOC_DAPM_INPUT("LINE2L"),
 	SND_SOC_DAPM_INPUT("LINE2R"),
+};
 
-	/*
-	 * Virtual output pin to detection block inside codec. This can be
-	 * used to keep codec bias on if gpio or detection features are needed.
-	 * Force pin on or construct a path with an input jack and mic bias
-	 * widgets.
-	 */
-	SND_SOC_DAPM_OUTPUT("Detection"),
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = {
+	/* Inputs to Left ADC */
+	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3104_left_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3104_left_pga_mixer_controls)),
+
+	/* Inputs to Right ADC */
+	SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3104_right_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3104_right_pga_mixer_controls)),
+
+	/* Output mixers */
+	SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_line_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_line_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_hp_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_hp_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_hpcom_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_hpcom_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2),
+
+	SND_SOC_DAPM_INPUT("MIC2L"),
+	SND_SOC_DAPM_INPUT("MIC2R"),
 };
 
 static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
@@ -712,17 +797,10 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"Left Line1R Mux", "single-ended", "LINE1R"},
 	{"Left Line1R Mux", "differential", "LINE1R"},
 
-	{"Left Line2L Mux", "single-ended", "LINE2L"},
-	{"Left Line2L Mux", "differential", "LINE2L"},
-
 	{"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
 	{"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
-	{"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
-	{"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
-	{"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
 
 	{"Left ADC", NULL, "Left PGA Mixer"},
-	{"Left ADC", NULL, "GPIO1 dmic modclk"},
 
 	/* Right Input */
 	{"Right Line1R Mux", "single-ended", "LINE1R"},
@@ -730,25 +808,10 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"Right Line1L Mux", "single-ended", "LINE1L"},
 	{"Right Line1L Mux", "differential", "LINE1L"},
 
-	{"Right Line2R Mux", "single-ended", "LINE2R"},
-	{"Right Line2R Mux", "differential", "LINE2R"},
-
 	{"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
 	{"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
-	{"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
-	{"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
-	{"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
 
 	{"Right ADC", NULL, "Right PGA Mixer"},
-	{"Right ADC", NULL, "GPIO1 dmic modclk"},
-
-	/*
-	 * Logical path between digital mic enable and GPIO1 modulator clock
-	 * output function
-	 */
-	{"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
-	{"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
-	{"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
 
 	/* Left DAC Output */
 	{"Left DAC Mux", "DAC_L1", "Left DAC"},
@@ -761,10 +824,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"Right DAC Mux", "DAC_R3", "Right DAC"},
 
 	/* Left Line Output */
-	{"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
 	{"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
 	{"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
 	{"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -773,10 +834,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"LLOUT", NULL, "Left Line Out"},
 
 	/* Right Line Output */
-	{"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
 	{"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
 	{"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
 	{"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -785,10 +844,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"RLOUT", NULL, "Right Line Out"},
 
 	/* Left HP Output */
-	{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
 	{"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
 	{"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
 	{"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -797,10 +854,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HPLOUT", NULL, "Left HP Out"},
 
 	/* Right HP Output */
-	{"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
 	{"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
 	{"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
 	{"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -809,10 +864,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HPROUT", NULL, "Right HP Out"},
 
 	/* Left HPCOM Output */
-	{"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
 	{"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
 	{"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
 	{"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -823,10 +876,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HPLCOM", NULL, "Left HP Com"},
 
 	/* Right HPCOM Output */
-	{"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
 	{"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
 	{"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
 	{"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -839,6 +890,72 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HPRCOM", NULL, "Right HP Com"},
 };
 
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra[] = {
+	/* Left Input */
+	{"Left Line2L Mux", "single-ended", "LINE2L"},
+	{"Left Line2L Mux", "differential", "LINE2L"},
+
+	{"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
+	{"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+	{"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+	{"Left ADC", NULL, "GPIO1 dmic modclk"},
+
+	/* Right Input */
+	{"Right Line2R Mux", "single-ended", "LINE2R"},
+	{"Right Line2R Mux", "differential", "LINE2R"},
+
+	{"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+	{"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
+	{"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+	{"Right ADC", NULL, "GPIO1 dmic modclk"},
+
+	/*
+	 * Logical path between digital mic enable and GPIO1 modulator clock
+	 * output function
+	 */
+	{"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
+	{"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
+	{"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+	/* Left Line Output */
+	{"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Right Line Output */
+	{"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Left HP Output */
+	{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Right HP Output */
+	{"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Left HPCOM Output */
+	{"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Right HPCOM Output */
+	{"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+};
+
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra_3104[] = {
+	/* Left Input */
+	{"Left PGA Mixer", "Mic2L Switch", "MIC2L"},
+	{"Left PGA Mixer", "Mic2R Switch", "MIC2R"},
+
+	/* Right Input */
+	{"Right PGA Mixer", "Mic2L Switch", "MIC2L"},
+	{"Right PGA Mixer", "Mic2R Switch", "MIC2R"},
+};
+
 static const struct snd_soc_dapm_route intercon_mono[] = {
 	/* Mono Output */
 	{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
@@ -867,17 +984,31 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
 	switch (aic3x->model) {
 	case AIC3X_MODEL_3X:
 	case AIC3X_MODEL_33:
+		snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+					  ARRAY_SIZE(aic3x_extra_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_extra,
+					ARRAY_SIZE(intercon_extra));
 		snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
 			ARRAY_SIZE(aic3x_dapm_mono_widgets));
 		snd_soc_dapm_add_routes(dapm, intercon_mono,
 					ARRAY_SIZE(intercon_mono));
 		break;
 	case AIC3X_MODEL_3007:
+		snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+					  ARRAY_SIZE(aic3x_extra_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_extra,
+					ARRAY_SIZE(intercon_extra));
 		snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
 			ARRAY_SIZE(aic3007_dapm_widgets));
 		snd_soc_dapm_add_routes(dapm, intercon_3007,
 					ARRAY_SIZE(intercon_3007));
 		break;
+	case AIC3X_MODEL_3104:
+		snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets,
+				ARRAY_SIZE(aic3104_extra_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_extra_3104,
+				ARRAY_SIZE(intercon_extra_3104));
+		break;
 	}
 
 	return 0;
@@ -1046,7 +1177,7 @@ static int aic3x_prepare(struct snd_pcm_substream *substream,
 		delay += aic3x->tdm_delay;
 
 	/* Configure data delay */
-	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay);
+	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
 
 	return 0;
 }
@@ -1438,23 +1569,33 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 	aic3x_init(codec);
 
 	if (aic3x->setup) {
-		/* setup GPIO functions */
-		snd_soc_write(codec, AIC3X_GPIO1_REG,
-			      (aic3x->setup->gpio_func[0] & 0xf) << 4);
-		snd_soc_write(codec, AIC3X_GPIO2_REG,
-			      (aic3x->setup->gpio_func[1] & 0xf) << 4);
+		if (aic3x->model != AIC3X_MODEL_3104) {
+			/* setup GPIO functions */
+			snd_soc_write(codec, AIC3X_GPIO1_REG,
+				      (aic3x->setup->gpio_func[0] & 0xf) << 4);
+			snd_soc_write(codec, AIC3X_GPIO2_REG,
+				      (aic3x->setup->gpio_func[1] & 0xf) << 4);
+		} else {
+			dev_warn(codec->dev, "GPIO functionality is not supported on tlv320aic3104\n");
+		}
 	}
 
 	switch (aic3x->model) {
 	case AIC3X_MODEL_3X:
 	case AIC3X_MODEL_33:
+		snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+				ARRAY_SIZE(aic3x_extra_snd_controls));
 		snd_soc_add_codec_controls(codec, aic3x_mono_controls,
 				ARRAY_SIZE(aic3x_mono_controls));
 		break;
 	case AIC3X_MODEL_3007:
+		snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+				ARRAY_SIZE(aic3x_extra_snd_controls));
 		snd_soc_add_codec_controls(codec,
 				&aic3x_classd_amp_gain_ctrl, 1);
 		break;
+	case AIC3X_MODEL_3104:
+		break;
 	}
 
 	/* set mic bias voltage */
@@ -1522,6 +1663,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
 	{ "tlv320aic33", AIC3X_MODEL_33 },
 	{ "tlv320aic3007", AIC3X_MODEL_3007 },
 	{ "tlv320aic3106", AIC3X_MODEL_3X },
+	{ "tlv320aic3104", AIC3X_MODEL_3104 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1673,6 +1815,7 @@ static const struct of_device_id tlv320aic3x_of_match[] = {
 	{ .compatible = "ti,tlv320aic33" },
 	{ .compatible = "ti,tlv320aic3007" },
 	{ .compatible = "ti,tlv320aic3106" },
+	{ .compatible = "ti,tlv320aic3104" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);

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

@@ -423,17 +423,18 @@ exit:
 static int dac33_playback_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (likely(dac33->substream)) {
-			dac33_calculate_times(dac33->substream, w->codec);
-			dac33_prepare_chip(dac33->substream, w->codec);
+			dac33_calculate_times(dac33->substream, codec);
+			dac33_prepare_chip(dac33->substream, codec);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		dac33_disable_digital(w->codec);
+		dac33_disable_digital(codec);
 		break;
 	}
 	return 0;

+ 32 - 3
sound/soc/codecs/ts3a227e.c

@@ -20,6 +20,8 @@
 #include <sound/jack.h>
 #include <sound/soc.h>
 
+#include "ts3a227e.h"
+
 struct ts3a227e {
 	struct regmap *regmap;
 	struct snd_soc_jack *jack;
@@ -79,6 +81,10 @@ static const int ts3a227e_buttons[] = {
 /* TS3A227E_REG_SETTING_2 0x05 */
 #define KP_ENABLE 0x04
 
+/* TS3A227E_REG_SETTING_3 0x06 */
+#define MICBIAS_SETTING_SFT (3)
+#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT)
+
 /* TS3A227E_REG_ACCESSORY_STATUS  0x0b */
 #define TYPE_3_POLE 0x01
 #define TYPE_4_POLE_OMTP 0x02
@@ -221,9 +227,9 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
 	struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component);
 
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
-	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
-	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
-	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
 	ts3a227e->jack = jack;
 	ts3a227e_jack_report(ts3a227e);
@@ -248,6 +254,21 @@ static const struct regmap_config ts3a227e_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
 };
 
+static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np)
+{
+	u32 micbias;
+	int err;
+
+	err = of_property_read_u32(np, "ti,micbias", &micbias);
+	if (!err) {
+		regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
+			MICBIAS_SETTING_MASK,
+			(micbias & 0x07) << MICBIAS_SETTING_SFT);
+	}
+
+	return 0;
+}
+
 static int ts3a227e_i2c_probe(struct i2c_client *i2c,
 			      const struct i2c_device_id *id)
 {
@@ -266,6 +287,14 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(ts3a227e->regmap))
 		return PTR_ERR(ts3a227e->regmap);
 
+	if (dev->of_node) {
+		ret = ts3a227e_parse_dt(ts3a227e, dev->of_node);
+		if (ret) {
+			dev_err(dev, "Failed to parse device tree: %d\n", ret);
+			return ret;
+		}
+	}
+
 	ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
 					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 					"TS3A227E", ts3a227e);

+ 34 - 21
sound/soc/codecs/twl4030.c

@@ -567,12 +567,13 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
 static int pin_name##pga_event(struct snd_soc_dapm_widget *w,		\
 			       struct snd_kcontrol *kcontrol, int event) \
 {									\
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);	\
+	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); \
 									\
 	switch (event) {						\
 	case SND_SOC_DAPM_POST_PMU:					\
 		twl4030->pin_name##_enabled = 1;			\
-		twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \
+		twl4030_write(codec, reg, twl4030_read(codec, reg));	\
 		break;							\
 	case SND_SOC_DAPM_POST_PMD:					\
 		twl4030->pin_name##_enabled = 0;			\
@@ -621,12 +622,14 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 static int handsfreelpga_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:
-		handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1);
+		handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0);
+		handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 0);
 		break;
 	}
 	return 0;
@@ -635,12 +638,14 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
 static int handsfreerpga_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:
-		handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1);
+		handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0);
+		handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 0);
 		break;
 	}
 	return 0;
@@ -649,19 +654,23 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 static int vibramux_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	twl4030_write(codec, TWL4030_REG_VIBRA_SET, 0xff);
 	return 0;
 }
 
 static int apll_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_PRE_PMU:
-		twl4030_apll_enable(w->codec, 1);
+		twl4030_apll_enable(codec, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		twl4030_apll_enable(w->codec, 0);
+		twl4030_apll_enable(codec, 0);
 		break;
 	}
 	return 0;
@@ -670,23 +679,24 @@ static int apll_event(struct snd_soc_dapm_widget *w,
 static int aif_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);
 	u8 audio_if;
 
-	audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF);
+	audio_if = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Enable AIF */
 		/* enable the PLL before we use it to clock the DAI */
-		twl4030_apll_enable(w->codec, 1);
+		twl4030_apll_enable(codec, 1);
 
-		twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
+		twl4030_write(codec, TWL4030_REG_AUDIO_IF,
 			      audio_if | TWL4030_AIF_EN);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* disable the DAI before we stop it's source PLL */
-		twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
+		twl4030_write(codec, TWL4030_REG_AUDIO_IF,
 			      audio_if &  ~TWL4030_AIF_EN);
-		twl4030_apll_enable(w->codec, 0);
+		twl4030_apll_enable(codec, 0);
 		break;
 	}
 	return 0;
@@ -758,20 +768,21 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* Do the ramp-up only once */
 		if (!twl4030->hsr_enabled)
-			headset_ramp(w->codec, 1);
+			headset_ramp(codec, 1);
 
 		twl4030->hsl_enabled = 1;
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Do the ramp-down only if both headsetL/R is disabled */
 		if (!twl4030->hsr_enabled)
-			headset_ramp(w->codec, 0);
+			headset_ramp(codec, 0);
 
 		twl4030->hsl_enabled = 0;
 		break;
@@ -782,20 +793,21 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* Do the ramp-up only once */
 		if (!twl4030->hsl_enabled)
-			headset_ramp(w->codec, 1);
+			headset_ramp(codec, 1);
 
 		twl4030->hsr_enabled = 1;
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Do the ramp-down only if both headsetL/R is disabled */
 		if (!twl4030->hsl_enabled)
-			headset_ramp(w->codec, 0);
+			headset_ramp(codec, 0);
 
 		twl4030->hsr_enabled = 0;
 		break;
@@ -806,7 +818,8 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 static int digimic_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	struct twl4030_codec_data *pdata = twl4030->pdata;
 
 	if (pdata && pdata->digimic_delay)

+ 2 - 2
sound/soc/codecs/twl6040.c

@@ -234,7 +234,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u8 hslctl, hsrctl;
 
 	/*
@@ -261,7 +261,7 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 

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

@@ -683,7 +683,7 @@ static const struct snd_kcontrol_new wm2000_controls[] = {
 static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 	int ret;
 

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

@@ -775,7 +775,8 @@ static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol,
 			 int event)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
 
 	switch (w->reg) {
 	case WM5100_CHANNEL_ENABLES_1:
@@ -839,7 +840,7 @@ static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 

+ 14 - 9
sound/soc/codecs/wm5102.c

@@ -28,6 +28,7 @@
 
 #include <linux/mfd/arizona/core.h>
 #include <linux/mfd/arizona/registers.h>
+#include <asm/unaligned.h>
 
 #include "arizona.h"
 #include "wm5102.h"
@@ -580,7 +581,7 @@ static const struct reg_default wm5102_sysclk_revb_patch[] = {
 static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
 	struct regmap *regmap = arizona->regmap;
 	const struct reg_default *patch = NULL;
@@ -617,11 +618,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-	uint16_t data;
 
 	mutex_lock(&arizona->dac_comp_lock);
-	data = cpu_to_be16(arizona->dac_comp_coeff);
-	memcpy(ucontrol->value.bytes.data, &data, sizeof(data));
+	put_unaligned_be16(arizona->dac_comp_coeff,
+			   ucontrol->value.bytes.data);
 	mutex_unlock(&arizona->dac_comp_lock);
 
 	return 0;
@@ -1272,19 +1272,24 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
 		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
 		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),

+ 13 - 7
sound/soc/codecs/wm5110.c

@@ -134,7 +134,7 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
 static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
 	struct regmap *regmap = arizona->regmap;
 	const struct reg_default *patch = NULL;
@@ -905,22 +905,28 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
 		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
 		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),

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

@@ -259,7 +259,7 @@ static void wm8350_pga_work(struct work_struct *work)
 static int pga_event(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
 	struct wm8350_output *out;
 

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

@@ -324,6 +324,7 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_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);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	u32 reg_shift = mc->shift;
@@ -332,7 +333,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 
 	switch (reg_shift) {
 	case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-		reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
+		reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER1);
 		if (reg & WM8400_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -340,7 +341,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-		reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
+		reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER2);
 		if (reg & WM8400_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -348,7 +349,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-		reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -356,7 +357,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-		reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");

+ 4 - 1
sound/soc/codecs/wm8731.c

@@ -217,7 +217,8 @@ SND_SOC_DAPM_INPUT("LLINEIN"),
 static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
 			    struct snd_soc_dapm_widget *sink)
 {
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
 	return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
 }
@@ -717,6 +718,8 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
 	if (wm8731 == NULL)
 		return -ENOMEM;
 
+	mutex_init(&wm8731->lock);
+
 	wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
 	if (IS_ERR(wm8731->regmap)) {
 		ret = PTR_ERR(wm8731->regmap);

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

@@ -308,9 +308,7 @@ static const struct snd_soc_dapm_route wm8770_intercon[] = {
 static int vout12supply_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec;
-
-	codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -327,9 +325,7 @@ static int vout12supply_event(struct snd_soc_dapm_widget *w,
 static int vout34supply_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec;
-
-	codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:

+ 2 - 2
sound/soc/codecs/wm8804.c

@@ -648,7 +648,7 @@ static struct snd_soc_dai_driver wm8804_dai = {
 	.symmetric_rates = 1
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
 	.probe = wm8804_probe,
 	.remove = wm8804_remove,
 	.set_bias_level = wm8804_set_bias_level,
@@ -664,7 +664,7 @@ static const struct of_device_id wm8804_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8804_of_match);
 
-static struct regmap_config wm8804_regmap_config = {
+static const struct regmap_config wm8804_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 

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

@@ -224,7 +224,7 @@ static void wm8900_reset(struct snd_soc_codec *codec)
 static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);
 
 	switch (event) {

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

@@ -260,7 +260,7 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
 static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {

+ 32 - 3
sound/soc/codecs/wm8904.c

@@ -673,7 +673,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int sysclk_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -711,7 +711,7 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 	int reg, val;
 	int dcs_mask;
@@ -2105,6 +2105,24 @@ static const struct regmap_config wm8904_regmap = {
 	.num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults),
 };
 
+#ifdef CONFIG_OF
+static enum wm8904_type wm8904_data = WM8904;
+static enum wm8904_type wm8912_data = WM8912;
+
+static const struct of_device_id wm8904_of_match[] = {
+	{
+		.compatible = "wlf,wm8904",
+		.data = &wm8904_data,
+	}, {
+		.compatible = "wlf,wm8912",
+		.data = &wm8912_data,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, wm8904_of_match);
+#endif
+
 static int wm8904_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -2132,7 +2150,17 @@ static int wm8904_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	wm8904->devtype = id->driver_data;
+	if (i2c->dev.of_node) {
+		const struct of_device_id *match;
+
+		match = of_match_node(wm8904_of_match, i2c->dev.of_node);
+		if (match == NULL)
+			return -EINVAL;
+		wm8904->devtype = *((enum wm8904_type *)match->data);
+	} else {
+		wm8904->devtype = id->driver_data;
+	}
+
 	i2c_set_clientdata(i2c, wm8904);
 	wm8904->pdata = i2c->dev.platform_data;
 
@@ -2266,6 +2294,7 @@ static struct i2c_driver wm8904_i2c_driver = {
 	.driver = {
 		.name = "wm8904",
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(wm8904_of_match),
 	},
 	.probe =    wm8904_i2c_probe,
 	.remove =   wm8904_i2c_remove,

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

@@ -333,7 +333,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int ret = 0;
 
 	/* Always disable the clocks - if we're doing reconfiguration this

+ 1 - 1
sound/soc/codecs/wm8958-dsp2.c

@@ -418,7 +418,7 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
 		  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int i;
 
 	switch (event) {

+ 48 - 3
sound/soc/codecs/wm8960.c

@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/clk.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -117,6 +118,7 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
 }
 
 struct wm8960_priv {
+	struct clk *mclk;
 	struct regmap *regmap;
 	int (*set_bias_level)(struct snd_soc_codec *,
 			      enum snd_soc_bias_level level);
@@ -618,14 +620,38 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 				      enum snd_soc_bias_level level)
 {
 	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		/* Set VMID to 2x50k */
-		snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
+		switch (codec->dapm.bias_level) {
+		case SND_SOC_BIAS_STANDBY:
+			if (!IS_ERR(wm8960->mclk)) {
+				ret = clk_prepare_enable(wm8960->mclk);
+				if (ret) {
+					dev_err(codec->dev,
+						"Failed to enable MCLK: %d\n",
+						ret);
+					return ret;
+				}
+			}
+
+			/* Set VMID to 2x50k */
+			snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
+			break;
+
+		case SND_SOC_BIAS_ON:
+			if (!IS_ERR(wm8960->mclk))
+				clk_disable_unprepare(wm8960->mclk);
+			break;
+
+		default:
+			break;
+		}
+
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
@@ -674,7 +700,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 					 enum snd_soc_bias_level level)
 {
 	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-	int reg;
+	int reg, ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -715,9 +741,22 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 					    WM8960_VREF, WM8960_VREF);
 
 			msleep(100);
+
+			if (!IS_ERR(wm8960->mclk)) {
+				ret = clk_prepare_enable(wm8960->mclk);
+				if (ret) {
+					dev_err(codec->dev,
+						"Failed to enable MCLK: %d\n",
+						ret);
+					return ret;
+				}
+			}
 			break;
 
 		case SND_SOC_BIAS_ON:
+			if (!IS_ERR(wm8960->mclk))
+				clk_disable_unprepare(wm8960->mclk);
+
 			/* Enable anti-pop mode */
 			snd_soc_update_bits(codec, WM8960_APOP1,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -1002,6 +1041,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
 	if (wm8960 == NULL)
 		return -ENOMEM;
 
+	wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(wm8960->mclk)) {
+		if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	}
+
 	wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
 	if (IS_ERR(wm8960->regmap))
 		return PTR_ERR(wm8960->regmap);

+ 2 - 2
sound/soc/codecs/wm8961.c

@@ -194,7 +194,7 @@ static bool wm8961_readable(struct device *dev, unsigned int reg)
 static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
 	u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
 	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
@@ -286,7 +286,7 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
 static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
 	u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1);
 

+ 3 - 3
sound/soc/codecs/wm8962.c

@@ -1866,7 +1866,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int timeout;
 	int reg;
 	int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
@@ -1960,7 +1960,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int reg;
 
 	switch (w->shift) {
@@ -1993,7 +1993,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 static int dsp2_event(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {

+ 3 - 3
sound/soc/codecs/wm8988.c

@@ -244,7 +244,7 @@ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
 static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2);
 
 	/* Use the DAC to gate LRC if active, otherwise use ADC */
@@ -813,7 +813,7 @@ static int wm8988_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
 	.probe =	wm8988_probe,
 	.set_bias_level = wm8988_set_bias_level,
 	.suspend_bias_off = true,
@@ -826,7 +826,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
 	.num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes),
 };
 
-static struct regmap_config wm8988_regmap = {
+static const struct regmap_config wm8988_regmap = {
 	.reg_bits = 7,
 	.val_bits = 9,
 

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

@@ -374,13 +374,14 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_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);
 	u32 reg_shift = kcontrol->private_value & 0xfff;
 	int ret = 0;
 	u16 reg;
 
 	switch (reg_shift) {
 	case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
-		reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1);
+		reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER1);
 		if (reg & WM8990_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -388,7 +389,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2);
+		reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER2);
 		if (reg & WM8990_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -396,7 +397,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
+		reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
 		if (reg & WM8990_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -404,7 +405,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
+		reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
 		if (reg & WM8990_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");

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

@@ -382,13 +382,14 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
 static int outmixer_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);
 	u32 reg_shift = kcontrol->private_value & 0xfff;
 	int ret = 0;
 	u16 reg;
 
 	switch (reg_shift) {
 	case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1);
+		reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER1);
 		if (reg & WM8991_LDLO) {
 			printk(KERN_WARNING
 			       "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -397,7 +398,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2);
+		reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER2);
 		if (reg & WM8991_RDRO) {
 			printk(KERN_WARNING
 			       "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -406,7 +407,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+		reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
 		if (reg & WM8991_LDSPK) {
 			printk(KERN_WARNING
 			       "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -415,7 +416,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
-		reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+		reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
 		if (reg & WM8991_RDSPK) {
 			printk(KERN_WARNING
 			       "Cannot set as Speaker Mixer RDSPK Set\n");

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

@@ -810,7 +810,7 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:

+ 12 - 11
sound/soc/codecs/wm8994.c

@@ -249,7 +249,8 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	int reg = snd_soc_read(codec, WM8994_CLOCKING_1);
 	const char *clk;
 
 	/* Check what we're currently using for CLK_SYS */
@@ -806,7 +807,7 @@ static void active_dereference(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -981,7 +982,7 @@ static void vmid_dereference(struct snd_soc_codec *codec)
 static int vmid_event(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1037,7 +1038,7 @@ static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994 *control = wm8994->wm8994;
 	int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
@@ -1135,7 +1136,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int i;
 	int dac;
 	int adc;
@@ -1220,7 +1221,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -1238,7 +1239,7 @@ static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -1256,7 +1257,7 @@ static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
 static int late_enable_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -1289,7 +1290,7 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 static int late_disable_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -1331,7 +1332,7 @@ static int micbias_ev(struct snd_soc_dapm_widget *w,
 static int dac_ev(struct snd_soc_dapm_widget *w,
 		  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int mask = 1 << w->shift;
 
 	snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
@@ -1372,7 +1373,7 @@ SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
 static int post_ev(struct snd_soc_dapm_widget *w,
 	    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	dev_dbg(codec->dev, "SRC status: %x\n",
 		snd_soc_read(codec,
 			     WM8994_RATE_STATUS));

+ 8 - 12
sound/soc/codecs/wm8995.c

@@ -44,7 +44,7 @@ static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = {
 	"MICVDD"
 };
 
-static struct reg_default wm8995_reg_defaults[] = {
+static const struct reg_default wm8995_reg_defaults[] = {
 	{ 0, 0x8995 },
 	{ 5, 0x0100 },
 	{ 16, 0x000b },
@@ -534,10 +534,11 @@ static void wm8995_update_class_w(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	unsigned int reg;
 	const char *clk;
 
-	reg = snd_soc_read(source->codec, WM8995_CLOCKING_1);
+	reg = snd_soc_read(codec, WM8995_CLOCKING_1);
 	/* Check what we're currently using for CLK_SYS */
 	if (reg & WM8995_SYSCLK_SRC)
 		clk = "AIF2CLK";
@@ -560,9 +561,7 @@ static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec;
-
-	codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -611,10 +610,9 @@ static void dc_servo_cmd(struct snd_soc_codec *codec,
 static int hp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int reg;
 
-	codec = w->codec;
 	reg = snd_soc_read(codec, WM8995_ANALOGUE_HP_1);
 
 	switch (event) {
@@ -761,9 +759,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec;
-
-	codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -2190,7 +2186,7 @@ static struct snd_soc_dai_driver wm8995_dai[] = {
 	}
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
 	.probe = wm8995_probe,
 	.remove = wm8995_remove,
 	.set_bias_level = wm8995_set_bias_level,
@@ -2204,7 +2200,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
 	.num_dapm_routes = ARRAY_SIZE(wm8995_intercon),
 };
 
-static struct regmap_config wm8995_regmap = {
+static const struct regmap_config wm8995_regmap = {
 	.reg_bits = 16,
 	.val_bits = 16,
 

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

@@ -599,7 +599,7 @@ static void wm8996_bg_disable(struct snd_soc_codec *codec)
 static int bg_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int ret = 0;
 
 	switch (event) {
@@ -634,7 +634,8 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int rmv_short_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 
 	/* Record which outputs we enabled */
 	switch (event) {
@@ -758,7 +759,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int dcs_start(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:

+ 7 - 4
sound/soc/codecs/wm8997.c

@@ -84,7 +84,7 @@ static const struct reg_default wm8997_sysclk_reva_patch[] = {
 static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
 	struct regmap *regmap = arizona->regmap;
 	const struct reg_default *patch = NULL;
@@ -610,13 +610,16 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
 		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
 		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),

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

@@ -734,7 +734,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
 
 	/* This should be done on init() for bypass paths */

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

@@ -254,7 +254,7 @@ SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
 static int hp_ev(struct snd_soc_dapm_widget *w,
 		 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0);
 
 	switch (event) {

+ 10 - 6
sound/soc/codecs/wm9705.c

@@ -344,23 +344,27 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 	struct snd_ac97 *ac97;
 	int ret = 0;
 
-	ac97 = snd_soc_new_ac97_codec(codec);
+	ac97 = snd_soc_alloc_ac97_codec(codec);
 	if (IS_ERR(ac97)) {
 		ret = PTR_ERR(ac97);
 		dev_err(codec->dev, "Failed to register AC97 codec\n");
 		return ret;
 	}
 
-	snd_soc_codec_set_drvdata(codec, ac97);
-
 	ret = wm9705_reset(codec);
 	if (ret)
-		goto reset_err;
+		goto err_put_device;
+
+	ret = device_add(&ac97->dev);
+	if (ret)
+		goto err_put_device;
+
+	snd_soc_codec_set_drvdata(codec, ac97);
 
 	return 0;
 
-reset_err:
-	snd_soc_free_ac97_codec(ac97);
+err_put_device:
+	put_device(&ac97->dev);
 	return ret;
 }
 

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

@@ -666,7 +666,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
-	wm9712->ac97 = snd_soc_new_ac97_codec(codec);
+	wm9712->ac97 = snd_soc_alloc_ac97_codec(codec);
 	if (IS_ERR(wm9712->ac97)) {
 		ret = PTR_ERR(wm9712->ac97);
 		dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
@@ -675,15 +675,19 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 
 	ret = wm9712_reset(codec, 0);
 	if (ret < 0)
-		goto reset_err;
+		goto err_put_device;
+
+	ret = device_add(&wm9712->ac97->dev);
+	if (ret)
+		goto err_put_device;
 
 	/* set alc mux to none */
 	ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
 
 	return 0;
 
-reset_err:
-	snd_soc_free_ac97_codec(wm9712->ac97);
+err_put_device:
+	put_device(&wm9712->ac97->dev);
 	return ret;
 }
 

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

@@ -217,7 +217,7 @@ SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 status, rate;
 
 	if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
@@ -1225,7 +1225,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0, reg;
 
-	wm9713->ac97 = snd_soc_new_ac97_codec(codec);
+	wm9713->ac97 = snd_soc_alloc_ac97_codec(codec);
 	if (IS_ERR(wm9713->ac97))
 		return PTR_ERR(wm9713->ac97);
 
@@ -1234,7 +1234,11 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 	wm9713_reset(codec, 0);
 	ret = wm9713_reset(codec, 1);
 	if (ret < 0)
-		goto reset_err;
+		goto err_put_device;
+
+	ret = device_add(&wm9713->ac97->dev);
+	if (ret)
+		goto err_put_device;
 
 	/* unmute the adc - move to kcontrol */
 	reg = ac97_read(codec, AC97_CD) & 0x7fff;
@@ -1242,8 +1246,8 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 
 	return 0;
 
-reset_err:
-	snd_soc_free_ac97_codec(wm9713->ac97);
+err_put_device:
+	put_device(&wm9713->ac97->dev);
 	return ret;
 }
 

+ 3 - 3
sound/soc/codecs/wm_adsp.c

@@ -1373,7 +1373,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
 	struct wm_adsp *dsp = &dsps[w->shift];
 	struct wm_adsp_alg_region *alg_region;
@@ -1605,7 +1605,7 @@ err:
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
 	struct wm_adsp *dsp = &dsps[w->shift];
 
@@ -1626,7 +1626,7 @@ EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
 	struct wm_adsp *dsp = &dsps[w->shift];
 	struct wm_adsp_alg_region *alg_region;

+ 5 - 5
sound/soc/codecs/wm_hubs.c

@@ -500,7 +500,7 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
 	switch (event) {
@@ -542,7 +542,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);
 
 	switch (event) {
@@ -594,7 +594,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int earpiece_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *control, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
 
 	switch (event) {
@@ -619,7 +619,7 @@ static int earpiece_event(struct snd_soc_dapm_widget *w,
 static int lineout_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *control, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 	bool *flag;
 
@@ -649,7 +649,7 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
 static int micbias_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
 	switch (w->shift) {

+ 1 - 2
sound/soc/davinci/Kconfig

@@ -58,13 +58,12 @@ choice
 	depends on MACH_DAVINCI_DM365_EVM
 
 config SND_DM365_AIC3X_CODEC
-	bool "Audio Codec - AIC3101"
+	tristate "Audio Codec - AIC3101"
 	help
 	  Say Y if you want to add support for AIC3101 audio codec
 
 config SND_DM365_VOICE_CODEC
 	tristate "Voice Codec - CQ93VC"
-	depends on SND_DAVINCI_SOC
 	select MFD_DAVINCI_VOICECODEC
 	select SND_DAVINCI_SOC_VCIF
 	select SND_SOC_CQ0093VC

+ 0 - 6
sound/soc/davinci/davinci-evm.c

@@ -14,7 +14,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/edma.h>
 #include <linux/i2c.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
@@ -25,11 +24,6 @@
 #include <asm/dma.h>
 #include <asm/mach-types.h>
 
-#include <linux/edma.h>
-
-#include "davinci-pcm.h"
-#include "davinci-i2s.h"
-
 struct snd_soc_card_drvdata_davinci {
 	struct clk *mclk;
 	unsigned sysclk;

Some files were not shown because too many files changed in this diff