Эх сурвалжийг харах

Merge remote-tracking branches 'asoc/fix/atmel', 'asoc/fix/intel', 'asoc/fix/rt5645', 'asoc/fix/rt5677' and 'asoc/fix/samsung' into asoc-linus

Mark Brown 11 жил өмнө
100 өөрчлөгдсөн 4297 нэмэгдсэн , 1354 устгасан
  1. 24 0
      Documentation/devicetree/bindings/sound/arndale.txt
  2. 1 1
      Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
  3. 10 5
      Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
  4. 23 21
      Documentation/devicetree/bindings/sound/fsl,esai.txt
  5. 18 19
      Documentation/devicetree/bindings/sound/fsl,spdif.txt
  6. 41 25
      Documentation/devicetree/bindings/sound/fsl-sai.txt
  7. 34 27
      Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
  8. 12 10
      Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
  9. 26 19
      Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
  10. 14 8
      Documentation/devicetree/bindings/sound/imx-audmux.txt
  11. 2 0
      Documentation/devicetree/bindings/sound/max98090.txt
  12. 7 2
      Documentation/devicetree/bindings/sound/renesas,fsi.txt
  13. 7 3
      Documentation/devicetree/bindings/sound/renesas,rsnd.txt
  14. 48 0
      Documentation/devicetree/bindings/sound/rt5631.txt
  15. 17 0
      Documentation/devicetree/bindings/sound/rt5677.txt
  16. 11 4
      Documentation/devicetree/bindings/sound/samsung-i2s.txt
  17. 13 0
      Documentation/devicetree/bindings/sound/sgtl5000.txt
  18. 26 0
      Documentation/devicetree/bindings/sound/ts3a227e.txt
  19. 31 0
      Documentation/devicetree/bindings/sound/wm8960.txt
  20. 6 0
      MAINTAINERS
  21. 9 0
      arch/arm/mach-pxa/spitz.c
  22. 62 0
      arch/x86/include/asm/platform_sst_audio.h
  23. 4 1
      drivers/base/regmap/Kconfig
  24. 1 0
      drivers/base/regmap/Makefile
  25. 114 0
      drivers/base/regmap/regmap-ac97.c
  26. 1 0
      include/linux/mfd/arizona/core.h
  27. 0 7
      include/linux/mfd/davinci_voicecodec.h
  28. 1 0
      include/linux/platform_data/asoc-s3c.h
  29. 7 0
      include/linux/regmap.h
  30. 4 4
      include/sound/rcar_snd.h
  31. 4 0
      include/sound/rt5645.h
  32. 10 0
      include/sound/rt5677.h
  33. 2 5
      include/sound/soc-dai.h
  34. 6 3
      include/sound/soc-dapm.h
  35. 82 34
      include/sound/soc.h
  36. 0 12
      include/sound/uda134x.h
  37. 0 25
      include/trace/events/asoc.h
  38. 5 1
      sound/soc/Makefile
  39. 0 9
      sound/soc/atmel/Kconfig
  40. 0 1
      sound/soc/atmel/Makefile
  41. 5 2
      sound/soc/atmel/atmel_ssc_dai.c
  42. 0 151
      sound/soc/atmel/snd-soc-afeb9260.c
  43. 1 1
      sound/soc/au1x/ac97c.c
  44. 1 1
      sound/soc/au1x/psc-ac97.c
  45. 1 1
      sound/soc/blackfin/bf5xx-ac97.c
  46. 0 2
      sound/soc/blackfin/bf5xx-ad1980.c
  47. 2 1
      sound/soc/cirrus/Kconfig
  48. 1 1
      sound/soc/cirrus/ep93xx-ac97.c
  49. 41 8
      sound/soc/codecs/Kconfig
  50. 10 0
      sound/soc/codecs/Makefile
  51. 16 16
      sound/soc/codecs/ab8500-codec.c
  52. 13 5
      sound/soc/codecs/ac97.c
  53. 9 5
      sound/soc/codecs/ad193x.c
  54. 117 95
      sound/soc/codecs/ad1980.c
  55. 0 26
      sound/soc/codecs/ad1980.h
  56. 3 3
      sound/soc/codecs/adau1373.c
  57. 81 5
      sound/soc/codecs/adau1701.c
  58. 13 12
      sound/soc/codecs/adau1761.c
  59. 15 18
      sound/soc/codecs/adau1781.c
  60. 64 7
      sound/soc/codecs/adau17x1.c
  61. 7 3
      sound/soc/codecs/adau17x1.h
  62. 2 2
      sound/soc/codecs/adav80x.c
  63. 4 27
      sound/soc/codecs/ak4535.c
  64. 1 32
      sound/soc/codecs/ak4641.c
  65. 0 16
      sound/soc/codecs/ak4642.c
  66. 0 13
      sound/soc/codecs/ak4671.c
  67. 1 21
      sound/soc/codecs/alc5623.c
  68. 2 20
      sound/soc/codecs/alc5632.c
  69. 28 6
      sound/soc/codecs/arizona.c
  70. 0 33
      sound/soc/codecs/cq93vc.c
  71. 0 2
      sound/soc/codecs/cs4265.c
  72. 62 0
      sound/soc/codecs/cs4271-i2c.c
  73. 55 0
      sound/soc/codecs/cs4271-spi.c
  74. 18 137
      sound/soc/codecs/cs4271.c
  75. 11 0
      sound/soc/codecs/cs4271.h
  76. 4 2
      sound/soc/codecs/cs42l51.c
  77. 3 3
      sound/soc/codecs/cs42l73.c
  78. 2 0
      sound/soc/codecs/hdmi.c
  79. 0 8
      sound/soc/codecs/lm49453.c
  80. 4 27
      sound/soc/codecs/max98088.c
  81. 160 41
      sound/soc/codecs/max98090.c
  82. 8 0
      sound/soc/codecs/max98090.h
  83. 11 12
      sound/soc/codecs/max98095.c
  84. 1 21
      sound/soc/codecs/max9850.c
  85. 172 59
      sound/soc/codecs/rt286.c
  86. 12 26
      sound/soc/codecs/rt5631.c
  87. 185 19
      sound/soc/codecs/rt5645.c
  88. 17 2
      sound/soc/codecs/rt5645.h
  89. 115 21
      sound/soc/codecs/rt5670.c
  90. 6 0
      sound/soc/codecs/rt5670.h
  91. 130 0
      sound/soc/codecs/rt5677-spi.c
  92. 21 0
      sound/soc/codecs/rt5677-spi.h
  93. 1131 67
      sound/soc/codecs/rt5677.c
  94. 146 16
      sound/soc/codecs/rt5677.h
  95. 81 30
      sound/soc/codecs/sgtl5000.c
  96. 70 11
      sound/soc/codecs/sigmadsp-i2c.c
  97. 35 11
      sound/soc/codecs/sigmadsp-regmap.c
  98. 670 41
      sound/soc/codecs/sigmadsp.c
  99. 42 17
      sound/soc/codecs/sigmadsp.h
  100. 4 2
      sound/soc/codecs/sirf-audio-codec.c

+ 24 - 0
Documentation/devicetree/bindings/sound/arndale.txt

@@ -0,0 +1,24 @@
+Audio Binding for Arndale boards
+
+Required properties:
+- compatible : Can be the following,
+			"samsung,arndale-rt5631"
+
+- samsung,audio-cpu: The phandle of the Samsung I2S controller
+- samsung,audio-codec: The phandle of the audio codec
+
+Optional:
+- samsung,model: The name of the sound-card
+
+Arndale Boards has many audio daughter cards, one of them is
+rt5631/alc5631. Below example shows audio bindings for rt5631/
+alc5631 based codec.
+
+Example:
+
+sound {
+		compatible = "samsung,arndale-rt5631";
+
+		samsung,audio-cpu = <&i2s0>
+		samsung,audio-codec = <&rt5631>;
+};

+ 1 - 1
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt

@@ -32,7 +32,7 @@ Optional properties:
 - rx-num-evt : FIFO levels.
 - rx-num-evt : FIFO levels.
 - sram-size-playback : size of sram to be allocated during playback
 - sram-size-playback : size of sram to be allocated during playback
 - sram-size-capture  : size of sram to be allocated during capture
 - sram-size-capture  : size of sram to be allocated during capture
-- interrupts : Interrupt numbers for McASP, currently not used by the driver
+- interrupts : Interrupt numbers for McASP
 - interrupt-names : Known interrupt names are "tx" and "rx"
 - interrupt-names : Known interrupt names are "tx" and "rx"
 - pinctrl-0: Should specify pin control group used for this controller.
 - pinctrl-0: Should specify pin control group used for this controller.
 - pinctrl-names: Should contain only one value - "default", for more details
 - pinctrl-names: Should contain only one value - "default", for more details

+ 10 - 5
Documentation/devicetree/bindings/sound/eukrea-tlv320.txt

@@ -1,11 +1,16 @@
 Audio complex for Eukrea boards with tlv320aic23 codec.
 Audio complex for Eukrea boards with tlv320aic23 codec.
 
 
 Required properties:
 Required properties:
-- compatible : "eukrea,asoc-tlv320"
-- eukrea,model : The user-visible name of this sound complex.
-- ssi-controller : The phandle of the SSI controller.
-- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
-- fsl,mux-ext-port : The external port of the i.MX audio muxer.
+
+  - compatible		: "eukrea,asoc-tlv320"
+
+  - eukrea,model	: The user-visible name of this sound complex.
+
+  - ssi-controller	: The phandle of the SSI controller.
+
+  - fsl,mux-int-port	: The internal port of the i.MX audio muxer (AUDMUX).
+
+  - fsl,mux-ext-port	: The external port of the i.MX audio muxer.
 
 
 Note: The AUDMUX port numbering should start at 1, which is consistent with
 Note: The AUDMUX port numbering should start at 1, which is consistent with
 hardware manual.
 hardware manual.

+ 23 - 21
Documentation/devicetree/bindings/sound/fsl,esai.txt

@@ -7,37 +7,39 @@ other DSPs. It has up to six transmitters and four receivers.
 
 
 Required properties:
 Required properties:
 
 
-  - compatible : Compatible list, must contain "fsl,imx35-esai" or
-		 "fsl,vf610-esai"
+  - compatible		: Compatible list, must contain "fsl,imx35-esai" or
+			  "fsl,vf610-esai"
 
 
-  - reg : Offset and length of the register set for the device.
+  - reg			: Offset and length of the register set for the device.
 
 
-  - interrupts : Contains the spdif interrupt.
+  - interrupts		: Contains the spdif interrupt.
 
 
-  - dmas : Generic dma devicetree binding as described in
-  Documentation/devicetree/bindings/dma/dma.txt.
+  - dmas		: Generic dma devicetree binding as described in
+			  Documentation/devicetree/bindings/dma/dma.txt.
 
 
-  - dma-names : Two dmas have to be defined, "tx" and "rx".
+  - dma-names		: Two dmas have to be defined, "tx" and "rx".
 
 
-  - clocks: Contains an entry for each entry in clock-names.
+  - clocks		: Contains an entry for each entry in clock-names.
 
 
-  - clock-names : Includes the following entries:
-	"core"		The core clock used to access registers
-	"extal"		The esai baud clock for esai controller used to derive
-			HCK, SCK and FS.
-	"fsys"		The system clock derived from ahb clock used to derive
-			HCK, SCK and FS.
+  - clock-names		: Includes the following entries:
+	"core"		  The core clock used to access registers
+	"extal"		  The esai baud clock for esai controller used to
+			  derive HCK, SCK and FS.
+	"fsys"		  The system clock derived from ahb clock used to
+			  derive HCK, SCK and FS.
 
 
-  - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
-    This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
+  - fsl,fifo-depth	: The number of elements in the transmit and receive
+			  FIFOs. This number is the maximum allowed value for
+			  TFCR[TFWM] or RFCR[RFWM].
 
 
   - fsl,esai-synchronous: This is a boolean property. If present, indicating
   - fsl,esai-synchronous: This is a boolean property. If present, indicating
-    that ESAI would work in the synchronous mode, which means all the settings
-    for Receiving would be duplicated from Transmition related registers.
+			  that ESAI would work in the synchronous mode, which
+			  means all the settings for Receiving would be
+			  duplicated from Transmition related registers.
 
 
-  - big-endian : If this property is absent, the native endian mode will
-    be in use as default, or the big endian mode will be in use for all the
-    device registers.
+  - big-endian		: If this property is absent, the native endian mode
+			  will be in use as default, or the big endian mode
+			  will be in use for all the device registers.
 
 
 Example:
 Example:
 
 

+ 18 - 19
Documentation/devicetree/bindings/sound/fsl,spdif.txt

@@ -6,32 +6,31 @@ a fibre cable.
 
 
 Required properties:
 Required properties:
 
 
-  - compatible : Compatible list, must contain "fsl,imx35-spdif".
+  - compatible		: Compatible list, must contain "fsl,imx35-spdif".
 
 
-  - reg : Offset and length of the register set for the device.
+  - reg			: Offset and length of the register set for the device.
 
 
-  - interrupts : Contains the spdif interrupt.
+  - interrupts		: Contains the spdif interrupt.
 
 
-  - dmas : Generic dma devicetree binding as described in
-  Documentation/devicetree/bindings/dma/dma.txt.
+  - dmas		: Generic dma devicetree binding as described in
+			  Documentation/devicetree/bindings/dma/dma.txt.
 
 
-  - dma-names : Two dmas have to be defined, "tx" and "rx".
+  - dma-names		: Two dmas have to be defined, "tx" and "rx".
 
 
-  - clocks : Contains an entry for each entry in clock-names.
+  - clocks		: Contains an entry for each entry in clock-names.
 
 
-  - clock-names : Includes the following entries:
-	"core"		The core clock of spdif controller
-	"rxtx<0-7>"	Clock source list for tx and rx clock.
-			This clock list should be identical to
-			the source list connecting to the spdif
-			clock mux in "SPDIF Transceiver Clock
-			Diagram" of SoC reference manual. It
-			can also be referred to TxClk_Source
-			bit of register SPDIF_STC.
+  - clock-names		: Includes the following entries:
+	"core"		  The core clock of spdif controller.
+	"rxtx<0-7>"	  Clock source list for tx and rx clock.
+			  This clock list should be identical to the source
+			  list connecting to the spdif clock mux in "SPDIF
+			  Transceiver Clock Diagram" of SoC reference manual.
+			  It can also be referred to TxClk_Source bit of
+			  register SPDIF_STC.
 
 
-   - big-endian : If this property is absent, the native endian mode will
-   be in use as default, or the big endian mode will be in use for all the
-   device registers.
+   - big-endian		: If this property is absent, the native endian mode
+			  will be in use as default, or the big endian mode
+			  will be in use for all the device registers.
 
 
 Example:
 Example:
 
 

+ 41 - 25
Documentation/devicetree/bindings/sound/fsl-sai.txt

@@ -5,32 +5,48 @@ which provides a synchronous audio interface that supports fullduplex
 serial interfaces with frame synchronization such as I2S, AC97, TDM, and
 serial interfaces with frame synchronization such as I2S, AC97, TDM, and
 codec/DSP interfaces.
 codec/DSP interfaces.
 
 
-
 Required properties:
 Required properties:
-- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai".
-- reg: Offset and length of the register set for the device.
-- clocks: Must contain an entry for each entry in clock-names.
-- clock-names : Must include the "bus" for register access and "mclk1" "mclk2"
-  "mclk3" for bit clock and frame clock providing.
-- dmas : Generic dma devicetree binding as described in
-  Documentation/devicetree/bindings/dma/dma.txt.
-- dma-names : Two dmas have to be defined, "tx" and "rx".
-- pinctrl-names: Must contain a "default" entry.
-- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
-  See ../pinctrl/pinctrl-bindings.txt for details of the property values.
-- big-endian: Boolean property, required if all the FTM_PWM registers
-  are big-endian rather than little-endian.
-- lsb-first: Configures whether the LSB or the MSB is transmitted first for
-  the fifo data. If this property is absent, the MSB is transmitted first as
-  default, or the LSB is transmitted first.
-- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
-  that SAI will work in the synchronous mode (sync Tx with Rx) which means
-  both the transimitter and receiver will send and receive data by following
-  receiver's bit clocks and frame sync clocks.
-- fsl,sai-asynchronous: This is a boolean property. If present, indicating
-  that SAI will work in the asynchronous mode, which means both transimitter
-  and receiver will send and receive data by following their own bit clocks
-  and frame sync clocks separately.
+
+  - compatible		: Compatible list, contains "fsl,vf610-sai" or
+			  "fsl,imx6sx-sai".
+
+  - reg			: Offset and length of the register set for the device.
+
+  - clocks		: Must contain an entry for each entry in clock-names.
+
+  - clock-names		: Must include the "bus" for register access and
+			  "mclk1", "mclk2", "mclk3" for bit clock and frame
+			  clock providing.
+  - dmas		: Generic dma devicetree binding as described in
+			  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names		: Two dmas have to be defined, "tx" and "rx".
+
+  - pinctrl-names	: Must contain a "default" entry.
+
+  - pinctrl-NNN		: One property must exist for each entry in
+			  pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
+			  for details of the property values.
+
+  - big-endian		: Boolean property, required if all the FTM_PWM
+			  registers are big-endian rather than little-endian.
+
+  - lsb-first		: Configures whether the LSB or the MSB is transmitted
+			  first for the fifo data. If this property is absent,
+			  the MSB is transmitted first as default, or the LSB
+			  is transmitted first.
+
+  - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
+			  that SAI will work in the synchronous mode (sync Tx
+			  with Rx) which means both the transimitter and the
+			  receiver will send and receive data by following
+			  receiver's bit clocks and frame sync clocks.
+
+  - fsl,sai-asynchronous: This is a boolean property. If present, indicating
+			  that SAI will work in the asynchronous mode, which
+			  means both transimitter and receiver will send and
+			  receive data by following their own bit clocks and
+			  frame sync clocks separately.
 
 
 Note:
 Note:
 - If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
 - If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the

+ 34 - 27
Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt

@@ -1,33 +1,40 @@
 Freescale i.MX audio complex with SGTL5000 codec
 Freescale i.MX audio complex with SGTL5000 codec
 
 
 Required properties:
 Required properties:
-- compatible : "fsl,imx-audio-sgtl5000"
-- model : The user-visible name of this sound complex
-- ssi-controller : The phandle of the i.MX SSI controller
-- audio-codec : The phandle of the SGTL5000 audio codec
-- 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 could be power
-  supplies, SGTL5000 pins, and the jacks on the board:
-
-  Power supplies:
-   * Mic Bias
-
-  SGTL5000 pins:
-   * MIC_IN
-   * LINE_IN
-   * HP_OUT
-   * LINE_OUT
-
-  Board connectors:
-   * Mic Jack
-   * Line In Jack
-   * Headphone Jack
-   * Line Out Jack
-   * Ext Spk
-
-- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
-- mux-ext-port : The external port of the i.MX audio muxer
+
+  - compatible		: "fsl,imx-audio-sgtl5000"
+
+  - model		: The user-visible name of this sound complex
+
+  - ssi-controller	: The phandle of the i.MX SSI controller
+
+  - audio-codec		: The phandle of the SGTL5000 audio codec
+
+  - 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 could be power supplies, SGTL5000
+			  pins, and the jacks on the board:
+
+			  Power supplies:
+			   * Mic Bias
+
+			  SGTL5000 pins:
+			   * MIC_IN
+			   * LINE_IN
+			   * HP_OUT
+			   * LINE_OUT
+
+			  Board connectors:
+			   * Mic Jack
+			   * Line In Jack
+			   * Headphone Jack
+			   * Line Out Jack
+			   * Ext Spk
+
+  - mux-int-port	: The internal port of the i.MX audio muxer (AUDMUX)
+
+  - mux-ext-port	: The external port of the i.MX audio muxer
 
 
 Note: The AUDMUX port numbering should start at 1, which is consistent with
 Note: The AUDMUX port numbering should start at 1, which is consistent with
 hardware manual.
 hardware manual.

+ 12 - 10
Documentation/devicetree/bindings/sound/imx-audio-spdif.txt

@@ -2,23 +2,25 @@ Freescale i.MX audio complex with S/PDIF transceiver
 
 
 Required properties:
 Required properties:
 
 
-  - compatible : "fsl,imx-audio-spdif"
+  - compatible		: "fsl,imx-audio-spdif"
 
 
-  - model : The user-visible name of this sound complex
+  - model		: The user-visible name of this sound complex
 
 
-  - spdif-controller : The phandle of the i.MX S/PDIF controller
+  - spdif-controller	: The phandle of the i.MX S/PDIF controller
 
 
 
 
 Optional properties:
 Optional properties:
 
 
-  - spdif-out : This is a boolean property. If present, the transmitting
-    function of S/PDIF will be enabled, indicating there's a physical
-    S/PDIF out connector/jack on the board or it's connecting to some
-    other IP block, such as an HDMI encoder/display-controller.
+  - spdif-out		: This is a boolean property. If present, the
+			  transmitting function of S/PDIF will be enabled,
+			  indicating there's a physical S/PDIF out connector
+			  or jack on the board or it's connecting to some
+			  other IP block, such as an HDMI encoder or
+			  display-controller.
 
 
-  - spdif-in : This is a boolean property. If present, the receiving
-    function of S/PDIF will be enabled, indicating there's a physical
-    S/PDIF in connector/jack on the board.
+  - spdif-in		: This is a boolean property. If present, the receiving
+			  function of S/PDIF will be enabled, indicating there
+			  is a physical S/PDIF in connector/jack on the board.
 
 
 * Note: At least one of these two properties should be set in the DT binding.
 * Note: At least one of these two properties should be set in the DT binding.
 
 

+ 26 - 19
Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt

@@ -1,25 +1,32 @@
 Freescale i.MX audio complex with WM8962 codec
 Freescale i.MX audio complex with WM8962 codec
 
 
 Required properties:
 Required properties:
-- compatible : "fsl,imx-audio-wm8962"
-- model : The user-visible name of this sound complex
-- ssi-controller : The phandle of the i.MX SSI controller
-- audio-codec : The phandle of the WM8962 audio codec
-- 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 could be power
-  supplies, WM8962 pins, and the jacks on the board:
-
-  Power supplies:
-   * Mic Bias
-
-  Board connectors:
-   * Mic Jack
-   * Headphone Jack
-   * Ext Spk
-
-- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
-- mux-ext-port : The external port of the i.MX audio muxer
+
+  - compatible		: "fsl,imx-audio-wm8962"
+
+  - model		: The user-visible name of this sound complex
+
+  - ssi-controller	: The phandle of the i.MX SSI controller
+
+  - audio-codec		: The phandle of the WM8962 audio codec
+
+  - 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 could be power supplies, WM8962
+			  pins, and the jacks on the board:
+
+			  Power supplies:
+			   * Mic Bias
+
+			  Board connectors:
+			   * Mic Jack
+			   * Headphone Jack
+			   * Ext Spk
+
+  - mux-int-port	: The internal port of the i.MX audio muxer (AUDMUX)
+
+  - mux-ext-port	: The external port of the i.MX audio muxer
 
 
 Note: The AUDMUX port numbering should start at 1, which is consistent with
 Note: The AUDMUX port numbering should start at 1, which is consistent with
 hardware manual.
 hardware manual.

+ 14 - 8
Documentation/devicetree/bindings/sound/imx-audmux.txt

@@ -1,18 +1,24 @@
 Freescale Digital Audio Mux (AUDMUX) device
 Freescale Digital Audio Mux (AUDMUX) device
 
 
 Required properties:
 Required properties:
-- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used on i.MX21,
-  or "fsl,imx31-audmux" for the version firstly used on i.MX31.
-- reg : Should contain AUDMUX registers location and length
+
+  - compatible		: "fsl,imx21-audmux" for AUDMUX version firstly used
+			  on i.MX21, or "fsl,imx31-audmux" for the version
+			  firstly used on i.MX31.
+
+  - reg			: Should contain AUDMUX registers location and length.
 
 
 An initial configuration can be setup using child nodes.
 An initial configuration can be setup using child nodes.
 
 
 Required properties of optional child nodes:
 Required properties of optional child nodes:
-- fsl,audmux-port : Integer of the audmux port that is configured by this
-  child node.
-- fsl,port-config : List of configuration options for the specific port. For
-  imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For
-  imx21-audmux it is a list of pcr values.
+
+  - fsl,audmux-port	: Integer of the audmux port that is configured by this
+			  child node.
+
+  - fsl,port-config	: List of configuration options for the specific port.
+			  For imx31-audmux and above, it is a list of tuples
+			  <ptcr pdcr>. For imx21-audmux it is a list of pcr
+			  values.
 
 
 Example:
 Example:
 
 

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

@@ -16,6 +16,8 @@ Optional properties:
 
 
 - clock-names: Should be "mclk"
 - clock-names: Should be "mclk"
 
 
+- maxim,dmic-freq: Frequency at which to clock DMIC
+
 Pins on the device (for linking into audio routes):
 Pins on the device (for linking into audio routes):
 
 
   * MIC1
   * MIC1

+ 7 - 2
Documentation/devicetree/bindings/sound/renesas,fsi.txt

@@ -1,11 +1,16 @@
 Renesas FSI
 Renesas FSI
 
 
 Required properties:
 Required properties:
-- compatible			: "renesas,sh_fsi2" or "renesas,sh_fsi"
+- compatible			: "renesas,fsi2-<soctype>",
+				  "renesas,sh_fsi2" or "renesas,sh_fsi" as
+				  fallback.
+				  Examples with soctypes are:
+				    - "renesas,fsi2-r8a7740" (R-Mobile A1)
+				    - "renesas,fsi2-sh73a0" (SH-Mobile AG5)
 - reg				: Should contain the register physical address and length
 - reg				: Should contain the register physical address and length
 - interrupts			: Should contain FSI interrupt
 - interrupts			: Should contain FSI interrupt
 
 
-- fsia,spdif-connection		: FSI is connected by S/PDFI
+- fsia,spdif-connection		: FSI is connected by S/PDIF
 - fsia,stream-mode-support	: FSI supports 16bit stream mode.
 - fsia,stream-mode-support	: FSI supports 16bit stream mode.
 - fsia,use-internal-clock	: FSI uses internal clock when master mode.
 - fsia,use-internal-clock	: FSI uses internal clock when master mode.
 
 

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

@@ -1,8 +1,12 @@
 Renesas R-Car sound
 Renesas R-Car sound
 
 
 Required properties:
 Required properties:
-- compatible			: "renesas,rcar_sound-gen1" if generation1
+- compatible			: "renesas,rcar_sound-<soctype>", fallbacks
+				  "renesas,rcar_sound-gen1" if generation1, and
 				  "renesas,rcar_sound-gen2" if generation2
 				  "renesas,rcar_sound-gen2" if generation2
+				  Examples with soctypes are:
+				    - "renesas,rcar_sound-r8a7790" (R-Car H2)
+				    - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
 - reg				: Should contain the register physical address.
 - reg				: Should contain the register physical address.
 				  required register is
 				  required register is
 				   SRU/ADG/SSI      if generation1
 				   SRU/ADG/SSI      if generation1
@@ -35,9 +39,9 @@ DAI subnode properties:
 
 
 Example:
 Example:
 
 
-rcar_sound: rcar_sound@0xffd90000 {
+rcar_sound: rcar_sound@ec500000 {
 	#sound-dai-cells = <1>;
 	#sound-dai-cells = <1>;
-	compatible = "renesas,rcar_sound-gen2";
+	compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
 	reg =	<0 0xec500000 0 0x1000>, /* SCU */
 	reg =	<0 0xec500000 0 0x1000>, /* SCU */
 		<0 0xec5a0000 0 0x100>,  /* ADG */
 		<0 0xec5a0000 0 0x100>,  /* ADG */
 		<0 0xec540000 0 0x1000>, /* SSIU */
 		<0 0xec540000 0 0x1000>, /* SSIU */

+ 48 - 0
Documentation/devicetree/bindings/sound/rt5631.txt

@@ -0,0 +1,48 @@
+ALC5631/RT5631 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "realtek,alc5631" or "realtek,rt5631"
+
+  - reg : the I2C address of the device.
+
+Pins on the device (for linking into audio routes):
+
+  * SPK_OUT_R_P
+  * SPK_OUT_R_N
+  * SPK_OUT_L_P
+  * SPK_OUT_L_N
+  * HP_OUT_L
+  * HP_OUT_R
+  * AUX_OUT2_LP
+  * AUX_OUT2_RN
+  * AUX_OUT1_LP
+  * AUX_OUT1_RN
+  * AUX_IN_L_JD
+  * AUX_IN_R_JD
+  * MONO_IN_P
+  * MONO_IN_N
+  * MIC1_P
+  * MIC1_N
+  * MIC2_P
+  * MIC2_N
+  * MONO_OUT_P
+  * MONO_OUT_N
+  * MICBIAS1
+  * MICBIAS2
+
+Example:
+
+alc5631: alc5631@1a {
+	compatible = "realtek,alc5631";
+	reg = <0x1a>;
+};
+
+or
+
+rt5631: rt5631@1a {
+	compatible = "realtek,rt5631";
+	reg = <0x1a>;
+};

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

@@ -27,6 +27,21 @@ Optional properties:
   Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
   Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
   rather than single-ended.
   rather than single-ended.
 
 
+- realtek,gpio-config
+  Array of six 8bit elements that configures GPIO.
+    0 - floating (reset value)
+    1 - pull down
+    2 - pull up
+
+- realtek,jd1-gpio
+  Configures GPIO Mic Jack detection 1.
+  Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively.
+
+- realtek,jd2-gpio
+- realtek,jd3-gpio
+  Configures GPIO Mic Jack detection 2 and 3.
+  Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively.
+
 Pins on the device (for linking into audio routes):
 Pins on the device (for linking into audio routes):
 
 
   * IN1P
   * IN1P
@@ -56,4 +71,6 @@ rt5677 {
 	realtek,pow-ldo2-gpio =
 	realtek,pow-ldo2-gpio =
 		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
 		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
 	realtek,in1-differential = "true";
 	realtek,in1-differential = "true";
+	realtek,gpio-config = /bits/ 8  <0 0 0 0 0 2>;   /* pull up GPIO6 */
+	realtek,jd2-gpio = <3>;  /* Enables Jack detection for GPIO6 */
 };
 };

+ 11 - 4
Documentation/devicetree/bindings/sound/samsung-i2s.txt

@@ -6,10 +6,17 @@ Required SoC Specific Properties:
    - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
    - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
    - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
    - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
      secondary fifo, s/w reset control and internal mux for root clk src.
      secondary fifo, s/w reset control and internal mux for root clk src.
-   - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
-     secondary fifo, s/w reset control, internal mux for root clk src and
-     TDM support. TDM (Time division multiplexing) is to allow transfer of
-     multiple channel audio data on single data line.
+   - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
+     playback, sterio channel capture, secondary fifo using internal
+     or external dma, s/w reset control, internal mux for root clk src
+     and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
+     is to allow transfer of multiple channel audio data on single data line.
+   - samsung,exynos7-i2s: with all the available features of exynos5 i2s,
+     exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
+     with only external dma and more no.of root clk sampling frequencies.
+   - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
+     stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
+     slightly modified bit offsets.
 
 
 - reg: physical base address of the controller and length of memory mapped
 - reg: physical base address of the controller and length of memory mapped
   region.
   region.

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

@@ -7,6 +7,17 @@ Required properties:
 
 
 - clocks : the clock provider of SYS_MCLK
 - clocks : the clock provider of SYS_MCLK
 
 
+- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs
+	The resistor can take values of 2k, 4k or 8k.
+	If set to 0 it will be off.
+	If this node is not mentioned or if the value is unknown, then
+	micbias	resistor is set to 4K.
+
+- micbias-voltage-m-volts : the bias voltage to be used in mVolts
+	The voltage can take values from 1.25V to 3V by 250mV steps
+	If this node is not mentionned or the value is unknown, then
+	the value is set to 1.25V.
+
 - VDDA-supply : the regulator provider of VDDA
 - VDDA-supply : the regulator provider of VDDA
 
 
 - VDDIO-supply: the regulator provider of VDDIO
 - VDDIO-supply: the regulator provider of VDDIO
@@ -21,6 +32,8 @@ codec: sgtl5000@0a {
 	compatible = "fsl,sgtl5000";
 	compatible = "fsl,sgtl5000";
 	reg = <0x0a>;
 	reg = <0x0a>;
 	clocks = <&clks 150>;
 	clocks = <&clks 150>;
+	micbias-resistor-k-ohms = <2>;
+	micbias-voltage-m-volts = <2250>;
 	VDDA-supply = <&reg_3p3v>;
 	VDDA-supply = <&reg_3p3v>;
 	VDDIO-supply = <&reg_3p3v>;
 	VDDIO-supply = <&reg_3p3v>;
 };
 };

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

@@ -0,0 +1,26 @@
+Texas Instruments TS3A227E
+Autonomous Audio Accessory Detection and Configuration Switch
+
+The TS3A227E detect headsets of 3-ring and 4-ring standards and
+switches automatically to route the microphone correctly.  It also
+handles key press detection in accordance with the Android audio
+headset specification v1.0.
+
+Required properties:
+
+ - compatible:		Should contain "ti,ts3a227e".
+ - reg:			The i2c address. Should contain <0x3b>.
+ - interrupt-parent:	The parent interrupt controller
+ - interrupts:		Interrupt number for /INT pin from the 227e
+
+
+Examples:
+
+	i2c {
+		ts3a227e@3b {
+			compatible = "ti,ts3a227e";
+			reg = <0x3b>;
+			interrupt-parent = <&gpio>;
+			interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		};
+	};

+ 31 - 0
Documentation/devicetree/bindings/sound/wm8960.txt

@@ -0,0 +1,31 @@
+WM8960 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "wlf,wm8960"
+
+  - reg : the I2C address of the device.
+
+Optional properties:
+  - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of
+	R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins
+	will be disabled only when ADC (Left and Right) and DAC (Left and Right)
+	are disabled.
+	When wm8960 works on synchronize mode and DACLRC pin is used to supply
+	frame clock, it will no frame clock for captrue unless enable DAC to enable
+	DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue.
+
+  - wlf,capless: This is a boolean property. If present, OUT3 pin will be
+	enabled and disabled together with HP_L and HP_R pins in response to jack
+	detect events.
+
+Example:
+
+codec: wm8960@1a {
+	compatible = "wlf,wm8960";
+	reg = <0x1a>;
+
+	wlf,shared-lrclk;
+};

+ 6 - 0
MAINTAINERS

@@ -6601,6 +6601,12 @@ S:	Supported
 F:	drivers/gpu/drm/i2c/tda998x_drv.c
 F:	drivers/gpu/drm/i2c/tda998x_drv.c
 F:	include/drm/i2c/tda998x.h
 F:	include/drm/i2c/tda998x.h
 
 
+NXP TFA9879 DRIVER
+M:	Peter Rosin <peda@axentia.se>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Maintained
+F:	sound/soc/codecs/tfa9879*
+
 OMAP SUPPORT
 OMAP SUPPORT
 M:	Tony Lindgren <tony@atomide.com>
 M:	Tony Lindgren <tony@atomide.com>
 L:	linux-omap@vger.kernel.org
 L:	linux-omap@vger.kernel.org

+ 9 - 0
arch/arm/mach-pxa/spitz.c

@@ -923,6 +923,14 @@ static void __init spitz_i2c_init(void)
 static inline void spitz_i2c_init(void) {}
 static inline void spitz_i2c_init(void) {}
 #endif
 #endif
 
 
+/******************************************************************************
+ * Audio devices
+ ******************************************************************************/
+static inline void spitz_audio_init(void)
+{
+	platform_device_register_simple("spitz-audio", -1, NULL, 0);
+}
+
 /******************************************************************************
 /******************************************************************************
  * Machine init
  * Machine init
  ******************************************************************************/
  ******************************************************************************/
@@ -970,6 +978,7 @@ static void __init spitz_init(void)
 	spitz_nor_init();
 	spitz_nor_init();
 	spitz_nand_init();
 	spitz_nand_init();
 	spitz_i2c_init();
 	spitz_i2c_init();
+	spitz_audio_init();
 }
 }
 
 
 static void __init spitz_fixup(struct tag *tags, char **cmdline)
 static void __init spitz_fixup(struct tag *tags, char **cmdline)

+ 62 - 0
arch/x86/include/asm/platform_sst_audio.h

@@ -16,6 +16,9 @@
 
 
 #include <linux/sfi.h>
 #include <linux/sfi.h>
 
 
+#define MAX_NUM_STREAMS_MRFLD	25
+#define MAX_NUM_STREAMS	MAX_NUM_STREAMS_MRFLD
+
 enum sst_audio_task_id_mrfld {
 enum sst_audio_task_id_mrfld {
 	SST_TASK_ID_NONE = 0,
 	SST_TASK_ID_NONE = 0,
 	SST_TASK_ID_SBA = 1,
 	SST_TASK_ID_SBA = 1,
@@ -73,6 +76,65 @@ struct sst_platform_data {
 	unsigned int strm_map_size;
 	unsigned int strm_map_size;
 };
 };
 
 
+struct sst_info {
+	u32 iram_start;
+	u32 iram_end;
+	bool iram_use;
+	u32 dram_start;
+	u32 dram_end;
+	bool dram_use;
+	u32 imr_start;
+	u32 imr_end;
+	bool imr_use;
+	u32 mailbox_start;
+	bool use_elf;
+	bool lpe_viewpt_rqd;
+	unsigned int max_streams;
+	u32 dma_max_len;
+	u8 num_probes;
+};
+
+struct sst_lib_dnld_info {
+	unsigned int mod_base;
+	unsigned int mod_end;
+	unsigned int mod_table_offset;
+	unsigned int mod_table_size;
+	bool mod_ddr_dnld;
+};
+
+struct sst_res_info {
+	unsigned int shim_offset;
+	unsigned int shim_size;
+	unsigned int shim_phy_addr;
+	unsigned int ssp0_offset;
+	unsigned int ssp0_size;
+	unsigned int dma0_offset;
+	unsigned int dma0_size;
+	unsigned int dma1_offset;
+	unsigned int dma1_size;
+	unsigned int iram_offset;
+	unsigned int iram_size;
+	unsigned int dram_offset;
+	unsigned int dram_size;
+	unsigned int mbox_offset;
+	unsigned int mbox_size;
+	unsigned int acpi_lpe_res_index;
+	unsigned int acpi_ddr_index;
+	unsigned int acpi_ipc_irq_index;
+};
+
+struct sst_ipc_info {
+	int ipc_offset;
+	unsigned int mbox_recv_off;
+};
+
+struct sst_platform_info {
+	const struct sst_info *probe_data;
+	const struct sst_ipc_info *ipc_info;
+	const struct sst_res_info *res_info;
+	const struct sst_lib_dnld_info *lib_info;
+	const char *platform;
+};
 int add_sst_platform_device(void);
 int add_sst_platform_device(void);
 #endif
 #endif
 
 

+ 4 - 1
drivers/base/regmap/Kconfig

@@ -3,12 +3,15 @@
 # subsystems should select the appropriate symbols.
 # subsystems should select the appropriate symbols.
 
 
 config REGMAP
 config REGMAP
-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
+	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
 	select LZO_COMPRESS
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	select LZO_DECOMPRESS
 	select IRQ_DOMAIN if REGMAP_IRQ
 	select IRQ_DOMAIN if REGMAP_IRQ
 	bool
 	bool
 
 
+config REGMAP_AC97
+	tristate
+
 config REGMAP_I2C
 config REGMAP_I2C
 	tristate
 	tristate
 	depends on I2C
 	depends on I2C

+ 1 - 0
drivers/base/regmap/Makefile

@@ -1,6 +1,7 @@
 obj-$(CONFIG_REGMAP) += regmap.o regcache.o
 obj-$(CONFIG_REGMAP) += regmap.o regcache.o
 obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
 obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
 obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
 obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
+obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
 obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
 obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
 obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o

+ 114 - 0
drivers/base/regmap/regmap-ac97.c

@@ -0,0 +1,114 @@
+/*
+ * Register map access API - AC'97 support
+ *
+ * Copyright 2013 Linaro Ltd.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/ac97_codec.h>
+
+bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_RESET:
+	case AC97_POWERDOWN:
+	case AC97_INT_PAGING:
+	case AC97_EXTENDED_ID:
+	case AC97_EXTENDED_STATUS:
+	case AC97_EXTENDED_MID:
+	case AC97_EXTENDED_MSTATUS:
+	case AC97_GPIO_STATUS:
+	case AC97_MISC_AFE:
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+	case AC97_CODEC_CLASS_REV:
+	case AC97_PCI_SVID:
+	case AC97_PCI_SID:
+	case AC97_FUNC_SELECT:
+	case AC97_FUNC_INFO:
+	case AC97_SENSE_INFO:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile);
+
+static int regmap_ac97_reg_read(void *context, unsigned int reg,
+	unsigned int *val)
+{
+	struct snd_ac97 *ac97 = context;
+
+	*val = ac97->bus->ops->read(ac97, reg);
+
+	return 0;
+}
+
+static int regmap_ac97_reg_write(void *context, unsigned int reg,
+	unsigned int val)
+{
+	struct snd_ac97 *ac97 = context;
+
+	ac97->bus->ops->write(ac97, reg, val);
+
+	return 0;
+}
+
+static const struct regmap_bus ac97_regmap_bus = {
+		.reg_write = regmap_ac97_reg_write,
+		.reg_read = regmap_ac97_reg_read,
+};
+
+/**
+ * regmap_init_ac97(): Initialise AC'97 register map
+ *
+ * @ac97: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
+				const struct regmap_config *config)
+{
+	return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_ac97);
+
+/**
+ * devm_regmap_init_ac97(): Initialise AC'97 register map
+ *
+ * @ac97: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
+				     const struct regmap_config *config)
+{
+	return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_ac97);
+
+MODULE_LICENSE("GPL v2");

+ 1 - 0
include/linux/mfd/arizona/core.h

@@ -141,6 +141,7 @@ struct arizona {
 
 
 	uint16_t dac_comp_coeff;
 	uint16_t dac_comp_coeff;
 	uint8_t dac_comp_enabled;
 	uint8_t dac_comp_enabled;
+	struct mutex dac_comp_lock;
 };
 };
 
 
 int arizona_clk32k_enable(struct arizona *arizona);
 int arizona_clk32k_enable(struct arizona *arizona);

+ 0 - 7
include/linux/mfd/davinci_voicecodec.h

@@ -99,12 +99,6 @@ struct davinci_vcif {
 	dma_addr_t dma_rx_addr;
 	dma_addr_t dma_rx_addr;
 };
 };
 
 
-struct cq93vc {
-	struct platform_device *pdev;
-	struct snd_soc_codec *codec;
-	u32 sysclk;
-};
-
 struct davinci_vc;
 struct davinci_vc;
 
 
 struct davinci_vc {
 struct davinci_vc {
@@ -122,7 +116,6 @@ struct davinci_vc {
 
 
 	/* Client devices */
 	/* Client devices */
 	struct davinci_vcif davinci_vcif;
 	struct davinci_vcif davinci_vcif;
-	struct cq93vc cq93vc;
 };
 };
 
 
 #endif
 #endif

+ 1 - 0
include/linux/platform_data/asoc-s3c.h

@@ -27,6 +27,7 @@ struct samsung_i2s {
 #define QUIRK_NO_MUXPSR		(1 << 2)
 #define QUIRK_NO_MUXPSR		(1 << 2)
 #define QUIRK_NEED_RSTCLR	(1 << 3)
 #define QUIRK_NEED_RSTCLR	(1 << 3)
 #define QUIRK_SUPPORTS_TDM	(1 << 4)
 #define QUIRK_SUPPORTS_TDM	(1 << 4)
+#define QUIRK_SUPPORTS_IDMA	(1 << 5)
 	/* Quirks of the I2S controller */
 	/* Quirks of the I2S controller */
 	u32 quirks;
 	u32 quirks;
 	dma_addr_t idma_addr;
 	dma_addr_t idma_addr;

+ 7 - 0
include/linux/regmap.h

@@ -27,6 +27,7 @@ struct spmi_device;
 struct regmap;
 struct regmap;
 struct regmap_range_cfg;
 struct regmap_range_cfg;
 struct regmap_field;
 struct regmap_field;
+struct snd_ac97;
 
 
 /* An enum of all the supported cache types */
 /* An enum of all the supported cache types */
 enum regcache_type {
 enum regcache_type {
@@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 				    void __iomem *regs,
 				    void __iomem *regs,
 				    const struct regmap_config *config);
 				    const struct regmap_config *config);
+struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
+				const struct regmap_config *config);
 
 
 struct regmap *devm_regmap_init(struct device *dev,
 struct regmap *devm_regmap_init(struct device *dev,
 				const struct regmap_bus *bus,
 				const struct regmap_bus *bus,
@@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 					 void __iomem *regs,
 					 void __iomem *regs,
 					 const struct regmap_config *config);
 					 const struct regmap_config *config);
+struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
+				     const struct regmap_config *config);
+
+bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
 
 
 /**
 /**
  * regmap_init_mmio(): Initialise register map
  * regmap_init_mmio(): Initialise register map

+ 4 - 4
include/sound/rcar_snd.h

@@ -36,14 +36,14 @@
 #define RSND_SSI_CLK_PIN_SHARE		(1 << 31)
 #define RSND_SSI_CLK_PIN_SHARE		(1 << 31)
 #define RSND_SSI_NO_BUSIF		(1 << 30) /* SSI+DMA without BUSIF */
 #define RSND_SSI_NO_BUSIF		(1 << 30) /* SSI+DMA without BUSIF */
 
 
-#define RSND_SSI(_dma_id, _pio_irq, _flags)		\
-{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
+#define RSND_SSI(_dma_id, _irq, _flags)		\
+{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
 #define RSND_SSI_UNUSED \
 #define RSND_SSI_UNUSED \
-{ .dma_id = -1, .pio_irq = -1, .flags = 0 }
+{ .dma_id = -1, .irq = -1, .flags = 0 }
 
 
 struct rsnd_ssi_platform_info {
 struct rsnd_ssi_platform_info {
 	int dma_id;
 	int dma_id;
-	int pio_irq;
+	int irq;
 	u32 flags;
 	u32 flags;
 };
 };
 
 

+ 4 - 0
include/sound/rt5645.h

@@ -23,6 +23,10 @@ struct rt5645_platform_data {
 
 
 	unsigned int hp_det_gpio;
 	unsigned int hp_det_gpio;
 	bool gpio_hp_det_active_high;
 	bool gpio_hp_det_active_high;
+
+	/* true if codec's jd function is used */
+	bool en_jd_func;
+	unsigned int jd_mode;
 };
 };
 
 
 #endif
 #endif

+ 10 - 0
include/sound/rt5677.h

@@ -27,6 +27,16 @@ struct rt5677_platform_data {
 	bool lout3_diff;
 	bool lout3_diff;
 	/* DMIC2 clock source selection */
 	/* DMIC2 clock source selection */
 	enum rt5677_dmic2_clk dmic2_clk_pin;
 	enum rt5677_dmic2_clk dmic2_clk_pin;
+
+	/* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
+	u8 gpio_config[6];
+
+	/* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
+	unsigned int jd1_gpio;
+	/* jd2 and jd3 can select 0 ~ 3 as
+		OFF, GPIO4, GPIO5 and GPIO6 respectively */
+	unsigned int jd2_gpio;
+	unsigned int jd3_gpio;
 };
 };
 
 
 #endif
 #endif

+ 2 - 5
include/sound/soc-dai.h

@@ -206,7 +206,6 @@ struct snd_soc_dai_driver {
 	/* DAI description */
 	/* DAI description */
 	const char *name;
 	const char *name;
 	unsigned int id;
 	unsigned int id;
-	int ac97_control;
 	unsigned int base;
 	unsigned int base;
 
 
 	/* DAI driver callbacks */
 	/* DAI driver callbacks */
@@ -216,6 +215,8 @@ struct snd_soc_dai_driver {
 	int (*resume)(struct snd_soc_dai *dai);
 	int (*resume)(struct snd_soc_dai *dai);
 	/* compress dai */
 	/* compress dai */
 	bool compress_dai;
 	bool compress_dai;
+	/* DAI is also used for the control bus */
+	bool bus_control;
 
 
 	/* ops */
 	/* ops */
 	const struct snd_soc_dai_ops *ops;
 	const struct snd_soc_dai_ops *ops;
@@ -241,7 +242,6 @@ struct snd_soc_dai {
 	const char *name;
 	const char *name;
 	int id;
 	int id;
 	struct device *dev;
 	struct device *dev;
-	void *ac97_pdata;	/* platform_data for the ac97 codec */
 
 
 	/* driver ops */
 	/* driver ops */
 	struct snd_soc_dai_driver *driver;
 	struct snd_soc_dai_driver *driver;
@@ -268,7 +268,6 @@ struct snd_soc_dai {
 	unsigned int sample_bits;
 	unsigned int sample_bits;
 
 
 	/* parent platform/codec */
 	/* parent platform/codec */
-	struct snd_soc_platform *platform;
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec *codec;
 	struct snd_soc_component *component;
 	struct snd_soc_component *component;
 
 
@@ -276,8 +275,6 @@ struct snd_soc_dai {
 	unsigned int tx_mask;
 	unsigned int tx_mask;
 	unsigned int rx_mask;
 	unsigned int rx_mask;
 
 
-	struct snd_soc_card *card;
-
 	struct list_head list;
 	struct list_head list;
 };
 };
 
 

+ 6 - 3
include/sound/soc-dapm.h

@@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
 unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 
 
 /* Mostly internal - should not normally be used */
 /* Mostly internal - should not normally be used */
-void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
+void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
 
 
 /* dapm path query */
 /* dapm path query */
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
@@ -508,9 +508,9 @@ struct snd_soc_dapm_path {
 
 
 	/* status */
 	/* status */
 	u32 connect:1;	/* source and sink widgets are connected */
 	u32 connect:1;	/* source and sink widgets are connected */
-	u32 walked:1;	/* path has been walked */
 	u32 walking:1;  /* path is in the process of being walked */
 	u32 walking:1;  /* path is in the process of being walked */
 	u32 weak:1;	/* path ignored for power management */
 	u32 weak:1;	/* path ignored for power management */
+	u32 is_supply:1;	/* At least one of the connected widgets is a supply */
 
 
 	int (*connected)(struct snd_soc_dapm_widget *source,
 	int (*connected)(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink);
 			 struct snd_soc_dapm_widget *sink);
@@ -544,11 +544,13 @@ struct snd_soc_dapm_widget {
 	unsigned char active:1;			/* active stream on DAC, ADC's */
 	unsigned char active:1;			/* active stream on DAC, ADC's */
 	unsigned char connected:1;		/* connected codec pin */
 	unsigned char connected:1;		/* connected codec pin */
 	unsigned char new:1;			/* cnew complete */
 	unsigned char new:1;			/* cnew complete */
-	unsigned char ext:1;			/* has external widgets */
 	unsigned char force:1;			/* force state */
 	unsigned char force:1;			/* force state */
 	unsigned char ignore_suspend:1;         /* kept enabled over suspend */
 	unsigned char ignore_suspend:1;         /* kept enabled over suspend */
 	unsigned char new_power:1;		/* power from this run */
 	unsigned char new_power:1;		/* power from this run */
 	unsigned char power_checked:1;		/* power checked this run */
 	unsigned char power_checked:1;		/* power checked this run */
+	unsigned char is_supply:1;		/* Widget is a supply type widget */
+	unsigned char is_sink:1;		/* Widget is a sink type widget */
+	unsigned char is_source:1;		/* Widget is a source type widget */
 	int subseq;				/* sort within widget type */
 	int subseq;				/* sort within widget type */
 
 
 	int (*power_check)(struct snd_soc_dapm_widget *w);
 	int (*power_check)(struct snd_soc_dapm_widget *w);
@@ -567,6 +569,7 @@ struct snd_soc_dapm_widget {
 	struct list_head sinks;
 	struct list_head sinks;
 
 
 	/* used during DAPM updates */
 	/* used during DAPM updates */
+	struct list_head work_list;
 	struct list_head power_list;
 	struct list_head power_list;
 	struct list_head dirty;
 	struct list_head dirty;
 	int inputs;
 	int inputs;

+ 82 - 34
include/sound/soc.h

@@ -36,6 +36,11 @@
 	{.reg = xreg, .rreg = xreg, .shift = shift_left, \
 	{.reg = xreg, .rreg = xreg, .shift = shift_left, \
 	.rshift = shift_right, .max = xmax, .platform_max = xmax, \
 	.rshift = shift_right, .max = xmax, .platform_max = xmax, \
 	.invert = xinvert, .autodisable = xautodisable})
 	.invert = xinvert, .autodisable = xautodisable})
+#define SOC_DOUBLE_S_VALUE(xreg, shift_left, shift_right, xmin, xmax, xsign_bit, xinvert, xautodisable) \
+	((unsigned long)&(struct soc_mixer_control) \
+	{.reg = xreg, .rreg = xreg, .shift = shift_left, \
+	.rshift = shift_right, .min = xmin, .max = xmax, .platform_max = xmax, \
+	.sign_bit = xsign_bit, .invert = xinvert, .autodisable = xautodisable})
 #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
 #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
 	SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
 	SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
 #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
 #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
@@ -171,11 +176,9 @@
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
 		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
 		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
 	.tlv.p  = (tlv_array), \
 	.tlv.p  = (tlv_array), \
-	.info   = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
-	.put    = snd_soc_put_volsw_s8, \
-	.private_value = (unsigned long)&(struct soc_mixer_control) \
-		{.reg = xreg, .min = xmin, .max = xmax, \
-		 .platform_max = xmax} }
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+	.put = snd_soc_put_volsw, \
+	.private_value = SOC_DOUBLE_S_VALUE(xreg, 0, 8, xmin, xmax, 7, 0, 0) }
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
 	.items = xitems, .texts = xtexts, \
 	.items = xitems, .texts = xtexts, \
@@ -366,8 +369,6 @@ struct snd_soc_jack_gpio;
 
 
 typedef int (*hw_write_t)(void *,const char* ,int);
 typedef int (*hw_write_t)(void *,const char* ,int);
 
 
-extern struct snd_ac97_bus_ops *soc_ac97_ops;
-
 enum snd_soc_pcm_subclass {
 enum snd_soc_pcm_subclass {
 	SND_SOC_PCM_CLASS_PCM	= 0,
 	SND_SOC_PCM_CLASS_PCM	= 0,
 	SND_SOC_PCM_CLASS_BE	= 1,
 	SND_SOC_PCM_CLASS_BE	= 1,
@@ -409,13 +410,9 @@ int devm_snd_soc_register_component(struct device *dev,
 			 const struct snd_soc_component_driver *cmpnt_drv,
 			 const struct snd_soc_component_driver *cmpnt_drv,
 			 struct snd_soc_dai_driver *dai_drv, int num_dai);
 			 struct snd_soc_dai_driver *dai_drv, int num_dai);
 void snd_soc_unregister_component(struct device *dev);
 void snd_soc_unregister_component(struct device *dev);
-int snd_soc_cache_sync(struct snd_soc_codec *codec);
 int snd_soc_cache_init(struct snd_soc_codec *codec);
 int snd_soc_cache_init(struct snd_soc_codec *codec);
 int snd_soc_cache_exit(struct snd_soc_codec *codec);
 int snd_soc_cache_exit(struct snd_soc_codec *codec);
-int snd_soc_cache_write(struct snd_soc_codec *codec,
-			unsigned int reg, unsigned int value);
-int snd_soc_cache_read(struct snd_soc_codec *codec,
-		       unsigned int reg, unsigned int *value);
+
 int snd_soc_platform_read(struct snd_soc_platform *platform,
 int snd_soc_platform_read(struct snd_soc_platform *platform,
 					unsigned int reg);
 					unsigned int reg);
 int snd_soc_platform_write(struct snd_soc_platform *platform,
 int snd_soc_platform_write(struct snd_soc_platform *platform,
@@ -500,14 +497,28 @@ int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
 int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
 int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
 				unsigned int mask, unsigned int value);
 				unsigned int mask, unsigned int value);
 
 
-int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
-	struct snd_ac97_bus_ops *ops, int num);
-void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
+void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
 
 
 int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
 int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
 int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
 int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
 		struct platform_device *pdev);
 		struct platform_device *pdev);
 
 
+extern struct snd_ac97_bus_ops *soc_ac97_ops;
+#else
+static inline int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+	struct platform_device *pdev)
+{
+	return 0;
+}
+
+static inline int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
+{
+	return 0;
+}
+#endif
+
 /*
 /*
  *Controls
  *Controls
  */
  */
@@ -545,12 +556,6 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
 int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 	struct snd_ctl_elem_value *ucontrol);
-int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo);
-int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
 int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
 	struct snd_ctl_elem_info *uinfo);
 int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
 int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
@@ -780,24 +785,18 @@ struct snd_soc_codec {
 	struct device *dev;
 	struct device *dev;
 	const struct snd_soc_codec_driver *driver;
 	const struct snd_soc_codec_driver *driver;
 
 
-	struct mutex mutex;
 	struct list_head list;
 	struct list_head list;
 	struct list_head card_list;
 	struct list_head card_list;
 
 
 	/* runtime */
 	/* runtime */
-	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	unsigned int cache_bypass:1; /* Suppress access to the cache */
 	unsigned int cache_bypass:1; /* Suppress access to the cache */
 	unsigned int suspended:1; /* Codec is in suspend PM state */
 	unsigned int suspended:1; /* Codec is in suspend PM state */
-	unsigned int ac97_registered:1; /* Codec has been AC97 registered */
-	unsigned int ac97_created:1; /* Codec has been created by SoC */
 	unsigned int cache_init:1; /* codec cache has been initialized */
 	unsigned int cache_init:1; /* codec cache has been initialized */
-	u32 cache_sync; /* Cache needs to be synced to hardware */
 
 
 	/* codec IO */
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
 	void *control_data; /* codec control (i2c/3wire) data */
 	hw_write_t hw_write;
 	hw_write_t hw_write;
 	void *reg_cache;
 	void *reg_cache;
-	struct mutex cache_rw_mutex;
 
 
 	/* component */
 	/* component */
 	struct snd_soc_component component;
 	struct snd_soc_component component;
@@ -860,8 +859,6 @@ struct snd_soc_platform_driver {
 
 
 	int (*probe)(struct snd_soc_platform *);
 	int (*probe)(struct snd_soc_platform *);
 	int (*remove)(struct snd_soc_platform *);
 	int (*remove)(struct snd_soc_platform *);
-	int (*suspend)(struct snd_soc_dai *dai);
-	int (*resume)(struct snd_soc_dai *dai);
 	struct snd_soc_component_driver component_driver;
 	struct snd_soc_component_driver component_driver;
 
 
 	/* pcm creation and destruction */
 	/* pcm creation and destruction */
@@ -886,7 +883,7 @@ struct snd_soc_platform_driver {
 
 
 struct snd_soc_dai_link_component {
 struct snd_soc_dai_link_component {
 	const char *name;
 	const char *name;
-	const struct device_node *of_node;
+	struct device_node *of_node;
 	const char *dai_name;
 	const char *dai_name;
 };
 };
 
 
@@ -894,8 +891,6 @@ struct snd_soc_platform {
 	struct device *dev;
 	struct device *dev;
 	const struct snd_soc_platform_driver *driver;
 	const struct snd_soc_platform_driver *driver;
 
 
-	unsigned int suspended:1; /* platform is suspended */
-
 	struct list_head list;
 	struct list_head list;
 
 
 	struct snd_soc_component component;
 	struct snd_soc_component component;
@@ -990,7 +985,7 @@ struct snd_soc_codec_conf {
 	 * DT/OF node, but not both.
 	 * DT/OF node, but not both.
 	 */
 	 */
 	const char *dev_name;
 	const char *dev_name;
-	const struct device_node *of_node;
+	struct device_node *of_node;
 
 
 	/*
 	/*
 	 * optional map of kcontrol, widget and path name prefixes that are
 	 * optional map of kcontrol, widget and path name prefixes that are
@@ -1007,7 +1002,7 @@ struct snd_soc_aux_dev {
 	 * DT/OF node, but not both.
 	 * DT/OF node, but not both.
 	 */
 	 */
 	const char *codec_name;
 	const char *codec_name;
-	const struct device_node *codec_of_node;
+	struct device_node *codec_of_node;
 
 
 	/* codec/machine specific init - e.g. add machine controls */
 	/* codec/machine specific init - e.g. add machine controls */
 	int (*init)(struct snd_soc_component *component);
 	int (*init)(struct snd_soc_component *component);
@@ -1264,6 +1259,17 @@ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
 int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
 	unsigned int val);
 	unsigned int val);
 
 
+/**
+ * snd_soc_cache_sync() - Sync the register cache with the hardware
+ * @codec: CODEC to sync
+ *
+ * Note: This function will call regcache_sync()
+ */
+static inline int snd_soc_cache_sync(struct snd_soc_codec *codec)
+{
+	return regcache_sync(codec->component.regmap);
+}
+
 /* component IO */
 /* component IO */
 int snd_soc_component_read(struct snd_soc_component *component,
 int snd_soc_component_read(struct snd_soc_component *component,
 	unsigned int reg, unsigned int *val);
 	unsigned int reg, unsigned int *val);
@@ -1277,6 +1283,45 @@ void snd_soc_component_async_complete(struct snd_soc_component *component);
 int snd_soc_component_test_bits(struct snd_soc_component *component,
 int snd_soc_component_test_bits(struct snd_soc_component *component,
 	unsigned int reg, unsigned int mask, unsigned int value);
 	unsigned int reg, unsigned int mask, unsigned int value);
 
 
+#ifdef CONFIG_REGMAP
+
+void snd_soc_component_init_regmap(struct snd_soc_component *component,
+	struct regmap *regmap);
+void snd_soc_component_exit_regmap(struct snd_soc_component *component);
+
+/**
+ * snd_soc_codec_init_regmap() - Initialize regmap instance for the CODEC
+ * @codec: The CODEC for which to initialize the regmap instance
+ * @regmap: The regmap instance that should be used by the CODEC
+ *
+ * This function allows deferred assignment of the regmap instance that is
+ * associated with the CODEC. Only use this if the regmap instance is not yet
+ * ready when the CODEC is registered. The function must also be called before
+ * the first IO attempt of the CODEC.
+ */
+static inline void snd_soc_codec_init_regmap(struct snd_soc_codec *codec,
+	struct regmap *regmap)
+{
+	snd_soc_component_init_regmap(&codec->component, regmap);
+}
+
+/**
+ * snd_soc_codec_exit_regmap() - De-initialize regmap instance for the CODEC
+ * @codec: The CODEC for which to de-initialize the regmap instance
+ *
+ * Calls regmap_exit() on the regmap instance associated to the CODEC and
+ * removes the regmap instance from the CODEC.
+ *
+ * This function should only be used if snd_soc_codec_init_regmap() was used to
+ * initialize the regmap instance.
+ */
+static inline void snd_soc_codec_exit_regmap(struct snd_soc_codec *codec)
+{
+	snd_soc_component_exit_regmap(&codec->component);
+}
+
+#endif
+
 /* device driver data */
 /* device driver data */
 
 
 static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
 static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
@@ -1451,6 +1496,9 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
 				     struct device_node **framemaster);
 				     struct device_node **framemaster);
 int snd_soc_of_get_dai_name(struct device_node *of_node,
 int snd_soc_of_get_dai_name(struct device_node *of_node,
 			    const char **dai_name);
 			    const char **dai_name);
+int snd_soc_of_get_dai_link_codecs(struct device *dev,
+				   struct device_node *of_node,
+				   struct snd_soc_dai_link *dai_link);
 
 
 #include <sound/soc-dai.h>
 #include <sound/soc-dai.h>
 
 

+ 0 - 12
include/sound/uda134x.h

@@ -18,18 +18,6 @@ struct uda134x_platform_data {
 	struct l3_pins l3;
 	struct l3_pins l3;
 	void (*power) (int);
 	void (*power) (int);
 	int model;
 	int model;
-	/*
-	  ALSA SOC usually puts the device in standby mode when it's not used
-	  for sometime. If you unset is_powered_on_standby the driver will
-	  turn off the ADC/DAC when this callback is invoked and turn it back
-	  on when needed. Unfortunately this will result in a very light bump
-	  (it can be audible only with good earphones). If this bothers you
-	  set is_powered_on_standby, you will have slightly higher power
-	  consumption. Please note that sending the L3 command for ADC is
-	  enough to make the bump, so it doesn't make difference if you
-	  completely take off power from the codec.
-	*/
-	int is_powered_on_standby;
 #define UDA134X_UDA1340 1
 #define UDA134X_UDA1340 1
 #define UDA134X_UDA1341 2
 #define UDA134X_UDA1341 2
 #define UDA134X_UDA1344 3
 #define UDA134X_UDA1344 3

+ 0 - 25
include/trace/events/asoc.h

@@ -288,31 +288,6 @@ TRACE_EVENT(snd_soc_jack_notify,
 	TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
 	TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
 );
 );
 
 
-TRACE_EVENT(snd_soc_cache_sync,
-
-	TP_PROTO(struct snd_soc_codec *codec, const char *type,
-		 const char *status),
-
-	TP_ARGS(codec, type, status),
-
-	TP_STRUCT__entry(
-		__string(	name,		codec->component.name)
-		__string(	status,		status		)
-		__string(	type,		type		)
-		__field(	int,		id		)
-	),
-
-	TP_fast_assign(
-		__assign_str(name, codec->component.name);
-		__assign_str(status, status);
-		__assign_str(type, type);
-		__entry->id = codec->component.id;
-	),
-
-	TP_printk("codec=%s.%d type=%s status=%s", __get_str(name),
-		  (int)__entry->id, __get_str(type), __get_str(status))
-);
-
 #endif /* _TRACE_ASOC_H */
 #endif /* _TRACE_ASOC_H */
 
 
 /* This part must be outside protection */
 /* This part must be outside protection */

+ 5 - 1
sound/soc/Makefile

@@ -1,10 +1,14 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
-snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o
+snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
 
 
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 endif
 endif
 
 
+ifneq ($(CONFIG_SND_SOC_AC97_BUS),)
+snd-soc-core-objs += soc-ac97.o
+endif
+
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= generic/
 obj-$(CONFIG_SND_SOC)	+= generic/

+ 0 - 9
sound/soc/atmel/Kconfig

@@ -52,12 +52,3 @@ config SND_AT91_SOC_SAM9X5_WM8731
 	help
 	help
 	  Say Y if you want to add support for audio SoC on an
 	  Say Y if you want to add support for audio SoC on an
 	  at91sam9x5 based board that is using WM8731 codec.
 	  at91sam9x5 based board that is using WM8731 codec.
-
-config SND_AT91_SOC_AFEB9260
-	tristate "SoC Audio support for AFEB9260 board"
-	depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
-	select SND_ATMEL_SOC_PDC
-	select SND_ATMEL_SOC_SSC
-	select SND_SOC_TLV320AIC23_I2C
-	help
-	  Say Y here to support sound on AFEB9260 board.

+ 0 - 1
sound/soc/atmel/Makefile

@@ -17,4 +17,3 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
-obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o

+ 5 - 2
sound/soc/atmel/atmel_ssc_dai.c

@@ -267,7 +267,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 	if (!ssc_p->dir_mask) {
 	if (!ssc_p->dir_mask) {
 		if (ssc_p->initialized) {
 		if (ssc_p->initialized) {
 			/* Shutdown the SSC clock. */
 			/* Shutdown the SSC clock. */
-			pr_debug("atmel_ssc_dau: Stopping clock\n");
+			pr_debug("atmel_ssc_dai: Stopping clock\n");
 			clk_disable(ssc_p->ssc->clk);
 			clk_disable(ssc_p->ssc->clk);
 
 
 			free_irq(ssc_p->ssc->irq, ssc_p);
 			free_irq(ssc_p->ssc->irq, ssc_p);
@@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 		 * transmit and receive, so if a value has already
 		 * transmit and receive, so if a value has already
 		 * been set, it must match this value.
 		 * been set, it must match this value.
 		 */
 		 */
-		if (ssc_p->cmr_div == 0)
+		if (ssc_p->dir_mask !=
+			(SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE))
+			ssc_p->cmr_div = div;
+		else if (ssc_p->cmr_div == 0)
 			ssc_p->cmr_div = div;
 			ssc_p->cmr_div = div;
 		else
 		else
 			if (div != ssc_p->cmr_div)
 			if (div != ssc_p->cmr_div)

+ 0 - 151
sound/soc/atmel/snd-soc-afeb9260.c

@@ -1,151 +0,0 @@
-/*
- * afeb9260.c  --  SoC audio for AFEB9260
- *
- * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <linux/atmel-ssc.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <linux/gpio.h>
-
-#include "../codecs/tlv320aic23.h"
-#include "atmel-pcm.h"
-#include "atmel_ssc_dai.h"
-
-#define CODEC_CLOCK 	12000000
-
-static int afeb9260_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;
-	int err;
-
-	/* Set the codec system clock for DAC and ADC */
-	err =
-	    snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
-
-	if (err < 0) {
-		printk(KERN_ERR "can't set codec system clock\n");
-		return err;
-	}
-
-	return err;
-}
-
-static struct snd_soc_ops afeb9260_ops = {
-	.hw_params = afeb9260_hw_params,
-};
-
-static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
-	SND_SOC_DAPM_HP("Headphone Jack", NULL),
-	SND_SOC_DAPM_LINE("Line In", NULL),
-	SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route afeb9260_audio_map[] = {
-	{"Headphone Jack", NULL, "LHPOUT"},
-	{"Headphone Jack", NULL, "RHPOUT"},
-
-	{"LLINEIN", NULL, "Line In"},
-	{"RLINEIN", NULL, "Line In"},
-
-	{"MICIN", NULL, "Mic Jack"},
-};
-
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link afeb9260_dai = {
-	.name = "TLV320AIC23",
-	.stream_name = "AIC23",
-	.cpu_dai_name = "atmel-ssc-dai.0",
-	.codec_dai_name = "tlv320aic23-hifi",
-	.platform_name = "atmel_pcm-audio",
-	.codec_name = "tlv320aic23-codec.0-001a",
-	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
-		   SND_SOC_DAIFMT_CBM_CFM,
-	.ops = &afeb9260_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_machine_afeb9260 = {
-	.name = "AFEB9260",
-	.owner = THIS_MODULE,
-	.dai_link = &afeb9260_dai,
-	.num_links = 1,
-
-	.dapm_widgets = tlv320aic23_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
-	.dapm_routes = afeb9260_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map),
-};
-
-static struct platform_device *afeb9260_snd_device;
-
-static int __init afeb9260_soc_init(void)
-{
-	int err;
-	struct device *dev;
-
-	if (!(machine_is_afeb9260()))
-		return -ENODEV;
-
-
-	afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!afeb9260_snd_device) {
-		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-		return -ENOMEM;
-	}
-
-	platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
-	err = platform_device_add(afeb9260_snd_device);
-	if (err)
-		goto err1;
-
-	dev = &afeb9260_snd_device->dev;
-
-	return 0;
-err1:
-	platform_device_put(afeb9260_snd_device);
-	return err;
-}
-
-static void __exit afeb9260_soc_exit(void)
-{
-	platform_device_unregister(afeb9260_snd_device);
-}
-
-module_init(afeb9260_soc_init);
-module_exit(afeb9260_soc_exit);
-
-MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
-MODULE_DESCRIPTION("ALSA SoC for AFEB9260");
-MODULE_LICENSE("GPL");
-

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

@@ -205,7 +205,7 @@ static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
 
 
 static struct snd_soc_dai_driver au1xac97c_dai_driver = {
 static struct snd_soc_dai_driver au1xac97c_dai_driver = {
 	.name			= "alchemy-ac97c",
 	.name			= "alchemy-ac97c",
-	.ac97_control		= 1,
+	.bus_control		= true,
 	.probe			= au1xac97c_dai_probe,
 	.probe			= au1xac97c_dai_probe,
 	.playback = {
 	.playback = {
 		.rates		= AC97_RATES,
 		.rates		= AC97_RATES,

+ 1 - 1
sound/soc/au1x/psc-ac97.c

@@ -343,7 +343,7 @@ static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
 };
 };
 
 
 static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
 static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
-	.ac97_control		= 1,
+	.bus_control		= true,
 	.probe			= au1xpsc_ac97_probe,
 	.probe			= au1xpsc_ac97_probe,
 	.playback = {
 	.playback = {
 		.rates		= AC97_RATES,
 		.rates		= AC97_RATES,

+ 1 - 1
sound/soc/blackfin/bf5xx-ac97.c

@@ -260,7 +260,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #endif
 #endif
 
 
 static struct snd_soc_dai_driver bfin_ac97_dai = {
 static struct snd_soc_dai_driver bfin_ac97_dai = {
-	.ac97_control = 1,
+	.bus_control = true,
 	.suspend = bf5xx_ac97_suspend,
 	.suspend = bf5xx_ac97_suspend,
 	.resume = bf5xx_ac97_resume,
 	.resume = bf5xx_ac97_resume,
 	.playback = {
 	.playback = {

+ 0 - 2
sound/soc/blackfin/bf5xx-ad1980.c

@@ -46,8 +46,6 @@
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
-#include "../codecs/ad1980.h"
-
 #include "bf5xx-ac97.h"
 #include "bf5xx-ac97.h"
 
 
 static struct snd_soc_card bf5xx_board;
 static struct snd_soc_card bf5xx_board;

+ 2 - 1
sound/soc/cirrus/Kconfig

@@ -36,7 +36,8 @@ config SND_EP93XX_SOC_EDB93XX
 	tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
 	tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
 	depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
 	depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
 	select SND_EP93XX_SOC_I2S
 	select SND_EP93XX_SOC_I2S
-	select SND_SOC_CS4271
+	select SND_SOC_CS4271_I2C if I2C
+	select SND_SOC_CS4271_SPI if SPI_MASTER
 	help
 	help
 	  Say Y or M here if you want to add support for I2S audio on the
 	  Say Y or M here if you want to add support for I2S audio on the
 	  Cirrus Logic EDB93xx boards.
 	  Cirrus Logic EDB93xx boards.

+ 1 - 1
sound/soc/cirrus/ep93xx-ac97.c

@@ -338,7 +338,7 @@ static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
 static struct snd_soc_dai_driver ep93xx_ac97_dai = {
 static struct snd_soc_dai_driver ep93xx_ac97_dai = {
 	.name		= "ep93xx-ac97",
 	.name		= "ep93xx-ac97",
 	.id		= 0,
 	.id		= 0,
-	.ac97_control	= 1,
+	.bus_control	= true,
 	.probe		= ep93xx_ac97_dai_probe,
 	.probe		= ep93xx_ac97_dai_probe,
 	.playback	= {
 	.playback	= {
 		.stream_name	= "AC97 Playback",
 		.stream_name	= "AC97 Playback",

+ 41 - 8
sound/soc/codecs/Kconfig

@@ -50,7 +50,8 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_CS42L73 if I2C
 	select SND_SOC_CS42L73 if I2C
 	select SND_SOC_CS4265 if I2C
 	select SND_SOC_CS4265 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_CS4270 if I2C
-	select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_CS4271_I2C if I2C
+	select SND_SOC_CS4271_SPI if SPI_MASTER
 	select SND_SOC_CS42XX8_I2C if I2C
 	select SND_SOC_CS42XX8_I2C if I2C
 	select SND_SOC_CX20442 if TTY
 	select SND_SOC_CX20442 if TTY
 	select SND_SOC_DA7210 if I2C
 	select SND_SOC_DA7210 if I2C
@@ -85,7 +86,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_RT5645 if I2C
 	select SND_SOC_RT5645 if I2C
 	select SND_SOC_RT5651 if I2C
 	select SND_SOC_RT5651 if I2C
 	select SND_SOC_RT5670 if I2C
 	select SND_SOC_RT5670 if I2C
-	select SND_SOC_RT5677 if I2C
+	select SND_SOC_RT5677 if I2C && SPI_MASTER
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SI476X if MFD_SI476X_CORE
 	select SND_SOC_SI476X if MFD_SI476X_CORE
 	select SND_SOC_SIRF_AUDIO_CODEC
 	select SND_SOC_SIRF_AUDIO_CODEC
@@ -101,6 +102,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TAS2552 if I2C
 	select SND_SOC_TAS2552 if I2C
 	select SND_SOC_TAS5086 if I2C
 	select SND_SOC_TAS5086 if I2C
+	select SND_SOC_TFA9879 if I2C
 	select SND_SOC_TLV320AIC23_I2C if I2C
 	select SND_SOC_TLV320AIC23_I2C if I2C
 	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
 	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -109,6 +111,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_TLV320AIC3X if I2C
 	select SND_SOC_TLV320AIC3X if I2C
 	select SND_SOC_TPA6130A2 if I2C
 	select SND_SOC_TPA6130A2 if I2C
 	select SND_SOC_TLV320DAC33 if I2C
 	select SND_SOC_TLV320DAC33 if I2C
+	select SND_SOC_TS3A227E if I2C
 	select SND_SOC_TWL4030 if TWL4030_CORE
 	select SND_SOC_TWL4030 if TWL4030_CORE
 	select SND_SOC_TWL6040 if TWL6040_CORE
 	select SND_SOC_TWL6040 if TWL6040_CORE
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA134X
@@ -223,6 +226,7 @@ config SND_SOC_AD193X_I2C
 	select SND_SOC_AD193X
 	select SND_SOC_AD193X
 
 
 config SND_SOC_AD1980
 config SND_SOC_AD1980
+	select REGMAP_AC97
 	tristate
 	tristate
 
 
 config SND_SOC_AD73311
 config SND_SOC_AD73311
@@ -336,7 +340,8 @@ config SND_SOC_CS42L51
 	tristate
 	tristate
 
 
 config SND_SOC_CS42L51_I2C
 config SND_SOC_CS42L51_I2C
-	tristate
+	tristate "Cirrus Logic CS42L51 CODEC (I2C)"
+	depends on I2C
 	select SND_SOC_CS42L51
 	select SND_SOC_CS42L51
 
 
 config SND_SOC_CS42L52
 config SND_SOC_CS42L52
@@ -370,8 +375,19 @@ config SND_SOC_CS4270_VD33_ERRATA
 	depends on SND_SOC_CS4270
 	depends on SND_SOC_CS4270
 
 
 config SND_SOC_CS4271
 config SND_SOC_CS4271
-	tristate "Cirrus Logic CS4271 CODEC"
-	depends on SND_SOC_I2C_AND_SPI
+	tristate
+
+config SND_SOC_CS4271_I2C
+	tristate "Cirrus Logic CS4271 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_CS4271
+	select REGMAP_I2C
+
+config SND_SOC_CS4271_SPI
+	tristate "Cirrus Logic CS4271 CODEC (SPI)"
+	depends on SPI_MASTER
+	select SND_SOC_CS4271
+	select REGMAP_SPI
 
 
 config SND_SOC_CS42XX8
 config SND_SOC_CS42XX8
 	tristate
 	tristate
@@ -487,7 +503,8 @@ config SND_SOC_RT286
 	depends on I2C
 	depends on I2C
 
 
 config SND_SOC_RT5631
 config SND_SOC_RT5631
-	tristate
+	tristate "Realtek ALC5631/RT5631 CODEC"
+	depends on I2C
 
 
 config SND_SOC_RT5640
 config SND_SOC_RT5640
 	tristate
 	tristate
@@ -503,6 +520,12 @@ config SND_SOC_RT5670
 
 
 config SND_SOC_RT5677
 config SND_SOC_RT5677
 	tristate
 	tristate
+	select REGMAP_I2C
+	select REGMAP_IRQ
+
+config SND_SOC_RT5677_SPI
+	tristate
+	default SND_SOC_RT5677
 
 
 #Freescale sgtl5000 codec
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
 config SND_SOC_SGTL5000
@@ -577,15 +600,21 @@ config SND_SOC_TAS5086
 	tristate "Texas Instruments TAS5086 speaker amplifier"
 	tristate "Texas Instruments TAS5086 speaker amplifier"
 	depends on I2C
 	depends on I2C
 
 
+config SND_SOC_TFA9879
+	tristate "NXP Semiconductors TFA9879 amplifier"
+	depends on I2C
+
 config SND_SOC_TLV320AIC23
 config SND_SOC_TLV320AIC23
 	tristate
 	tristate
 
 
 config SND_SOC_TLV320AIC23_I2C
 config SND_SOC_TLV320AIC23_I2C
-	tristate
+	tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C"
+	depends on I2C
 	select SND_SOC_TLV320AIC23
 	select SND_SOC_TLV320AIC23
 
 
 config SND_SOC_TLV320AIC23_SPI
 config SND_SOC_TLV320AIC23_SPI
-	tristate
+	tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI"
+	depends on SPI_MASTER
 	select SND_SOC_TLV320AIC23
 	select SND_SOC_TLV320AIC23
 
 
 config SND_SOC_TLV320AIC26
 config SND_SOC_TLV320AIC26
@@ -607,6 +636,10 @@ config SND_SOC_TLV320AIC3X
 config SND_SOC_TLV320DAC33
 config SND_SOC_TLV320DAC33
 	tristate
 	tristate
 
 
+config SND_SOC_TS3A227E
+	tristate "TI Headset/Mic detect and keypress chip"
+	depends on I2C
+
 config SND_SOC_TWL4030
 config SND_SOC_TWL4030
 	select MFD_TWL4030_AUDIO
 	select MFD_TWL4030_AUDIO
 	tristate
 	tristate

+ 10 - 0
sound/soc/codecs/Makefile

@@ -41,6 +41,8 @@ snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4265-objs := cs4265.o
 snd-soc-cs4265-objs := cs4265.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
 snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs4271-i2c-objs := cs4271-i2c.o
+snd-soc-cs4271-spi-objs := cs4271-spi.o
 snd-soc-cs42xx8-objs := cs42xx8.o
 snd-soc-cs42xx8-objs := cs42xx8.o
 snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
 snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-cx20442-objs := cx20442.o
@@ -80,6 +82,7 @@ snd-soc-rt5645-objs := rt5645.o
 snd-soc-rt5651-objs := rt5651.o
 snd-soc-rt5651-objs := rt5651.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-objs := rt5677.o
+snd-soc-rt5677-spi-objs := rt5677-spi.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
 snd-soc-alc5632-objs := alc5632.o
@@ -101,6 +104,7 @@ snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas5086-objs := tas5086.o
+snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
 snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
@@ -109,6 +113,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
+snd-soc-ts3a227e-objs := ts3a227e.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda134x-objs := uda134x.o
@@ -217,6 +222,8 @@ obj-$(CONFIG_SND_SOC_CS42L73)	+= snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4265)	+= snd-soc-cs4265.o
 obj-$(CONFIG_SND_SOC_CS4265)	+= snd-soc-cs4265.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS4271_I2C)	+= snd-soc-cs4271-i2c.o
+obj-$(CONFIG_SND_SOC_CS4271_SPI)	+= snd-soc-cs4271-spi.o
 obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
 obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
 obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
 obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
@@ -256,6 +263,7 @@ obj-$(CONFIG_SND_SOC_RT5645)	+= snd-soc-rt5645.o
 obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o
 obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o
 obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o
 obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o
+obj-$(CONFIG_SND_SOC_RT5677_SPI)	+= snd-soc-rt5677-spi.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP)	+= snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SIGMADSP)	+= snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o
@@ -274,6 +282,7 @@ obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS2552)	+= snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS2552)	+= snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TFA9879)	+= snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)	+= snd-soc-tlv320aic23-spi.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)	+= snd-soc-tlv320aic23-spi.o
@@ -282,6 +291,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX)     += snd-soc-tlv320aic31xx.o
 obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o
 obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
+obj-$(CONFIG_SND_SOC_TS3A227E)	+= snd-soc-ts3a227e.o
 obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o

+ 16 - 16
sound/soc/codecs/ab8500-codec.c

@@ -126,13 +126,13 @@ struct ab8500_codec_drvdata_dbg {
 /* Private data for AB8500 device-driver */
 /* Private data for AB8500 device-driver */
 struct ab8500_codec_drvdata {
 struct ab8500_codec_drvdata {
 	struct regmap *regmap;
 	struct regmap *regmap;
+	struct mutex ctrl_lock;
 
 
 	/* Sidetone */
 	/* Sidetone */
 	long *sid_fir_values;
 	long *sid_fir_values;
 	enum sid_state sid_status;
 	enum sid_state sid_status;
 
 
 	/* ANC */
 	/* ANC */
-	struct mutex anc_lock;
 	long *anc_fir_values;
 	long *anc_fir_values;
 	long *anc_iir_values;
 	long *anc_iir_values;
 	enum anc_state anc_status;
 	enum anc_state anc_status;
@@ -1129,9 +1129,9 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&drvdata->ctrl_lock);
 	ucontrol->value.integer.value[0] = drvdata->sid_status;
 	ucontrol->value.integer.value[0] = drvdata->sid_status;
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&drvdata->ctrl_lock);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1154,7 +1154,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&drvdata->ctrl_lock);
 
 
 	sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
 	sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
 	if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
 	if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
@@ -1185,7 +1185,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 	drvdata->sid_status = SID_FIR_CONFIGURED;
 	drvdata->sid_status = SID_FIR_CONFIGURED;
 
 
 out:
 out:
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&drvdata->ctrl_lock);
 
 
 	dev_dbg(codec->dev, "%s: Exit\n", __func__);
 	dev_dbg(codec->dev, "%s: Exit\n", __func__);
 
 
@@ -1198,9 +1198,9 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&drvdata->ctrl_lock);
 	ucontrol->value.integer.value[0] = drvdata->anc_status;
 	ucontrol->value.integer.value[0] = drvdata->anc_status;
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&drvdata->ctrl_lock);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1217,7 +1217,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 
 
 	dev_dbg(dev, "%s: Enter.\n", __func__);
 	dev_dbg(dev, "%s: Enter.\n", __func__);
 
 
-	mutex_lock(&drvdata->anc_lock);
+	mutex_lock(&drvdata->ctrl_lock);
 
 
 	req = ucontrol->value.integer.value[0];
 	req = ucontrol->value.integer.value[0];
 	if (req >= ARRAY_SIZE(enum_anc_state)) {
 	if (req >= ARRAY_SIZE(enum_anc_state)) {
@@ -1244,9 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 	}
 	}
 	snd_soc_dapm_sync(&codec->dapm);
 	snd_soc_dapm_sync(&codec->dapm);
 
 
-	mutex_lock(&codec->mutex);
 	anc_configure(codec, apply_fir, apply_iir);
 	anc_configure(codec, apply_fir, apply_iir);
-	mutex_unlock(&codec->mutex);
 
 
 	if (apply_fir) {
 	if (apply_fir) {
 		if (drvdata->anc_status == ANC_IIR_CONFIGURED)
 		if (drvdata->anc_status == ANC_IIR_CONFIGURED)
@@ -1265,7 +1263,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 	snd_soc_dapm_sync(&codec->dapm);
 	snd_soc_dapm_sync(&codec->dapm);
 
 
 cleanup:
 cleanup:
-	mutex_unlock(&drvdata->anc_lock);
+	mutex_unlock(&drvdata->ctrl_lock);
 
 
 	if (status < 0)
 	if (status < 0)
 		dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
 		dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
@@ -1294,14 +1292,15 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 			struct snd_ctl_elem_value *ucontrol)
 {
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
 	struct filter_control *fc =
 	struct filter_control *fc =
 			(struct filter_control *)kcontrol->private_value;
 			(struct filter_control *)kcontrol->private_value;
 	unsigned int i;
 	unsigned int i;
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&drvdata->ctrl_lock);
 	for (i = 0; i < fc->count; i++)
 	for (i = 0; i < fc->count; i++)
 		ucontrol->value.integer.value[i] = fc->value[i];
 		ucontrol->value.integer.value[i] = fc->value[i];
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&drvdata->ctrl_lock);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1310,14 +1309,15 @@ static int filter_control_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 		struct snd_ctl_elem_value *ucontrol)
 {
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
 	struct filter_control *fc =
 	struct filter_control *fc =
 			(struct filter_control *)kcontrol->private_value;
 			(struct filter_control *)kcontrol->private_value;
 	unsigned int i;
 	unsigned int i;
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&drvdata->ctrl_lock);
 	for (i = 0; i < fc->count; i++)
 	for (i = 0; i < fc->count; i++)
 		fc->value[i] = ucontrol->value.integer.value[i];
 		fc->value[i] = ucontrol->value.integer.value[i];
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&drvdata->ctrl_lock);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2545,7 +2545,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
 
 	(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
 	(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
 
 
-	mutex_init(&drvdata->anc_lock);
+	mutex_init(&drvdata->ctrl_lock);
 
 
 	return status;
 	return status;
 }
 }

+ 13 - 5
sound/soc/codecs/ac97.c

@@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 			struct snd_soc_dai *dai)
 {
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
+	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
 
 
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
-	return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
+	return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
 }
 }
 
 
 #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
 #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -53,7 +54,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = {
 
 
 static struct snd_soc_dai_driver ac97_dai = {
 static struct snd_soc_dai_driver ac97_dai = {
 	.name = "ac97-hifi",
 	.name = "ac97-hifi",
-	.ac97_control = 1,
 	.playback = {
 	.playback = {
 		.stream_name = "AC97 Playback",
 		.stream_name = "AC97 Playback",
 		.channels_min = 1,
 		.channels_min = 1,
@@ -71,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = {
 
 
 static int ac97_soc_probe(struct snd_soc_codec *codec)
 static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_ac97 *ac97;
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97_template ac97_template;
 	struct snd_ac97_template ac97_template;
 	int ret;
 	int ret;
@@ -82,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
 		return ret;
 		return ret;
 
 
 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
-	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
+	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
+	snd_soc_codec_set_drvdata(codec, ac97);
+
 	return 0;
 	return 0;
 }
 }
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int ac97_soc_suspend(struct snd_soc_codec *codec)
 static int ac97_soc_suspend(struct snd_soc_codec *codec)
 {
 {
-	snd_ac97_suspend(codec->ac97);
+	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+	snd_ac97_suspend(ac97);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static int ac97_soc_resume(struct snd_soc_codec *codec)
 static int ac97_soc_resume(struct snd_soc_codec *codec)
 {
 {
-	snd_ac97_resume(codec->ac97);
+
+	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+	snd_ac97_resume(ac97);
 
 
 	return 0;
 	return 0;
 }
 }

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

@@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = {
 };
 };
 
 
 static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
 static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
-	SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1),
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
 	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
+	SND_SOC_DAPM_VMID("VMID"),
 	SND_SOC_DAPM_OUTPUT("DAC1OUT"),
 	SND_SOC_DAPM_OUTPUT("DAC1OUT"),
 	SND_SOC_DAPM_OUTPUT("DAC2OUT"),
 	SND_SOC_DAPM_OUTPUT("DAC2OUT"),
 	SND_SOC_DAPM_OUTPUT("DAC3OUT"),
 	SND_SOC_DAPM_OUTPUT("DAC3OUT"),
@@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
 
 
 static const struct snd_soc_dapm_route audio_paths[] = {
 static const struct snd_soc_dapm_route audio_paths[] = {
 	{ "DAC", NULL, "SYSCLK" },
 	{ "DAC", NULL, "SYSCLK" },
+	{ "DAC Output", NULL, "DAC" },
+	{ "DAC Output", NULL, "VMID" },
 	{ "ADC", NULL, "SYSCLK" },
 	{ "ADC", NULL, "SYSCLK" },
 	{ "DAC", NULL, "ADC_PWR" },
 	{ "DAC", NULL, "ADC_PWR" },
 	{ "ADC", NULL, "ADC_PWR" },
 	{ "ADC", NULL, "ADC_PWR" },
-	{ "DAC1OUT", NULL, "DAC" },
-	{ "DAC2OUT", NULL, "DAC" },
-	{ "DAC3OUT", NULL, "DAC" },
-	{ "DAC4OUT", NULL, "DAC" },
+	{ "DAC1OUT", NULL, "DAC Output" },
+	{ "DAC2OUT", NULL, "DAC Output" },
+	{ "DAC3OUT", NULL, "DAC Output" },
+	{ "DAC4OUT", NULL, "DAC Output" },
 	{ "ADC", NULL, "ADC1IN" },
 	{ "ADC", NULL, "ADC1IN" },
 	{ "ADC", NULL, "ADC2IN" },
 	{ "ADC", NULL, "ADC2IN" },
 	{ "SYSCLK", NULL, "PLL_PWR" },
 	{ "SYSCLK", NULL, "PLL_PWR" },

+ 117 - 95
sound/soc/codecs/ad1980.c

@@ -24,34 +24,86 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/device.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/soc.h>
 
 
-#include "ad1980.h"
+static const struct reg_default ad1980_reg_defaults[] = {
+	{ 0x02, 0x8000 },
+	{ 0x04, 0x8000 },
+	{ 0x06, 0x8000 },
+	{ 0x0c, 0x8008 },
+	{ 0x0e, 0x8008 },
+	{ 0x10, 0x8808 },
+	{ 0x12, 0x8808 },
+	{ 0x16, 0x8808 },
+	{ 0x18, 0x8808 },
+	{ 0x1a, 0x0000 },
+	{ 0x1c, 0x8000 },
+	{ 0x20, 0x0000 },
+	{ 0x28, 0x03c7 },
+	{ 0x2c, 0xbb80 },
+	{ 0x2e, 0xbb80 },
+	{ 0x30, 0xbb80 },
+	{ 0x32, 0xbb80 },
+	{ 0x36, 0x8080 },
+	{ 0x38, 0x8080 },
+	{ 0x3a, 0x2000 },
+	{ 0x60, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x72, 0x0000 },
+	{ 0x74, 0x1001 },
+	{ 0x76, 0x0000 },
+};
 
 
-/*
- * AD1980 register cache
- */
-static const u16 ad1980_reg[] = {
-	0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6  */
-	0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e  */
-	0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
-	0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
-	0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
-	0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
-	0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
-	0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
-	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
-	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
-	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
-	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
-	0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
-	0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
-	0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
-	0x0000, 0x0000, 0x4144, 0x5370  /* 78 - 7e */
+static bool ad1980_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_RESET ... AC97_MASTER_MONO:
+	case AC97_PHONE ... AC97_CD:
+	case AC97_AUX ... AC97_GENERAL_PURPOSE:
+	case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE:
+	case AC97_SPDIF:
+	case AC97_CODEC_CLASS_REV:
+	case AC97_PCI_SVID:
+	case AC97_AD_CODEC_CFG:
+	case AC97_AD_JACK_SPDIF:
+	case AC97_AD_SERIAL_CFG:
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool ad1980_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return false;
+	default:
+		return ad1980_readable_reg(dev, reg);
+	}
+}
+
+static const struct regmap_config ad1980_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x7e,
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = regmap_ac97_default_volatile,
+	.readable_reg = ad1980_readable_reg,
+	.writeable_reg = ad1980_writeable_reg,
+
+	.reg_defaults = ad1980_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults),
 };
 };
 
 
 static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
 static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
@@ -134,45 +186,8 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
 	{ "HP_OUT_R", NULL, "Playback" },
 	{ "HP_OUT_R", NULL, "Playback" },
 };
 };
 
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-
-	switch (reg) {
-	case AC97_RESET:
-	case AC97_INT_PAGING:
-	case AC97_POWERDOWN:
-	case AC97_EXTENDED_STATUS:
-	case AC97_VENDOR_ID1:
-	case AC97_VENDOR_ID2:
-		return soc_ac97_ops->read(codec->ac97, reg);
-	default:
-		reg = reg >> 1;
-
-		if (reg >= ARRAY_SIZE(ad1980_reg))
-			return -EINVAL;
-
-		return cache[reg];
-	}
-}
-
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int val)
-{
-	u16 *cache = codec->reg_cache;
-
-	soc_ac97_ops->write(codec->ac97, reg, val);
-	reg = reg >> 1;
-	if (reg < ARRAY_SIZE(ad1980_reg))
-		cache[reg] = val;
-
-	return 0;
-}
-
 static struct snd_soc_dai_driver ad1980_dai = {
 static struct snd_soc_dai_driver ad1980_dai = {
 	.name = "ad1980-hifi",
 	.name = "ad1980-hifi",
-	.ac97_control = 1,
 	.playback = {
 	.playback = {
 		.stream_name = "Playback",
 		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_min = 2,
@@ -189,108 +204,115 @@ static struct snd_soc_dai_driver ad1980_dai = {
 
 
 static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
 static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
 {
 {
+	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
 	unsigned int retry_cnt = 0;
 	unsigned int retry_cnt = 0;
 
 
 	do {
 	do {
 		if (try_warm && soc_ac97_ops->warm_reset) {
 		if (try_warm && soc_ac97_ops->warm_reset) {
-			soc_ac97_ops->warm_reset(codec->ac97);
-			if (ac97_read(codec, AC97_RESET) == 0x0090)
+			soc_ac97_ops->warm_reset(ac97);
+			if (snd_soc_read(codec, AC97_RESET) == 0x0090)
 				return 1;
 				return 1;
 		}
 		}
 
 
-		soc_ac97_ops->reset(codec->ac97);
+		soc_ac97_ops->reset(ac97);
 		/*
 		/*
 		 * Set bit 16slot in register 74h, then every slot will has only
 		 * Set bit 16slot in register 74h, then every slot will has only
 		 * 16 bits. This command is sent out in 20bit mode, in which
 		 * 16 bits. This command is sent out in 20bit mode, in which
 		 * case the first nibble of data is eaten by the addr. (Tag is
 		 * case the first nibble of data is eaten by the addr. (Tag is
 		 * always 16 bit)
 		 * always 16 bit)
 		 */
 		 */
-		ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
+		snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
 
 
-		if (ac97_read(codec, AC97_RESET)  == 0x0090)
+		if (snd_soc_read(codec, AC97_RESET)  == 0x0090)
 			return 0;
 			return 0;
 	} while (retry_cnt++ < 10);
 	} while (retry_cnt++ < 10);
 
 
-	printk(KERN_ERR "AD1980 AC97 reset failed\n");
+	dev_err(codec->dev, "Failed to reset: AC97 link error\n");
+
 	return -EIO;
 	return -EIO;
 }
 }
 
 
 static int ad1980_soc_probe(struct snd_soc_codec *codec)
 static int ad1980_soc_probe(struct snd_soc_codec *codec)
 {
 {
+	struct snd_ac97 *ac97;
+	struct regmap *regmap;
 	int ret;
 	int ret;
 	u16 vendor_id2;
 	u16 vendor_id2;
 	u16 ext_status;
 	u16 ext_status;
 
 
-	printk(KERN_INFO "AD1980 SoC Audio Codec\n");
-
-	ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
-	if (ret < 0) {
-		printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
+	ac97 = snd_soc_new_ac97_codec(codec);
+	if (IS_ERR(ac97)) {
+		ret = PTR_ERR(ac97);
+		dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
 		return ret;
 		return ret;
 	}
 	}
 
 
+	regmap = regmap_init_ac97(ac97, &ad1980_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		goto err_free_ac97;
+	}
+
+	snd_soc_codec_init_regmap(codec, regmap);
+	snd_soc_codec_set_drvdata(codec, ac97);
+
 	ret = ad1980_reset(codec, 0);
 	ret = ad1980_reset(codec, 0);
-	if (ret < 0) {
-		printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
+	if (ret < 0)
 		goto reset_err;
 		goto reset_err;
-	}
 
 
 	/* Read out vendor ID to make sure it is ad1980 */
 	/* Read out vendor ID to make sure it is ad1980 */
-	if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
+	if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) {
 		ret = -ENODEV;
 		ret = -ENODEV;
 		goto reset_err;
 		goto reset_err;
 	}
 	}
 
 
-	vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
+	vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
 
 
 	if (vendor_id2 != 0x5370) {
 	if (vendor_id2 != 0x5370) {
 		if (vendor_id2 != 0x5374) {
 		if (vendor_id2 != 0x5374) {
 			ret = -ENODEV;
 			ret = -ENODEV;
 			goto reset_err;
 			goto reset_err;
 		} else {
 		} else {
-			printk(KERN_WARNING "ad1980: "
-				"Found AD1981 - only 2/2 IN/OUT Channels "
-				"supported\n");
+			dev_warn(codec->dev,
+				"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
 		}
 		}
 	}
 	}
 
 
 	/* unmute captures and playbacks volume */
 	/* unmute captures and playbacks volume */
-	ac97_write(codec, AC97_MASTER, 0x0000);
-	ac97_write(codec, AC97_PCM, 0x0000);
-	ac97_write(codec, AC97_REC_GAIN, 0x0000);
-	ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
-	ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
+	snd_soc_write(codec, AC97_MASTER, 0x0000);
+	snd_soc_write(codec, AC97_PCM, 0x0000);
+	snd_soc_write(codec, AC97_REC_GAIN, 0x0000);
+	snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
+	snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000);
 
 
 	/*power on LFE/CENTER/Surround DACs*/
 	/*power on LFE/CENTER/Surround DACs*/
-	ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
-	ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
-
-	snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls,
-				ARRAY_SIZE(ad1980_snd_ac97_controls));
+	ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS);
+	snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
 
 
 	return 0;
 	return 0;
 
 
 reset_err:
 reset_err:
-	snd_soc_free_ac97_codec(codec);
+	snd_soc_codec_exit_regmap(codec);
+err_free_ac97:
+	snd_soc_free_ac97_codec(ac97);
 	return ret;
 	return ret;
 }
 }
 
 
 static int ad1980_soc_remove(struct snd_soc_codec *codec)
 static int ad1980_soc_remove(struct snd_soc_codec *codec)
 {
 {
-	snd_soc_free_ac97_codec(codec);
+	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_codec_exit_regmap(codec);
+	snd_soc_free_ac97_codec(ac97);
 	return 0;
 	return 0;
 }
 }
 
 
 static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
 static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
 	.probe = 	ad1980_soc_probe,
 	.probe = 	ad1980_soc_probe,
 	.remove = 	ad1980_soc_remove,
 	.remove = 	ad1980_soc_remove,
-	.reg_cache_size = ARRAY_SIZE(ad1980_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = ad1980_reg,
-	.reg_cache_step = 2,
-	.write = ac97_write,
-	.read = ac97_read,
 
 
+	.controls = ad1980_snd_ac97_controls,
+	.num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
 	.dapm_widgets = ad1980_dapm_widgets,
 	.dapm_widgets = ad1980_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
 	.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
 	.dapm_routes = ad1980_dapm_routes,
 	.dapm_routes = ad1980_dapm_routes,

+ 0 - 26
sound/soc/codecs/ad1980.h

@@ -1,26 +0,0 @@
-/*
- * ad1980.h  --  ad1980 Soc Audio driver
- *
- * WARNING:
- *
- * Because Analog Devices Inc. discontinued the ad1980 sound chip since
- * Sep. 2009, this ad1980 driver is not maintained, tested and supported
- * by ADI now.
- */
-
-#ifndef _AD1980_H
-#define _AD1980_H
-/* Bit definition of Power-Down Control/Status Register */
-#define ADC		0x0001
-#define DAC		0x0002
-#define ANL		0x0004
-#define REF		0x0008
-#define PR0		0x0100
-#define PR1		0x0200
-#define PR2		0x0400
-#define PR3		0x0800
-#define PR4		0x1000
-#define PR5		0x2000
-#define PR6		0x4000
-
-#endif

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

@@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = {
 static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
 static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	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 adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 	unsigned int pll_id = w->name[3] - '1';
 	unsigned int pll_id = w->name[3] - '1';
 	unsigned int val;
 	unsigned int val;
@@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
 static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
 static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
 	struct snd_soc_dapm_widget *sink)
 	struct snd_soc_dapm_widget *sink)
 {
 {
-	struct snd_soc_codec *codec = source->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 	unsigned int dai;
 	unsigned int dai;
 	const char *clk;
 	const char *clk;
@@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
 static int adau1373_check_src(struct snd_soc_dapm_widget *source,
 static int adau1373_check_src(struct snd_soc_dapm_widget *source,
 	struct snd_soc_dapm_widget *sink)
 	struct snd_soc_dapm_widget *sink)
 {
 {
-	struct snd_soc_codec *codec = source->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 	unsigned int dai;
 	unsigned int dai;
 
 

+ 81 - 5
sound/soc/codecs/adau1701.c

@@ -22,9 +22,14 @@
 #include <sound/pcm_params.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc.h>
 
 
+#include <asm/unaligned.h>
+
 #include "sigmadsp.h"
 #include "sigmadsp.h"
 #include "adau1701.h"
 #include "adau1701.h"
 
 
+#define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i))
+#define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i))
+
 #define ADAU1701_DSPCTRL	0x081c
 #define ADAU1701_DSPCTRL	0x081c
 #define ADAU1701_SEROCTL	0x081e
 #define ADAU1701_SEROCTL	0x081e
 #define ADAU1701_SERICTL	0x081f
 #define ADAU1701_SERICTL	0x081f
@@ -42,6 +47,7 @@
 #define ADAU1701_DSPCTRL_CR		(1 << 2)
 #define ADAU1701_DSPCTRL_CR		(1 << 2)
 #define ADAU1701_DSPCTRL_DAM		(1 << 3)
 #define ADAU1701_DSPCTRL_DAM		(1 << 3)
 #define ADAU1701_DSPCTRL_ADM		(1 << 4)
 #define ADAU1701_DSPCTRL_ADM		(1 << 4)
+#define ADAU1701_DSPCTRL_IST		(1 << 5)
 #define ADAU1701_DSPCTRL_SR_48		0x00
 #define ADAU1701_DSPCTRL_SR_48		0x00
 #define ADAU1701_DSPCTRL_SR_96		0x01
 #define ADAU1701_DSPCTRL_SR_96		0x01
 #define ADAU1701_DSPCTRL_SR_192		0x02
 #define ADAU1701_DSPCTRL_SR_192		0x02
@@ -102,7 +108,10 @@ struct adau1701 {
 	unsigned int pll_clkdiv;
 	unsigned int pll_clkdiv;
 	unsigned int sysclk;
 	unsigned int sysclk;
 	struct regmap *regmap;
 	struct regmap *regmap;
+	struct i2c_client *client;
 	u8 pin_config[12];
 	u8 pin_config[12];
+
+	struct sigmadsp *sigmadsp;
 };
 };
 
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -159,6 +168,7 @@ static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
 {
 {
 	switch (reg) {
 	switch (reg) {
 	case ADAU1701_DACSET:
 	case ADAU1701_DACSET:
+	case ADAU1701_DSPCTRL:
 		return true;
 		return true;
 	default:
 	default:
 		return false;
 		return false;
@@ -238,12 +248,58 @@ static int adau1701_reg_read(void *context, unsigned int reg,
 	return 0;
 	return 0;
 }
 }
 
 
-static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
+static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
+	const uint8_t bytes[], size_t len)
+{
+	struct i2c_client *client = to_i2c_client(sigmadsp->dev);
+	struct adau1701 *adau1701 = i2c_get_clientdata(client);
+	unsigned int val;
+	unsigned int i;
+	uint8_t buf[10];
+	int ret;
+
+	ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val);
+	if (ret)
+		return ret;
+
+	if (val & ADAU1701_DSPCTRL_IST)
+		msleep(50);
+
+	for (i = 0; i < len / 4; i++) {
+		put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf);
+		buf[2] = 0x00;
+		memcpy(buf + 3, bytes + i * 4, 4);
+		ret = i2c_master_send(client, buf, 7);
+		if (ret < 0)
+			return ret;
+		else if (ret != 7)
+			return -EIO;
+
+		put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf);
+		put_unaligned_le16(addr + i, buf + 2);
+		ret = i2c_master_send(client, buf, 4);
+		if (ret < 0)
+			return ret;
+		else if (ret != 4)
+			return -EIO;
+	}
+
+	return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
+		ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST);
+}
+
+static const struct sigmadsp_ops adau1701_sigmadsp_ops = {
+	.safeload = adau1701_safeload,
+};
+
+static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
+	unsigned int rate)
 {
 {
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *client = to_i2c_client(codec->dev);
 	int ret;
 	int ret;
 
 
+	sigmadsp_reset(adau1701->sigmadsp);
+
 	if (clkdiv != ADAU1707_CLKDIV_UNSET &&
 	if (clkdiv != ADAU1707_CLKDIV_UNSET &&
 	    gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
 	    gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
 	    gpio_is_valid(adau1701->gpio_pll_mode[1])) {
 	    gpio_is_valid(adau1701->gpio_pll_mode[1])) {
@@ -284,7 +340,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
 	 * know the correct PLL setup
 	 * know the correct PLL setup
 	 */
 	 */
 	if (clkdiv != ADAU1707_CLKDIV_UNSET) {
 	if (clkdiv != ADAU1707_CLKDIV_UNSET) {
-		ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
+		ret = sigmadsp_setup(adau1701->sigmadsp, rate);
 		if (ret) {
 		if (ret) {
 			dev_warn(codec->dev, "Failed to load firmware\n");
 			dev_warn(codec->dev, "Failed to load firmware\n");
 			return ret;
 			return ret;
@@ -385,7 +441,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
 	 * firmware upload.
 	 * firmware upload.
 	 */
 	 */
 	if (clkdiv != adau1701->pll_clkdiv) {
 	if (clkdiv != adau1701->pll_clkdiv) {
-		ret = adau1701_reset(codec, clkdiv);
+		ret = adau1701_reset(codec, clkdiv, params_rate(params));
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 	}
 	}
@@ -554,6 +610,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	return 0;
 	return 0;
 }
 }
 
 
+static int adau1701_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec);
+
+	return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
+}
+
 #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
 #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
 	SNDRV_PCM_RATE_192000)
 	SNDRV_PCM_RATE_192000)
 
 
@@ -564,6 +628,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = {
 	.set_fmt	= adau1701_set_dai_fmt,
 	.set_fmt	= adau1701_set_dai_fmt,
 	.hw_params	= adau1701_hw_params,
 	.hw_params	= adau1701_hw_params,
 	.digital_mute	= adau1701_digital_mute,
 	.digital_mute	= adau1701_digital_mute,
+	.startup	= adau1701_startup,
 };
 };
 
 
 static struct snd_soc_dai_driver adau1701_dai = {
 static struct snd_soc_dai_driver adau1701_dai = {
@@ -600,6 +665,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	unsigned int val;
 	unsigned int val;
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 
 
+	ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component);
+	if (ret)
+		return ret;
+
 	/*
 	/*
 	 * Let the pll_clkdiv variable default to something that won't happen
 	 * Let the pll_clkdiv variable default to something that won't happen
 	 * at runtime. That way, we can postpone the firmware download from
 	 * at runtime. That way, we can postpone the firmware download from
@@ -609,7 +678,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
 	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
 
 
 	/* initalize with pre-configured pll mode settings */
 	/* initalize with pre-configured pll mode settings */
-	ret = adau1701_reset(codec, adau1701->pll_clkdiv);
+	ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
@@ -667,6 +736,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 	if (!adau1701)
 	if (!adau1701)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	adau1701->client = client;
 	adau1701->regmap = devm_regmap_init(dev, NULL, client,
 	adau1701->regmap = devm_regmap_init(dev, NULL, client,
 					    &adau1701_regmap);
 					    &adau1701_regmap);
 	if (IS_ERR(adau1701->regmap))
 	if (IS_ERR(adau1701->regmap))
@@ -722,6 +792,12 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 	adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
 	adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
 
 
 	i2c_set_clientdata(client, adau1701);
 	i2c_set_clientdata(client, adau1701);
+
+	adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
+		&adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
+	if (IS_ERR(adau1701->sigmadsp))
+		return PTR_ERR(adau1701->sigmadsp);
+
 	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
 	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
 			&adau1701_dai, 1);
 			&adau1701_dai, 1);
 	return ret;
 	return ret;

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

@@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control =
 static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
 static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	struct snd_kcontrol *kcontrol, int event)
 {
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 
 
 	/* After any power changes have been made the dejitter circuit
 	/* After any power changes have been made the dejitter circuit
 	 * has to be reinitialized. */
 	 * has to be reinitialized. */
@@ -702,11 +703,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
 			ARRAY_SIZE(adau1761_dapm_routes));
 			ARRAY_SIZE(adau1761_dapm_routes));
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-
-		ret = adau17x1_load_firmware(adau, codec->dev,
-			ADAU1761_FIRMWARE);
-		if (ret)
-			dev_warn(codec->dev, "Failed to firmware\n");
 	}
 	}
 
 
 	ret = adau17x1_add_routes(codec);
 	ret = adau17x1_add_routes(codec);
@@ -775,16 +771,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
 	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
 	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
 {
 {
 	struct snd_soc_dai_driver *dai_drv;
 	struct snd_soc_dai_driver *dai_drv;
+	const char *firmware_name;
 	int ret;
 	int ret;
 
 
-	ret = adau17x1_probe(dev, regmap, type, switch_mode);
-	if (ret)
-		return ret;
-
-	if (type == ADAU1361)
+	if (type == ADAU1361) {
 		dai_drv = &adau1361_dai_driver;
 		dai_drv = &adau1361_dai_driver;
-	else
+		firmware_name = NULL;
+	} else {
 		dai_drv = &adau1761_dai_driver;
 		dai_drv = &adau1761_dai_driver;
+		firmware_name = ADAU1761_FIRMWARE;
+	}
+
+	ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
+	if (ret)
+		return ret;
 
 
 	return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
 	return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
 }
 }
@@ -798,6 +798,7 @@ const struct regmap_config adau1761_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
 	.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
 	.readable_reg = adau1761_readable_register,
 	.readable_reg = adau1761_readable_register,
 	.volatile_reg = adau17x1_volatile_register,
 	.volatile_reg = adau17x1_volatile_register,
+	.precious_reg = adau17x1_precious_register,
 	.cache_type = REGCACHE_RBTREE,
 	.cache_type = REGCACHE_RBTREE,
 };
 };
 EXPORT_SYMBOL_GPL(adau1761_regmap_config);
 EXPORT_SYMBOL_GPL(adau1761_regmap_config);

+ 15 - 18
sound/soc/codecs/adau1781.c

@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
 static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
 static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	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 adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 
 
 	/* After any power changes have been made the dejitter circuit
 	/* After any power changes have been made the dejitter circuit
@@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
 {
 {
 	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
 	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
-	const char *firmware;
 	int ret;
 	int ret;
 
 
 	ret = adau17x1_add_widgets(codec);
 	ret = adau17x1_add_widgets(codec);
@@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
 			return ret;
 			return ret;
 	}
 	}
 
 
-	switch (adau->type) {
-	case ADAU1381:
-		firmware = ADAU1381_FIRMWARE;
-		break;
-	case ADAU1781:
-		firmware = ADAU1781_FIRMWARE;
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	ret = adau17x1_add_routes(codec);
 	ret = adau17x1_add_routes(codec);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	ret = adau17x1_load_firmware(adau, codec->dev, firmware);
-	if (ret)
-		dev_warn(codec->dev, "Failed to load firmware\n");
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -488,6 +472,7 @@ const struct regmap_config adau1781_regmap_config = {
 	.num_reg_defaults	= ARRAY_SIZE(adau1781_reg_defaults),
 	.num_reg_defaults	= ARRAY_SIZE(adau1781_reg_defaults),
 	.readable_reg		= adau1781_readable_register,
 	.readable_reg		= adau1781_readable_register,
 	.volatile_reg		= adau17x1_volatile_register,
 	.volatile_reg		= adau17x1_volatile_register,
+	.precious_reg		= adau17x1_precious_register,
 	.cache_type		= REGCACHE_RBTREE,
 	.cache_type		= REGCACHE_RBTREE,
 };
 };
 EXPORT_SYMBOL_GPL(adau1781_regmap_config);
 EXPORT_SYMBOL_GPL(adau1781_regmap_config);
@@ -495,9 +480,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config);
 int adau1781_probe(struct device *dev, struct regmap *regmap,
 int adau1781_probe(struct device *dev, struct regmap *regmap,
 	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
 	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
 {
 {
+	const char *firmware_name;
 	int ret;
 	int ret;
 
 
-	ret = adau17x1_probe(dev, regmap, type, switch_mode);
+	switch (type) {
+	case ADAU1381:
+		firmware_name = ADAU1381_FIRMWARE;
+		break;
+	case ADAU1781:
+		firmware_name = ADAU1781_FIRMWARE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 

+ 64 - 7
sound/soc/codecs/adau17x1.c

@@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
 static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
 static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	struct snd_kcontrol *kcontrol, int event)
 {
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
 
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -307,6 +308,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	struct adau *adau = snd_soc_codec_get_drvdata(codec);
 	unsigned int val, div, dsp_div;
 	unsigned int val, div, dsp_div;
 	unsigned int freq;
 	unsigned int freq;
+	int ret;
 
 
 	if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
 	if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
 		freq = adau->pll_freq;
 		freq = adau->pll_freq;
@@ -356,6 +358,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
 		regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
 		regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
 	}
 	}
 
 
+	if (adau->sigmadsp) {
+		ret = adau17x1_setup_firmware(adau, params_rate(params));
+		if (ret < 0)
+			return ret;
+	}
+
 	if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
 	if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
 		return 0;
 		return 0;
 
 
@@ -661,12 +669,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	return 0;
 	return 0;
 }
 }
 
 
+static int adau17x1_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+
+	if (adau->sigmadsp)
+		return sigmadsp_restrict_params(adau->sigmadsp, substream);
+
+	return 0;
+}
+
 const struct snd_soc_dai_ops adau17x1_dai_ops = {
 const struct snd_soc_dai_ops adau17x1_dai_ops = {
 	.hw_params	= adau17x1_hw_params,
 	.hw_params	= adau17x1_hw_params,
 	.set_sysclk	= adau17x1_set_dai_sysclk,
 	.set_sysclk	= adau17x1_set_dai_sysclk,
 	.set_fmt	= adau17x1_set_dai_fmt,
 	.set_fmt	= adau17x1_set_dai_fmt,
 	.set_pll	= adau17x1_set_dai_pll,
 	.set_pll	= adau17x1_set_dai_pll,
 	.set_tdm_slot	= adau17x1_set_dai_tdm_slot,
 	.set_tdm_slot	= adau17x1_set_dai_tdm_slot,
+	.startup	= adau17x1_startup,
 };
 };
 EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
 EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
 
 
@@ -687,8 +707,22 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
 }
 }
 EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
 EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
 
 
+bool adau17x1_precious_register(struct device *dev, unsigned int reg)
+{
+	/* SigmaDSP parameter memory */
+	if (reg < 0x400)
+		return true;
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_precious_register);
+
 bool adau17x1_readable_register(struct device *dev, unsigned int reg)
 bool adau17x1_readable_register(struct device *dev, unsigned int reg)
 {
 {
+	/* SigmaDSP parameter memory */
+	if (reg < 0x400)
+		return true;
+
 	switch (reg) {
 	switch (reg) {
 	case ADAU17X1_CLOCK_CONTROL:
 	case ADAU17X1_CLOCK_CONTROL:
 	case ADAU17X1_PLL_CONTROL:
 	case ADAU17X1_PLL_CONTROL:
@@ -745,8 +779,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
 }
 }
 EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
 EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
 
 
-int adau17x1_load_firmware(struct adau *adau, struct device *dev,
-	const char *firmware)
+int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
 {
 {
 	int ret;
 	int ret;
 	int dspsr;
 	int dspsr;
@@ -758,7 +791,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
 	regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
 	regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
 	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
 	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
 
 
-	ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
+	ret = sigmadsp_setup(adau->sigmadsp, rate);
 	if (ret) {
 	if (ret) {
 		regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
 		regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
 		return ret;
 		return ret;
@@ -767,7 +800,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
+EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
 
 
 int adau17x1_add_widgets(struct snd_soc_codec *codec)
 int adau17x1_add_widgets(struct snd_soc_codec *codec)
 {
 {
@@ -787,8 +820,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
 		ret = snd_soc_dapm_new_controls(&codec->dapm,
 		ret = snd_soc_dapm_new_controls(&codec->dapm,
 			adau17x1_dsp_dapm_widgets,
 			adau17x1_dsp_dapm_widgets,
 			ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
 			ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
+		if (ret)
+			return ret;
+
+		if (!adau->sigmadsp)
+			return 0;
+
+		ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
+		if (ret) {
+			dev_err(codec->dev, "Failed to attach firmware: %d\n",
+				ret);
+			return ret;
+		}
 	}
 	}
-	return ret;
+
+	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
 EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
 
 
@@ -829,7 +875,8 @@ int adau17x1_resume(struct snd_soc_codec *codec)
 EXPORT_SYMBOL_GPL(adau17x1_resume);
 EXPORT_SYMBOL_GPL(adau17x1_resume);
 
 
 int adau17x1_probe(struct device *dev, struct regmap *regmap,
 int adau17x1_probe(struct device *dev, struct regmap *regmap,
-	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
+	const char *firmware_name)
 {
 {
 	struct adau *adau;
 	struct adau *adau;
 
 
@@ -846,6 +893,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
 
 
 	dev_set_drvdata(dev, adau);
 	dev_set_drvdata(dev, adau);
 
 
+	if (firmware_name) {
+		adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
+			firmware_name);
+		if (IS_ERR(adau->sigmadsp)) {
+			dev_warn(dev, "Could not find firmware file: %ld\n",
+				PTR_ERR(adau->sigmadsp));
+			adau->sigmadsp = NULL;
+		}
+	}
+
 	if (switch_mode)
 	if (switch_mode)
 		switch_mode(dev);
 		switch_mode(dev);
 
 

+ 7 - 3
sound/soc/codecs/adau17x1.h

@@ -4,6 +4,8 @@
 #include <linux/regmap.h>
 #include <linux/regmap.h>
 #include <linux/platform_data/adau17x1.h>
 #include <linux/platform_data/adau17x1.h>
 
 
+#include "sigmadsp.h"
+
 enum adau17x1_type {
 enum adau17x1_type {
 	ADAU1361,
 	ADAU1361,
 	ADAU1761,
 	ADAU1761,
@@ -42,22 +44,24 @@ struct adau {
 	bool dsp_bypass[2];
 	bool dsp_bypass[2];
 
 
 	struct regmap *regmap;
 	struct regmap *regmap;
+	struct sigmadsp *sigmadsp;
 };
 };
 
 
 int adau17x1_add_widgets(struct snd_soc_codec *codec);
 int adau17x1_add_widgets(struct snd_soc_codec *codec);
 int adau17x1_add_routes(struct snd_soc_codec *codec);
 int adau17x1_add_routes(struct snd_soc_codec *codec);
 int adau17x1_probe(struct device *dev, struct regmap *regmap,
 int adau17x1_probe(struct device *dev, struct regmap *regmap,
-	enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
+	const char *firmware_name);
 int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
 int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
 	enum adau17x1_micbias_voltage micbias);
 	enum adau17x1_micbias_voltage micbias);
 bool adau17x1_readable_register(struct device *dev, unsigned int reg);
 bool adau17x1_readable_register(struct device *dev, unsigned int reg);
 bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
 bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
+bool adau17x1_precious_register(struct device *dev, unsigned int reg);
 int adau17x1_resume(struct snd_soc_codec *codec);
 int adau17x1_resume(struct snd_soc_codec *codec);
 
 
 extern const struct snd_soc_dai_ops adau17x1_dai_ops;
 extern const struct snd_soc_dai_ops adau17x1_dai_ops;
 
 
-int adau17x1_load_firmware(struct adau *adau, struct device *dev,
-	const char *firmware);
+int adau17x1_setup_firmware(struct adau *adau, unsigned int rate);
 bool adau17x1_has_dsp(struct adau *adau);
 bool adau17x1_has_dsp(struct adau *adau);
 
 
 #define ADAU17X1_CLOCK_CONTROL			0x4000
 #define ADAU17X1_CLOCK_CONTROL			0x4000

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

@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
 static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
 static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 			 struct snd_soc_dapm_widget *sink)
 {
 {
-	struct snd_soc_codec *codec = source->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	const char *clk;
 	const char *clk;
 
 
@@ -236,7 +236,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
 static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
 static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 			 struct snd_soc_dapm_widget *sink)
 {
 {
-	struct snd_soc_codec *codec = source->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
 
 	return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
 	return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;

+ 4 - 27
sound/soc/codecs/ak4535.c

@@ -373,33 +373,9 @@ static struct snd_soc_dai_driver ak4535_dai = {
 	.ops = &ak4535_dai_ops,
 	.ops = &ak4535_dai_ops,
 };
 };
 
 
-static int ak4535_suspend(struct snd_soc_codec *codec)
-{
-	ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static int ak4535_resume(struct snd_soc_codec *codec)
 static int ak4535_resume(struct snd_soc_codec *codec)
 {
 {
 	snd_soc_cache_sync(codec);
 	snd_soc_cache_sync(codec);
-	ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-
-static int ak4535_probe(struct snd_soc_codec *codec)
-{
-	/* power on device */
-	ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	snd_soc_add_codec_controls(codec, ak4535_snd_controls,
-				ARRAY_SIZE(ak4535_snd_controls));
-	return 0;
-}
-
-/* power down chip */
-static int ak4535_remove(struct snd_soc_codec *codec)
-{
-	ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -416,11 +392,12 @@ static const struct regmap_config ak4535_regmap = {
 };
 };
 
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
-	.probe =	ak4535_probe,
-	.remove =	ak4535_remove,
-	.suspend =	ak4535_suspend,
 	.resume =	ak4535_resume,
 	.resume =	ak4535_resume,
 	.set_bias_level = ak4535_set_bias_level,
 	.set_bias_level = ak4535_set_bias_level,
+	.suspend_bias_off = true,
+
+	.controls = ak4535_snd_controls,
+	.num_controls = ARRAY_SIZE(ak4535_snd_controls),
 	.dapm_widgets = ak4535_dapm_widgets,
 	.dapm_widgets = ak4535_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
 	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
 	.dapm_routes = ak4535_audio_map,
 	.dapm_routes = ak4535_audio_map,

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

@@ -505,39 +505,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 },
 },
 };
 };
 
 
-static int ak4641_suspend(struct snd_soc_codec *codec)
-{
-	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-static int ak4641_resume(struct snd_soc_codec *codec)
-{
-	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-
-static int ak4641_probe(struct snd_soc_codec *codec)
-{
-	/* power on device */
-	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
-static int ak4641_remove(struct snd_soc_codec *codec)
-{
-	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-
 static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
 static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
-	.probe			= ak4641_probe,
-	.remove			= ak4641_remove,
-	.suspend		= ak4641_suspend,
-	.resume			= ak4641_resume,
 	.controls		= ak4641_snd_controls,
 	.controls		= ak4641_snd_controls,
 	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
 	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
 	.dapm_widgets		= ak4641_dapm_widgets,
 	.dapm_widgets		= ak4641_dapm_widgets,
@@ -545,6 +513,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
 	.dapm_routes		= ak4641_audio_map,
 	.dapm_routes		= ak4641_audio_map,
 	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
 	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
 	.set_bias_level		= ak4641_set_bias_level,
 	.set_bias_level		= ak4641_set_bias_level,
+	.suspend_bias_off	= true,
 };
 };
 
 
 static const struct regmap_config ak4641_regmap = {
 static const struct regmap_config ak4641_regmap = {

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

@@ -491,23 +491,7 @@ static int ak4642_resume(struct snd_soc_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-
-static int ak4642_probe(struct snd_soc_codec *codec)
-{
-	ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
-static int ak4642_remove(struct snd_soc_codec *codec)
-{
-	ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
 static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
-	.probe			= ak4642_probe,
-	.remove			= ak4642_remove,
 	.resume			= ak4642_resume,
 	.resume			= ak4642_resume,
 	.set_bias_level		= ak4642_set_bias_level,
 	.set_bias_level		= ak4642_set_bias_level,
 	.controls		= ak4642_snd_controls,
 	.controls		= ak4642_snd_controls,

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

@@ -611,20 +611,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
 	.ops = &ak4671_dai_ops,
 	.ops = &ak4671_dai_ops,
 };
 };
 
 
-static int ak4671_probe(struct snd_soc_codec *codec)
-{
-	return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-static int ak4671_remove(struct snd_soc_codec *codec)
-{
-	ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
-	.probe = ak4671_probe,
-	.remove = ak4671_remove,
 	.set_bias_level = ak4671_set_bias_level,
 	.set_bias_level = ak4671_set_bias_level,
 	.controls = ak4671_snd_controls,
 	.controls = ak4671_snd_controls,
 	.num_controls = ARRAY_SIZE(ak4671_snd_controls),
 	.num_controls = ARRAY_SIZE(ak4671_snd_controls),

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

@@ -866,7 +866,6 @@ static int alc5623_suspend(struct snd_soc_codec *codec)
 {
 {
 	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
 	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
 
 
-	alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	regcache_cache_only(alc5623->regmap, true);
 	regcache_cache_only(alc5623->regmap, true);
 
 
 	return 0;
 	return 0;
@@ -887,15 +886,6 @@ static int alc5623_resume(struct snd_soc_codec *codec)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	/* charge alc5623 caps */
-	if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
-		alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-		codec->dapm.bias_level = SND_SOC_BIAS_ON;
-		alc5623_set_bias_level(codec, codec->dapm.bias_level);
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -906,9 +896,6 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 
 
 	alc5623_reset(codec);
 	alc5623_reset(codec);
 
 
-	/* power on device */
-	alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	if (alc5623->add_ctrl) {
 	if (alc5623->add_ctrl) {
 		snd_soc_write(codec, ALC5623_ADD_CTRL_REG,
 		snd_soc_write(codec, ALC5623_ADD_CTRL_REG,
 				alc5623->add_ctrl);
 				alc5623->add_ctrl);
@@ -964,19 +951,12 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-/* power down chip */
-static int alc5623_remove(struct snd_soc_codec *codec)
-{
-	alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
 static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
 	.probe = alc5623_probe,
 	.probe = alc5623_probe,
-	.remove = alc5623_remove,
 	.suspend = alc5623_suspend,
 	.suspend = alc5623_suspend,
 	.resume = alc5623_resume,
 	.resume = alc5623_resume,
 	.set_bias_level = alc5623_set_bias_level,
 	.set_bias_level = alc5623_set_bias_level,
+	.suspend_bias_off = true,
 };
 };
 
 
 static const struct regmap_config alc5623_regmap = {
 static const struct regmap_config alc5623_regmap = {

+ 2 - 20
sound/soc/codecs/alc5632.c

@@ -1038,23 +1038,15 @@ static struct snd_soc_dai_driver alc5632_dai = {
 };
 };
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
-static int alc5632_suspend(struct snd_soc_codec *codec)
-{
-	alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static int alc5632_resume(struct snd_soc_codec *codec)
 static int alc5632_resume(struct snd_soc_codec *codec)
 {
 {
 	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
 	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
 
 
 	regcache_sync(alc5632->regmap);
 	regcache_sync(alc5632->regmap);
 
 
-	alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	return 0;
 	return 0;
 }
 }
 #else
 #else
-#define	alc5632_suspend	NULL
 #define	alc5632_resume	NULL
 #define	alc5632_resume	NULL
 #endif
 #endif
 
 
@@ -1062,9 +1054,6 @@ static int alc5632_probe(struct snd_soc_codec *codec)
 {
 {
 	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
 	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
 
 
-	/* power on device  */
-	alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	switch (alc5632->id) {
 	switch (alc5632->id) {
 	case 0x5c:
 	case 0x5c:
 		snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls,
 		snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls,
@@ -1077,19 +1066,12 @@ static int alc5632_probe(struct snd_soc_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-/* power down chip */
-static int alc5632_remove(struct snd_soc_codec *codec)
-{
-	alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
 static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
 	.probe = alc5632_probe,
 	.probe = alc5632_probe,
-	.remove = alc5632_remove,
-	.suspend = alc5632_suspend,
 	.resume = alc5632_resume,
 	.resume = alc5632_resume,
 	.set_bias_level = alc5632_set_bias_level,
 	.set_bias_level = alc5632_set_bias_level,
+	.suspend_bias_off = true,
+
 	.controls = alc5632_snd_controls,
 	.controls = alc5632_snd_controls,
 	.num_controls = ARRAY_SIZE(alc5632_snd_controls),
 	.num_controls = ARRAY_SIZE(alc5632_snd_controls),
 	.dapm_widgets = alc5632_dapm_widgets,
 	.dapm_widgets = alc5632_dapm_widgets,

+ 28 - 6
sound/soc/codecs/arizona.c

@@ -61,6 +61,11 @@
 #define ARIZONA_FLL_MIN_OUTDIV 2
 #define ARIZONA_FLL_MIN_OUTDIV 2
 #define ARIZONA_FLL_MAX_OUTDIV 7
 #define ARIZONA_FLL_MAX_OUTDIV 7
 
 
+#define ARIZONA_FMT_DSP_MODE_A          0
+#define ARIZONA_FMT_DSP_MODE_B          1
+#define ARIZONA_FMT_I2S_MODE            2
+#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
+
 #define arizona_fll_err(_fll, fmt, ...) \
 #define arizona_fll_err(_fll, fmt, ...) \
 	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
 	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
 #define arizona_fll_warn(_fll, fmt, ...) \
 #define arizona_fll_warn(_fll, fmt, ...) \
@@ -648,7 +653,7 @@ SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
 EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
 EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
 
 
 static const char * const arizona_in_dmic_osr_text[] = {
 static const char * const arizona_in_dmic_osr_text[] = {
-	"1.536MHz", "3.072MHz", "6.144MHz",
+	"1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
 };
 };
 
 
 const struct soc_enum arizona_in_dmic_osr[] = {
 const struct soc_enum arizona_in_dmic_osr[] = {
@@ -946,10 +951,26 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_A:
-		mode = 0;
+		mode = ARIZONA_FMT_DSP_MODE_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
+				!= SND_SOC_DAIFMT_CBM_CFM) {
+			arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
+			return -EINVAL;
+		}
+		mode = ARIZONA_FMT_DSP_MODE_B;
 		break;
 		break;
 	case SND_SOC_DAIFMT_I2S:
 	case SND_SOC_DAIFMT_I2S:
-		mode = 2;
+		mode = ARIZONA_FMT_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
+				!= SND_SOC_DAIFMT_CBM_CFM) {
+			arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
+			return -EINVAL;
+		}
+		mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
 		break;
 		break;
 	default:
 	default:
 		arizona_aif_err(dai, "Unsupported DAI format %d\n",
 		arizona_aif_err(dai, "Unsupported DAI format %d\n",
@@ -1164,13 +1185,13 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
 		{ 0x80, 0x0 },
 		{ 0x80, 0x0 },
 	};
 	};
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&arizona->dac_comp_lock);
 
 
 	dac_comp[1].def = arizona->dac_comp_coeff;
 	dac_comp[1].def = arizona->dac_comp_coeff;
 	if (rate >= 176400)
 	if (rate >= 176400)
 		dac_comp[2].def = arizona->dac_comp_enabled;
 		dac_comp[2].def = arizona->dac_comp_enabled;
 
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&arizona->dac_comp_lock);
 
 
 	regmap_multi_reg_write(arizona->regmap,
 	regmap_multi_reg_write(arizona->regmap,
 			       dac_comp,
 			       dac_comp,
@@ -1298,7 +1319,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 
 
 	/* Force multiple of 2 channels for I2S mode */
 	/* Force multiple of 2 channels for I2S mode */
 	val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
 	val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
-	if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) {
+	val &= ARIZONA_AIF1_FMT_MASK;
+	if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
 		arizona_aif_dbg(dai, "Forcing stereo mode\n");
 		arizona_aif_dbg(dai, "Forcing stereo mode\n");
 		bclk_target /= channels;
 		bclk_target /= channels;
 		bclk_target *= channels + 1;
 		bclk_target *= channels + 1;

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

@@ -62,14 +62,10 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
 static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 				 int clk_id, unsigned int freq, int dir)
 {
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct davinci_vc *davinci_vc = codec->dev->platform_data;
-
 	switch (freq) {
 	switch (freq) {
 	case 22579200:
 	case 22579200:
 	case 27000000:
 	case 27000000:
 	case 33868800:
 	case 33868800:
-		davinci_vc->cq93vc.sysclk = freq;
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -126,32 +122,6 @@ static struct snd_soc_dai_driver cq93vc_dai = {
 	.ops = &cq93vc_dai_ops,
 	.ops = &cq93vc_dai_ops,
 };
 };
 
 
-static int cq93vc_resume(struct snd_soc_codec *codec)
-{
-	cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
-static int cq93vc_probe(struct snd_soc_codec *codec)
-{
-	struct davinci_vc *davinci_vc = codec->dev->platform_data;
-
-	davinci_vc->cq93vc.codec = codec;
-
-	/* Off, with power on */
-	cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-
-static int cq93vc_remove(struct snd_soc_codec *codec)
-{
-	cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
 static struct regmap *cq93vc_get_regmap(struct device *dev)
 static struct regmap *cq93vc_get_regmap(struct device *dev)
 {
 {
 	struct davinci_vc *davinci_vc = dev->platform_data;
 	struct davinci_vc *davinci_vc = dev->platform_data;
@@ -161,9 +131,6 @@ static struct regmap *cq93vc_get_regmap(struct device *dev)
 
 
 static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
 static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
 	.set_bias_level = cq93vc_set_bias_level,
 	.set_bias_level = cq93vc_set_bias_level,
-	.probe = cq93vc_probe,
-	.remove = cq93vc_remove,
-	.resume = cq93vc_resume,
 	.get_regmap = cq93vc_get_regmap,
 	.get_regmap = cq93vc_get_regmap,
 	.controls = cq93vc_snd_controls,
 	.controls = cq93vc_snd_controls,
 	.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
 	.num_controls = ARRAY_SIZE(cq93vc_snd_controls),

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

@@ -32,7 +32,6 @@
 #include "cs4265.h"
 #include "cs4265.h"
 
 
 struct cs4265_private {
 struct cs4265_private {
-	struct device *dev;
 	struct regmap *regmap;
 	struct regmap *regmap;
 	struct gpio_desc *reset_gpio;
 	struct gpio_desc *reset_gpio;
 	u8 format;
 	u8 format;
@@ -598,7 +597,6 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
 			       GFP_KERNEL);
 			       GFP_KERNEL);
 	if (cs4265 == NULL)
 	if (cs4265 == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
-	cs4265->dev = &i2c_client->dev;
 
 
 	cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
 	cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
 	if (IS_ERR(cs4265->regmap)) {
 	if (IS_ERR(cs4265->regmap)) {

+ 62 - 0
sound/soc/codecs/cs4271-i2c.c

@@ -0,0 +1,62 @@
+/*
+ * CS4271 I2C audio driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cs4271.h"
+
+static int cs4271_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = cs4271_regmap_config;
+	config.reg_bits = 8;
+	config.val_bits = 8;
+
+	return cs4271_probe(&client->dev,
+			    devm_regmap_init_i2c(client, &config));
+}
+
+static int cs4271_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id cs4271_i2c_id[] = {
+	{ "cs4271", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+
+static struct i2c_driver cs4271_i2c_driver = {
+	.driver = {
+		.name = "cs4271",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(cs4271_dt_ids),
+	},
+	.probe = cs4271_i2c_probe,
+	.remove = cs4271_i2c_remove,
+	.id_table = cs4271_i2c_id,
+};
+module_i2c_driver(cs4271_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS4271 I2C Driver");
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_LICENSE("GPL");

+ 55 - 0
sound/soc/codecs/cs4271-spi.c

@@ -0,0 +1,55 @@
+/*
+ * CS4271 SPI audio driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cs4271.h"
+
+static int cs4271_spi_probe(struct spi_device *spi)
+{
+	struct regmap_config config;
+
+	config = cs4271_regmap_config;
+	config.reg_bits = 16;
+	config.val_bits = 8;
+	config.read_flag_mask = 0x21;
+	config.write_flag_mask = 0x20;
+
+	return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static int cs4271_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	return 0;
+}
+
+static struct spi_driver cs4271_spi_driver = {
+	.driver = {
+		.name	= "cs4271",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(cs4271_dt_ids),
+	},
+	.probe		= cs4271_spi_probe,
+	.remove		= cs4271_spi_remove,
+};
+module_spi_driver(cs4271_spi_driver);
+
+MODULE_DESCRIPTION("ASoC CS4271 SPI Driver");
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_LICENSE("GPL");

+ 18 - 137
sound/soc/codecs/cs4271.c

@@ -23,8 +23,6 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/of_gpio.h>
@@ -32,6 +30,7 @@
 #include <sound/soc.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
 #include <sound/cs4271.h>
 #include <sound/cs4271.h>
+#include "cs4271.h"
 
 
 #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 			    SNDRV_PCM_FMTBIT_S24_LE | \
 			    SNDRV_PCM_FMTBIT_S24_LE | \
@@ -527,14 +526,15 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
-static const struct of_device_id cs4271_dt_ids[] = {
+const struct of_device_id cs4271_dt_ids[] = {
 	{ .compatible = "cirrus,cs4271", },
 	{ .compatible = "cirrus,cs4271", },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
 MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
+EXPORT_SYMBOL_GPL(cs4271_dt_ids);
 #endif
 #endif
 
 
-static int cs4271_probe(struct snd_soc_codec *codec)
+static int cs4271_codec_probe(struct snd_soc_codec *codec)
 {
 {
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
 	struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
@@ -587,7 +587,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-static int cs4271_remove(struct snd_soc_codec *codec)
+static int cs4271_codec_remove(struct snd_soc_codec *codec)
 {
 {
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
 
@@ -599,8 +599,8 @@ static int cs4271_remove(struct snd_soc_codec *codec)
 };
 };
 
 
 static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
 static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
-	.probe			= cs4271_probe,
-	.remove			= cs4271_remove,
+	.probe			= cs4271_codec_probe,
+	.remove			= cs4271_codec_remove,
 	.suspend		= cs4271_soc_suspend,
 	.suspend		= cs4271_soc_suspend,
 	.resume			= cs4271_soc_resume,
 	.resume			= cs4271_soc_resume,
 
 
@@ -642,14 +642,8 @@ static int cs4271_common_probe(struct device *dev,
 	return 0;
 	return 0;
 }
 }
 
 
-#if defined(CONFIG_SPI_MASTER)
-
-static const struct regmap_config cs4271_spi_regmap = {
-	.reg_bits = 16,
-	.val_bits = 8,
+const struct regmap_config cs4271_regmap_config = {
 	.max_register = CS4271_LASTREG,
 	.max_register = CS4271_LASTREG,
-	.read_flag_mask = 0x21,
-	.write_flag_mask = 0x20,
 
 
 	.reg_defaults = cs4271_reg_defaults,
 	.reg_defaults = cs4271_reg_defaults,
 	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
 	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
@@ -657,140 +651,27 @@ static const struct regmap_config cs4271_spi_regmap = {
 
 
 	.volatile_reg = cs4271_volatile_reg,
 	.volatile_reg = cs4271_volatile_reg,
 };
 };
+EXPORT_SYMBOL_GPL(cs4271_regmap_config);
 
 
-static int cs4271_spi_probe(struct spi_device *spi)
+int cs4271_probe(struct device *dev, struct regmap *regmap)
 {
 {
 	struct cs4271_private *cs4271;
 	struct cs4271_private *cs4271;
 	int ret;
 	int ret;
 
 
-	ret = cs4271_common_probe(&spi->dev, &cs4271);
-	if (ret < 0)
-		return ret;
-
-	spi_set_drvdata(spi, cs4271);
-	cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
-	if (IS_ERR(cs4271->regmap))
-		return PTR_ERR(cs4271->regmap);
-
-	return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
-		&cs4271_dai, 1);
-}
-
-static int cs4271_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
-static struct spi_driver cs4271_spi_driver = {
-	.driver = {
-		.name	= "cs4271",
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(cs4271_dt_ids),
-	},
-	.probe		= cs4271_spi_probe,
-	.remove		= cs4271_spi_remove,
-};
-#endif /* defined(CONFIG_SPI_MASTER) */
-
-#if IS_ENABLED(CONFIG_I2C)
-static const struct i2c_device_id cs4271_i2c_id[] = {
-	{"cs4271", 0},
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
 
 
-static const struct regmap_config cs4271_i2c_regmap = {
-	.reg_bits = 8,
-	.val_bits = 8,
-	.max_register = CS4271_LASTREG,
-
-	.reg_defaults = cs4271_reg_defaults,
-	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
-	.cache_type = REGCACHE_RBTREE,
-
-	.volatile_reg = cs4271_volatile_reg,
-};
-
-static int cs4271_i2c_probe(struct i2c_client *client,
-			    const struct i2c_device_id *id)
-{
-	struct cs4271_private *cs4271;
-	int ret;
-
-	ret = cs4271_common_probe(&client->dev, &cs4271);
+	ret = cs4271_common_probe(dev, &cs4271);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	i2c_set_clientdata(client, cs4271);
-	cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
-	if (IS_ERR(cs4271->regmap))
-		return PTR_ERR(cs4271->regmap);
+	dev_set_drvdata(dev, cs4271);
+	cs4271->regmap = regmap;
 
 
-	return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
-		&cs4271_dai, 1);
-}
-
-static int cs4271_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
-static struct i2c_driver cs4271_i2c_driver = {
-	.driver = {
-		.name	= "cs4271",
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(cs4271_dt_ids),
-	},
-	.id_table	= cs4271_i2c_id,
-	.probe		= cs4271_i2c_probe,
-	.remove		= cs4271_i2c_remove,
-};
-#endif /* IS_ENABLED(CONFIG_I2C) */
-
-/*
- * We only register our serial bus driver here without
- * assignment to particular chip. So if any of the below
- * fails, there is some problem with I2C or SPI subsystem.
- * In most cases this module will be compiled with support
- * of only one serial bus.
- */
-static int __init cs4271_modinit(void)
-{
-	int ret;
-
-#if IS_ENABLED(CONFIG_I2C)
-	ret = i2c_add_driver(&cs4271_i2c_driver);
-	if (ret) {
-		pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
-		return ret;
-	}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-	ret = spi_register_driver(&cs4271_spi_driver);
-	if (ret) {
-		pr_err("Failed to register CS4271 SPI driver: %d\n", ret);
-		return ret;
-	}
-#endif
-
-	return 0;
-}
-module_init(cs4271_modinit);
-
-static void __exit cs4271_modexit(void)
-{
-#if defined(CONFIG_SPI_MASTER)
-	spi_unregister_driver(&cs4271_spi_driver);
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-	i2c_del_driver(&cs4271_i2c_driver);
-#endif
+	return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai,
+				      1);
 }
 }
-module_exit(cs4271_modexit);
+EXPORT_SYMBOL_GPL(cs4271_probe);
 
 
 MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
 MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
 MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
 MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");

+ 11 - 0
sound/soc/codecs/cs4271.h

@@ -0,0 +1,11 @@
+#ifndef _CS4271_PRIV_H
+#define _CS4271_PRIV_H
+
+#include <linux/regmap.h>
+
+extern const struct of_device_id cs4271_dt_ids[];
+extern const struct regmap_config cs4271_regmap_config;
+
+int cs4271_probe(struct device *dev, struct regmap *regmap);
+
+#endif

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

@@ -153,15 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 		struct snd_kcontrol *kcontrol, int event)
 {
 {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMD:
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+		snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
 				    CS42L51_POWER_CTL1_PDN,
 				    CS42L51_POWER_CTL1_PDN,
 				    CS42L51_POWER_CTL1_PDN);
 				    CS42L51_POWER_CTL1_PDN);
 		break;
 		break;
 	default:
 	default:
 	case SND_SOC_DAPM_POST_PMD:
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+		snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
 				    CS42L51_POWER_CTL1_PDN, 0);
 				    CS42L51_POWER_CTL1_PDN, 0);
 		break;
 		break;
 	}
 	}

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

@@ -584,7 +584,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
 static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	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 cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 	case SND_SOC_DAPM_POST_PMD:
@@ -600,7 +600,7 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	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 cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 	case SND_SOC_DAPM_POST_PMD:
@@ -618,7 +618,7 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	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 cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 	case SND_SOC_DAPM_POST_PMD:

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

@@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
 			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
 			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits = 24,
 	},
 	},
 	.capture = {
 	.capture = {
 		.stream_name = "Capture",
 		.stream_name = "Capture",
@@ -75,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = {
 	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
 	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
 	.dapm_routes = hdmi_routes,
 	.dapm_routes = hdmi_routes,
 	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
 	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
+	.ignore_pmdown_time = true,
 };
 };
 
 
 static int hdmi_codec_probe(struct platform_device *pdev)
 static int hdmi_codec_probe(struct platform_device *pdev)

+ 0 - 8
sound/soc/codecs/lm49453.c

@@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
 	},
 	},
 };
 };
 
 
-/* power down chip */
-static int lm49453_remove(struct snd_soc_codec *codec)
-{
-	lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
-	.remove = lm49453_remove,
 	.set_bias_level = lm49453_set_bias_level,
 	.set_bias_level = lm49453_set_bias_level,
 	.controls = lm49453_snd_controls,
 	.controls = lm49453_snd_controls,
 	.num_controls = ARRAY_SIZE(lm49453_snd_controls),
 	.num_controls = ARRAY_SIZE(lm49453_snd_controls),

+ 4 - 27
sound/soc/codecs/max98088.c

@@ -875,7 +875,7 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
 static int max98088_mic_event(struct snd_soc_dapm_widget *w,
 static int max98088_mic_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
                             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 max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
 
 
        switch (event) {
        switch (event) {
@@ -905,7 +905,7 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w,
 static int max98088_line_pga(struct snd_soc_dapm_widget *w,
 static int max98088_line_pga(struct snd_soc_dapm_widget *w,
                             int event, int line, u8 channel)
                             int event, int line, u8 channel)
 {
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        u8 *state;
        u8 *state;
 
 
@@ -1887,25 +1887,6 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
                max98088_handle_eq_pdata(codec);
                max98088_handle_eq_pdata(codec);
 }
 }
 
 
-#ifdef CONFIG_PM
-static int max98088_suspend(struct snd_soc_codec *codec)
-{
-       max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int max98088_resume(struct snd_soc_codec *codec)
-{
-       max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-#else
-#define max98088_suspend NULL
-#define max98088_resume NULL
-#endif
-
 static int max98088_probe(struct snd_soc_codec *codec)
 static int max98088_probe(struct snd_soc_codec *codec)
 {
 {
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
@@ -1946,9 +1927,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
 
 
        snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
        snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
 
 
-       /* initialize registers cache to hardware default */
-       max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
        snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
 
 
        snd_soc_write(codec, M98088_REG_22_MIX_DAC,
        snd_soc_write(codec, M98088_REG_22_MIX_DAC,
@@ -1974,7 +1952,6 @@ static int max98088_remove(struct snd_soc_codec *codec)
 {
 {
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
        struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
 
 
-       max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
        kfree(max98088->eq_texts);
        kfree(max98088->eq_texts);
 
 
        return 0;
        return 0;
@@ -1983,9 +1960,9 @@ static int max98088_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
 static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
 	.probe   = max98088_probe,
 	.probe   = max98088_probe,
 	.remove  = max98088_remove,
 	.remove  = max98088_remove,
-	.suspend = max98088_suspend,
-	.resume  = max98088_resume,
 	.set_bias_level = max98088_set_bias_level,
 	.set_bias_level = max98088_set_bias_level,
+	.suspend_bias_off = true,
+
 	.controls = max98088_snd_controls,
 	.controls = max98088_snd_controls,
 	.num_controls = ARRAY_SIZE(max98088_snd_controls),
 	.num_controls = ARRAY_SIZE(max98088_snd_controls),
 	.dapm_widgets = max98088_dapm_widgets,
 	.dapm_widgets = max98088_dapm_widgets,

+ 160 - 41
sound/soc/codecs/max98090.c

@@ -806,7 +806,7 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
 static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
 static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 				 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 max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 
 
 	unsigned int val = snd_soc_read(codec, w->reg);
 	unsigned int val = snd_soc_read(codec, w->reg);
@@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
 	{"MIC1 Input", NULL, "MIC1"},
 	{"MIC1 Input", NULL, "MIC1"},
 	{"MIC2 Input", NULL, "MIC2"},
 	{"MIC2 Input", NULL, "MIC2"},
 
 
+	{"DMICL", NULL, "DMICL_ENA"},
+	{"DMICL", NULL, "DMICR_ENA"},
+	{"DMICR", NULL, "DMICL_ENA"},
+	{"DMICR", NULL, "DMICR_ENA"},
 	{"DMICL", NULL, "AHPF"},
 	{"DMICL", NULL, "AHPF"},
 	{"DMICR", NULL, "AHPF"},
 	{"DMICR", NULL, "AHPF"},
 
 
@@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
 	{"DMIC Mux", "ADC", "ADCR"},
 	{"DMIC Mux", "ADC", "ADCR"},
 	{"DMIC Mux", "DMIC", "DMICL"},
 	{"DMIC Mux", "DMIC", "DMICL"},
 	{"DMIC Mux", "DMIC", "DMICR"},
 	{"DMIC Mux", "DMIC", "DMICR"},
-	{"DMIC Mux", "DMIC", "DMICL_ENA"},
-	{"DMIC Mux", "DMIC", "DMICR_ENA"},
 
 
 	{"LBENL Mux", "Normal", "DMIC Mux"},
 	{"LBENL Mux", "Normal", "DMIC Mux"},
 	{"LBENL Mux", "Loopback", "LTENL Mux"},
 	{"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1395,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
 	{"STENL Mux", "Sidetone Left", "DMICL"},
 	{"STENL Mux", "Sidetone Left", "DMICL"},
 	{"STENR Mux", "Sidetone Right", "ADCR"},
 	{"STENR Mux", "Sidetone Right", "ADCR"},
 	{"STENR Mux", "Sidetone Right", "DMICR"},
 	{"STENR Mux", "Sidetone Right", "DMICR"},
-	{"DACL", "NULL", "STENL Mux"},
-	{"DACR", "NULL", "STENL Mux"},
+	{"DACL", NULL, "STENL Mux"},
+	{"DACR", NULL, "STENR Mux"},
 
 
 	{"AIFINL", NULL, "SHDN"},
 	{"AIFINL", NULL, "SHDN"},
 	{"AIFINR", NULL, "SHDN"},
 	{"AIFINR", NULL, "SHDN"},
@@ -1826,27 +1828,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 	return 0;
 }
 }
 
 
-static const int comp_pclk_rates[] = {
-	11289600, 12288000, 12000000, 13000000, 19200000
-};
-
-static const int dmic_micclk[] = {
-	2, 2, 2, 2, 4, 2
-};
+static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 };
 
 
 static const int comp_lrclk_rates[] = {
 static const int comp_lrclk_rates[] = {
 	8000, 16000, 32000, 44100, 48000, 96000
 	8000, 16000, 32000, 44100, 48000, 96000
 };
 };
 
 
-static const int dmic_comp[6][6] = {
-	{7, 8, 3, 3, 3, 3},
-	{7, 8, 3, 3, 3, 3},
-	{7, 8, 3, 3, 3, 3},
-	{7, 8, 3, 1, 1, 1},
-	{7, 8, 3, 1, 2, 2},
-	{7, 8, 3, 3, 3, 3}
+struct dmic_table {
+	int pclk;
+	struct {
+		int freq;
+		int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */
+	} settings[6]; /* One for each dmic divisor. */
 };
 };
 
 
+static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
+	{
+		.pclk = 11289600,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+		},
+	},
+	{
+		.pclk = 12000000,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+		}
+	},
+	{
+		.pclk = 12288000,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+		}
+	},
+	{
+		.pclk = 13000000,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+		}
+	},
+	{
+		.pclk = 19200000,
+		.settings = {
+			{ .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } },
+			{ .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+		}
+	},
+};
+
+static int max98090_find_divisor(int target_freq, int pclk)
+{
+	int current_diff = INT_MAX;
+	int test_diff = INT_MAX;
+	int divisor_index = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) {
+		test_diff = abs(target_freq - (pclk / dmic_divisors[i]));
+		if (test_diff < current_diff) {
+			current_diff = test_diff;
+			divisor_index = i;
+		}
+	}
+
+	return divisor_index;
+}
+
+static int max98090_find_closest_pclk(int pclk)
+{
+	int m1;
+	int m2;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dmic_table); i++) {
+		if (pclk == dmic_table[i].pclk)
+			return i;
+		if (pclk < dmic_table[i].pclk) {
+			if (i == 0)
+				return i;
+			m1 = pclk - dmic_table[i-1].pclk;
+			m2 = dmic_table[i].pclk - pclk;
+			if (m1 < m2)
+				return i - 1;
+			else
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int max98090_configure_dmic(struct max98090_priv *max98090,
+				   int target_dmic_clk, int pclk, int fs)
+{
+	int micclk_index;
+	int pclk_index;
+	int dmic_freq;
+	int dmic_comp;
+	int i;
+
+	pclk_index = max98090_find_closest_pclk(pclk);
+	if (pclk_index < 0)
+		return pclk_index;
+
+	micclk_index = max98090_find_divisor(target_dmic_clk, pclk);
+
+	for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
+		if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2)
+			break;
+	}
+
+	dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq;
+	dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i];
+
+	regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE,
+			   M98090_MICCLK_MASK,
+			   micclk_index << M98090_MICCLK_SHIFT);
+
+	regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG,
+			   M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK,
+			   dmic_comp << M98090_DMIC_COMP_SHIFT |
+			   dmic_freq << M98090_DMIC_FREQ_SHIFT);
+
+	return 0;
+}
+
 static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 				   struct snd_soc_dai *dai)
@@ -1854,7 +1984,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
 	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 	struct max98090_cdata *cdata;
 	struct max98090_cdata *cdata;
-	int i, j;
 
 
 	cdata = &max98090->dai[0];
 	cdata = &max98090->dai[0];
 	max98090->bclk = snd_soc_params_to_bclk(params);
 	max98090->bclk = snd_soc_params_to_bclk(params);
@@ -1893,27 +2022,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 		snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
 		snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
 			M98090_DHF_MASK, M98090_DHF_MASK);
 			M98090_DHF_MASK, M98090_DHF_MASK);
 
 
-	/* Check for supported PCLK to LRCLK ratios */
-	for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) {
-		if (comp_pclk_rates[j] == max98090->sysclk) {
-			break;
-		}
-	}
-
-	for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
-		if (max98090->lrclk <= (comp_lrclk_rates[i] +
-			comp_lrclk_rates[i + 1]) / 2) {
-			break;
-		}
-	}
-
-	snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE,
-			M98090_MICCLK_MASK,
-			dmic_micclk[j] << M98090_MICCLK_SHIFT);
-
-	snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG,
-			M98090_DMIC_COMP_MASK,
-			dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT);
+	max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
+				max98090->lrclk);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1944,12 +2054,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
 	if ((freq >= 10000000) && (freq <= 20000000)) {
 	if ((freq >= 10000000) && (freq <= 20000000)) {
 		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
 		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
 			M98090_PSCLK_DIV1);
 			M98090_PSCLK_DIV1);
+		max98090->pclk = freq;
 	} else if ((freq > 20000000) && (freq <= 40000000)) {
 	} else if ((freq > 20000000) && (freq <= 40000000)) {
 		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
 		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
 			M98090_PSCLK_DIV2);
 			M98090_PSCLK_DIV2);
+		max98090->pclk = freq >> 1;
 	} else if ((freq > 40000000) && (freq <= 60000000)) {
 	} else if ((freq > 40000000) && (freq <= 60000000)) {
 		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
 		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
 			M98090_PSCLK_DIV4);
 			M98090_PSCLK_DIV4);
+		max98090->pclk = freq >> 2;
 	} else {
 	} else {
 		dev_err(codec->dev, "Invalid master clock frequency\n");
 		dev_err(codec->dev, "Invalid master clock frequency\n");
 		return -EINVAL;
 		return -EINVAL;
@@ -2324,6 +2437,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	/* Initialize private data */
 	/* Initialize private data */
 
 
 	max98090->sysclk = (unsigned)-1;
 	max98090->sysclk = (unsigned)-1;
+	max98090->pclk = (unsigned)-1;
 	max98090->master = false;
 	max98090->master = false;
 
 
 	cdata = &max98090->dai[0];
 	cdata = &max98090->dai[0];
@@ -2463,6 +2577,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
 	i2c_set_clientdata(i2c, max98090);
 	i2c_set_clientdata(i2c, max98090);
 	max98090->pdata = i2c->dev.platform_data;
 	max98090->pdata = i2c->dev.platform_data;
 
 
+	ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq",
+				   &max98090->dmic_freq);
+	if (ret < 0)
+		max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ;
+
 	max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
 	max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
 	if (IS_ERR(max98090->regmap)) {
 	if (IS_ERR(max98090->regmap)) {
 		ret = PTR_ERR(max98090->regmap);
 		ret = PTR_ERR(max98090->regmap);

+ 8 - 0
sound/soc/codecs/max98090.h

@@ -11,6 +11,12 @@
 #ifndef _MAX98090_H
 #ifndef _MAX98090_H
 #define _MAX98090_H
 #define _MAX98090_H
 
 
+/*
+ * The default operating frequency for a DMIC attached to the codec.
+ * This can be overridden by a device tree property.
+ */
+#define MAX98090_DEFAULT_DMIC_FREQ		2500000
+
 /*
 /*
  * MAX98090 Register Definitions
  * MAX98090 Register Definitions
  */
  */
@@ -1518,8 +1524,10 @@ struct max98090_priv {
 	struct max98090_pdata *pdata;
 	struct max98090_pdata *pdata;
 	struct clk *mclk;
 	struct clk *mclk;
 	unsigned int sysclk;
 	unsigned int sysclk;
+	unsigned int pclk;
 	unsigned int bclk;
 	unsigned int bclk;
 	unsigned int lrclk;
 	unsigned int lrclk;
+	u32 dmic_freq;
 	struct max98090_cdata dai[1];
 	struct max98090_cdata dai[1];
 	int jack_state;
 	int jack_state;
 	struct delayed_work jack_work;
 	struct delayed_work jack_work;

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

@@ -16,6 +16,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/pcm_params.h>
@@ -57,6 +58,7 @@ struct max98095_priv {
 	unsigned int mic2pre;
 	unsigned int mic2pre;
 	struct snd_soc_jack *headphone_jack;
 	struct snd_soc_jack *headphone_jack;
 	struct snd_soc_jack *mic_jack;
 	struct snd_soc_jack *mic_jack;
+	struct mutex lock;
 };
 };
 
 
 static const struct reg_default max98095_reg_def[] = {
 static const struct reg_default max98095_reg_def[] = {
@@ -864,7 +866,7 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
 static int max98095_mic_event(struct snd_soc_dapm_widget *w,
 static int max98095_mic_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 			     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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 
 
 	switch (event) {
 	switch (event) {
@@ -894,7 +896,7 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w,
 static int max98095_line_pga(struct snd_soc_dapm_widget *w,
 static int max98095_line_pga(struct snd_soc_dapm_widget *w,
 			     int event, u8 channel)
 			     int event, u8 channel)
 {
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	u8 *state;
 	u8 *state;
 
 
@@ -942,7 +944,7 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
 static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
 static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 			     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) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMU:
@@ -1803,7 +1805,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
 	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
 	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&max98095->lock);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
 	m98095_eq_band(codec, channel, 0, coef_set->band1);
 	m98095_eq_band(codec, channel, 0, coef_set->band1);
 	m98095_eq_band(codec, channel, 1, coef_set->band2);
 	m98095_eq_band(codec, channel, 1, coef_set->band2);
@@ -1811,7 +1813,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
 	m98095_eq_band(codec, channel, 3, coef_set->band4);
 	m98095_eq_band(codec, channel, 3, coef_set->band4);
 	m98095_eq_band(codec, channel, 4, coef_set->band5);
 	m98095_eq_band(codec, channel, 4, coef_set->band5);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&max98095->lock);
 
 
 	/* Restore the original on/off state */
 	/* Restore the original on/off state */
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
@@ -1957,12 +1959,12 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
 	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
 	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
 
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&max98095->lock);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
 	m98095_biquad_band(codec, channel, 0, coef_set->band1);
 	m98095_biquad_band(codec, channel, 0, coef_set->band1);
 	m98095_biquad_band(codec, channel, 1, coef_set->band2);
 	m98095_biquad_band(codec, channel, 1, coef_set->band2);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
 	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&max98095->lock);
 
 
 	/* Restore the original on/off state */
 	/* Restore the original on/off state */
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
 	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
@@ -2317,9 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
 	snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
 
 
-	/* initialize registers cache to hardware default */
-	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	snd_soc_write(codec, M98095_048_MIX_DAC_LR,
 	snd_soc_write(codec, M98095_048_MIX_DAC_LR,
 		M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
 		M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
 
 
@@ -2359,8 +2358,6 @@ static int max98095_remove(struct snd_soc_codec *codec)
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
 	struct i2c_client *client = to_i2c_client(codec->dev);
 	struct i2c_client *client = to_i2c_client(codec->dev);
 
 
-	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
 	if (max98095->headphone_jack || max98095->mic_jack)
 	if (max98095->headphone_jack || max98095->mic_jack)
 		max98095_jack_detect_disable(codec);
 		max98095_jack_detect_disable(codec);
 
 
@@ -2395,6 +2392,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
 	if (max98095 == NULL)
 	if (max98095 == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	mutex_init(&max98095->lock);
+
 	max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
 	max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
 	if (IS_ERR(max98095->regmap)) {
 	if (IS_ERR(max98095->regmap)) {
 		ret = PTR_ERR(max98095->regmap);
 		ret = PTR_ERR(max98095->regmap);

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

@@ -291,25 +291,6 @@ static struct snd_soc_dai_driver max9850_dai = {
 	.ops = &max9850_dai_ops,
 	.ops = &max9850_dai_ops,
 };
 };
 
 
-#ifdef CONFIG_PM
-static int max9850_suspend(struct snd_soc_codec *codec)
-{
-	max9850_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int max9850_resume(struct snd_soc_codec *codec)
-{
-	max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-#else
-#define max9850_suspend NULL
-#define max9850_resume NULL
-#endif
-
 static int max9850_probe(struct snd_soc_codec *codec)
 static int max9850_probe(struct snd_soc_codec *codec)
 {
 {
 	/* enable zero-detect */
 	/* enable zero-detect */
@@ -324,9 +305,8 @@ static int max9850_probe(struct snd_soc_codec *codec)
 
 
 static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
 static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
 	.probe =	max9850_probe,
 	.probe =	max9850_probe,
-	.suspend =	max9850_suspend,
-	.resume =	max9850_resume,
 	.set_bias_level = max9850_set_bias_level,
 	.set_bias_level = max9850_set_bias_level,
+	.suspend_bias_off = true,
 
 
 	.controls = max9850_controls,
 	.controls = max9850_controls,
 	.num_controls = ARRAY_SIZE(max9850_controls),
 	.num_controls = ARRAY_SIZE(max9850_controls),

+ 172 - 59
sound/soc/codecs/rt286.c

@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/dmi.h>
 #include <linux/acpi.h>
 #include <linux/acpi.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -36,11 +37,13 @@
 
 
 struct rt286_priv {
 struct rt286_priv {
 	struct regmap *regmap;
 	struct regmap *regmap;
+	struct snd_soc_codec *codec;
 	struct rt286_platform_data pdata;
 	struct rt286_platform_data pdata;
 	struct i2c_client *i2c;
 	struct i2c_client *i2c;
 	struct snd_soc_jack *jack;
 	struct snd_soc_jack *jack;
 	struct delayed_work jack_detect_work;
 	struct delayed_work jack_detect_work;
 	int sys_clk;
 	int sys_clk;
+	int clk_id;
 	struct reg_default *index_cache;
 	struct reg_default *index_cache;
 };
 };
 
 
@@ -188,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
 	u8 data[4];
 	u8 data[4];
 	int ret, i;
 	int ret, i;
 
 
-	/*handle index registers*/
+	/* handle index registers */
 	if (reg <= 0xff) {
 	if (reg <= 0xff) {
 		rt286_hw_write(client, RT286_COEF_INDEX, reg);
 		rt286_hw_write(client, RT286_COEF_INDEX, reg);
 		for (i = 0; i < INDEX_CACHE_SIZE; i++) {
 		for (i = 0; i < INDEX_CACHE_SIZE; i++) {
@@ -231,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
 	__be32 be_reg;
 	__be32 be_reg;
 	unsigned int index, vid, buf = 0x0;
 	unsigned int index, vid, buf = 0x0;
 
 
-	/*handle index registers*/
+	/* handle index registers */
 	if (reg <= 0xff) {
 	if (reg <= 0xff) {
 		rt286_hw_write(client, RT286_COEF_INDEX, reg);
 		rt286_hw_write(client, RT286_COEF_INDEX, reg);
 		reg = RT286_PROC_COEF;
 		reg = RT286_PROC_COEF;
@@ -298,7 +301,6 @@ static int rt286_support_power_controls[] = {
 static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 {
 {
 	unsigned int val, buf;
 	unsigned int val, buf;
-	int i;
 
 
 	*hp = false;
 	*hp = false;
 	*mic = false;
 	*mic = false;
@@ -309,67 +311,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 		if (*hp) {
 		if (*hp) {
 			/* power on HV,VERF */
 			/* power on HV,VERF */
 			regmap_update_bits(rt286->regmap,
 			regmap_update_bits(rt286->regmap,
-				RT286_POWER_CTRL1, 0x1001, 0x0);
+				RT286_DC_GAIN, 0x200, 0x200);
+
+			snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
+							"HV");
+			snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
+							"VREF");
 			/* power LDO1 */
 			/* power LDO1 */
-			regmap_update_bits(rt286->regmap,
-				RT286_POWER_CTRL2, 0x4, 0x4);
-			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
-			regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
+			snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
+							"LDO1");
+			snd_soc_dapm_sync(&rt286->codec->dapm);
 
 
-			msleep(200);
-			i = 40;
-			while (((val & 0x0800) == 0) && (i > 0)) {
-				regmap_read(rt286->regmap,
-					RT286_CBJ_CTRL2, &val);
-				i--;
-				msleep(20);
-			}
+			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
+			msleep(50);
 
 
-			if (0x0400 == (val & 0x0700)) {
-				*mic = false;
+			regmap_update_bits(rt286->regmap,
+				RT286_CBJ_CTRL1, 0xfcc0, 0xd400);
+			msleep(300);
+			regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
 
 
-				regmap_write(rt286->regmap,
-					RT286_SET_MIC1, 0x20);
-				/* power off HV,VERF */
-				regmap_update_bits(rt286->regmap,
-					RT286_POWER_CTRL1, 0x1001, 0x1001);
-				regmap_update_bits(rt286->regmap,
-					RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
-				regmap_update_bits(rt286->regmap,
-					RT286_CBJ_CTRL1, 0x0030, 0x0000);
-				regmap_update_bits(rt286->regmap,
-					RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
-			} else if ((0x0200 == (val & 0x0700)) ||
-				(0x0100 == (val & 0x0700))) {
+			if (0x0070 == (val & 0x0070)) {
 				*mic = true;
 				*mic = true;
-				regmap_update_bits(rt286->regmap,
-					RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
-				regmap_update_bits(rt286->regmap,
-					RT286_CBJ_CTRL1, 0x0030, 0x0020);
-				regmap_update_bits(rt286->regmap,
-					RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
 			} else {
 			} else {
-				*mic = false;
+				regmap_update_bits(rt286->regmap,
+					RT286_CBJ_CTRL1, 0xfcc0, 0xe400);
+				msleep(300);
+				regmap_read(rt286->regmap,
+					RT286_CBJ_CTRL2, &val);
+				if (0x0070 == (val & 0x0070))
+					*mic = true;
+				else
+					*mic = false;
 			}
 			}
-
-			regmap_update_bits(rt286->regmap,
-						RT286_MISC_CTRL1,
-						0x0060, 0x0000);
-		} else {
-			regmap_update_bits(rt286->regmap,
-						RT286_MISC_CTRL1,
-						0x0060, 0x0020);
 			regmap_update_bits(rt286->regmap,
 			regmap_update_bits(rt286->regmap,
-						RT286_A_BIAS_CTRL3,
-						0xc000, 0x8000);
-			regmap_update_bits(rt286->regmap,
-						RT286_CBJ_CTRL1,
-						0x0030, 0x0020);
-			regmap_update_bits(rt286->regmap,
-						RT286_A_BIAS_CTRL2,
-						0xc000, 0x8000);
+				RT286_DC_GAIN, 0x200, 0x0);
 
 
+		} else {
 			*mic = false;
 			*mic = false;
+			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
 		}
 		}
 	} else {
 	} else {
 		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
 		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@@ -378,6 +357,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 		*mic = buf & 0x80000000;
 		*mic = buf & 0x80000000;
 	}
 	}
 
 
+	snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
+	snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
+	if (!*hp)
+		snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
+	snd_soc_dapm_sync(&rt286->codec->dapm);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -415,6 +400,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 }
 }
 EXPORT_SYMBOL_GPL(rt286_mic_detect);
 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);
+
+	if (rt286->clk_id == RT286_SCLK_S_MCLK)
+		return 1;
+	else
+		return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
 static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
 static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
 
 
@@ -568,7 +564,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w,
 	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;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec,
+			RT286_CBJ_CTRL1, 0x0400, 0x0000);
+		mdelay(50);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec,
+			RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
+		snd_soc_update_bits(codec,
+			RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec,
+			RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
+		snd_soc_update_bits(codec,
+			RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
 static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
+		12, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
+		0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
+		2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
+		13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1,
+		5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
+		0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
 	/* Input Lines */
 	/* Input Lines */
 	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
 	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
 	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
 	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
@@ -642,6 +715,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
 };
 };
 
 
 static const struct snd_soc_dapm_route rt286_dapm_routes[] = {
 static const struct snd_soc_dapm_route rt286_dapm_routes[] = {
+	{"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
+	{"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
+	{"Front", NULL, "MCLK MODE", is_mclk_mode},
+	{"Surround", NULL, "MCLK MODE", is_mclk_mode},
+
+	{"HP Power", NULL, "LDO1"},
+	{"HP Power", NULL, "LDO2"},
+
+	{"MIC1", NULL, "LDO1"},
+	{"MIC1", NULL, "LDO2"},
+	{"MIC1", NULL, "HV"},
+	{"MIC1", NULL, "VREF"},
+	{"MIC1", NULL, "MIC1 Input Buffer"},
+
+	{"SPO", NULL, "LDO1"},
+	{"SPO", NULL, "LDO2"},
+	{"SPO", NULL, "HV"},
+	{"SPO", NULL, "VREF"},
+
 	{"DMIC1", NULL, "DMIC1 Pin"},
 	{"DMIC1", NULL, "DMIC1 Pin"},
 	{"DMIC2", NULL, "DMIC2 Pin"},
 	{"DMIC2", NULL, "DMIC2 Pin"},
 	{"DMIC1", NULL, "DMIC Receiver"},
 	{"DMIC1", NULL, "DMIC Receiver"},
@@ -880,6 +972,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
 	}
 	}
 
 
 	rt286->sys_clk = freq;
 	rt286->sys_clk = freq;
+	rt286->clk_id = clk_id;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -915,13 +1008,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
 
 
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_ON:
 		mdelay(10);
 		mdelay(10);
+		snd_soc_update_bits(codec,
+			RT286_CBJ_CTRL1, 0x0400, 0x0400);
+		snd_soc_update_bits(codec,
+			RT286_DC_GAIN, 0x200, 0x0);
+
 		break;
 		break;
 
 
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		snd_soc_write(codec,
 		snd_soc_write(codec,
 			RT286_SET_AUDIO_POWER, AC_PWRST_D3);
 			RT286_SET_AUDIO_POWER, AC_PWRST_D3);
 		snd_soc_update_bits(codec,
 		snd_soc_update_bits(codec,
-			RT286_DC_GAIN, 0x200, 0x0);
+			RT286_CBJ_CTRL1, 0x0400, 0x0000);
 		break;
 		break;
 
 
 	default:
 	default:
@@ -962,6 +1060,7 @@ static int rt286_probe(struct snd_soc_codec *codec)
 {
 {
 	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 
 
+	rt286->codec = codec;
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 
 
 	if (rt286->i2c->irq) {
 	if (rt286->i2c->irq) {
@@ -1107,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = {
 };
 };
 MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
 MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
 
 
+static struct dmi_system_id force_combo_jack_table[] = {
+	{
+		.ident = "Intel Wilson Beach",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
+		}
+	},
+	{ }
+};
+
 static int rt286_i2c_probe(struct i2c_client *i2c,
 static int rt286_i2c_probe(struct i2c_client *i2c,
 			   const struct i2c_device_id *id)
 			   const struct i2c_device_id *id)
 {
 {
@@ -1142,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
 	if (pdata)
 	if (pdata)
 		rt286->pdata = *pdata;
 		rt286->pdata = *pdata;
 
 
+	if (dmi_check_system(force_combo_jack_table))
+		rt286->pdata.cbj_en = true;
+
 	regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
 	regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
 
 
 	for (i = 0; i < RT286_POWER_REG_LEN; i++)
 	for (i = 0; i < RT286_POWER_REG_LEN; i++)
@@ -1152,7 +1264,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
 	if (!rt286->pdata.cbj_en) {
 	if (!rt286->pdata.cbj_en) {
 		regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000);
 		regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000);
 		regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816);
 		regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816);
-		regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
 		regmap_update_bits(rt286->regmap,
 		regmap_update_bits(rt286->regmap,
 					RT286_CBJ_CTRL1, 0xf000, 0xb000);
 					RT286_CBJ_CTRL1, 0xf000, 0xb000);
 	} else {
 	} else {
@@ -1169,10 +1280,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
 
 
 	mdelay(10);
 	mdelay(10);
 
 
-	/*Power down LDO2*/
-	regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0);
+	regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
+	/* Power down LDO, VREF */
+	regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0);
+	regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001);
 
 
-	/*Set depop parameter*/
+	/* Set depop parameter */
 	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a);
 	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a);
 	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
 	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
 	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
 	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);

+ 12 - 26
sound/soc/codecs/rt5631.c

@@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-static int rt5631_remove(struct snd_soc_codec *codec)
-{
-	rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int rt5631_suspend(struct snd_soc_codec *codec)
-{
-	rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	return 0;
-}
-
-static int rt5631_resume(struct snd_soc_codec *codec)
-{
-	rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	return 0;
-}
-#else
-#define rt5631_suspend NULL
-#define rt5631_resume NULL
-#endif
-
 #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
 #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
 #define RT5631_FORMAT	(SNDRV_PCM_FMTBIT_S16_LE | \
 #define RT5631_FORMAT	(SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
 
 
 static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
 static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
 	.probe = rt5631_probe,
 	.probe = rt5631_probe,
-	.remove = rt5631_remove,
-	.suspend = rt5631_suspend,
-	.resume = rt5631_resume,
 	.set_bias_level = rt5631_set_bias_level,
 	.set_bias_level = rt5631_set_bias_level,
+	.suspend_bias_off = true,
 	.controls = rt5631_snd_controls,
 	.controls = rt5631_snd_controls,
 	.num_controls = ARRAY_SIZE(rt5631_snd_controls),
 	.num_controls = ARRAY_SIZE(rt5631_snd_controls),
 	.dapm_widgets = rt5631_dapm_widgets,
 	.dapm_widgets = rt5631_dapm_widgets,
@@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
 
 
 static const struct i2c_device_id rt5631_i2c_id[] = {
 static const struct i2c_device_id rt5631_i2c_id[] = {
 	{ "rt5631", 0 },
 	{ "rt5631", 0 },
+	{ "alc5631", 0 },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
 MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
 
 
+#ifdef CONFIG_OF
+static struct of_device_id rt5631_i2c_dt_ids[] = {
+	{ .compatible = "realtek,rt5631"},
+	{ .compatible = "realtek,alc5631"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids);
+#endif
+
 static const struct regmap_config rt5631_regmap_config = {
 static const struct regmap_config rt5631_regmap_config = {
 	.reg_bits = 8,
 	.reg_bits = 8,
 	.val_bits = 16,
 	.val_bits = 16,
@@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = {
 	.driver = {
 	.driver = {
 		.name = "rt5631",
 		.name = "rt5631",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
 	},
 	},
 	.probe = rt5631_i2c_probe,
 	.probe = rt5631_i2c_probe,
 	.remove   = rt5631_i2c_remove,
 	.remove   = rt5631_i2c_remove,

+ 185 - 19
sound/soc/codecs/rt5645.c

@@ -554,6 +554,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 		return 0;
 		return 0;
 }
 }
 
 
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+
+	switch (source->shift) {
+	case 0:
+		reg = RT5645_ASRC_3;
+		shift = 0;
+		break;
+	case 1:
+		reg = RT5645_ASRC_3;
+		shift = 4;
+		break;
+	case 3:
+		reg = RT5645_ASRC_2;
+		shift = 0;
+		break;
+	case 8:
+		reg = RT5645_ASRC_2;
+		shift = 4;
+		break;
+	case 9:
+		reg = RT5645_ASRC_2;
+		shift = 8;
+		break;
+	case 10:
+		reg = RT5645_ASRC_2;
+		shift = 12;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+	switch (val) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
 /* Digital Mixer */
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
 static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
@@ -1246,6 +1293,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
 	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
 		RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
 		RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
 
 
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1,
+			      11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1,
+			      12, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1,
+			      10, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1,
+			      9, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1,
+			      8, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1,
+			      7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1,
+			      5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1,
+			      4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1,
+			      3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1,
+			      1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1,
+			      0, 0, NULL, 0),
+
 	/* Input Side */
 	/* Input Side */
 	/* micbias */
 	/* micbias */
 	SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
 	SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
@@ -1504,6 +1575,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 };
 };
 
 
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 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 },
+	{ "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+	{ "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+	{ "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc },
+	{ "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc },
+	{ "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+	{ "I2S1", NULL, "I2S1 ASRC" },
+	{ "I2S2", NULL, "I2S2 ASRC" },
+
 	{ "IN1P", NULL, "LDO2" },
 	{ "IN1P", NULL, "LDO2" },
 	{ "IN2P", NULL, "LDO2" },
 	{ "IN2P", NULL, "LDO2" },
 
 
@@ -1550,12 +1632,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 
 
 	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
 	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
 	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
 	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" },
 
 
 	{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
 	{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
 	{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
 	{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
+	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" },
 
 
 	{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
 	{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
 	{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
 	{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
+	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" },
 
 
 	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
 	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
 	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
 	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
@@ -2029,8 +2114,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
 	unsigned int val = 0;
 	unsigned int val = 0;
 
 
-	if (rx_mask || tx_mask)
+	if (rx_mask || tx_mask) {
 		val |= (1 << 14);
 		val |= (1 << 14);
+		snd_soc_update_bits(codec, RT5645_BASS_BACK,
+			RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
+	}
 
 
 	switch (slots) {
 	switch (slots) {
 	case 4:
 	case 4:
@@ -2071,8 +2159,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 			enum snd_soc_bias_level level)
 {
 {
 	switch (level) {
 	switch (level) {
-	case SND_SOC_BIAS_STANDBY:
-		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
 			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
 			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_BG | RT5645_PWR_VREF2,
 				RT5645_PWR_BG | RT5645_PWR_VREF2,
@@ -2087,15 +2175,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 		}
 		}
 		break;
 		break;
 
 
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+			RT5645_PWR_VREF1 | RT5645_PWR_MB |
+			RT5645_PWR_BG | RT5645_PWR_VREF2,
+			RT5645_PWR_VREF1 | RT5645_PWR_MB |
+			RT5645_PWR_BG | RT5645_PWR_VREF2);
+		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+			RT5645_PWR_FV1 | RT5645_PWR_FV2,
+			RT5645_PWR_FV1 | RT5645_PWR_FV2);
+		break;
+
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 		snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
 		snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
 		snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
 		snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
-		snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000);
-		snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000);
-		snd_soc_write(codec, RT5645_PWR_VOL, 0x0000);
-		snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000);
-		snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000);
-		snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000);
+		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+				RT5645_PWR_VREF1 | RT5645_PWR_MB |
+				RT5645_PWR_BG | RT5645_PWR_VREF2 |
+				RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0);
 		break;
 		break;
 
 
 	default:
 	default:
@@ -2106,13 +2203,16 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 	return 0;
 }
 }
 
 
-static int rt5645_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *jack)
+static int rt5645_jack_detect(struct snd_soc_codec *codec)
 {
 {
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 	int gpio_state, jack_type = 0;
 	int gpio_state, jack_type = 0;
 	unsigned int val;
 	unsigned int val;
 
 
+	if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
+		dev_err(codec->dev, "invalid gpio\n");
+		return -EINVAL;
+	}
 	gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
 	gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
 
 
 	dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
 	dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
@@ -2145,34 +2245,44 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec,
 
 
 		snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
 		snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
 		snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
 		snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
-		snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
+		if (rt5645->pdata.jd_mode == 0)
+			snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
 		snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
 		snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
 		snd_soc_dapm_sync(&codec->dapm);
 		snd_soc_dapm_sync(&codec->dapm);
 	}
 	}
 
 
-	snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET);
-
+	snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
+	snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
 	return 0;
 	return 0;
 }
 }
 
 
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *jack)
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
 {
 {
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
 
-	rt5645->jack = jack;
-
-	rt5645_jack_detect(codec, rt5645->jack);
+	rt5645->hp_jack = hp_jack;
+	rt5645->mic_jack = mic_jack;
+	rt5645_jack_detect(codec);
 
 
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
 EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
 
 
+static void rt5645_jack_detect_work(struct work_struct *work)
+{
+	struct rt5645_priv *rt5645 =
+		container_of(work, struct rt5645_priv, jack_detect_work.work);
+
+	rt5645_jack_detect(rt5645->codec);
+}
+
 static irqreturn_t rt5645_irq(int irq, void *data)
 static irqreturn_t rt5645_irq(int irq, void *data)
 {
 {
 	struct rt5645_priv *rt5645 = data;
 	struct rt5645_priv *rt5645 = data;
 
 
-	rt5645_jack_detect(rt5645->codec, rt5645->jack);
+	queue_delayed_work(system_power_efficient_wq,
+			   &rt5645->jack_detect_work, msecs_to_jiffies(250));
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
@@ -2187,6 +2297,13 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
 	snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
 
 
+	/* for JD function */
+	if (rt5645->pdata.en_jd_func) {
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
+		snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+		snd_soc_dapm_sync(&codec->dapm);
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2420,6 +2537,51 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 
 
 	}
 	}
 
 
+	if (rt5645->pdata.en_jd_func) {
+		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+			RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
+			RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
+		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
+			RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
+		regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
+			RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
+			RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
+		regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+			RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
+	}
+
+	if (rt5645->pdata.jd_mode) {
+		regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				   RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
+		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+				   RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE);
+		regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER,
+				   RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE);
+		regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+				   RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+				   RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+		switch (rt5645->pdata.jd_mode) {
+		case 1:
+			regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+					   RT5645_JD1_MODE_MASK,
+					   RT5645_JD1_MODE_0);
+			break;
+		case 2:
+			regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+					   RT5645_JD1_MODE_MASK,
+					   RT5645_JD1_MODE_1);
+			break;
+		case 3:
+			regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+					   RT5645_JD1_MODE_MASK,
+					   RT5645_JD1_MODE_2);
+			break;
+		default:
+			break;
+		}
+	}
+
 	if (rt5645->i2c->irq) {
 	if (rt5645->i2c->irq) {
 		ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
 		ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
 			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
 			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
@@ -2438,6 +2600,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 			dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
 			dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
 	}
 	}
 
 
+	INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
+
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
 				      rt5645_dai, ARRAY_SIZE(rt5645_dai));
 				      rt5645_dai, ARRAY_SIZE(rt5645_dai));
 }
 }
@@ -2449,6 +2613,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
 	if (i2c->irq)
 	if (i2c->irq)
 		free_irq(i2c->irq, rt5645);
 		free_irq(i2c->irq, rt5645);
 
 
+	cancel_delayed_work_sync(&rt5645->jack_detect_work);
+
 	if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
 	if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
 		gpio_free(rt5645->pdata.hp_det_gpio);
 		gpio_free(rt5645->pdata.hp_det_gpio);
 
 

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

@@ -594,6 +594,7 @@
 #define RT5645_M_DAC1_HM_SFT			14
 #define RT5645_M_DAC1_HM_SFT			14
 #define RT5645_M_HPVOL_HM			(0x1 << 13)
 #define RT5645_M_HPVOL_HM			(0x1 << 13)
 #define RT5645_M_HPVOL_HM_SFT			13
 #define RT5645_M_HPVOL_HM_SFT			13
+#define RT5645_IRQ_PSV_MODE			(0x1 << 12)
 
 
 /* SPK Left Mixer Control (0x46) */
 /* SPK Left Mixer Control (0x46) */
 #define RT5645_G_RM_L_SM_L_MASK			(0x3 << 14)
 #define RT5645_G_RM_L_SM_L_MASK			(0x3 << 14)
@@ -1348,6 +1349,12 @@
 #define RT5645_PWR_CLK25M_SFT			4
 #define RT5645_PWR_CLK25M_SFT			4
 #define RT5645_PWR_CLK25M_PD			(0x0 << 4)
 #define RT5645_PWR_CLK25M_PD			(0x0 << 4)
 #define RT5645_PWR_CLK25M_PU			(0x1 << 4)
 #define RT5645_PWR_CLK25M_PU			(0x1 << 4)
+#define RT5645_IRQ_CLK_MCLK			(0x0 << 3)
+#define RT5645_IRQ_CLK_INT			(0x1 << 3)
+#define RT5645_JD1_MODE_MASK			(0x3 << 0)
+#define RT5645_JD1_MODE_0			(0x0 << 0)
+#define RT5645_JD1_MODE_1			(0x1 << 0)
+#define RT5645_JD1_MODE_2			(0x2 << 0)
 
 
 /* VAD Control 4 (0x9d) */
 /* VAD Control 4 (0x9d) */
 #define RT5645_VAD_SEL_MASK			(0x3 << 8)
 #define RT5645_VAD_SEL_MASK			(0x3 << 8)
@@ -1636,6 +1643,7 @@
 #define RT5645_OT_P_SFT				10
 #define RT5645_OT_P_SFT				10
 #define RT5645_OT_P_NOR				(0x0 << 10)
 #define RT5645_OT_P_NOR				(0x0 << 10)
 #define RT5645_OT_P_INV				(0x1 << 10)
 #define RT5645_OT_P_INV				(0x1 << 10)
+#define RT5645_IRQ_JD_1_1_EN			(0x1 << 9)
 
 
 /* IRQ Control 2 (0xbe) */
 /* IRQ Control 2 (0xbe) */
 #define RT5645_IRQ_MB1_OC_MASK			(0x1 << 15)
 #define RT5645_IRQ_MB1_OC_MASK			(0x1 << 15)
@@ -1853,6 +1861,7 @@
 #define RT5645_M_BB_HPF_R_SFT			6
 #define RT5645_M_BB_HPF_R_SFT			6
 #define RT5645_G_BB_BST_MASK			(0x3f)
 #define RT5645_G_BB_BST_MASK			(0x3f)
 #define RT5645_G_BB_BST_SFT			0
 #define RT5645_G_BB_BST_SFT			0
+#define RT5645_G_BB_BST_25DB			0x14
 
 
 /* MP3 Plus Control 1 (0xd0) */
 /* MP3 Plus Control 1 (0xd0) */
 #define RT5645_M_MP3_L_MASK			(0x1 << 15)
 #define RT5645_M_MP3_L_MASK			(0x1 << 15)
@@ -2116,6 +2125,10 @@ enum {
 #define RT5645_RXDP2_SEL_ADC			(0x1 << 3)
 #define RT5645_RXDP2_SEL_ADC			(0x1 << 3)
 #define RT5645_RXDP2_SEL_SFT			(3)
 #define RT5645_RXDP2_SEL_SFT			(3)
 
 
+/* General Control3 (0xfc) */
+#define RT5645_JD_PSV_MODE			(0x1 << 12)
+#define RT5645_IRQ_CLK_GATE_CTRL		(0x1 << 11)
+#define RT5645_MICINDET_MANU			(0x1 << 7)
 
 
 /* Vendor ID (0xfd) */
 /* Vendor ID (0xfd) */
 #define RT5645_VER_C				0x2
 #define RT5645_VER_C				0x2
@@ -2167,7 +2180,9 @@ struct rt5645_priv {
 	struct rt5645_platform_data pdata;
 	struct rt5645_platform_data pdata;
 	struct regmap *regmap;
 	struct regmap *regmap;
 	struct i2c_client *i2c;
 	struct i2c_client *i2c;
-	struct snd_soc_jack *jack;
+	struct snd_soc_jack *hp_jack;
+	struct snd_soc_jack *mic_jack;
+	struct delayed_work jack_detect_work;
 
 
 	int sysclk;
 	int sysclk;
 	int sysclk_src;
 	int sysclk_src;
@@ -2181,6 +2196,6 @@ struct rt5645_priv {
 };
 };
 
 
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
 int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *jack);
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
 
 
 #endif /* __RT5645_H__ */
 #endif /* __RT5645_H__ */

+ 115 - 21
sound/soc/codecs/rt5670.c

@@ -16,6 +16,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/acpi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -575,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 
 
 }
 }
 
 
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
+	if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384)
+		return 1;
+
+	return 0;
+}
+
 /* Digital Mixer */
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
 static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@ -1281,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
 			      9, 0, NULL, 0),
 			      9, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1,
 	SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1,
 			      8, 0, NULL, 0),
 			      8, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1,
+			      7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1,
+			      6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1,
+			      5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1,
+			      4, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1,
 	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1,
 			      3, 0, NULL, 0),
 			      3, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1,
 	SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1,
@@ -1595,29 +1616,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
 	/* PDM */
 	/* PDM */
 	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2,
 	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2,
 		RT5670_PWR_PDM1_BIT, 0, NULL, 0),
 		RT5670_PWR_PDM1_BIT, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
-		RT5670_PWR_PDM2_BIT, 0, NULL, 0),
 
 
 	SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL,
 	SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL,
 			 RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux),
 			 RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux),
 	SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL,
 	SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL,
 			 RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux),
 			 RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux),
-	SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
-			 RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
-	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
-			 RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
 
 
 	/* Output Lines */
 	/* Output Lines */
 	SND_SOC_DAPM_OUTPUT("HPOL"),
 	SND_SOC_DAPM_OUTPUT("HPOL"),
 	SND_SOC_DAPM_OUTPUT("HPOR"),
 	SND_SOC_DAPM_OUTPUT("HPOR"),
 	SND_SOC_DAPM_OUTPUT("LOUTL"),
 	SND_SOC_DAPM_OUTPUT("LOUTL"),
 	SND_SOC_DAPM_OUTPUT("LOUTR"),
 	SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
+		RT5670_PWR_PDM2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
+			 RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
+	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
+			 RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
 	SND_SOC_DAPM_OUTPUT("PDM1L"),
 	SND_SOC_DAPM_OUTPUT("PDM1L"),
 	SND_SOC_DAPM_OUTPUT("PDM1R"),
 	SND_SOC_DAPM_OUTPUT("PDM1R"),
 	SND_SOC_DAPM_OUTPUT("PDM2L"),
 	SND_SOC_DAPM_OUTPUT("PDM2L"),
 	SND_SOC_DAPM_OUTPUT("PDM2R"),
 	SND_SOC_DAPM_OUTPUT("PDM2R"),
 };
 };
 
 
+static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPOLP"),
+	SND_SOC_DAPM_OUTPUT("SPOLN"),
+	SND_SOC_DAPM_OUTPUT("SPORP"),
+	SND_SOC_DAPM_OUTPUT("SPORN"),
+};
+
 static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
 static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
 	{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
 	{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
 	{ "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc },
 	{ "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1626,9 +1658,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
 	{ "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc },
 	{ "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc },
 	{ "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc },
 	{ "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc },
 	{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
 	{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
+	{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
+	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
+	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
 
 
-	{ "I2S1", NULL, "I2S1 ASRC" },
-	{ "I2S2", NULL, "I2S2 ASRC" },
+	{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+	{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
 
 
 	{ "DMIC1", NULL, "DMIC L1" },
 	{ "DMIC1", NULL, "DMIC L1" },
 	{ "DMIC1", NULL, "DMIC R1" },
 	{ "DMIC1", NULL, "DMIC R1" },
@@ -1970,12 +2006,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
 	{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
 	{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
 	{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
 	{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
 	{ "PDM1 R Mux", NULL, "PDM1 Power" },
 	{ "PDM1 R Mux", NULL, "PDM1 Power" },
-	{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
-	{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
-	{ "PDM2 L Mux", NULL, "PDM2 Power" },
-	{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
-	{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
-	{ "PDM2 R Mux", NULL, "PDM2 Power" },
 
 
 	{ "HP Amp", NULL, "HPO MIX" },
 	{ "HP Amp", NULL, "HPO MIX" },
 	{ "HP Amp", NULL, "Mic Det Power" },
 	{ "HP Amp", NULL, "Mic Det Power" },
@@ -1993,13 +2023,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
 	{ "LOUTR", NULL, "LOUT R Playback" },
 	{ "LOUTR", NULL, "LOUT R Playback" },
 	{ "LOUTL", NULL, "Improve HP Amp Drv" },
 	{ "LOUTL", NULL, "Improve HP Amp Drv" },
 	{ "LOUTR", NULL, "Improve HP Amp Drv" },
 	{ "LOUTR", NULL, "Improve HP Amp Drv" },
+};
 
 
+static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = {
+	{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+	{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
+	{ "PDM2 L Mux", NULL, "PDM2 Power" },
+	{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+	{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
+	{ "PDM2 R Mux", NULL, "PDM2 Power" },
 	{ "PDM1L", NULL, "PDM1 L Mux" },
 	{ "PDM1L", NULL, "PDM1 L Mux" },
 	{ "PDM1R", NULL, "PDM1 R Mux" },
 	{ "PDM1R", NULL, "PDM1 R Mux" },
 	{ "PDM2L", NULL, "PDM2 L Mux" },
 	{ "PDM2L", NULL, "PDM2 L Mux" },
 	{ "PDM2R", NULL, "PDM2 R Mux" },
 	{ "PDM2R", NULL, "PDM2 R Mux" },
 };
 };
 
 
+static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = {
+	{ "SPO Amp", NULL, "PDM1 L Mux" },
+	{ "SPO Amp", NULL, "PDM1 R Mux" },
+	{ "SPOLP", NULL, "SPO Amp" },
+	{ "SPOLN", NULL, "SPO Amp" },
+	{ "SPORP", NULL, "SPO Amp" },
+	{ "SPORN", NULL, "SPO Amp" },
+};
+
 static int rt5670_hw_params(struct snd_pcm_substream *substream,
 static int rt5670_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
 {
@@ -2287,6 +2334,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 			enum snd_soc_bias_level level)
 			enum snd_soc_bias_level level)
 {
 {
+	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
 		if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
@@ -2308,16 +2357,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 		}
 		}
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000);
-		snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001);
-		snd_soc_write(codec, RT5670_PWR_VOL, 0x0000);
-		snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001);
-		snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800);
-		snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004);
-		snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
+		snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
+				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
 		snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
 		snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
 				RT5670_LDO_SEL_MASK, 0x1);
 				RT5670_LDO_SEL_MASK, 0x1);
 		break;
 		break;
+	case SND_SOC_BIAS_OFF:
+		if (rt5670->pdata.jd_mode)
+			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_MB |
+				RT5670_PWR_BG | RT5670_PWR_VREF2 |
+				RT5670_PWR_FV1 | RT5670_PWR_FV2,
+				RT5670_PWR_MB | RT5670_PWR_BG);
+		else
+			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_MB |
+				RT5670_PWR_BG | RT5670_PWR_VREF2 |
+				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
+
+		snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
+		break;
 
 
 	default:
 	default:
 		break;
 		break;
@@ -2331,6 +2391,29 @@ static int rt5670_probe(struct snd_soc_codec *codec)
 {
 {
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
 
+	switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
+	case RT5670_ID_5670:
+	case RT5670_ID_5671:
+		snd_soc_dapm_new_controls(&codec->dapm,
+			rt5670_specific_dapm_widgets,
+			ARRAY_SIZE(rt5670_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5670_specific_dapm_routes,
+			ARRAY_SIZE(rt5670_specific_dapm_routes));
+		break;
+	case RT5670_ID_5672:
+		snd_soc_dapm_new_controls(&codec->dapm,
+			rt5672_specific_dapm_widgets,
+			ARRAY_SIZE(rt5672_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5672_specific_dapm_routes,
+			ARRAY_SIZE(rt5672_specific_dapm_routes));
+		break;
+	default:
+		dev_err(codec->dev,
+			"The driver is for RT5670 RT5671 or RT5672 only\n");
+		return -ENODEV;
+	}
 	rt5670->codec = codec;
 	rt5670->codec = codec;
 
 
 	return 0;
 	return 0;
@@ -2452,10 +2535,20 @@ static const struct regmap_config rt5670_regmap = {
 
 
 static const struct i2c_device_id rt5670_i2c_id[] = {
 static const struct i2c_device_id rt5670_i2c_id[] = {
 	{ "rt5670", 0 },
 	{ "rt5670", 0 },
+	{ "rt5671", 0 },
+	{ "rt5672", 0 },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
 MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
 
 
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt5670_acpi_match[] = {
+	{ "10EC5670", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
+#endif
+
 static int rt5670_i2c_probe(struct i2c_client *i2c,
 static int rt5670_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 		    const struct i2c_device_id *id)
 {
 {
@@ -2644,6 +2737,7 @@ static struct i2c_driver rt5670_i2c_driver = {
 	.driver = {
 	.driver = {
 		.name = "rt5670",
 		.name = "rt5670",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
+		.acpi_match_table = ACPI_PTR(rt5670_acpi_match),
 	},
 	},
 	.probe = rt5670_i2c_probe,
 	.probe = rt5670_i2c_probe,
 	.remove   = rt5670_i2c_remove,
 	.remove   = rt5670_i2c_remove,

+ 6 - 0
sound/soc/codecs/rt5670.h

@@ -228,6 +228,12 @@
 #define RT5670_R_VOL_MASK			(0x3f)
 #define RT5670_R_VOL_MASK			(0x3f)
 #define RT5670_R_VOL_SFT			0
 #define RT5670_R_VOL_SFT			0
 
 
+/* SW Reset & Device ID (0x00) */
+#define RT5670_ID_MASK				(0x3 << 1)
+#define RT5670_ID_5670				(0x0 << 1)
+#define RT5670_ID_5672				(0x1 << 1)
+#define RT5670_ID_5671				(0x2 << 1)
+
 /* Combo Jack Control 1 (0x0a) */
 /* Combo Jack Control 1 (0x0a) */
 #define RT5670_CBJ_BST1_MASK			(0xf << 12)
 #define RT5670_CBJ_BST1_MASK			(0xf << 12)
 #define RT5670_CBJ_BST1_SFT			(12)
 #define RT5670_CBJ_BST1_SFT			(12)

+ 130 - 0
sound/soc/codecs/rt5677-spi.c

@@ -0,0 +1,130 @@
+/*
+ * rt5677-spi.c  --  RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_qos.h>
+#include <linux/sysfs.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+
+#include "rt5677-spi.h"
+
+static struct spi_device *g_spi;
+
+/**
+ * rt5677_spi_write - Write data to SPI.
+ * @txbuf: Data Buffer for writing.
+ * @len: Data length.
+ *
+ *
+ * Returns true for success.
+ */
+int rt5677_spi_write(u8 *txbuf, size_t len)
+{
+	int status;
+
+	status = spi_write(g_spi, txbuf, len);
+
+	if (status)
+		dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_write);
+
+/**
+ * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address.
+ * @addr: Start address.
+ * @txbuf: Data Buffer for writng.
+ * @len: Data length, it must be a multiple of 8.
+ *
+ *
+ * Returns true for success.
+ */
+int rt5677_spi_burst_write(u32 addr, const struct firmware *fw)
+{
+	u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE;
+	u8 *write_buf;
+	unsigned int i, end, offset = 0;
+
+	write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL);
+
+	if (write_buf == NULL)
+		return -ENOMEM;
+
+	while (offset < fw->size) {
+		if (offset + RT5677_SPI_BUF_LEN <= fw->size)
+			end = RT5677_SPI_BUF_LEN;
+		else
+			end = fw->size % RT5677_SPI_BUF_LEN;
+
+		write_buf[0] = spi_cmd;
+		write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
+		write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
+		write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
+		write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+		for (i = 0; i < end; i += 8) {
+			write_buf[i + 12] = fw->data[offset + i + 0];
+			write_buf[i + 11] = fw->data[offset + i + 1];
+			write_buf[i + 10] = fw->data[offset + i + 2];
+			write_buf[i +  9] = fw->data[offset + i + 3];
+			write_buf[i +  8] = fw->data[offset + i + 4];
+			write_buf[i +  7] = fw->data[offset + i + 5];
+			write_buf[i +  6] = fw->data[offset + i + 6];
+			write_buf[i +  5] = fw->data[offset + i + 7];
+		}
+
+		write_buf[end + 5] = spi_cmd;
+
+		rt5677_spi_write(write_buf, end + 6);
+
+		offset += RT5677_SPI_BUF_LEN;
+	}
+
+	kfree(write_buf);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_burst_write);
+
+static int rt5677_spi_probe(struct spi_device *spi)
+{
+	g_spi = spi;
+	return 0;
+}
+
+static struct spi_driver rt5677_spi_driver = {
+	.driver = {
+		.name = "rt5677",
+		.owner = THIS_MODULE,
+	},
+	.probe = rt5677_spi_probe,
+};
+module_spi_driver(rt5677_spi_driver);
+
+MODULE_DESCRIPTION("ASoC RT5677 SPI driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");

+ 21 - 0
sound/soc/codecs/rt5677-spi.h

@@ -0,0 +1,21 @@
+/*
+ * rt5677-spi.h  --  RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5677_SPI_H__
+#define __RT5677_SPI_H__
+
+#define RT5677_SPI_BUF_LEN 240
+#define RT5677_SPI_CMD_BURST_WRITE 0x05
+
+int rt5677_spi_write(u8 *txbuf, size_t len);
+int rt5677_spi_burst_write(u32 addr, const struct firmware *fw);
+
+#endif /* __RT5677_SPI_H__ */

+ 1131 - 67
sound/soc/codecs/rt5677.c

@@ -20,6 +20,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/firmware.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -31,6 +32,7 @@
 
 
 #include "rl6231.h"
 #include "rl6231.h"
 #include "rt5677.h"
 #include "rt5677.h"
+#include "rt5677-spi.h"
 
 
 #define RT5677_DEVICE_ID 0x6327
 #define RT5677_DEVICE_ID 0x6327
 
 
@@ -53,12 +55,13 @@ static const struct regmap_range_cfg rt5677_ranges[] = {
 };
 };
 
 
 static const struct reg_default init_list[] = {
 static const struct reg_default init_list[] = {
+	{RT5677_ASRC_12,	0x0018},
 	{RT5677_PR_BASE + 0x3d,	0x364d},
 	{RT5677_PR_BASE + 0x3d,	0x364d},
-	{RT5677_PR_BASE + 0x17, 0x4fc0},
-	{RT5677_PR_BASE + 0x13, 0x0312},
-	{RT5677_PR_BASE + 0x1e, 0x0000},
-	{RT5677_PR_BASE + 0x12, 0x0eaa},
-	{RT5677_PR_BASE + 0x14, 0x018a},
+	{RT5677_PR_BASE + 0x17,	0x4fc0},
+	{RT5677_PR_BASE + 0x13,	0x0312},
+	{RT5677_PR_BASE + 0x1e,	0x0000},
+	{RT5677_PR_BASE + 0x12,	0x0eaa},
+	{RT5677_PR_BASE + 0x14,	0x018a},
 };
 };
 #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list)
 #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list)
 
 
@@ -171,7 +174,7 @@ static const struct reg_default rt5677_reg[] = {
 	{RT5677_ASRC_9			, 0x0000},
 	{RT5677_ASRC_9			, 0x0000},
 	{RT5677_ASRC_10			, 0x0000},
 	{RT5677_ASRC_10			, 0x0000},
 	{RT5677_ASRC_11			, 0x0000},
 	{RT5677_ASRC_11			, 0x0000},
-	{RT5677_ASRC_12			, 0x0008},
+	{RT5677_ASRC_12			, 0x0018},
 	{RT5677_ASRC_13			, 0x0000},
 	{RT5677_ASRC_13			, 0x0000},
 	{RT5677_ASRC_14			, 0x0000},
 	{RT5677_ASRC_14			, 0x0000},
 	{RT5677_ASRC_15			, 0x0000},
 	{RT5677_ASRC_15			, 0x0000},
@@ -537,10 +540,232 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg)
 	}
 	}
 }
 }
 
 
+/**
+ * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode.
+ * @rt5677: Private Data.
+ * @addr: Address index.
+ * @value: Address data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
+		unsigned int addr, unsigned int value, unsigned int opcode)
+{
+	struct snd_soc_codec *codec = rt5677->codec;
+	int ret;
+
+	mutex_lock(&rt5677->dsp_cmd_lock);
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
+		addr >> 16);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
+		addr & 0xffff);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
+		value >> 16);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set data msb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
+		value & 0xffff);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
+		opcode);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
+		goto err;
+	}
+
+err:
+	mutex_unlock(&rt5677->dsp_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode.
+ * rt5677: Private Data.
+ * @addr: Address index.
+ * @value: Address data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_read_addr(
+	struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value)
+{
+	struct snd_soc_codec *codec = rt5677->codec;
+	int ret;
+	unsigned int msb, lsb;
+
+	mutex_lock(&rt5677->dsp_cmd_lock);
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
+		addr >> 16);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
+		addr & 0xffff);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
+		0x0002);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
+		goto err;
+	}
+
+	regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb);
+	regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb);
+	*value = (msb << 16) | lsb;
+
+err:
+	mutex_unlock(&rt5677->dsp_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * rt5677_dsp_mode_i2c_write - Write register on DSP mode.
+ * rt5677: Private Data.
+ * @reg: Register index.
+ * @value: Register data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677,
+		unsigned int reg, unsigned int value)
+{
+	return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2,
+		value, 0x0001);
+}
+
+/**
+ * rt5677_dsp_mode_i2c_read - Read register on DSP mode.
+ * @codec: SoC audio codec device.
+ * @reg: Register index.
+ * @value: Register data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_read(
+	struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value)
+{
+	int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2,
+		value);
+
+	*value &= 0xffff;
+
+	return ret;
+}
+
+static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on)
+{
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+	if (on) {
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2);
+		rt5677->is_dsp_mode = true;
+	} else {
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0);
+		rt5677->is_dsp_mode = false;
+	}
+}
+
+static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
+{
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	static bool activity;
+	int ret;
+
+	if (on && !activity) {
+		activity = true;
+
+		regcache_cache_only(rt5677->regmap, false);
+		regcache_cache_bypass(rt5677->regmap, true);
+
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00);
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+			RT5677_LDO1_SEL_MASK, 0x0);
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_LDO1, RT5677_PWR_LDO1);
+		regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+			RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
+		regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+			RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK,
+			RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS);
+		regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
+		regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
+		rt5677_set_dsp_mode(codec, true);
+
+		ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1,
+			codec->dev);
+		if (ret == 0) {
+			rt5677_spi_burst_write(0x50000000, rt5677->fw1);
+			release_firmware(rt5677->fw1);
+		}
+
+		ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2,
+			codec->dev);
+		if (ret == 0) {
+			rt5677_spi_burst_write(0x60000000, rt5677->fw2);
+			release_firmware(rt5677->fw2);
+		}
+
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0);
+
+		regcache_cache_bypass(rt5677->regmap, false);
+		regcache_cache_only(rt5677->regmap, true);
+	} else if (!on && activity) {
+		activity = false;
+
+		regcache_cache_only(rt5677->regmap, false);
+		regcache_cache_bypass(rt5677->regmap, true);
+
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1);
+		rt5677_set_dsp_mode(codec, false);
+		regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001);
+
+		regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+
+		regcache_cache_bypass(rt5677->regmap, false);
+		regcache_mark_dirty(rt5677->regmap);
+		regcache_sync(rt5677->regmap);
+	}
+
+	return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
 static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
 
 
@@ -556,6 +781,31 @@ static unsigned int bst_tlv[] = {
 	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
 	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
 };
 };
 
 
+static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = rt5677->dsp_vad_en;
+
+	return 0;
+}
+
+static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+	rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
+
+	if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+		rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
+
+	return 0;
+}
+
 static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 	/* OUTPUT Control */
 	/* OUTPUT Control */
 	SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1,
 	SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1,
@@ -567,13 +817,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 
 
 	/* DAC Digital Volume */
 	/* DAC Digital Volume */
 	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL,
 	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL,
-		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
 	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL,
 	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL,
-		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
 	SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL,
 	SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL,
-		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
 	SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL,
 	SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL,
-		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
 
 
 	/* IN1/IN2 Control */
 	/* IN1/IN2 Control */
 	SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv),
 	SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv),
@@ -592,19 +842,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
 		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
 
 
 	SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL,
-		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
 		adc_vol_tlv),
 		adc_vol_tlv),
 	SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL,
-		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
 		adc_vol_tlv),
 		adc_vol_tlv),
 	SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL,
-		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
 		adc_vol_tlv),
 		adc_vol_tlv),
 	SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL,
-		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
 		adc_vol_tlv),
 		adc_vol_tlv),
 	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL,
 	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL,
-		RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0,
+		RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0,
 		adc_vol_tlv),
 		adc_vol_tlv),
 
 
 	/* Sidetone Control */
 	/* Sidetone Control */
@@ -627,6 +877,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 	SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2,
 	SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2,
 		RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0,
 		RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0,
 		adc_bst_tlv),
 		adc_bst_tlv),
+
+	SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0,
+		rt5677_dsp_vad_get, rt5677_dsp_vad_put),
 };
 };
 
 
 /**
 /**
@@ -1086,7 +1339,7 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux =
 static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux =
 	SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum);
 	SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum);
 
 
-/* Stereo ADC Source 2 */ /* MX-27 MX26  MX25 [11:10] */
+/* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */
 static const char * const rt5677_stereo_adc2_src[] = {
 static const char * const rt5677_stereo_adc2_src[] = {
 	"DD MIX1", "DMIC", "Stereo DAC MIX"
 	"DD MIX1", "DMIC", "Stereo DAC MIX"
 };
 };
@@ -1171,7 +1424,7 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux =
 static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux =
 	SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum);
 	SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum);
 
 
-/* Stereo1 ADC Source 1 */ /* MX-27 MX26  MX25 [13:12] */
+/* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */
 static const char * const rt5677_stereo_adc1_src[] = {
 static const char * const rt5677_stereo_adc1_src[] = {
 	"DD MIX1", "ADC1/2", "Stereo DAC MIX"
 	"DD MIX1", "ADC1/2", "Stereo DAC MIX"
 };
 };
@@ -1443,7 +1696,7 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5677_pdm2_r_mux =
 static const struct snd_kcontrol_new rt5677_pdm2_r_mux =
 	SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum);
 	SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum);
 
 
-/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/
+/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */
 static const char * const rt5677_if12_adc1_src[] = {
 static const char * const rt5677_if12_adc1_src[] = {
 	"STO1 ADC MIX", "OB01", "VAD ADC"
 	"STO1 ADC MIX", "OB01", "VAD ADC"
 };
 };
@@ -1521,7 +1774,7 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5677_slb_adc3_mux =
 static const struct snd_kcontrol_new rt5677_slb_adc3_mux =
 	SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum);
 	SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum);
 
 
-/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10]  MX-08 [7:6] */
+/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */
 static const char * const rt5677_if12_adc4_src[] = {
 static const char * const rt5677_if12_adc4_src[] = {
 	"STO4 ADC MIX", "OB67", "OB01"
 	"STO4 ADC MIX", "OB67", "OB01"
 };
 };
@@ -1547,7 +1800,7 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5677_slb_adc4_mux =
 static const struct snd_kcontrol_new rt5677_slb_adc4_mux =
 	SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum);
 	SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum);
 
 
-/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/
+/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */
 static const char * const rt5677_if34_adc_src[] = {
 static const char * const rt5677_if34_adc_src[] = {
 	"STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX",
 	"STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX",
 	"MONO ADC MIX", "OB01", "OB23", "VAD ADC"
 	"MONO ADC MIX", "OB01", "OB23", "VAD ADC"
@@ -1567,6 +1820,213 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5677_if4_adc_mux =
 static const struct snd_kcontrol_new rt5677_if4_adc_mux =
 	SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum);
 	SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum);
 
 
+/* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */
+static const char * const rt5677_if12_adc_swap_src[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum);
+
+/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */
+static const char * const rt5677_if1_adc_tdm_swap_src[] = {
+	"1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
+	"3/1/2/4", "3/4/1/2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2,
+	RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum);
+
+/* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */
+static const char * const rt5677_if2_adc_tdm_swap_src[] = {
+	"1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
+	"2/3/1/4", "3/4/1/2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2,
+	RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum);
+
+/* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0]
+					MX-3F[14:12][10:8][6:4][2:0]
+					MX-43[14:12][10:8][6:4][2:0]
+					MX-44[14:12][10:8][6:4][2:0] */
+static const char * const rt5677_if12_dac_tdm_sel_src[] = {
+	"Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum);
+
 static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	struct snd_kcontrol *kcontrol, int event)
 {
 {
@@ -1678,6 +2138,77 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 	return 0;
 	return 0;
 }
 }
 
 
+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 rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	unsigned int value;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value);
+		if (value & RT5677_IF1_ADC_CTRL_MASK)
+			regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1,
+				RT5677_IF1_ADC_MODE_MASK,
+				RT5677_IF1_ADC_MODE_TDM);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+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 rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	unsigned int value;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value);
+		if (value & RT5677_IF2_ADC_CTRL_MASK)
+			regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1,
+				RT5677_IF2_ADC_MODE_MASK,
+				RT5677_IF2_ADC_MODE_TDM);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+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 rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
+			!rt5677->is_vref_slow) {
+			mdelay(20);
+			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+				RT5677_PWR_FV1 | RT5677_PWR_FV2,
+				RT5677_PWR_FV1 | RT5677_PWR_FV2);
+			rt5677->is_vref_slow = true;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
 	SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
 		0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU),
 		0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU),
@@ -1837,10 +2368,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 	SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 
 	/* DSP */
 	/* DSP */
 	SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0,
@@ -1963,6 +2492,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 			&rt5677_if1_adc3_mux),
 			&rt5677_if1_adc3_mux),
 	SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_if1_adc4_mux),
 			&rt5677_if1_adc4_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc1_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc2_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc3_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc4_swap_mux),
+	SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event,
+			SND_SOC_DAPM_PRE_PMU),
 	SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_if2_adc1_mux),
 			&rt5677_if2_adc1_mux),
 	SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0,
@@ -1971,6 +2511,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 			&rt5677_if2_adc3_mux),
 			&rt5677_if2_adc3_mux),
 	SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_if2_adc4_mux),
 			&rt5677_if2_adc4_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc1_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc2_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc3_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc4_swap_mux),
+	SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event,
+			SND_SOC_DAPM_PRE_PMU),
 	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_if3_adc_mux),
 			&rt5677_if3_adc_mux),
 	SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0,
@@ -1984,6 +2535,40 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0,
 			&rt5677_slb_adc4_mux),
 			&rt5677_slb_adc4_mux),
 
 
+	SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac3_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac4_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac5_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac6_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac7_tdm_sel_mux),
+
+	SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac3_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac4_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac5_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac6_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac7_tdm_sel_mux),
+
 	/* Audio Interface */
 	/* Audio Interface */
 	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
@@ -2022,7 +2607,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 		rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)),
 		rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)),
 
 
 	/* Output Side */
 	/* Output Side */
-	/* DAC mixer before sound effect  */
+	/* DAC mixer before sound effect */
 	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
 		rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)),
 		rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)),
 	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
 	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
@@ -2109,13 +2694,20 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT,
 	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT,
 		1, &rt5677_pdm2_r_mux),
 		1, &rt5677_pdm2_r_mux),
 
 
-	SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
+	SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
 		0, NULL, 0),
 		0, NULL, 0),
-	SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
+	SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
 		0, NULL, 0),
 		0, NULL, 0),
-	SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
+	SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
 		0, NULL, 0),
 		0, NULL, 0),
 
 
+	SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0,
+		rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0,
+		rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0,
+		rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+
 	/* Output Lines */
 	/* Output Lines */
 	SND_SOC_DAPM_OUTPUT("LOUT1"),
 	SND_SOC_DAPM_OUTPUT("LOUT1"),
 	SND_SOC_DAPM_OUTPUT("LOUT2"),
 	SND_SOC_DAPM_OUTPUT("LOUT2"),
@@ -2124,6 +2716,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("PDM1R"),
 	SND_SOC_DAPM_OUTPUT("PDM1R"),
 	SND_SOC_DAPM_OUTPUT("PDM2L"),
 	SND_SOC_DAPM_OUTPUT("PDM2L"),
 	SND_SOC_DAPM_OUTPUT("PDM2R"),
 	SND_SOC_DAPM_OUTPUT("PDM2R"),
+
+	SND_SOC_DAPM_POST("vref", rt5677_vref_event),
 };
 };
 
 
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
@@ -2354,11 +2948,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "IF1 ADC4 Mux", "OB67", "OB67" },
 	{ "IF1 ADC4 Mux", "OB67", "OB67" },
 	{ "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
 	{ "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
 
 
+	{ "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" },
+	{ "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" },
+	{ "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" },
+	{ "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" },
+
+	{ "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" },
+	{ "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" },
+	{ "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" },
+	{ "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" },
+
+	{ "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" },
+	{ "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" },
+	{ "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" },
+	{ "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" },
+
+	{ "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" },
+	{ "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" },
+	{ "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" },
+	{ "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" },
+
+	{ "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" },
+
+	{ "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" },
+
 	{ "AIF1TX", NULL, "I2S1" },
 	{ "AIF1TX", NULL, "I2S1" },
-	{ "AIF1TX", NULL, "IF1 ADC1 Mux" },
-	{ "AIF1TX", NULL, "IF1 ADC2 Mux" },
-	{ "AIF1TX", NULL, "IF1 ADC3 Mux" },
-	{ "AIF1TX", NULL, "IF1 ADC4 Mux" },
+	{ "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" },
 
 
 	{ "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
 	{ "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
 	{ "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" },
 	{ "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" },
@@ -2375,11 +3000,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "IF2 ADC4 Mux", "OB67", "OB67" },
 	{ "IF2 ADC4 Mux", "OB67", "OB67" },
 	{ "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
 	{ "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
 
 
+	{ "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" },
+	{ "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" },
+	{ "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" },
+	{ "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" },
+
+	{ "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" },
+	{ "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" },
+	{ "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" },
+	{ "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" },
+
+	{ "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" },
+	{ "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" },
+	{ "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" },
+	{ "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" },
+
+	{ "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" },
+	{ "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" },
+	{ "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" },
+	{ "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" },
+
+	{ "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" },
+	{ "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" },
+	{ "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" },
+	{ "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" },
+
+	{ "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" },
+
 	{ "AIF2TX", NULL, "I2S2" },
 	{ "AIF2TX", NULL, "I2S2" },
-	{ "AIF2TX", NULL, "IF2 ADC1 Mux" },
-	{ "AIF2TX", NULL, "IF2 ADC2 Mux" },
-	{ "AIF2TX", NULL, "IF2 ADC3 Mux" },
-	{ "AIF2TX", NULL, "IF2 ADC4 Mux" },
+	{ "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" },
 
 
 	{ "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
 	{ "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
 	{ "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
 	{ "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
@@ -2569,14 +3225,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "IF1 DAC6", NULL, "I2S1" },
 	{ "IF1 DAC6", NULL, "I2S1" },
 	{ "IF1 DAC7", NULL, "I2S1" },
 	{ "IF1 DAC7", NULL, "I2S1" },
 
 
-	{ "IF1 DAC01", NULL, "IF1 DAC0" },
-	{ "IF1 DAC01", NULL, "IF1 DAC1" },
-	{ "IF1 DAC23", NULL, "IF1 DAC2" },
-	{ "IF1 DAC23", NULL, "IF1 DAC3" },
-	{ "IF1 DAC45", NULL, "IF1 DAC4" },
-	{ "IF1 DAC45", NULL, "IF1 DAC5" },
-	{ "IF1 DAC67", NULL, "IF1 DAC6" },
-	{ "IF1 DAC67", NULL, "IF1 DAC7" },
+	{ "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC01", NULL, "IF1 DAC0 Mux" },
+	{ "IF1 DAC01", NULL, "IF1 DAC1 Mux" },
+	{ "IF1 DAC23", NULL, "IF1 DAC2 Mux" },
+	{ "IF1 DAC23", NULL, "IF1 DAC3 Mux" },
+	{ "IF1 DAC45", NULL, "IF1 DAC4 Mux" },
+	{ "IF1 DAC45", NULL, "IF1 DAC5 Mux" },
+	{ "IF1 DAC67", NULL, "IF1 DAC6 Mux" },
+	{ "IF1 DAC67", NULL, "IF1 DAC7 Mux" },
 
 
 	{ "IF2 DAC0", NULL, "AIF2RX" },
 	{ "IF2 DAC0", NULL, "AIF2RX" },
 	{ "IF2 DAC1", NULL, "AIF2RX" },
 	{ "IF2 DAC1", NULL, "AIF2RX" },
@@ -2595,14 +3323,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "IF2 DAC6", NULL, "I2S2" },
 	{ "IF2 DAC6", NULL, "I2S2" },
 	{ "IF2 DAC7", NULL, "I2S2" },
 	{ "IF2 DAC7", NULL, "I2S2" },
 
 
-	{ "IF2 DAC01", NULL, "IF2 DAC0" },
-	{ "IF2 DAC01", NULL, "IF2 DAC1" },
-	{ "IF2 DAC23", NULL, "IF2 DAC2" },
-	{ "IF2 DAC23", NULL, "IF2 DAC3" },
-	{ "IF2 DAC45", NULL, "IF2 DAC4" },
-	{ "IF2 DAC45", NULL, "IF2 DAC5" },
-	{ "IF2 DAC67", NULL, "IF2 DAC6" },
-	{ "IF2 DAC67", NULL, "IF2 DAC7" },
+	{ "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC01", NULL, "IF2 DAC0 Mux" },
+	{ "IF2 DAC01", NULL, "IF2 DAC1 Mux" },
+	{ "IF2 DAC23", NULL, "IF2 DAC2 Mux" },
+	{ "IF2 DAC23", NULL, "IF2 DAC3 Mux" },
+	{ "IF2 DAC45", NULL, "IF2 DAC4 Mux" },
+	{ "IF2 DAC45", NULL, "IF2 DAC5 Mux" },
+	{ "IF2 DAC67", NULL, "IF2 DAC6 Mux" },
+	{ "IF2 DAC67", NULL, "IF2 DAC7 Mux" },
 
 
 	{ "IF3 DAC", NULL, "AIF3RX" },
 	{ "IF3 DAC", NULL, "AIF3RX" },
 	{ "IF3 DAC", NULL, "I2S3" },
 	{ "IF3 DAC", NULL, "I2S3" },
@@ -2806,9 +3606,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "LOUT2 amp", NULL, "DAC 2" },
 	{ "LOUT2 amp", NULL, "DAC 2" },
 	{ "LOUT3 amp", NULL, "DAC 3" },
 	{ "LOUT3 amp", NULL, "DAC 3" },
 
 
-	{ "LOUT1", NULL, "LOUT1 amp" },
-	{ "LOUT2", NULL, "LOUT2 amp" },
-	{ "LOUT3", NULL, "LOUT3 amp" },
+	{ "LOUT1 vref", NULL, "LOUT1 amp" },
+	{ "LOUT2 vref", NULL, "LOUT2 amp" },
+	{ "LOUT3 vref", NULL, "LOUT3 amp" },
+
+	{ "LOUT1", NULL, "LOUT1 vref" },
+	{ "LOUT2", NULL, "LOUT2 vref" },
+	{ "LOUT3", NULL, "LOUT3 vref" },
 
 
 	{ "PDM1L", NULL, "PDM1 L Mux" },
 	{ "PDM1L", NULL, "PDM1 L Mux" },
 	{ "PDM1R", NULL, "PDM1 R Mux" },
 	{ "PDM1R", NULL, "PDM1 R Mux" },
@@ -2837,7 +3641,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream,
 	rt5677->lrck[dai->id] = params_rate(params);
 	rt5677->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]);
 	pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]);
 	if (pre_div < 0) {
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting\n");
+		dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n",
+			rt5677->sysclk, rt5677->lrck[dai->id]);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	frame_size = snd_soc_params_to_frame_size(params);
@@ -3181,6 +3986,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 
 
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
 		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+			rt5677_set_dsp_vad(codec, false);
+
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
 				RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
 				RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
 				0x0055);
 				0x0055);
@@ -3188,14 +3995,12 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 				RT5677_PR_BASE + RT5677_BIAS_CUR4,
 				RT5677_PR_BASE + RT5677_BIAS_CUR4,
 				0x0f00, 0x0f00);
 				0x0f00, 0x0f00);
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+				RT5677_PWR_FV1 | RT5677_PWR_FV2 |
 				RT5677_PWR_VREF1 | RT5677_PWR_MB |
 				RT5677_PWR_VREF1 | RT5677_PWR_MB |
 				RT5677_PWR_BG | RT5677_PWR_VREF2,
 				RT5677_PWR_BG | RT5677_PWR_VREF2,
 				RT5677_PWR_VREF1 | RT5677_PWR_MB |
 				RT5677_PWR_VREF1 | RT5677_PWR_MB |
 				RT5677_PWR_BG | RT5677_PWR_VREF2);
 				RT5677_PWR_BG | RT5677_PWR_VREF2);
-			mdelay(20);
-			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
-				RT5677_PWR_FV1 | RT5677_PWR_FV2,
-				RT5677_PWR_FV1 | RT5677_PWR_FV2);
+			rt5677->is_vref_slow = false;
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
 				RT5677_PWR_CORE, RT5677_PWR_CORE);
 				RT5677_PWR_CORE, RT5677_PWR_CORE);
 			regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
 			regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
@@ -3214,6 +4019,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 		regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000);
 		regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000);
 		regmap_update_bits(rt5677->regmap,
 		regmap_update_bits(rt5677->regmap,
 			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
 			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
+
+		if (rt5677->dsp_vad_en)
+			rt5677_set_dsp_vad(codec, true);
 		break;
 		break;
 
 
 	default:
 	default:
@@ -3309,6 +4117,78 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 	return 0;
 	return 0;
 }
 }
 
 
+/** Configures the gpio as
+ *   0 - floating
+ *   1 - pull down
+ *   2 - pull up
+ */
+static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
+		int value)
+{
+	int shift;
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO2:
+		shift = 2 * (1 - offset);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2,
+			0x3 << shift,
+			(value & 0x3) << shift);
+		break;
+
+	case RT5677_GPIO3 ... RT5677_GPIO6:
+		shift = 2 * (9 - offset);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3,
+			0x3 << shift,
+			(value & 0x3) << shift);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+	struct regmap_irq_chip_data *data = rt5677->irq_data;
+	int irq;
+
+	if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
+		if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+			(rt5677->pdata.jd1_gpio == 2 &&
+				offset == RT5677_GPIO2) ||
+			(rt5677->pdata.jd1_gpio == 3 &&
+				offset == RT5677_GPIO3)) {
+			irq = RT5677_IRQ_JD1;
+		} else {
+			return -ENXIO;
+		}
+	}
+
+	if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
+		if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+			(rt5677->pdata.jd2_gpio == 2 &&
+				offset == RT5677_GPIO5) ||
+			(rt5677->pdata.jd2_gpio == 3 &&
+				offset == RT5677_GPIO6)) {
+			irq = RT5677_IRQ_JD2;
+		} else if ((rt5677->pdata.jd3_gpio == 1 &&
+				offset == RT5677_GPIO4) ||
+			(rt5677->pdata.jd3_gpio == 2 &&
+				offset == RT5677_GPIO5) ||
+			(rt5677->pdata.jd3_gpio == 3 &&
+				offset == RT5677_GPIO6)) {
+			irq = RT5677_IRQ_JD3;
+		} else {
+			return -ENXIO;
+		}
+	}
+
+	return regmap_irq_get_virq(data, irq);
+}
+
 static struct gpio_chip rt5677_template_chip = {
 static struct gpio_chip rt5677_template_chip = {
 	.label			= "rt5677",
 	.label			= "rt5677",
 	.owner			= THIS_MODULE,
 	.owner			= THIS_MODULE,
@@ -3316,6 +4196,7 @@ static struct gpio_chip rt5677_template_chip = {
 	.set			= rt5677_gpio_set,
 	.set			= rt5677_gpio_set,
 	.direction_input	= rt5677_gpio_direction_in,
 	.direction_input	= rt5677_gpio_direction_in,
 	.get			= rt5677_gpio_get,
 	.get			= rt5677_gpio_get,
+	.to_irq			= rt5677_to_irq,
 	.can_sleep		= 1,
 	.can_sleep		= 1,
 };
 };
 
 
@@ -3341,6 +4222,11 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
 	gpiochip_remove(&rt5677->gpio_chip);
 	gpiochip_remove(&rt5677->gpio_chip);
 }
 }
 #else
 #else
+static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
+		int value)
+{
+}
+
 static void rt5677_init_gpio(struct i2c_client *i2c)
 static void rt5677_init_gpio(struct i2c_client *i2c)
 {
 {
 }
 }
@@ -3353,6 +4239,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
 static int rt5677_probe(struct snd_soc_codec *codec)
 static int rt5677_probe(struct snd_soc_codec *codec)
 {
 {
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	int i;
 
 
 	rt5677->codec = codec;
 	rt5677->codec = codec;
 
 
@@ -3371,6 +4258,37 @@ static int rt5677_probe(struct snd_soc_codec *codec)
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
 	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
 	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
 
 
+	for (i = 0; i < RT5677_GPIO_NUM; i++)
+		rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
+
+	if (rt5677->irq_data) {
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000,
+			0x8000);
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018,
+			0x0008);
+
+		if (rt5677->pdata.jd1_gpio)
+			regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+				RT5677_SEL_GPIO_JD1_MASK,
+				rt5677->pdata.jd1_gpio <<
+				RT5677_SEL_GPIO_JD1_SFT);
+
+		if (rt5677->pdata.jd2_gpio)
+			regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+				RT5677_SEL_GPIO_JD2_MASK,
+				rt5677->pdata.jd2_gpio <<
+				RT5677_SEL_GPIO_JD2_SFT);
+
+		if (rt5677->pdata.jd3_gpio)
+			regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+				RT5677_SEL_GPIO_JD3_MASK,
+				rt5677->pdata.jd3_gpio <<
+				RT5677_SEL_GPIO_JD3_SFT);
+	}
+
+	mutex_init(&rt5677->dsp_cmd_lock);
+	mutex_init(&rt5677->dsp_pri_lock);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3390,8 +4308,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 {
 {
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 
-	regcache_cache_only(rt5677->regmap, true);
-	regcache_mark_dirty(rt5677->regmap);
+	if (!rt5677->dsp_vad_en) {
+		regcache_cache_only(rt5677->regmap, true);
+		regcache_mark_dirty(rt5677->regmap);
+	}
+
 	if (gpio_is_valid(rt5677->pow_ldo2))
 	if (gpio_is_valid(rt5677->pow_ldo2))
 		gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 		gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
 
@@ -3406,8 +4327,11 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 		gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
 		gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
 		msleep(10);
 		msleep(10);
 	}
 	}
-	regcache_cache_only(rt5677->regmap, false);
-	regcache_sync(rt5677->regmap);
+
+	if (!rt5677->dsp_vad_en) {
+		regcache_cache_only(rt5677->regmap, false);
+		regcache_sync(rt5677->regmap);
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -3416,6 +4340,51 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 #define rt5677_resume NULL
 #define rt5677_resume NULL
 #endif
 #endif
 
 
+static int rt5677_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct i2c_client *client = context;
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
+
+	if (rt5677->is_dsp_mode) {
+		if (reg > 0xff) {
+			mutex_lock(&rt5677->dsp_pri_lock);
+			rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+				reg & 0xff);
+			rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
+			mutex_unlock(&rt5677->dsp_pri_lock);
+		} else {
+			rt5677_dsp_mode_i2c_read(rt5677, reg, val);
+		}
+	} else {
+		regmap_read(rt5677->regmap_physical, reg, val);
+	}
+
+	return 0;
+}
+
+static int rt5677_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct i2c_client *client = context;
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
+
+	if (rt5677->is_dsp_mode) {
+		if (reg > 0xff) {
+			mutex_lock(&rt5677->dsp_pri_lock);
+			rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+				reg & 0xff);
+			rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
+				val);
+			mutex_unlock(&rt5677->dsp_pri_lock);
+		} else {
+			rt5677_dsp_mode_i2c_write(rt5677, reg, val);
+		}
+	} else {
+		regmap_write(rt5677->regmap_physical, reg, val);
+	}
+
+	return 0;
+}
+
 #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000
 #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000
 #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
@@ -3541,6 +4510,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
 	.num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes),
 	.num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes),
 };
 };
 
 
+static const struct regmap_config rt5677_regmap_physical = {
+	.name = "physical",
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) *
+						RT5677_PR_SPACING),
+	.readable_reg = rt5677_readable_register,
+
+	.cache_type = REGCACHE_NONE,
+	.ranges = rt5677_ranges,
+	.num_ranges = ARRAY_SIZE(rt5677_ranges),
+};
+
 static const struct regmap_config rt5677_regmap = {
 static const struct regmap_config rt5677_regmap = {
 	.reg_bits = 8,
 	.reg_bits = 8,
 	.val_bits = 16,
 	.val_bits = 16,
@@ -3550,6 +4533,8 @@ static const struct regmap_config rt5677_regmap = {
 
 
 	.volatile_reg = rt5677_volatile_register,
 	.volatile_reg = rt5677_volatile_register,
 	.readable_reg = rt5677_readable_register,
 	.readable_reg = rt5677_readable_register,
+	.reg_read = rt5677_read,
+	.reg_write = rt5677_write,
 
 
 	.cache_type = REGCACHE_RBTREE,
 	.cache_type = REGCACHE_RBTREE,
 	.reg_defaults = rt5677_reg,
 	.reg_defaults = rt5677_reg,
@@ -3590,9 +4575,77 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
 			(rt5677->pow_ldo2 != -ENOENT))
 			(rt5677->pow_ldo2 != -ENOENT))
 		return rt5677->pow_ldo2;
 		return rt5677->pow_ldo2;
 
 
+	of_property_read_u8_array(np, "realtek,gpio-config",
+		rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
+
+	of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio);
+	of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio);
+	of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio);
+
+	return 0;
+}
+
+static struct regmap_irq rt5677_irqs[] = {
+	[RT5677_IRQ_JD1] = {
+		.reg_offset = 0,
+		.mask = RT5677_EN_IRQ_GPIO_JD1,
+	},
+	[RT5677_IRQ_JD2] = {
+		.reg_offset = 0,
+		.mask = RT5677_EN_IRQ_GPIO_JD2,
+	},
+	[RT5677_IRQ_JD3] = {
+		.reg_offset = 0,
+		.mask = RT5677_EN_IRQ_GPIO_JD3,
+	},
+};
+
+static struct regmap_irq_chip rt5677_irq_chip = {
+	.name = "rt5677",
+	.irqs = rt5677_irqs,
+	.num_irqs = ARRAY_SIZE(rt5677_irqs),
+
+	.num_regs = 1,
+	.status_base = RT5677_IRQ_CTRL1,
+	.mask_base = RT5677_IRQ_CTRL1,
+	.mask_invert = 1,
+};
+
+static int rt5677_init_irq(struct i2c_client *i2c)
+{
+	int ret;
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+	if (!rt5677->pdata.jd1_gpio &&
+		!rt5677->pdata.jd2_gpio &&
+		!rt5677->pdata.jd3_gpio)
+		return 0;
+
+	if (!i2c->irq) {
+		dev_err(&i2c->dev, "No interrupt specified\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
+		&rt5677_irq_chip, &rt5677->irq_data);
+
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
+static void rt5677_free_irq(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+	if (rt5677->irq_data)
+		regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
+}
+
 static int rt5677_i2c_probe(struct i2c_client *i2c,
 static int rt5677_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 		    const struct i2c_device_id *id)
 {
 {
@@ -3638,7 +4691,16 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 		msleep(10);
 		msleep(10);
 	}
 	}
 
 
-	rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap);
+	rt5677->regmap_physical = devm_regmap_init_i2c(i2c,
+					&rt5677_regmap_physical);
+	if (IS_ERR(rt5677->regmap_physical)) {
+		ret = PTR_ERR(rt5677->regmap_physical);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap);
 	if (IS_ERR(rt5677->regmap)) {
 	if (IS_ERR(rt5677->regmap)) {
 		ret = PTR_ERR(rt5677->regmap);
 		ret = PTR_ERR(rt5677->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -3690,6 +4752,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 	}
 	}
 
 
 	rt5677_init_gpio(i2c);
 	rt5677_init_gpio(i2c);
+	rt5677_init_irq(i2c);
 
 
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
 				      rt5677_dai, ARRAY_SIZE(rt5677_dai));
 				      rt5677_dai, ARRAY_SIZE(rt5677_dai));
@@ -3698,6 +4761,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 static int rt5677_i2c_remove(struct i2c_client *i2c)
 static int rt5677_i2c_remove(struct i2c_client *i2c)
 {
 {
 	snd_soc_unregister_codec(&i2c->dev);
 	snd_soc_unregister_codec(&i2c->dev);
+	rt5677_free_irq(i2c);
 	rt5677_free_gpio(i2c);
 	rt5677_free_gpio(i2c);
 
 
 	return 0;
 	return 0;

+ 146 - 16
sound/soc/codecs/rt5677.h

@@ -13,6 +13,7 @@
 #define __RT5677_H__
 #define __RT5677_H__
 
 
 #include <sound/rt5677.h>
 #include <sound/rt5677.h>
+#include <linux/gpio/driver.h>
 
 
 /* Info */
 /* Info */
 #define RT5677_RESET				0x00
 #define RT5677_RESET				0x00
@@ -305,10 +306,10 @@
 #define RT5677_R_MUTE_SFT			7
 #define RT5677_R_MUTE_SFT			7
 #define RT5677_VOL_R_MUTE			(0x1 << 6)
 #define RT5677_VOL_R_MUTE			(0x1 << 6)
 #define RT5677_VOL_R_SFT			6
 #define RT5677_VOL_R_SFT			6
-#define RT5677_L_VOL_MASK			(0x3f << 8)
-#define RT5677_L_VOL_SFT			8
-#define RT5677_R_VOL_MASK			(0x3f)
-#define RT5677_R_VOL_SFT			0
+#define RT5677_L_VOL_MASK			(0x7f << 9)
+#define RT5677_L_VOL_SFT			9
+#define RT5677_R_VOL_MASK			(0x7f << 1)
+#define RT5677_R_VOL_SFT			1
 
 
 /* LOUT1 Control (0x01) */
 /* LOUT1 Control (0x01) */
 #define RT5677_LOUT1_L_MUTE			(0x1 << 15)
 #define RT5677_LOUT1_L_MUTE			(0x1 << 15)
@@ -446,16 +447,16 @@
 #define RT5677_SEL_DAC2_R_SRC_SFT		0
 #define RT5677_SEL_DAC2_R_SRC_SFT		0
 
 
 /* Stereo1 ADC Digital Volume Control (0x1c) */
 /* Stereo1 ADC Digital Volume Control (0x1c) */
-#define RT5677_STO1_ADC_L_VOL_MASK		(0x7f << 8)
-#define RT5677_STO1_ADC_L_VOL_SFT		8
-#define RT5677_STO1_ADC_R_VOL_MASK		(0x7f)
-#define RT5677_STO1_ADC_R_VOL_SFT		0
+#define RT5677_STO1_ADC_L_VOL_MASK		(0x3f << 9)
+#define RT5677_STO1_ADC_L_VOL_SFT		9
+#define RT5677_STO1_ADC_R_VOL_MASK		(0x3f << 1)
+#define RT5677_STO1_ADC_R_VOL_SFT		1
 
 
 /* Mono ADC Digital Volume Control (0x1d) */
 /* Mono ADC Digital Volume Control (0x1d) */
-#define RT5677_MONO_ADC_L_VOL_MASK		(0x7f << 8)
-#define RT5677_MONO_ADC_L_VOL_SFT		8
-#define RT5677_MONO_ADC_R_VOL_MASK		(0x7f)
-#define RT5677_MONO_ADC_R_VOL_SFT		0
+#define RT5677_MONO_ADC_L_VOL_MASK		(0x3f << 9)
+#define RT5677_MONO_ADC_L_VOL_SFT		9
+#define RT5677_MONO_ADC_R_VOL_MASK		(0x3f << 1)
+#define RT5677_MONO_ADC_R_VOL_SFT		1
 
 
 /* Stereo 1/2 ADC Boost Gain Control (0x1e) */
 /* Stereo 1/2 ADC Boost Gain Control (0x1e) */
 #define RT5677_STO1_ADC_L_BST_MASK		(0x3 << 14)
 #define RT5677_STO1_ADC_L_BST_MASK		(0x3 << 14)
@@ -798,7 +799,21 @@
 #define RT5677_PDM2_I2C_EXE			(0x1 << 1)
 #define RT5677_PDM2_I2C_EXE			(0x1 << 1)
 #define RT5677_PDM2_I2C_BUSY			(0x1 << 0)
 #define RT5677_PDM2_I2C_BUSY			(0x1 << 0)
 
 
-/* MX3C TDM1 control 1 (0x3c) */
+/* TDM1 control 1 (0x3b) */
+#define RT5677_IF1_ADC_MODE_MASK		(0x1 << 12)
+#define RT5677_IF1_ADC_MODE_SFT			12
+#define RT5677_IF1_ADC_MODE_I2S			(0x0 << 12)
+#define RT5677_IF1_ADC_MODE_TDM			(0x1 << 12)
+#define RT5677_IF1_ADC1_SWAP_MASK		(0x3 << 6)
+#define RT5677_IF1_ADC1_SWAP_SFT		6
+#define RT5677_IF1_ADC2_SWAP_MASK		(0x3 << 4)
+#define RT5677_IF1_ADC2_SWAP_SFT		4
+#define RT5677_IF1_ADC3_SWAP_MASK		(0x3 << 2)
+#define RT5677_IF1_ADC3_SWAP_SFT		2
+#define RT5677_IF1_ADC4_SWAP_MASK		(0x3 << 0)
+#define RT5677_IF1_ADC4_SWAP_SFT		0
+
+/* TDM1 control 2 (0x3c) */
 #define RT5677_IF1_ADC4_MASK			(0x3 << 10)
 #define RT5677_IF1_ADC4_MASK			(0x3 << 10)
 #define RT5677_IF1_ADC4_SFT			10
 #define RT5677_IF1_ADC4_SFT			10
 #define RT5677_IF1_ADC3_MASK			(0x3 << 8)
 #define RT5677_IF1_ADC3_MASK			(0x3 << 8)
@@ -807,8 +822,44 @@
 #define RT5677_IF1_ADC2_SFT			6
 #define RT5677_IF1_ADC2_SFT			6
 #define RT5677_IF1_ADC1_MASK			(0x3 << 4)
 #define RT5677_IF1_ADC1_MASK			(0x3 << 4)
 #define RT5677_IF1_ADC1_SFT			4
 #define RT5677_IF1_ADC1_SFT			4
-
-/* MX41 TDM2 control 1 (0x41) */
+#define RT5677_IF1_ADC_CTRL_MASK		(0x7 << 0)
+#define RT5677_IF1_ADC_CTRL_SFT			0
+
+/* TDM1 control 4 (0x3e) */
+#define RT5677_IF1_DAC0_MASK			(0x7 << 12)
+#define RT5677_IF1_DAC0_SFT			12
+#define RT5677_IF1_DAC1_MASK			(0x7 << 8)
+#define RT5677_IF1_DAC1_SFT			8
+#define RT5677_IF1_DAC2_MASK			(0x7 << 4)
+#define RT5677_IF1_DAC2_SFT			4
+#define RT5677_IF1_DAC3_MASK			(0x7 << 0)
+#define RT5677_IF1_DAC3_SFT			0
+
+/* TDM1 control 5 (0x3f) */
+#define RT5677_IF1_DAC4_MASK			(0x7 << 12)
+#define RT5677_IF1_DAC4_SFT			12
+#define RT5677_IF1_DAC5_MASK			(0x7 << 8)
+#define RT5677_IF1_DAC5_SFT			8
+#define RT5677_IF1_DAC6_MASK			(0x7 << 4)
+#define RT5677_IF1_DAC6_SFT			4
+#define RT5677_IF1_DAC7_MASK			(0x7 << 0)
+#define RT5677_IF1_DAC7_SFT			0
+
+/* TDM2 control 1 (0x40) */
+#define RT5677_IF2_ADC_MODE_MASK		(0x1 << 12)
+#define RT5677_IF2_ADC_MODE_SFT			12
+#define RT5677_IF2_ADC_MODE_I2S			(0x0 << 12)
+#define RT5677_IF2_ADC_MODE_TDM			(0x1 << 12)
+#define RT5677_IF2_ADC1_SWAP_MASK		(0x3 << 6)
+#define RT5677_IF2_ADC1_SWAP_SFT		6
+#define RT5677_IF2_ADC2_SWAP_MASK		(0x3 << 4)
+#define RT5677_IF2_ADC2_SWAP_SFT		4
+#define RT5677_IF2_ADC3_SWAP_MASK		(0x3 << 2)
+#define RT5677_IF2_ADC3_SWAP_SFT		2
+#define RT5677_IF2_ADC4_SWAP_MASK		(0x3 << 0)
+#define RT5677_IF2_ADC4_SWAP_SFT		0
+
+/* TDM2 control 2 (0x41) */
 #define RT5677_IF2_ADC4_MASK			(0x3 << 10)
 #define RT5677_IF2_ADC4_MASK			(0x3 << 10)
 #define RT5677_IF2_ADC4_SFT			10
 #define RT5677_IF2_ADC4_SFT			10
 #define RT5677_IF2_ADC3_MASK			(0x3 << 8)
 #define RT5677_IF2_ADC3_MASK			(0x3 << 8)
@@ -817,6 +868,28 @@
 #define RT5677_IF2_ADC2_SFT			6
 #define RT5677_IF2_ADC2_SFT			6
 #define RT5677_IF2_ADC1_MASK			(0x3 << 4)
 #define RT5677_IF2_ADC1_MASK			(0x3 << 4)
 #define RT5677_IF2_ADC1_SFT			4
 #define RT5677_IF2_ADC1_SFT			4
+#define RT5677_IF2_ADC_CTRL_MASK		(0x7 << 0)
+#define RT5677_IF2_ADC_CTRL_SFT			0
+
+/* TDM2 control 4 (0x43) */
+#define RT5677_IF2_DAC0_MASK			(0x7 << 12)
+#define RT5677_IF2_DAC0_SFT			12
+#define RT5677_IF2_DAC1_MASK			(0x7 << 8)
+#define RT5677_IF2_DAC1_SFT			8
+#define RT5677_IF2_DAC2_MASK			(0x7 << 4)
+#define RT5677_IF2_DAC2_SFT			4
+#define RT5677_IF2_DAC3_MASK			(0x7 << 0)
+#define RT5677_IF2_DAC3_SFT			0
+
+/* TDM2 control 5 (0x44) */
+#define RT5677_IF2_DAC4_MASK			(0x7 << 12)
+#define RT5677_IF2_DAC4_SFT			12
+#define RT5677_IF2_DAC5_MASK			(0x7 << 8)
+#define RT5677_IF2_DAC5_SFT			8
+#define RT5677_IF2_DAC6_MASK			(0x7 << 4)
+#define RT5677_IF2_DAC6_SFT			4
+#define RT5677_IF2_DAC7_MASK			(0x7 << 0)
+#define RT5677_IF2_DAC7_SFT			0
 
 
 /* Digital Microphone Control 1 (0x50) */
 /* Digital Microphone Control 1 (0x50) */
 #define RT5677_DMIC_1_EN_MASK			(0x1 << 15)
 #define RT5677_DMIC_1_EN_MASK			(0x1 << 15)
@@ -1367,6 +1440,48 @@
 #define RT5677_SEL_SRC_IB01			(0x1 << 0)
 #define RT5677_SEL_SRC_IB01			(0x1 << 0)
 #define RT5677_SEL_SRC_IB01_SFT			0
 #define RT5677_SEL_SRC_IB01_SFT			0
 
 
+/* Jack Detect Control 1 (0xb5) */
+#define RT5677_SEL_GPIO_JD1_MASK		(0x3 << 14)
+#define RT5677_SEL_GPIO_JD1_SFT			14
+#define RT5677_SEL_GPIO_JD2_MASK		(0x3 << 12)
+#define RT5677_SEL_GPIO_JD2_SFT			12
+#define RT5677_SEL_GPIO_JD3_MASK		(0x3 << 10)
+#define RT5677_SEL_GPIO_JD3_SFT			10
+
+/* IRQ Control 1 (0xbd) */
+#define RT5677_STA_GPIO_JD1			(0x1 << 15)
+#define RT5677_STA_GPIO_JD1_SFT			15
+#define RT5677_EN_IRQ_GPIO_JD1			(0x1 << 14)
+#define RT5677_EN_IRQ_GPIO_JD1_SFT		14
+#define RT5677_EN_GPIO_JD1_STICKY		(0x1 << 13)
+#define RT5677_EN_GPIO_JD1_STICKY_SFT		13
+#define RT5677_INV_GPIO_JD1			(0x1 << 12)
+#define RT5677_INV_GPIO_JD1_SFT			12
+#define RT5677_STA_GPIO_JD2			(0x1 << 11)
+#define RT5677_STA_GPIO_JD2_SFT			11
+#define RT5677_EN_IRQ_GPIO_JD2			(0x1 << 10)
+#define RT5677_EN_IRQ_GPIO_JD2_SFT		10
+#define RT5677_EN_GPIO_JD2_STICKY		(0x1 << 9)
+#define RT5677_EN_GPIO_JD2_STICKY_SFT		9
+#define RT5677_INV_GPIO_JD2			(0x1 << 8)
+#define RT5677_INV_GPIO_JD2_SFT			8
+#define RT5677_STA_MICBIAS1_OVCD		(0x1 << 7)
+#define RT5677_STA_MICBIAS1_OVCD_SFT		7
+#define RT5677_EN_IRQ_MICBIAS1_OVCD		(0x1 << 6)
+#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT		6
+#define RT5677_EN_MICBIAS1_OVCD_STICKY		(0x1 << 5)
+#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT	5
+#define RT5677_INV_MICBIAS1_OVCD		(0x1 << 4)
+#define RT5677_INV_MICBIAS1_OVCD_SFT		4
+#define RT5677_STA_GPIO_JD3			(0x1 << 3)
+#define RT5677_STA_GPIO_JD3_SFT			3
+#define RT5677_EN_IRQ_GPIO_JD3			(0x1 << 2)
+#define RT5677_EN_IRQ_GPIO_JD3_SFT		2
+#define RT5677_EN_GPIO_JD3_STICKY		(0x1 << 1)
+#define RT5677_EN_GPIO_JD3_STICKY_SFT		1
+#define RT5677_INV_GPIO_JD3			(0x1 << 0)
+#define RT5677_INV_GPIO_JD3_SFT			0
+
 /* GPIO status (0xbf) */
 /* GPIO status (0xbf) */
 #define RT5677_GPIO6_STATUS_MASK		(0x1 << 5)
 #define RT5677_GPIO6_STATUS_MASK		(0x1 << 5)
 #define RT5677_GPIO6_STATUS_SFT			5
 #define RT5677_GPIO6_STATUS_SFT			5
@@ -1506,6 +1621,9 @@
 #define RT5677_GPIO5_FUNC_GPIO			(0x0 << 9)
 #define RT5677_GPIO5_FUNC_GPIO			(0x0 << 9)
 #define RT5677_GPIO5_FUNC_DMIC			(0x1 << 9)
 #define RT5677_GPIO5_FUNC_DMIC			(0x1 << 9)
 
 
+#define RT5677_FIRMWARE1	"rt5677_dsp_fw1.bin"
+#define RT5677_FIRMWARE2	"rt5677_dsp_fw2.bin"
+
 /* System Clock Source */
 /* System Clock Source */
 enum {
 enum {
 	RT5677_SCLK_S_MCLK,
 	RT5677_SCLK_S_MCLK,
@@ -1541,10 +1659,18 @@ enum {
 	RT5677_GPIO_NUM,
 	RT5677_GPIO_NUM,
 };
 };
 
 
+enum {
+	RT5677_IRQ_JD1,
+	RT5677_IRQ_JD2,
+	RT5677_IRQ_JD3,
+};
+
 struct rt5677_priv {
 struct rt5677_priv {
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec *codec;
 	struct rt5677_platform_data pdata;
 	struct rt5677_platform_data pdata;
-	struct regmap *regmap;
+	struct regmap *regmap, *regmap_physical;
+	const struct firmware *fw1, *fw2;
+	struct mutex dsp_cmd_lock, dsp_pri_lock;
 
 
 	int sysclk;
 	int sysclk;
 	int sysclk_src;
 	int sysclk_src;
@@ -1558,6 +1684,10 @@ struct rt5677_priv {
 #ifdef CONFIG_GPIOLIB
 #ifdef CONFIG_GPIOLIB
 	struct gpio_chip gpio_chip;
 	struct gpio_chip gpio_chip;
 #endif
 #endif
+	bool dsp_vad_en;
+	struct regmap_irq_chip_data *irq_data;
+	bool is_dsp_mode;
+	bool is_vref_slow;
 };
 };
 
 
 #endif /* __RT5677_H__ */
 #endif /* __RT5677_H__ */

+ 81 - 30
sound/soc/codecs/sgtl5000.c

@@ -16,6 +16,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/log2.h>
 #include <linux/regmap.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
@@ -121,6 +122,13 @@ struct ldo_regulator {
 	bool enabled;
 	bool enabled;
 };
 };
 
 
+enum sgtl5000_micbias_resistor {
+	SGTL5000_MICBIAS_OFF = 0,
+	SGTL5000_MICBIAS_2K = 2,
+	SGTL5000_MICBIAS_4K = 4,
+	SGTL5000_MICBIAS_8K = 8,
+};
+
 /* sgtl5000 private structure in codec */
 /* sgtl5000 private structure in codec */
 struct sgtl5000_priv {
 struct sgtl5000_priv {
 	int sysclk;	/* sysclk rate */
 	int sysclk;	/* sysclk rate */
@@ -131,6 +139,8 @@ struct sgtl5000_priv {
 	struct regmap *regmap;
 	struct regmap *regmap;
 	struct clk *mclk;
 	struct clk *mclk;
 	int revision;
 	int revision;
+	u8 micbias_resistor;
+	u8 micbias_voltage;
 };
 };
 
 
 /*
 /*
@@ -145,12 +155,14 @@ struct sgtl5000_priv {
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 	struct snd_kcontrol *kcontrol, int event)
 {
 {
+	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
+
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMU:
-		/* change mic bias resistor to 4Kohm */
+		/* change mic bias resistor */
 		snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
 		snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
-				SGTL5000_BIAS_R_MASK,
-				SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
+			SGTL5000_BIAS_R_MASK,
+			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
 		break;
 		break;
 
 
 	case SND_SOC_DAPM_PRE_PMD:
 	case SND_SOC_DAPM_PRE_PMD:
@@ -530,16 +542,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 
 /*
 /*
  * set clock according to i2s frame clock,
  * set clock according to i2s frame clock,
- * sgtl5000 provide 2 clock sources.
- * 1. sys_mclk. sample freq can only configure to
+ * sgtl5000 provides 2 clock sources:
+ * 1. sys_mclk: sample freq can only be configured to
  *	1/256, 1/384, 1/512 of sys_mclk.
  *	1/256, 1/384, 1/512 of sys_mclk.
- * 2. pll. can derive any audio clocks.
+ * 2. pll: can derive any audio clocks.
  *
  *
  * clock setting rules:
  * clock setting rules:
- * 1. in slave mode, only sys_mclk can use.
- * 2. as constraint by sys_mclk, sample freq should
- *	set to 32k, 44.1k and above.
- * 3. using sys_mclk prefer to pll to save power.
+ * 1. in slave mode, only sys_mclk can be used
+ * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz
+ * and above.
+ * 3. usage of sys_mclk is preferred over pll to save power.
  */
  */
 static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 {
 {
@@ -549,8 +561,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 
 
 	/*
 	/*
 	 * sample freq should be divided by frame clock,
 	 * sample freq should be divided by frame clock,
-	 * if frame clock lower than 44.1khz, sample feq should set to
-	 * 32khz or 44.1khz.
+	 * if frame clock is lower than 44.1 kHz, sample freq should be set to
+	 * 32 kHz or 44.1 kHz.
 	 */
 	 */
 	switch (frame_rate) {
 	switch (frame_rate) {
 	case 8000:
 	case 8000:
@@ -603,9 +615,10 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 
 
 	/*
 	/*
 	 * calculate the divider of mclk/sample_freq,
 	 * calculate the divider of mclk/sample_freq,
-	 * factor of freq =96k can only be 256, since mclk in range (12m,27m)
+	 * factor of freq = 96 kHz can only be 256, since mclk is in the range
+	 * of 8 MHz - 27 MHz
 	 */
 	 */
-	switch (sgtl5000->sysclk / sys_fs) {
+	switch (sgtl5000->sysclk / frame_rate) {
 	case 256:
 	case 256:
 		clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
 		clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
 			SGTL5000_MCLK_FREQ_SHIFT;
 			SGTL5000_MCLK_FREQ_SHIFT;
@@ -619,7 +632,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 			SGTL5000_MCLK_FREQ_SHIFT;
 			SGTL5000_MCLK_FREQ_SHIFT;
 		break;
 		break;
 	default:
 	default:
-		/* if mclk not satisify the divider, use pll */
+		/* if mclk does not satisfy the divider, use pll */
 		if (sgtl5000->master) {
 		if (sgtl5000->master) {
 			clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
 			clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
 				SGTL5000_MCLK_FREQ_SHIFT;
 				SGTL5000_MCLK_FREQ_SHIFT;
@@ -628,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 				"PLL not supported in slave mode\n");
 				"PLL not supported in slave mode\n");
 			dev_err(codec->dev, "%d ratio is not supported. "
 			dev_err(codec->dev, "%d ratio is not supported. "
 				"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
 				"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
-				sgtl5000->sysclk / sys_fs);
+				sgtl5000->sysclk / frame_rate);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 	}
 	}
@@ -795,7 +808,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
 				SGTL5000_LINEREG_D_POWERUP,
 				SGTL5000_LINEREG_D_POWERUP,
 				SGTL5000_LINEREG_D_POWERUP);
 				SGTL5000_LINEREG_D_POWERUP);
 
 
-	/* when internal ldo enabled, simple digital power can be disabled */
+	/* when internal ldo is enabled, simple digital power can be disabled */
 	snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
 	snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
 				SGTL5000_LINREG_SIMPLE_POWERUP,
 				SGTL5000_LINREG_SIMPLE_POWERUP,
 				0);
 				0);
@@ -1079,7 +1092,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
 /*
 /*
  * sgtl5000 has 3 internal power supplies:
  * sgtl5000 has 3 internal power supplies:
  * 1. VAG, normally set to vdda/2
  * 1. VAG, normally set to vdda/2
- * 2. chargepump, set to different value
+ * 2. charge pump, set to different value
  *	according to voltage of vdda and vddio
  *	according to voltage of vdda and vddio
  * 3. line out VAG, normally set to vddio/2
  * 3. line out VAG, normally set to vddio/2
  *
  *
@@ -1325,8 +1338,13 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
 			SGTL5000_HP_ZCD_EN |
 			SGTL5000_HP_ZCD_EN |
 			SGTL5000_ADC_ZCD_EN);
 			SGTL5000_ADC_ZCD_EN);
 
 
-	snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
+	snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+			SGTL5000_BIAS_R_MASK,
+			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
 
 
+	snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+			SGTL5000_BIAS_R_MASK,
+			sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT);
 	/*
 	/*
 	 * disable DAP
 	 * disable DAP
 	 * TODO:
 	 * TODO:
@@ -1416,10 +1434,10 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 {
 {
 	struct sgtl5000_priv *sgtl5000;
 	struct sgtl5000_priv *sgtl5000;
 	int ret, reg, rev;
 	int ret, reg, rev;
-	unsigned int mclk;
+	struct device_node *np = client->dev.of_node;
+	u32 value;
 
 
-	sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
-								GFP_KERNEL);
+	sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL);
 	if (!sgtl5000)
 	if (!sgtl5000)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -1440,14 +1458,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 		return ret;
 		return ret;
 	}
 	}
 
 
-	/* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */
-	mclk = clk_get_rate(sgtl5000->mclk);
-	if (mclk < 8000000 || mclk > 27000000) {
-		dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n",
-			mclk / 1000000, mclk / 1000 % 1000);
-		return -EINVAL;
-	}
-
 	ret = clk_prepare_enable(sgtl5000->mclk);
 	ret = clk_prepare_enable(sgtl5000->mclk);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
@@ -1469,6 +1479,47 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 	dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
 	dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
 	sgtl5000->revision = rev;
 	sgtl5000->revision = rev;
 
 
+	if (np) {
+		if (!of_property_read_u32(np,
+			"micbias-resistor-k-ohms", &value)) {
+			switch (value) {
+			case SGTL5000_MICBIAS_OFF:
+				sgtl5000->micbias_resistor = 0;
+				break;
+			case SGTL5000_MICBIAS_2K:
+				sgtl5000->micbias_resistor = 1;
+				break;
+			case SGTL5000_MICBIAS_4K:
+				sgtl5000->micbias_resistor = 2;
+				break;
+			case SGTL5000_MICBIAS_8K:
+				sgtl5000->micbias_resistor = 3;
+				break;
+			default:
+				sgtl5000->micbias_resistor = 2;
+				dev_err(&client->dev,
+					"Unsuitable MicBias resistor\n");
+			}
+		} else {
+			/* default is 4Kohms */
+			sgtl5000->micbias_resistor = 2;
+		}
+		if (!of_property_read_u32(np,
+			"micbias-voltage-m-volts", &value)) {
+			/* 1250mV => 0 */
+			/* steps of 250mV */
+			if ((value >= 1250) && (value <= 3000))
+				sgtl5000->micbias_voltage = (value / 250) - 5;
+			else {
+				sgtl5000->micbias_voltage = 0;
+				dev_err(&client->dev,
+					"Unsuitable MicBias resistor\n");
+			}
+		} else {
+			sgtl5000->micbias_voltage = 0;
+		}
+	}
+
 	i2c_set_clientdata(client, sgtl5000);
 	i2c_set_clientdata(client, sgtl5000);
 
 
 	/* Ensure sgtl5000 will start with sane register values */
 	/* Ensure sgtl5000 will start with sane register values */

+ 70 - 11
sound/soc/codecs/sigmadsp-i2c.c

@@ -6,29 +6,88 @@
  * Licensed under the GPL-2 or later.
  * Licensed under the GPL-2 or later.
  */
  */
 
 
-#include <linux/i2c.h>
 #include <linux/export.h>
 #include <linux/export.h>
+#include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
 
 
 #include "sigmadsp.h"
 #include "sigmadsp.h"
 
 
-static int sigma_action_write_i2c(void *control_data,
-	const struct sigma_action *sa, size_t len)
+static int sigmadsp_write_i2c(void *control_data,
+	unsigned int addr, const uint8_t data[], size_t len)
+{
+	uint8_t *buf;
+	int ret;
+
+	buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA);
+	if (!buf)
+		return -ENOMEM;
+
+	put_unaligned_be16(addr, buf);
+	memcpy(buf + 2, data, len);
+
+	ret = i2c_master_send(control_data, buf, len + 2);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int sigmadsp_read_i2c(void *control_data,
+	unsigned int addr, uint8_t data[], size_t len)
 {
 {
-	return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
-		len);
+	struct i2c_client *client = control_data;
+	struct i2c_msg msgs[2];
+	uint8_t buf[2];
+	int ret;
+
+	put_unaligned_be16(addr, buf);
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(buf);
+	msgs[0].buf = buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = len;
+	msgs[1].buf = data;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+	return 0;
 }
 }
 
 
-int process_sigma_firmware(struct i2c_client *client, const char *name)
+/**
+ * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * @client: The parent I2C device
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
+	const struct sigmadsp_ops *ops,	const char *firmware_name)
 {
 {
-	struct sigma_firmware ssfw;
+	struct sigmadsp *sigmadsp;
+
+	sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name);
+	if (IS_ERR(sigmadsp))
+		return sigmadsp;
 
 
-	ssfw.control_data = client;
-	ssfw.write = sigma_action_write_i2c;
+	sigmadsp->control_data = client;
+	sigmadsp->write = sigmadsp_write_i2c;
+	sigmadsp->read = sigmadsp_read_i2c;
 
 
-	return _process_sigma_firmware(&client->dev, &ssfw, name);
+	return sigmadsp;
 }
 }
-EXPORT_SYMBOL(process_sigma_firmware);
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c);
 
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");
 MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");

+ 35 - 11
sound/soc/codecs/sigmadsp-regmap.c

@@ -12,24 +12,48 @@
 
 
 #include "sigmadsp.h"
 #include "sigmadsp.h"
 
 
-static int sigma_action_write_regmap(void *control_data,
-	const struct sigma_action *sa, size_t len)
+static int sigmadsp_write_regmap(void *control_data,
+	unsigned int addr, const uint8_t data[], size_t len)
 {
 {
-	return regmap_raw_write(control_data, be16_to_cpu(sa->addr),
-		sa->payload, len - 2);
+	return regmap_raw_write(control_data, addr,
+		data, len);
 }
 }
 
 
-int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
-	const char *name)
+static int sigmadsp_read_regmap(void *control_data,
+	unsigned int addr, uint8_t data[], size_t len)
 {
 {
-	struct sigma_firmware ssfw;
+	return regmap_raw_read(control_data, addr,
+		data, len);
+}
+
+/**
+ * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * @dev: The parent device
+ * @regmap: Regmap instance to use
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
+	struct regmap *regmap, const struct sigmadsp_ops *ops,
+	const char *firmware_name)
+{
+	struct sigmadsp *sigmadsp;
+
+	sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name);
+	if (IS_ERR(sigmadsp))
+		return sigmadsp;
 
 
-	ssfw.control_data = regmap;
-	ssfw.write = sigma_action_write_regmap;
+	sigmadsp->control_data = regmap;
+	sigmadsp->write = sigmadsp_write_regmap;
+	sigmadsp->read = sigmadsp_read_regmap;
 
 
-	return _process_sigma_firmware(dev, &ssfw, name);
+	return sigmadsp;
 }
 }
-EXPORT_SYMBOL(process_sigma_firmware_regmap);
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap);
 
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");
 MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");

+ 670 - 41
sound/soc/codecs/sigmadsp.c

@@ -1,23 +1,74 @@
 /*
 /*
  * Load Analog Devices SigmaStudio firmware files
  * Load Analog Devices SigmaStudio firmware files
  *
  *
- * Copyright 2009-2011 Analog Devices Inc.
+ * Copyright 2009-2014 Analog Devices Inc.
  *
  *
  * Licensed under the GPL-2 or later.
  * Licensed under the GPL-2 or later.
  */
  */
 
 
 #include <linux/crc32.h>
 #include <linux/crc32.h>
-#include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/firmware.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/regmap.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/slab.h>
+
+#include <sound/control.h>
+#include <sound/soc.h>
 
 
 #include "sigmadsp.h"
 #include "sigmadsp.h"
 
 
 #define SIGMA_MAGIC "ADISIGM"
 #define SIGMA_MAGIC "ADISIGM"
 
 
+#define SIGMA_FW_CHUNK_TYPE_DATA 0
+#define SIGMA_FW_CHUNK_TYPE_CONTROL 1
+#define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2
+
+struct sigmadsp_control {
+	struct list_head head;
+	uint32_t samplerates;
+	unsigned int addr;
+	unsigned int num_bytes;
+	const char *name;
+	struct snd_kcontrol *kcontrol;
+	bool cached;
+	uint8_t cache[];
+};
+
+struct sigmadsp_data {
+	struct list_head head;
+	uint32_t samplerates;
+	unsigned int addr;
+	unsigned int length;
+	uint8_t data[];
+};
+
+struct sigma_fw_chunk {
+	__le32 length;
+	__le32 tag;
+	__le32 samplerates;
+} __packed;
+
+struct sigma_fw_chunk_data {
+	struct sigma_fw_chunk chunk;
+	__le16 addr;
+	uint8_t data[];
+} __packed;
+
+struct sigma_fw_chunk_control {
+	struct sigma_fw_chunk chunk;
+	__le16 type;
+	__le16 addr;
+	__le16 num_bytes;
+	const char name[];
+} __packed;
+
+struct sigma_fw_chunk_samplerate {
+	struct sigma_fw_chunk chunk;
+	__le32 samplerates[];
+} __packed;
+
 struct sigma_firmware_header {
 struct sigma_firmware_header {
 	unsigned char magic[7];
 	unsigned char magic[7];
 	u8 version;
 	u8 version;
@@ -28,12 +79,286 @@ enum {
 	SIGMA_ACTION_WRITEXBYTES = 0,
 	SIGMA_ACTION_WRITEXBYTES = 0,
 	SIGMA_ACTION_WRITESINGLE,
 	SIGMA_ACTION_WRITESINGLE,
 	SIGMA_ACTION_WRITESAFELOAD,
 	SIGMA_ACTION_WRITESAFELOAD,
-	SIGMA_ACTION_DELAY,
-	SIGMA_ACTION_PLLWAIT,
-	SIGMA_ACTION_NOOP,
 	SIGMA_ACTION_END,
 	SIGMA_ACTION_END,
 };
 };
 
 
+struct sigma_action {
+	u8 instr;
+	u8 len_hi;
+	__le16 len;
+	__be16 addr;
+	unsigned char payload[];
+} __packed;
+
+static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr,
+	const uint8_t data[], size_t len)
+{
+	return sigmadsp->write(sigmadsp->control_data, addr, data, len);
+}
+
+static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr,
+	uint8_t data[], size_t len)
+{
+	return sigmadsp->read(sigmadsp->control_data, addr, data, len);
+}
+
+static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *info)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+
+	info->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	info->count = ctrl->num_bytes;
+
+	return 0;
+}
+
+static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp,
+	struct sigmadsp_control *ctrl, void *data)
+{
+	/* safeload loads up to 20 bytes in a atomic operation */
+	if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops &&
+	    sigmadsp->ops->safeload)
+		return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data,
+			ctrl->num_bytes);
+	else
+		return sigmadsp_write(sigmadsp, ctrl->addr, data,
+			ctrl->num_bytes);
+}
+
+static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+	struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
+	uint8_t *data;
+	int ret = 0;
+
+	mutex_lock(&sigmadsp->lock);
+
+	data = ucontrol->value.bytes.data;
+
+	if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
+		ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data);
+
+	if (ret == 0) {
+		memcpy(ctrl->cache, data, ctrl->num_bytes);
+		ctrl->cached = true;
+	}
+
+	mutex_unlock(&sigmadsp->lock);
+
+	return ret;
+}
+
+static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+	struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
+	int ret = 0;
+
+	mutex_lock(&sigmadsp->lock);
+
+	if (!ctrl->cached) {
+		ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache,
+			ctrl->num_bytes);
+	}
+
+	if (ret == 0) {
+		ctrl->cached = true;
+		memcpy(ucontrol->value.bytes.data, ctrl->cache,
+			ctrl->num_bytes);
+	}
+
+	mutex_unlock(&sigmadsp->lock);
+
+	return ret;
+}
+
+static void sigmadsp_control_free(struct snd_kcontrol *kcontrol)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+
+	ctrl->kcontrol = NULL;
+}
+
+static bool sigma_fw_validate_control_name(const char *name, unsigned int len)
+{
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		/* Normal ASCII characters are valid */
+		if (name[i] < ' ' || name[i] > '~')
+			return false;
+	}
+
+	return true;
+}
+
+static int sigma_fw_load_control(struct sigmadsp *sigmadsp,
+	const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+	const struct sigma_fw_chunk_control *ctrl_chunk;
+	struct sigmadsp_control *ctrl;
+	unsigned int num_bytes;
+	size_t name_len;
+	char *name;
+	int ret;
+
+	if (length <= sizeof(*ctrl_chunk))
+		return -EINVAL;
+
+	ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk;
+
+	name_len = length - sizeof(*ctrl_chunk);
+	if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+		name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1;
+
+	/* Make sure there are no non-displayable characaters in the string */
+	if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len))
+		return -EINVAL;
+
+	num_bytes = le16_to_cpu(ctrl_chunk->num_bytes);
+	ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	name = kzalloc(name_len + 1, GFP_KERNEL);
+	if (!name) {
+		ret = -ENOMEM;
+		goto err_free_ctrl;
+	}
+	memcpy(name, ctrl_chunk->name, name_len);
+	name[name_len] = '\0';
+	ctrl->name = name;
+
+	ctrl->addr = le16_to_cpu(ctrl_chunk->addr);
+	ctrl->num_bytes = num_bytes;
+	ctrl->samplerates = le32_to_cpu(chunk->samplerates);
+
+	list_add_tail(&ctrl->head, &sigmadsp->ctrl_list);
+
+	return 0;
+
+err_free_ctrl:
+	kfree(ctrl);
+
+	return ret;
+}
+
+static int sigma_fw_load_data(struct sigmadsp *sigmadsp,
+	const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+	const struct sigma_fw_chunk_data *data_chunk;
+	struct sigmadsp_data *data;
+
+	if (length <= sizeof(*data_chunk))
+		return -EINVAL;
+
+	data_chunk = (struct sigma_fw_chunk_data *)chunk;
+
+	length -= sizeof(*data_chunk);
+
+	data = kzalloc(sizeof(*data) + length, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = le16_to_cpu(data_chunk->addr);
+	data->length = length;
+	data->samplerates = le32_to_cpu(chunk->samplerates);
+	memcpy(data->data, data_chunk->data, length);
+	list_add_tail(&data->head, &sigmadsp->data_list);
+
+	return 0;
+}
+
+static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp,
+	const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+	const struct sigma_fw_chunk_samplerate *rate_chunk;
+	unsigned int num_rates;
+	unsigned int *rates;
+	unsigned int i;
+
+	rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk;
+
+	num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32);
+
+	if (num_rates > 32 || num_rates == 0)
+		return -EINVAL;
+
+	/* We only allow one samplerates block per file */
+	if (sigmadsp->rate_constraints.count)
+		return -EINVAL;
+
+	rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL);
+	if (!rates)
+		return -ENOMEM;
+
+	for (i = 0; i < num_rates; i++)
+		rates[i] = le32_to_cpu(rate_chunk->samplerates[i]);
+
+	sigmadsp->rate_constraints.count = num_rates;
+	sigmadsp->rate_constraints.list = rates;
+
+	return 0;
+}
+
+static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp,
+	const struct firmware *fw)
+{
+	struct sigma_fw_chunk *chunk;
+	unsigned int length, pos;
+	int ret;
+
+	/*
+	 * Make sure that there is at least one chunk to avoid integer
+	 * underflows later on. Empty firmware is still valid though.
+	 */
+	if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header))
+		return 0;
+
+	pos = sizeof(struct sigma_firmware_header);
+
+	while (pos < fw->size - sizeof(*chunk)) {
+		chunk = (struct sigma_fw_chunk *)(fw->data + pos);
+
+		length = le32_to_cpu(chunk->length);
+
+		if (length > fw->size - pos || length < sizeof(*chunk))
+			return -EINVAL;
+
+		switch (le32_to_cpu(chunk->tag)) {
+		case SIGMA_FW_CHUNK_TYPE_DATA:
+			ret = sigma_fw_load_data(sigmadsp, chunk, length);
+			break;
+		case SIGMA_FW_CHUNK_TYPE_CONTROL:
+			ret = sigma_fw_load_control(sigmadsp, chunk, length);
+			break;
+		case SIGMA_FW_CHUNK_TYPE_SAMPLERATES:
+			ret = sigma_fw_load_samplerates(sigmadsp, chunk, length);
+			break;
+		default:
+			dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n",
+				chunk->tag);
+			ret = 0;
+			break;
+		}
+
+		if (ret)
+			return ret;
+
+		/*
+		 * This can not overflow since if length is larger than the
+		 * maximum firmware size (0x4000000) we'll error out earilier.
+		 */
+		pos += ALIGN(length, sizeof(__le32));
+	}
+
+	return 0;
+}
+
 static inline u32 sigma_action_len(struct sigma_action *sa)
 static inline u32 sigma_action_len(struct sigma_action *sa)
 {
 {
 	return (sa->len_hi << 16) | le16_to_cpu(sa->len);
 	return (sa->len_hi << 16) | le16_to_cpu(sa->len);
@@ -62,11 +387,11 @@ static size_t sigma_action_size(struct sigma_action *sa)
  * Returns a negative error value in case of an error, 0 if processing of
  * Returns a negative error value in case of an error, 0 if processing of
  * the firmware should be stopped after this action, 1 otherwise.
  * the firmware should be stopped after this action, 1 otherwise.
  */
  */
-static int
-process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
+static int process_sigma_action(struct sigmadsp *sigmadsp,
+	struct sigma_action *sa)
 {
 {
 	size_t len = sigma_action_len(sa);
 	size_t len = sigma_action_len(sa);
-	int ret;
+	struct sigmadsp_data *data;
 
 
 	pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
 	pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
 		sa->instr, sa->addr, len);
 		sa->instr, sa->addr, len);
@@ -75,13 +400,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
 	case SIGMA_ACTION_WRITEXBYTES:
 	case SIGMA_ACTION_WRITEXBYTES:
 	case SIGMA_ACTION_WRITESINGLE:
 	case SIGMA_ACTION_WRITESINGLE:
 	case SIGMA_ACTION_WRITESAFELOAD:
 	case SIGMA_ACTION_WRITESAFELOAD:
-		ret = ssfw->write(ssfw->control_data, sa, len);
-		if (ret < 0)
+		if (len < 3)
 			return -EINVAL;
 			return -EINVAL;
-		break;
-	case SIGMA_ACTION_DELAY:
-		udelay(len);
-		len = 0;
+
+		data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+
+		data->addr = be16_to_cpu(sa->addr);
+		data->length = len - 2;
+		memcpy(data->data, sa->payload, data->length);
+		list_add_tail(&data->head, &sigmadsp->data_list);
 		break;
 		break;
 	case SIGMA_ACTION_END:
 	case SIGMA_ACTION_END:
 		return 0;
 		return 0;
@@ -92,22 +421,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
 	return 1;
 	return 1;
 }
 }
 
 
-static int
-process_sigma_actions(struct sigma_firmware *ssfw)
+static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp,
+	const struct firmware *fw)
 {
 {
 	struct sigma_action *sa;
 	struct sigma_action *sa;
-	size_t size;
+	size_t size, pos;
 	int ret;
 	int ret;
 
 
-	while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
-		sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
+	pos = sizeof(struct sigma_firmware_header);
+
+	while (pos + sizeof(*sa) <= fw->size) {
+		sa = (struct sigma_action *)(fw->data + pos);
 
 
 		size = sigma_action_size(sa);
 		size = sigma_action_size(sa);
-		ssfw->pos += size;
-		if (ssfw->pos > ssfw->fw->size || size == 0)
+		pos += size;
+		if (pos > fw->size || size == 0)
 			break;
 			break;
 
 
-		ret = process_sigma_action(ssfw, sa);
+		ret = process_sigma_action(sigmadsp, sa);
 
 
 		pr_debug("%s: action returned %i\n", __func__, ret);
 		pr_debug("%s: action returned %i\n", __func__, ret);
 
 
@@ -115,29 +446,47 @@ process_sigma_actions(struct sigma_firmware *ssfw)
 			return ret;
 			return ret;
 	}
 	}
 
 
-	if (ssfw->pos != ssfw->fw->size)
+	if (pos != fw->size)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-int _process_sigma_firmware(struct device *dev,
-	struct sigma_firmware *ssfw, const char *name)
+static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp)
 {
 {
-	int ret;
-	struct sigma_firmware_header *ssfw_head;
+	struct sigmadsp_control *ctrl, *_ctrl;
+	struct sigmadsp_data *data, *_data;
+
+	list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) {
+		kfree(ctrl->name);
+		kfree(ctrl);
+	}
+
+	list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head)
+		kfree(data);
+
+	INIT_LIST_HEAD(&sigmadsp->ctrl_list);
+	INIT_LIST_HEAD(&sigmadsp->data_list);
+}
+
+static void devm_sigmadsp_release(struct device *dev, void *res)
+{
+	sigmadsp_firmware_release((struct sigmadsp *)res);
+}
+
+static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
+{
+	const struct sigma_firmware_header *ssfw_head;
 	const struct firmware *fw;
 	const struct firmware *fw;
+	int ret;
 	u32 crc;
 	u32 crc;
 
 
-	pr_debug("%s: loading firmware %s\n", __func__, name);
-
 	/* first load the blob */
 	/* first load the blob */
-	ret = request_firmware(&fw, name, dev);
+	ret = request_firmware(&fw, name, sigmadsp->dev);
 	if (ret) {
 	if (ret) {
 		pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
 		pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
-		return ret;
+		goto done;
 	}
 	}
-	ssfw->fw = fw;
 
 
 	/* then verify the header */
 	/* then verify the header */
 	ret = -EINVAL;
 	ret = -EINVAL;
@@ -149,13 +498,13 @@ int _process_sigma_firmware(struct device *dev,
 	 * overflows later in the loading process.
 	 * overflows later in the loading process.
 	 */
 	 */
 	if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
 	if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
-		dev_err(dev, "Failed to load firmware: Invalid size\n");
+		dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
 		goto done;
 		goto done;
 	}
 	}
 
 
 	ssfw_head = (void *)fw->data;
 	ssfw_head = (void *)fw->data;
 	if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
 	if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
-		dev_err(dev, "Failed to load firmware: Invalid magic\n");
+		dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
 		goto done;
 		goto done;
 	}
 	}
 
 
@@ -163,23 +512,303 @@ int _process_sigma_firmware(struct device *dev,
 			fw->size - sizeof(*ssfw_head));
 			fw->size - sizeof(*ssfw_head));
 	pr_debug("%s: crc=%x\n", __func__, crc);
 	pr_debug("%s: crc=%x\n", __func__, crc);
 	if (crc != le32_to_cpu(ssfw_head->crc)) {
 	if (crc != le32_to_cpu(ssfw_head->crc)) {
-		dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
+		dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
 			le32_to_cpu(ssfw_head->crc), crc);
 			le32_to_cpu(ssfw_head->crc), crc);
 		goto done;
 		goto done;
 	}
 	}
 
 
-	ssfw->pos = sizeof(*ssfw_head);
+	switch (ssfw_head->version) {
+	case 1:
+		ret = sigmadsp_fw_load_v1(sigmadsp, fw);
+		break;
+	case 2:
+		ret = sigmadsp_fw_load_v2(sigmadsp, fw);
+		break;
+	default:
+		dev_err(sigmadsp->dev,
+			"Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n",
+			ssfw_head->version);
+		ret = -EINVAL;
+		break;
+	}
 
 
-	/* finally process all of the actions */
-	ret = process_sigma_actions(ssfw);
+	if (ret)
+		sigmadsp_firmware_release(sigmadsp);
 
 
- done:
+done:
 	release_firmware(fw);
 	release_firmware(fw);
 
 
-	pr_debug("%s: loaded %s\n", __func__, name);
+	return ret;
+}
+
+static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev,
+	const struct sigmadsp_ops *ops, const char *firmware_name)
+{
+	sigmadsp->ops = ops;
+	sigmadsp->dev = dev;
+
+	INIT_LIST_HEAD(&sigmadsp->ctrl_list);
+	INIT_LIST_HEAD(&sigmadsp->data_list);
+	mutex_init(&sigmadsp->lock);
+
+	return sigmadsp_firmware_load(sigmadsp, firmware_name);
+}
+
+/**
+ * devm_sigmadsp_init() - Initialize SigmaDSP instance
+ * @dev: The parent device
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init(struct device *dev,
+	const struct sigmadsp_ops *ops, const char *firmware_name)
+{
+	struct sigmadsp *sigmadsp;
+	int ret;
+
+	sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp),
+		GFP_KERNEL);
+	if (!sigmadsp)
+		return ERR_PTR(-ENOMEM);
+
+	ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name);
+	if (ret) {
+		devres_free(sigmadsp);
+		return ERR_PTR(ret);
+	}
+
+	devres_add(dev, sigmadsp);
+
+	return sigmadsp;
+}
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init);
+
+static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate)
+{
+	unsigned int i;
+
+	for (i = 0; i < sigmadsp->rate_constraints.count; i++) {
+		if (sigmadsp->rate_constraints.list[i] == rate)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp,
+	unsigned int samplerate)
+{
+	int samplerate_index;
+
+	if (samplerate == 0)
+		return 0;
+
+	if (sigmadsp->rate_constraints.count) {
+		samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate);
+		if (samplerate_index < 0)
+			return 0;
+
+		return BIT(samplerate_index);
+	} else {
+		return ~0;
+	}
+}
+
+static bool sigmadsp_samplerate_valid(unsigned int supported,
+	unsigned int requested)
+{
+	/* All samplerates are supported */
+	if (!supported)
+		return true;
+
+	return supported & requested;
+}
+
+static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp,
+	struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
+{
+	struct snd_kcontrol_new template;
+	struct snd_kcontrol *kcontrol;
+
+	memset(&template, 0, sizeof(template));
+	template.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	template.name = ctrl->name;
+	template.info = sigmadsp_ctrl_info;
+	template.get = sigmadsp_ctrl_get;
+	template.put = sigmadsp_ctrl_put;
+	template.private_value = (unsigned long)ctrl;
+	template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask))
+		template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+
+	kcontrol = snd_ctl_new1(&template, sigmadsp);
+	if (!kcontrol)
+		return -ENOMEM;
+
+	kcontrol->private_free = sigmadsp_control_free;
+	ctrl->kcontrol = kcontrol;
+
+	return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol);
+}
+
+static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
+	struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
+{
+	struct snd_card *card = sigmadsp->component->card->snd_card;
+	struct snd_kcontrol_volatile *vd;
+	struct snd_ctl_elem_id id;
+	bool active;
+	bool changed = false;
+
+	active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask);
+
+	down_write(&card->controls_rwsem);
+	if (!ctrl->kcontrol) {
+		up_write(&card->controls_rwsem);
+		return;
+	}
+
+	id = ctrl->kcontrol->id;
+	vd = &ctrl->kcontrol->vd[0];
+	if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) {
+		vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+		changed = true;
+	}
+	up_write(&card->controls_rwsem);
+
+	if (active && changed) {
+		mutex_lock(&sigmadsp->lock);
+		if (ctrl->cached)
+			sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
+		mutex_unlock(&sigmadsp->lock);
+	}
+
+	if (changed)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id);
+}
+
+/**
+ * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component
+ * @sigmadsp: The sigmadsp instance to attach
+ * @component: The component to attach to
+ *
+ * Typically called in the components probe callback.
+ *
+ * Note, once this function has been called the firmware must not be released
+ * until after the ALSA snd_card that the component belongs to has been
+ * disconnected, even if sigmadsp_attach() returns an error.
+ */
+int sigmadsp_attach(struct sigmadsp *sigmadsp,
+	struct snd_soc_component *component)
+{
+	struct sigmadsp_control *ctrl;
+	unsigned int samplerate_mask;
+	int ret;
+
+	sigmadsp->component = component;
+
+	samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp,
+		sigmadsp->current_samplerate);
+
+	list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) {
+		ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_attach);
+
+/**
+ * sigmadsp_setup() - Setup the DSP for the specified samplerate
+ * @sigmadsp: The sigmadsp instance to configure
+ * @samplerate: The samplerate the DSP should be configured for
+ *
+ * Loads the appropriate firmware program and parameter memory (if not already
+ * loaded) and enables the controls for the specified samplerate. Any control
+ * parameter changes that have been made previously will be restored.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate)
+{
+	struct sigmadsp_control *ctrl;
+	unsigned int samplerate_mask;
+	struct sigmadsp_data *data;
+	int ret;
+
+	if (sigmadsp->current_samplerate == samplerate)
+		return 0;
+
+	samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate);
+	if (samplerate_mask == 0)
+		return -EINVAL;
+
+	list_for_each_entry(data, &sigmadsp->data_list, head) {
+		if (!sigmadsp_samplerate_valid(data->samplerates,
+		    samplerate_mask))
+			continue;
+		ret = sigmadsp_write(sigmadsp, data->addr, data->data,
+			data->length);
+		if (ret)
+			goto err;
+	}
+
+	list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
+		sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask);
+
+	sigmadsp->current_samplerate = samplerate;
+
+	return 0;
+err:
+	sigmadsp_reset(sigmadsp);
 
 
 	return ret;
 	return ret;
 }
 }
-EXPORT_SYMBOL_GPL(_process_sigma_firmware);
+EXPORT_SYMBOL_GPL(sigmadsp_setup);
+
+/**
+ * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset
+ * @sigmadsp: The sigmadsp instance to reset
+ *
+ * Should be called whenever the DSP has been reset and parameter and program
+ * memory need to be re-loaded.
+ */
+void sigmadsp_reset(struct sigmadsp *sigmadsp)
+{
+	struct sigmadsp_control *ctrl;
+
+	list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
+		sigmadsp_activate_ctrl(sigmadsp, ctrl, false);
+
+	sigmadsp->current_samplerate = 0;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_reset);
+
+/**
+ * sigmadsp_restrict_params() - Applies DSP firmware specific constraints
+ * @sigmadsp: The sigmadsp instance
+ * @substream: The substream to restrict
+ *
+ * Applies samplerate constraints that may be required by the firmware Should
+ * typically be called from the CODEC/component drivers startup callback.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
+	struct snd_pcm_substream *substream)
+{
+	if (sigmadsp->rate_constraints.count == 0)
+		return 0;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints);
+}
+EXPORT_SYMBOL_GPL(sigmadsp_restrict_params);
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 42 - 17
sound/soc/codecs/sigmadsp.h

@@ -11,31 +11,56 @@
 
 
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/regmap.h>
 #include <linux/regmap.h>
+#include <linux/list.h>
 
 
-struct sigma_action {
-	u8 instr;
-	u8 len_hi;
-	__le16 len;
-	__be16 addr;
-	unsigned char payload[];
-} __packed;
+#include <sound/pcm.h>
 
 
-struct sigma_firmware {
-	const struct firmware *fw;
-	size_t pos;
+struct sigmadsp;
+struct snd_soc_component;
+struct snd_pcm_substream;
+
+struct sigmadsp_ops {
+	int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr,
+			const uint8_t *data, size_t len);
+};
+
+struct sigmadsp {
+	const struct sigmadsp_ops *ops;
+
+	struct list_head ctrl_list;
+	struct list_head data_list;
+
+	struct snd_pcm_hw_constraint_list rate_constraints;
+
+	unsigned int current_samplerate;
+	struct snd_soc_component *component;
+	struct device *dev;
+
+	struct mutex lock;
 
 
 	void *control_data;
 	void *control_data;
-	int (*write)(void *control_data, const struct sigma_action *sa,
-			size_t len);
+	int (*write)(void *, unsigned int, const uint8_t *, size_t);
+	int (*read)(void *, unsigned int, uint8_t *, size_t);
 };
 };
 
 
-int _process_sigma_firmware(struct device *dev,
-	struct sigma_firmware *ssfw, const char *name);
+struct sigmadsp *devm_sigmadsp_init(struct device *dev,
+	const struct sigmadsp_ops *ops, const char *firmware_name);
+void sigmadsp_reset(struct sigmadsp *sigmadsp);
+
+int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
+	struct snd_pcm_substream *substream);
 
 
 struct i2c_client;
 struct i2c_client;
 
 
-extern int process_sigma_firmware(struct i2c_client *client, const char *name);
-extern int process_sigma_firmware_regmap(struct device *dev,
-		struct regmap *regmap, const char *name);
+struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
+	struct regmap *regmap, const struct sigmadsp_ops *ops,
+	const char *firmware_name);
+struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
+	const struct sigmadsp_ops *ops,	const char *firmware_name);
+
+int sigmadsp_attach(struct sigmadsp *sigmadsp,
+	struct snd_soc_component *component);
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate);
+void sigmadsp_reset(struct sigmadsp *sigmadsp);
 
 
 #endif
 #endif

+ 4 - 2
sound/soc/codecs/sirf-audio-codec.c

@@ -120,7 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
 {
 {
 #define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
 #define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
 #define ATLAS6_CODEC_RESET_BITS (1 << 28)
 #define ATLAS6_CODEC_RESET_BITS (1 << 28)
-	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 	case SND_SOC_DAPM_PRE_PMU:
 		enable_and_reset_codec(sirf_audio_codec->regmap,
 		enable_and_reset_codec(sirf_audio_codec->regmap,
@@ -142,7 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
 {
 {
 #define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
 #define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
 #define PRIMA2_CODEC_RESET_BITS (1 << 26)
 #define PRIMA2_CODEC_RESET_BITS (1 << 26)
-	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
 	switch (event) {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMU:
 		enable_and_reset_codec(sirf_audio_codec->regmap,
 		enable_and_reset_codec(sirf_audio_codec->regmap,

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно