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

Merge remote-tracking branches 'asoc/topic/ad1836', 'asoc/topic/ad193x', 'asoc/topic/adav80x', 'asoc/topic/adsp', 'asoc/topic/ak4641', 'asoc/topic/ak4642', 'asoc/topic/arizona', 'asoc/topic/atmel', 'asoc/topic/au1x', 'asoc/topic/axi', 'asoc/topic/bcm2835', 'asoc/topic/blackfin', 'asoc/topic/cs4271', 'asoc/topic/cs42l52', 'asoc/topic/da7210', 'asoc/topic/davinci', 'asoc/topic/ep93xx', 'asoc/topic/fsl', 'asoc/topic/fsl-mxs', 'asoc/topic/generic', 'asoc/topic/hdmi', 'asoc/topic/jack', 'asoc/topic/jz4740', 'asoc/topic/max98090', 'asoc/topic/mxs', 'asoc/topic/omap', 'asoc/topic/pxa', 'asoc/topic/rcar', 'asoc/topic/s6000', 'asoc/topic/sai', 'asoc/topic/samsung', 'asoc/topic/sgtl5000', 'asoc/topic/spear', 'asoc/topic/ssm2518', 'asoc/topic/ssm2602', 'asoc/topic/tegra', 'asoc/topic/tlv320aic3x', 'asoc/topic/twl6040', 'asoc/topic/txx9', 'asoc/topic/uda1380', 'asoc/topic/width', 'asoc/topic/wm8510', 'asoc/topic/wm8523', 'asoc/topic/wm8580', 'asoc/topic/wm8711', 'asoc/topic/wm8728', 'asoc/topic/wm8731', 'asoc/topic/wm8741', 'asoc/topic/wm8750', 'asoc/topic/wm8753', 'asoc/topic/wm8776', 'asoc/topic/wm8804', 'asoc/topic/wm8900', 'asoc/topic/wm8901', 'asoc/topic/wm8940', 'asoc/topic/wm8962', 'asoc/topic/wm8974', 'asoc/topic/wm8985', 'asoc/topic/wm8988', 'asoc/topic/wm8990', 'asoc/topic/wm8991', 'asoc/topic/wm8994', 'asoc/topic/wm8995', 'asoc/topic/wm9081' and 'asoc/topic/x86' into asoc-next

100 өөрчлөгдсөн 3956 нэмэгдсэн , 2030 устгасан
  1. 31 0
      Documentation/devicetree/bindings/sound/adi,axi-i2s.txt
  2. 30 0
      Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt
  3. 25 0
      Documentation/devicetree/bindings/sound/bcm2835-i2s.txt
  4. 46 0
      Documentation/devicetree/bindings/sound/cs42l52.txt
  5. 4 2
      Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
  6. 40 0
      Documentation/devicetree/bindings/sound/fsl-sai.txt
  7. 17 0
      Documentation/devicetree/bindings/sound/hdmi.txt
  8. 43 0
      Documentation/devicetree/bindings/sound/max98090.txt
  9. 51 0
      Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
  10. 11 2
      Documentation/devicetree/bindings/sound/simple-card.txt
  11. 1 0
      arch/arm/Kconfig
  12. 4 3
      arch/arm/mach-s3c64xx/Kconfig
  13. 1 1
      arch/arm/mach-s3c64xx/Makefile
  14. 5 0
      arch/arm/mach-s3c64xx/common.h
  15. 0 762
      arch/arm/mach-s3c64xx/dma.c
  16. 42 102
      arch/arm/mach-s3c64xx/include/mach/dma.h
  17. 244 0
      arch/arm/mach-s3c64xx/pl080.c
  18. 8 2
      arch/arm/plat-samsung/devs.c
  19. 7 1
      arch/arm/plat-samsung/dma-ops.c
  20. 2 2
      drivers/clk/samsung/clk-s3c64xx.c
  21. 89 3
      drivers/mfd/twl6040.c
  22. 135 4
      drivers/mfd/wm5110-tables.c
  23. 1 1
      drivers/spi/Kconfig
  24. 162 0
      include/linux/mfd/arizona/registers.h
  25. 2 4
      include/linux/platform_data/asoc-ti-mcbsp.h
  26. 1 0
      include/linux/platform_data/davinci_asp.h
  27. 4 10
      include/sound/cs42l52.h
  28. 12 0
      include/sound/pcm_params.h
  29. 2 1
      include/sound/rcar_snd.h
  30. 11 4
      include/sound/soc.h
  31. 0 1
      include/sound/spear_dma.h
  32. 3 1
      sound/soc/Kconfig
  33. 3 1
      sound/soc/Makefile
  34. 21 0
      sound/soc/adi/Kconfig
  35. 5 0
      sound/soc/adi/Makefile
  36. 277 0
      sound/soc/adi/axi-i2s.c
  37. 272 0
      sound/soc/adi/axi-spdif.c
  38. 0 2
      sound/soc/atmel/sam9x5_wm8731.c
  39. 0 9
      sound/soc/au1x/dbdma2.c
  40. 0 14
      sound/soc/au1x/dma.c
  41. 10 0
      sound/soc/bcm/Kconfig
  42. 5 0
      sound/soc/bcm/Makefile
  43. 879 0
      sound/soc/bcm/bcm2835-i2s.c
  44. 0 1
      sound/soc/blackfin/bf5xx-ac97-pcm.c
  45. 0 3
      sound/soc/blackfin/bf5xx-i2s-pcm.c
  46. 1 1
      sound/soc/cirrus/edb93xx.c
  47. 18 2
      sound/soc/cirrus/ep93xx-ac97.c
  48. 20 2
      sound/soc/cirrus/ep93xx-i2s.c
  49. 5 43
      sound/soc/cirrus/ep93xx-pcm.c
  50. 22 0
      sound/soc/cirrus/ep93xx-pcm.h
  51. 1 1
      sound/soc/cirrus/simone.c
  52. 1 1
      sound/soc/cirrus/snappercl15.c
  53. 2 0
      sound/soc/codecs/Kconfig
  54. 2 0
      sound/soc/codecs/ad1836.c
  55. 3 3
      sound/soc/codecs/ad193x.c
  56. 3 3
      sound/soc/codecs/adav80x.c
  57. 25 13
      sound/soc/codecs/ak4641.c
  58. 62 76
      sound/soc/codecs/ak4642.c
  59. 130 74
      sound/soc/codecs/arizona.c
  60. 4 1
      sound/soc/codecs/arizona.h
  61. 4 4
      sound/soc/codecs/cs4271.c
  62. 75 30
      sound/soc/codecs/cs42l52.c
  63. 3 3
      sound/soc/codecs/da7210.c
  64. 11 1
      sound/soc/codecs/hdmi.c
  65. 24 52
      sound/soc/codecs/sgtl5000.c
  66. 4 4
      sound/soc/codecs/ssm2518.c
  67. 5 51
      sound/soc/codecs/ssm2602.c
  68. 83 43
      sound/soc/codecs/tlv320aic3x.c
  69. 66 161
      sound/soc/codecs/twl6040.c
  70. 3 3
      sound/soc/codecs/uda1380.c
  71. 2 2
      sound/soc/codecs/wm5102.c
  72. 373 6
      sound/soc/codecs/wm5110.c
  73. 3 3
      sound/soc/codecs/wm8510.c
  74. 3 3
      sound/soc/codecs/wm8523.c
  75. 3 3
      sound/soc/codecs/wm8580.c
  76. 3 3
      sound/soc/codecs/wm8711.c
  77. 3 3
      sound/soc/codecs/wm8728.c
  78. 3 3
      sound/soc/codecs/wm8731.c
  79. 3 3
      sound/soc/codecs/wm8741.c
  80. 3 3
      sound/soc/codecs/wm8750.c
  81. 3 3
      sound/soc/codecs/wm8753.c
  82. 3 3
      sound/soc/codecs/wm8776.c
  83. 3 3
      sound/soc/codecs/wm8804.c
  84. 3 3
      sound/soc/codecs/wm8900.c
  85. 128 93
      sound/soc/codecs/wm8940.c
  86. 2 2
      sound/soc/codecs/wm8962.c
  87. 33 21
      sound/soc/codecs/wm8974.c
  88. 3 3
      sound/soc/codecs/wm8985.c
  89. 3 3
      sound/soc/codecs/wm8988.c
  90. 105 153
      sound/soc/codecs/wm8990.c
  91. 0 9
      sound/soc/codecs/wm8990.h
  92. 153 140
      sound/soc/codecs/wm8991.c
  93. 0 9
      sound/soc/codecs/wm8991.h
  94. 5 6
      sound/soc/codecs/wm8994.c
  95. 3 3
      sound/soc/codecs/wm8995.c
  96. 2 2
      sound/soc/codecs/wm8997.c
  97. 1 1
      sound/soc/codecs/wm9081.c
  98. 10 10
      sound/soc/codecs/wm_adsp.c
  99. 12 17
      sound/soc/davinci/Kconfig
  100. 2 6
      sound/soc/davinci/Makefile

+ 31 - 0
Documentation/devicetree/bindings/sound/adi,axi-i2s.txt

@@ -0,0 +1,31 @@
+ADI AXI-I2S controller
+
+Required properties:
+ - compatible : Must be "adi,axi-i2s-1.00.a"
+ - reg : Must contain I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's clocks.
+   The controller expects two clocks, the clock used for the AXI interface and
+   the clock used as the sampling rate reference clock sample.
+ - clock-names : "axi" for the clock to the AXI interface, "ref" for the sample
+   rate reference clock.
+ - dmas: Pairs of phandle and specifier for the DMA channels that are used by
+   the core. The core expects two dma channels, one for transmit and one for
+   receive.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
+please check:
+	* resource-names.txt
+	* clock/clock-bindings.txt
+	* dma/dma.txt
+
+Example:
+
+	i2s: i2s@0x77600000 {
+		compatible = "adi,axi-i2s-1.00.a";
+		reg = <0x77600000 0x1000>;
+		clocks = <&clk 15>, <&audio_clock>;
+		clock-names = "axi", "ref";
+		dmas = <&ps7_dma 0>, <&ps7_dma 1>;
+		dma-names = "tx", "rx";
+	};

+ 30 - 0
Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt

@@ -0,0 +1,30 @@
+ADI AXI-SPDIF controller
+
+Required properties:
+ - compatible : Must be "adi,axi-spdif-1.00.a"
+ - reg : Must contain SPDIF core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's clocks.
+   The controller expects two clocks, the clock used for the AXI interface and
+   the clock used as the sampling rate reference clock sample.
+ - clock-names: "axi" for the clock to the AXI interface, "ref" for the sample
+   rate reference clock.
+ - dmas: Pairs of phandle and specifier for the DMA channel that is used by
+   the core. The core expects one dma channel for transmit.
+ - dma-names : Must be "tx"
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
+please check:
+	* resource-names.txt
+	* clock/clock-bindings.txt
+	* dma/dma.txt
+
+Example:
+
+	spdif: spdif@0x77400000 {
+		compatible = "adi,axi-spdif-tx-1.00.a";
+		reg = <0x77600000 0x1000>;
+		clocks = <&clk 15>, <&audio_clock>;
+		clock-names = "axi", "ref";
+		dmas = <&ps7_dma 0>;
+		dma-names = "tx";
+	};

+ 25 - 0
Documentation/devicetree/bindings/sound/bcm2835-i2s.txt

@@ -0,0 +1,25 @@
+* Broadcom BCM2835 SoC I2S/PCM module
+
+Required properties:
+- compatible: "brcm,bcm2835-i2s"
+- reg: A list of base address and size entries:
+	* The first entry should cover the PCM registers
+	* The second entry should cover the PCM clock registers
+- dmas: List of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: Identifier string for each DMA request line in the dmas property.
+  These strings correspond 1:1 with the ordered pairs in dmas.
+
+  One of the DMA channels will be responsible for transmission (should be
+  named "tx") and one for reception (should be named "rx").
+
+Example:
+
+bcm2835_i2s: i2s@7e203000 {
+	compatible = "brcm,bcm2835-i2s";
+	reg = <0x7e203000 0x20>,
+	      <0x7e101098 0x02>;
+
+	dmas = <&dma 2>,
+	       <&dma 3>;
+	dma-names = "tx", "rx";
+};

+ 46 - 0
Documentation/devicetree/bindings/sound/cs42l52.txt

@@ -0,0 +1,46 @@
+CS42L52 audio CODEC
+
+Required properties:
+
+  - compatible : "cirrus,cs42l52"
+
+  - reg : the I2C address of the device for I2C
+
+Optional properties:
+
+  - cirrus,reset-gpio : GPIO controller's phandle and the number
+  of the GPIO used to reset the codec.
+
+  - cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency.
+  Allowable values of 0x00 through 0x0F. These are raw values written to the
+  register, not the actual frequency. The frequency is determined by the following.
+  Frequency = (64xFs)/(N+2)
+  N = chgfreq_val
+  Fs = Sample Rate (variable)
+
+  - cirrus,mica-differential-cfg : boolean, If present, then the MICA input is configured
+  as a differential input. If not present then the MICA input is configured as
+  Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input.
+
+  - cirrus,micb-differential-cfg : boolean, If present, then the MICB input is configured
+  as a differential input. If not present then the MICB input is configured as
+  Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input.
+
+  - cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin
+  0 = 0.5 x VA
+  1 = 0.6 x VA
+  2 = 0.7 x VA
+  3 = 0.8 x VA
+  4 = 0.83 x VA
+  5 = 0.91 x VA
+
+Example:
+
+codec: codec@4a {
+	compatible = "cirrus,cs42l52";
+	reg = <0x4a>;
+	reset-gpio = <&gpio 10 0>;
+	cirrus,chgfreq-divisor = <0x05>;
+	cirrus.mica-differential-cfg;
+	cirrus,micbias-lvl = <5>;
+};

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

@@ -4,7 +4,8 @@ Required properties:
 - compatible :
 	"ti,dm646x-mcasp-audio"	: for DM646x platforms
 	"ti,da830-mcasp-audio"	: for both DA830 & DA850 platforms
-	"ti,am33xx-mcasp-audio"	: for AM33xx platforms (AM33xx, TI81xx)
+	"ti,am33xx-mcasp-audio"	: for AM33xx platforms (AM33xx, AM43xx, TI81xx)
+	"ti,dra7-mcasp-audio"	: for DRA7xx platforms
 
 - reg : Should contain reg specifiers for the entries in the reg-names property.
 - reg-names : Should contain:
@@ -36,7 +37,8 @@ Optional properties:
 - pinctrl-0: Should specify pin control group used for this controller.
 - pinctrl-names: Should contain only one value - "default", for more details
   		 please refer to pinctrl-bindings.txt
-  
+- fck_parent : Should contain a valid clock name which will be used as parent
+	       for the McASP fck
 
 Example:
 

+ 40 - 0
Documentation/devicetree/bindings/sound/fsl-sai.txt

@@ -0,0 +1,40 @@
+Freescale Synchronous Audio Interface (SAI).
+
+The SAI is based on I2S module that used communicating with audio codecs,
+which provides a synchronous audio interface that supports fullduplex
+serial interfaces with frame synchronization such as I2S, AC97, TDM, and
+codec/DSP interfaces.
+
+
+Required properties:
+- compatible: Compatible list, contains "fsl,vf610-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 "sai" entry.
+- 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-regs: If this property is absent, the little endian mode will
+  be in use as default, or the big endian mode will be in use for all the
+  device registers.
+- big-endian-data: If this property is absent, the little endian mode will
+  be in use as default, or the big endian mode will be in use for all the
+  fifo data.
+
+Example:
+sai2: sai@40031000 {
+	      compatible = "fsl,vf610-sai";
+	      reg = <0x40031000 0x1000>;
+	      pinctrl-names = "default";
+	      pinctrl-0 = <&pinctrl_sai2_1>;
+	      clocks = <&clks VF610_CLK_SAI2>;
+	      clock-names = "sai";
+	      dma-names = "tx", "rx";
+	      dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
+		   <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
+	      big-endian-regs;
+	      big-endian-data;
+};

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

@@ -0,0 +1,17 @@
+Device-Tree bindings for dummy HDMI codec
+
+Required properties:
+	- compatible: should be "linux,hdmi-audio".
+
+CODEC output pins:
+  * TX
+
+CODEC input pins:
+  * RX
+
+Example node:
+
+	hdmi_audio: hdmi_audio@0 {
+		compatible = "linux,hdmi-audio";
+		status = "okay";
+	};

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

@@ -0,0 +1,43 @@
+MAX98090 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "maxim,max98090".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Pins on the device (for linking into audio routes):
+
+  * MIC1
+  * MIC2
+  * DMICL
+  * DMICR
+  * IN1
+  * IN2
+  * IN3
+  * IN4
+  * IN5
+  * IN6
+  * IN12
+  * IN34
+  * IN56
+  * HPL
+  * HPR
+  * SPKL
+  * SPKR
+  * RCVL
+  * RCVR
+  * MICBIAS
+
+Example:
+
+audio-codec@10 {
+	compatible = "maxim,max98090";
+	reg = <0x10>;
+	interrupt-parent = <&gpio>;
+	interrupts = <TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
+};

+ 51 - 0
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt

@@ -0,0 +1,51 @@
+NVIDIA Tegra audio complex, with MAX98090 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-max98090"
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  - pll_a
+  - pll_a_out0
+  - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the MAX98090's pins (as documented in its binding), and the jacks
+  on the board:
+
+  * Headphones
+  * Speakers
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the MAX98090 audio codec.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-max98090-venice2",
+		     "nvidia,tegra-audio-max98090";
+	nvidia,model = "NVIDIA Tegra Venice2";
+
+	nvidia,audio-routing =
+		"Headphones", "HPR",
+		"Headphones", "HPL",
+		"Speakers", "SPKR",
+		"Speakers", "SPKL",
+		"Mic Jack", "MICBIAS",
+		"IN34", "Mic Jack";
+
+	nvidia,i2s-controller = <&tegra_i2s1>;
+	nvidia,audio-codec = <&acodec>;
+
+	clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
+		 <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
+		 <&tegra_car TEGRA124_CLK_EXTERN1>;
+	clock-names = "pll_a", "pll_a_out0", "mclk";
+};

+ 11 - 2
Documentation/devicetree/bindings/sound/simple-card.txt

@@ -9,8 +9,13 @@ Required properties:
 Optional properties:
 
 - simple-audio-card,format		: CPU/CODEC common audio format.
-					"i2s", "right_j", "left_j" , "dsp_a"
-					"dsp_b", "ac97", "pdm", "msb", "lsb"
+					  "i2s", "right_j", "left_j" , "dsp_a"
+					  "dsp_b", "ac97", "pdm", "msb", "lsb"
+- simple-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.
+
 Required subnodes:
 
 - simple-audio-card,cpu			: CPU   sub-node
@@ -38,6 +43,10 @@ Example:
 sound {
 	compatible = "simple-audio-card";
 	simple-audio-card,format = "left_j";
+	simple-audio-routing =
+		"MIC_IN", "Mic Jack",
+		"Headphone Jack", "HP_OUT",
+		"Ext Spk", "LINE_OUT";
 
 	simple-audio-card,cpu {
 		sound-dai = <&sh_fsi2 0>;

+ 1 - 0
arch/arm/Kconfig

@@ -723,6 +723,7 @@ config ARCH_S3C64XX
 	bool "Samsung S3C64XX"
 	select ARCH_HAS_CPUFREQ
 	select ARCH_REQUIRE_GPIOLIB
+	select ARM_AMBA
 	select ARM_VIC
 	select CLKDEV_LOOKUP
 	select CLKSRC_SAMSUNG_PWM

+ 4 - 3
arch/arm/mach-s3c64xx/Kconfig

@@ -17,9 +17,10 @@ config CPU_S3C6410
 	help
 	  Enable S3C6410 CPU support
 
-config S3C64XX_DMA
-	bool "S3C64XX DMA"
-	select S3C_DMA
+config S3C64XX_PL080
+	bool "S3C64XX DMA using generic PL08x driver"
+	select AMBA_PL08X
+	select SAMSUNG_DMADEV
 
 config S3C64XX_SETUP_SDHCI
 	bool

+ 1 - 1
arch/arm/mach-s3c64xx/Makefile

@@ -26,7 +26,7 @@ obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
 # DMA support
 
-obj-$(CONFIG_S3C64XX_DMA)	+= dma.o
+obj-$(CONFIG_S3C64XX_PL080)	+= pl080.o
 
 # Device support
 

+ 5 - 0
arch/arm/mach-s3c64xx/common.h

@@ -58,4 +58,9 @@ int __init s3c64xx_pm_late_initcall(void);
 static inline int s3c64xx_pm_late_initcall(void) { return 0; }
 #endif
 
+#ifdef CONFIG_S3C64XX_PL080
+extern struct pl08x_platform_data s3c64xx_dma0_plat_data;
+extern struct pl08x_platform_data s3c64xx_dma1_plat_data;
+#endif
+
 #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */

+ 0 - 762
arch/arm/mach-s3c64xx/dma.c

@@ -1,762 +0,0 @@
-/* linux/arch/arm/plat-s3c64xx/dma.c
- *
- * Copyright 2009 Openmoko, Inc.
- * Copyright 2009 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *	http://armlinux.simtec.co.uk/
- *
- * S3C64XX DMA core
- *
- * 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.
-*/
-
-/*
- * NOTE: Code in this file is not used when booting with Device Tree support.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/dmapool.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/amba/pl080.h>
-#include <linux/of.h>
-
-#include <mach/dma.h>
-#include <mach/map.h>
-#include <mach/irqs.h>
-
-#include "regs-sys.h"
-
-/* dma channel state information */
-
-struct s3c64xx_dmac {
-	struct device		dev;
-	struct clk		*clk;
-	void __iomem		*regs;
-	struct s3c2410_dma_chan *channels;
-	enum dma_ch		 chanbase;
-};
-
-/* pool to provide LLI buffers */
-static struct dma_pool *dma_pool;
-
-/* Debug configuration and code */
-
-static unsigned char debug_show_buffs = 0;
-
-static void dbg_showchan(struct s3c2410_dma_chan *chan)
-{
-	pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n",
-		 chan->number,
-		 readl(chan->regs + PL080_CH_SRC_ADDR),
-		 readl(chan->regs + PL080_CH_DST_ADDR),
-		 readl(chan->regs + PL080_CH_LLI),
-		 readl(chan->regs + PL080_CH_CONTROL),
-		 readl(chan->regs + PL080S_CH_CONTROL2),
-		 readl(chan->regs + PL080S_CH_CONFIG));
-}
-
-static void show_lli(struct pl080s_lli *lli)
-{
-	pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n",
-		 lli, lli->src_addr, lli->dst_addr, lli->next_lli,
-		 lli->control0, lli->control1);
-}
-
-static void dbg_showbuffs(struct s3c2410_dma_chan *chan)
-{
-	struct s3c64xx_dma_buff *ptr;
-	struct s3c64xx_dma_buff *end;
-
-	pr_debug("DMA%d: buffs next %p, curr %p, end %p\n",
-		 chan->number, chan->next, chan->curr, chan->end);
-
-	ptr = chan->next;
-	end = chan->end;
-
-	if (debug_show_buffs) {
-		for (; ptr != NULL; ptr = ptr->next) {
-			pr_debug("DMA%d: %08x ",
-				 chan->number, ptr->lli_dma);
-			show_lli(ptr->lli);
-		}
-	}
-}
-
-/* End of Debug */
-
-static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel)
-{
-	struct s3c2410_dma_chan *chan;
-	unsigned int start, offs;
-
-	start = 0;
-
-	if (channel >= DMACH_PCM1_TX)
-		start = 8;
-
-	for (offs = 0; offs < 8; offs++) {
-		chan = &s3c2410_chans[start + offs];
-		if (!chan->in_use)
-			goto found;
-	}
-
-	return NULL;
-
-found:
-	s3c_dma_chan_map[channel] = chan;
-	return chan;
-}
-
-int s3c2410_dma_config(enum dma_ch channel, int xferunit)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	switch (xferunit) {
-	case 1:
-		chan->hw_width = 0;
-		break;
-	case 2:
-		chan->hw_width = 1;
-		break;
-	case 4:
-		chan->hw_width = 2;
-		break;
-	default:
-		printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_config);
-
-static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
-				 struct pl080s_lli *lli,
-				 dma_addr_t data, int size)
-{
-	dma_addr_t src, dst;
-	u32 control0, control1;
-
-	switch (chan->source) {
-	case DMA_FROM_DEVICE:
-		src = chan->dev_addr;
-		dst = data;
-		control0 = PL080_CONTROL_SRC_AHB2;
-		control0 |= PL080_CONTROL_DST_INCR;
-		break;
-
-	case DMA_TO_DEVICE:
-		src = data;
-		dst = chan->dev_addr;
-		control0 = PL080_CONTROL_DST_AHB2;
-		control0 |= PL080_CONTROL_SRC_INCR;
-		break;
-	default:
-		BUG();
-	}
-
-	/* note, we do not currently setup any of the burst controls */
-
-	control1 = size >> chan->hw_width;	/* size in no of xfers */
-	control0 |= PL080_CONTROL_PROT_SYS;	/* always in priv. mode */
-	control0 |= PL080_CONTROL_TC_IRQ_EN;	/* always fire IRQ */
-	control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
-	control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
-
-	lli->src_addr = src;
-	lli->dst_addr = dst;
-	lli->next_lli = 0;
-	lli->control0 = control0;
-	lli->control1 = control1;
-}
-
-static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan,
-				struct pl080s_lli *lli)
-{
-	void __iomem *regs = chan->regs;
-
-	pr_debug("%s: LLI %p => regs\n", __func__, lli);
-	show_lli(lli);
-
-	writel(lli->src_addr, regs + PL080_CH_SRC_ADDR);
-	writel(lli->dst_addr, regs + PL080_CH_DST_ADDR);
-	writel(lli->next_lli, regs + PL080_CH_LLI);
-	writel(lli->control0, regs + PL080_CH_CONTROL);
-	writel(lli->control1, regs + PL080S_CH_CONTROL2);
-}
-
-static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
-{
-	struct s3c64xx_dmac *dmac = chan->dmac;
-	u32 config;
-	u32 bit = chan->bit;
-
-	dbg_showchan(chan);
-
-	pr_debug("%s: clearing interrupts\n", __func__);
-
-	/* clear interrupts */
-	writel(bit, dmac->regs + PL080_TC_CLEAR);
-	writel(bit, dmac->regs + PL080_ERR_CLEAR);
-
-	pr_debug("%s: starting channel\n", __func__);
-
-	config = readl(chan->regs + PL080S_CH_CONFIG);
-	config |= PL080_CONFIG_ENABLE;
-	config &= ~PL080_CONFIG_HALT;
-
-	pr_debug("%s: writing config %08x\n", __func__, config);
-	writel(config, chan->regs + PL080S_CH_CONFIG);
-
-	return 0;
-}
-
-static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan)
-{
-	u32 config;
-	int timeout;
-
-	pr_debug("%s: stopping channel\n", __func__);
-
-	dbg_showchan(chan);
-
-	config = readl(chan->regs + PL080S_CH_CONFIG);
-	config |= PL080_CONFIG_HALT;
-	writel(config, chan->regs + PL080S_CH_CONFIG);
-
-	timeout = 1000;
-	do {
-		config = readl(chan->regs + PL080S_CH_CONFIG);
-		pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
-		if (config & PL080_CONFIG_ACTIVE)
-			udelay(10);
-		else
-			break;
-		} while (--timeout > 0);
-
-	if (config & PL080_CONFIG_ACTIVE) {
-		printk(KERN_ERR "%s: channel still active\n", __func__);
-		return -EFAULT;
-	}
-
-	config = readl(chan->regs + PL080S_CH_CONFIG);
-	config &= ~PL080_CONFIG_ENABLE;
-	writel(config, chan->regs + PL080S_CH_CONFIG);
-
-	return 0;
-}
-
-static inline void s3c64xx_dma_bufffdone(struct s3c2410_dma_chan *chan,
-					 struct s3c64xx_dma_buff *buf,
-					 enum s3c2410_dma_buffresult result)
-{
-	if (chan->callback_fn != NULL)
-		(chan->callback_fn)(chan, buf->pw, 0, result);
-}
-
-static void s3c64xx_dma_freebuff(struct s3c64xx_dma_buff *buff)
-{
-	dma_pool_free(dma_pool, buff->lli, buff->lli_dma);
-	kfree(buff);
-}
-
-static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan)
-{
-	struct s3c64xx_dma_buff *buff, *next;
-	u32 config;
-
-	dbg_showchan(chan);
-
-	pr_debug("%s: flushing channel\n", __func__);
-
-	config = readl(chan->regs + PL080S_CH_CONFIG);
-	config &= ~PL080_CONFIG_ENABLE;
-	writel(config, chan->regs + PL080S_CH_CONFIG);
-
-	/* dump all the buffers associated with this channel */
-
-	for (buff = chan->curr; buff != NULL; buff = next) {
-		next = buff->next;
-		pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next);
-
-		s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT);
-		s3c64xx_dma_freebuff(buff);
-	}
-
-	chan->curr = chan->next = chan->end = NULL;
-
-	return 0;
-}
-
-int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	WARN_ON(!chan);
-	if (!chan)
-		return -EINVAL;
-
-	switch (op) {
-	case S3C2410_DMAOP_START:
-		return s3c64xx_dma_start(chan);
-
-	case S3C2410_DMAOP_STOP:
-		return s3c64xx_dma_stop(chan);
-
-	case S3C2410_DMAOP_FLUSH:
-		return s3c64xx_dma_flush(chan);
-
-	/* believe PAUSE/RESUME are no-ops */
-	case S3C2410_DMAOP_PAUSE:
-	case S3C2410_DMAOP_RESUME:
-	case S3C2410_DMAOP_STARTED:
-	case S3C2410_DMAOP_TIMEOUT:
-		return 0;
-	}
-
-	return -ENOENT;
-}
-EXPORT_SYMBOL(s3c2410_dma_ctrl);
-
-/* s3c2410_dma_enque
- *
- */
-
-int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
-			dma_addr_t data, int size)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	struct s3c64xx_dma_buff *next;
-	struct s3c64xx_dma_buff *buff;
-	struct pl080s_lli *lli;
-	unsigned long flags;
-	int ret;
-
-	WARN_ON(!chan);
-	if (!chan)
-		return -EINVAL;
-
-	buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_ATOMIC);
-	if (!buff) {
-		printk(KERN_ERR "%s: no memory for buffer\n", __func__);
-		return -ENOMEM;
-	}
-
-	lli = dma_pool_alloc(dma_pool, GFP_ATOMIC, &buff->lli_dma);
-	if (!lli) {
-		printk(KERN_ERR "%s: no memory for lli\n", __func__);
-		ret = -ENOMEM;
-		goto err_buff;
-	}
-
-	pr_debug("%s: buff %p, dp %08x lli (%p, %08x) %d\n",
-		 __func__, buff, data, lli, (u32)buff->lli_dma, size);
-
-	buff->lli = lli;
-	buff->pw = id;
-
-	s3c64xx_dma_fill_lli(chan, lli, data, size);
-
-	local_irq_save(flags);
-
-	if ((next = chan->next) != NULL) {
-		struct s3c64xx_dma_buff *end = chan->end;
-		struct pl080s_lli *endlli = end->lli;
-
-		pr_debug("enquing onto channel\n");
-
-		end->next = buff;
-		endlli->next_lli = buff->lli_dma;
-
-		if (chan->flags & S3C2410_DMAF_CIRCULAR) {
-			struct s3c64xx_dma_buff *curr = chan->curr;
-			lli->next_lli = curr->lli_dma;
-		}
-
-		if (next == chan->curr) {
-			writel(buff->lli_dma, chan->regs + PL080_CH_LLI);
-			chan->next = buff;
-		}
-
-		show_lli(endlli);
-		chan->end = buff;
-	} else {
-		pr_debug("enquing onto empty channel\n");
-
-		chan->curr = buff;
-		chan->next = buff;
-		chan->end = buff;
-
-		s3c64xx_lli_to_regs(chan, lli);
-	}
-
-	local_irq_restore(flags);
-
-	show_lli(lli);
-
-	dbg_showchan(chan);
-	dbg_showbuffs(chan);
-	return 0;
-
-err_buff:
-	kfree(buff);
-	return ret;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_enqueue);
-
-
-int s3c2410_dma_devconfig(enum dma_ch channel,
-			  enum dma_data_direction source,
-			  unsigned long devaddr)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	u32 peripheral;
-	u32 config = 0;
-
-	pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n",
-		 __func__, channel, source, devaddr, chan);
-
-	WARN_ON(!chan);
-	if (!chan)
-		return -EINVAL;
-
-	peripheral = (chan->peripheral & 0xf);
-	chan->source = source;
-	chan->dev_addr = devaddr;
-
-	pr_debug("%s: peripheral %d\n", __func__, peripheral);
-
-	switch (source) {
-	case DMA_FROM_DEVICE:
-		config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
-		config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
-		break;
-	case DMA_TO_DEVICE:
-		config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
-		config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
-		break;
-	default:
-		printk(KERN_ERR "%s: bad source\n", __func__);
-		return -EINVAL;
-	}
-
-	/* allow TC and ERR interrupts */
-	config |= PL080_CONFIG_TC_IRQ_MASK;
-	config |= PL080_CONFIG_ERR_IRQ_MASK;
-
-	pr_debug("%s: config %08x\n", __func__, config);
-
-	writel(config, chan->regs + PL080S_CH_CONFIG);
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_devconfig);
-
-
-int s3c2410_dma_getposition(enum dma_ch channel,
-			    dma_addr_t *src, dma_addr_t *dst)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	WARN_ON(!chan);
-	if (!chan)
-		return -EINVAL;
-
-	if (src != NULL)
-		*src = readl(chan->regs + PL080_CH_SRC_ADDR);
-
-	if (dst != NULL)
-		*dst = readl(chan->regs + PL080_CH_DST_ADDR);
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_getposition);
-
-/* s3c2410_request_dma
- *
- * get control of an dma channel
-*/
-
-int s3c2410_dma_request(enum dma_ch channel,
-			struct s3c2410_dma_client *client,
-			void *dev)
-{
-	struct s3c2410_dma_chan *chan;
-	unsigned long flags;
-
-	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
-		 channel, client->name, dev);
-
-	local_irq_save(flags);
-
-	chan = s3c64xx_dma_map_channel(channel);
-	if (chan == NULL) {
-		local_irq_restore(flags);
-		return -EBUSY;
-	}
-
-	dbg_showchan(chan);
-
-	chan->client = client;
-	chan->in_use = 1;
-	chan->peripheral = channel;
-	chan->flags = 0;
-
-	local_irq_restore(flags);
-
-	/* need to setup */
-
-	pr_debug("%s: channel initialised, %p\n", __func__, chan);
-
-	return chan->number | DMACH_LOW_LEVEL;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_request);
-
-/* s3c2410_dma_free
- *
- * release the given channel back to the system, will stop and flush
- * any outstanding transfers, and ensure the channel is ready for the
- * next claimant.
- *
- * Note, although a warning is currently printed if the freeing client
- * info is not the same as the registrant's client info, the free is still
- * allowed to go through.
-*/
-
-int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	unsigned long flags;
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	local_irq_save(flags);
-
-	if (chan->client != client) {
-		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
-		       channel, chan->client, client);
-	}
-
-	/* sort out stopping and freeing the channel */
-
-
-	chan->client = NULL;
-	chan->in_use = 0;
-
-	if (!(channel & DMACH_LOW_LEVEL))
-		s3c_dma_chan_map[channel] = NULL;
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_free);
-
-static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
-{
-	struct s3c64xx_dmac *dmac = pw;
-	struct s3c2410_dma_chan *chan;
-	enum s3c2410_dma_buffresult res;
-	u32 tcstat, errstat;
-	u32 bit;
-	int offs;
-
-	tcstat = readl(dmac->regs + PL080_TC_STATUS);
-	errstat = readl(dmac->regs + PL080_ERR_STATUS);
-
-	for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
-		struct s3c64xx_dma_buff *buff;
-
-		if (!(errstat & bit) && !(tcstat & bit))
-			continue;
-
-		chan = dmac->channels + offs;
-		res = S3C2410_RES_ERR;
-
-		if (tcstat & bit) {
-			writel(bit, dmac->regs + PL080_TC_CLEAR);
-			res = S3C2410_RES_OK;
-		}
-
-		if (errstat & bit)
-			writel(bit, dmac->regs + PL080_ERR_CLEAR);
-
-		/* 'next' points to the buffer that is next to the
-		 * currently active buffer.
-		 * For CIRCULAR queues, 'next' will be same as 'curr'
-		 * when 'end' is the active buffer.
-		 */
-		buff = chan->curr;
-		while (buff && buff != chan->next
-				&& buff->next != chan->next)
-			buff = buff->next;
-
-		if (!buff)
-			BUG();
-
-		if (buff == chan->next)
-			buff = chan->end;
-
-		s3c64xx_dma_bufffdone(chan, buff, res);
-
-		/* Free the node and update curr, if non-circular queue */
-		if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) {
-			chan->curr = buff->next;
-			s3c64xx_dma_freebuff(buff);
-		}
-
-		/* Update 'next' */
-		buff = chan->next;
-		if (chan->next == chan->end) {
-			chan->next = chan->curr;
-			if (!(chan->flags & S3C2410_DMAF_CIRCULAR))
-				chan->end = NULL;
-		} else {
-			chan->next = buff->next;
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
-static struct bus_type dma_subsys = {
-	.name		= "s3c64xx-dma",
-	.dev_name	= "s3c64xx-dma",
-};
-
-static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
-			     int irq, unsigned int base)
-{
-	struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno];
-	struct s3c64xx_dmac *dmac;
-	char clkname[16];
-	void __iomem *regs;
-	void __iomem *regptr;
-	int err, ch;
-
-	dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL);
-	if (!dmac) {
-		printk(KERN_ERR "%s: failed to alloc mem\n", __func__);
-		return -ENOMEM;
-	}
-
-	dmac->dev.id = chno / 8;
-	dmac->dev.bus = &dma_subsys;
-
-	err = device_register(&dmac->dev);
-	if (err) {
-		printk(KERN_ERR "%s: failed to register device\n", __func__);
-		goto err_alloc;
-	}
-
-	regs = ioremap(base, 0x200);
-	if (!regs) {
-		printk(KERN_ERR "%s: failed to ioremap()\n", __func__);
-		err = -ENXIO;
-		goto err_dev;
-	}
-
-	snprintf(clkname, sizeof(clkname), "dma%d", dmac->dev.id);
-
-	dmac->clk = clk_get(NULL, clkname);
-	if (IS_ERR(dmac->clk)) {
-		printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname);
-		err = PTR_ERR(dmac->clk);
-		goto err_map;
-	}
-
-	clk_prepare_enable(dmac->clk);
-
-	dmac->regs = regs;
-	dmac->chanbase = chbase;
-	dmac->channels = chptr;
-
-	err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac);
-	if (err < 0) {
-		printk(KERN_ERR "%s: failed to get irq\n", __func__);
-		goto err_clk;
-	}
-
-	regptr = regs + PL080_Cx_BASE(0);
-
-	for (ch = 0; ch < 8; ch++, chptr++) {
-		pr_debug("%s: registering DMA %d (%p)\n",
-			 __func__, chno + ch, regptr);
-
-		chptr->bit = 1 << ch;
-		chptr->number = chno + ch;
-		chptr->dmac = dmac;
-		chptr->regs = regptr;
-		regptr += PL080_Cx_STRIDE;
-	}
-
-	/* for the moment, permanently enable the controller */
-	writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
-
-	printk(KERN_INFO "PL080: IRQ %d, at %p, channels %d..%d\n",
-	       irq, regs, chno, chno+8);
-
-	return 0;
-
-err_clk:
-	clk_disable_unprepare(dmac->clk);
-	clk_put(dmac->clk);
-err_map:
-	iounmap(regs);
-err_dev:
-	device_unregister(&dmac->dev);
-err_alloc:
-	kfree(dmac);
-	return err;
-}
-
-static int __init s3c64xx_dma_init(void)
-{
-	int ret;
-
-	/* This driver is not supported when booting with device tree. */
-	if (of_have_populated_dt())
-		return -ENODEV;
-
-	printk(KERN_INFO "%s: Registering DMA channels\n", __func__);
-
-	dma_pool = dma_pool_create("DMA-LLI", NULL, sizeof(struct pl080s_lli), 16, 0);
-	if (!dma_pool) {
-		printk(KERN_ERR "%s: failed to create pool\n", __func__);
-		return -ENOMEM;
-	}
-
-	ret = subsys_system_register(&dma_subsys, NULL);
-	if (ret) {
-		printk(KERN_ERR "%s: failed to create subsys\n", __func__);
-		return -ENOMEM;
-	}
-
-	/* Set all DMA configuration to be DMA, not SDMA */
-	writel(0xffffff, S3C64XX_SDMA_SEL);
-
-	/* Register standard DMA controllers */
-	s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000);
-	s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000);
-
-	return 0;
-}
-
-arch_initcall(s3c64xx_dma_init);

+ 42 - 102
arch/arm/mach-s3c64xx/include/mach/dma.h

@@ -11,51 +11,48 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
-#define S3C_DMA_CHANNELS	(16)
+#define S3C64XX_DMA_CHAN(name)		((unsigned long)(name))
+
+/* DMA0/SDMA0 */
+#define DMACH_UART0		S3C64XX_DMA_CHAN("uart0_tx")
+#define DMACH_UART0_SRC2	S3C64XX_DMA_CHAN("uart0_rx")
+#define DMACH_UART1		S3C64XX_DMA_CHAN("uart1_tx")
+#define DMACH_UART1_SRC2	S3C64XX_DMA_CHAN("uart1_rx")
+#define DMACH_UART2		S3C64XX_DMA_CHAN("uart2_tx")
+#define DMACH_UART2_SRC2	S3C64XX_DMA_CHAN("uart2_rx")
+#define DMACH_UART3		S3C64XX_DMA_CHAN("uart3_tx")
+#define DMACH_UART3_SRC2	S3C64XX_DMA_CHAN("uart3_rx")
+#define DMACH_PCM0_TX		S3C64XX_DMA_CHAN("pcm0_tx")
+#define DMACH_PCM0_RX		S3C64XX_DMA_CHAN("pcm0_rx")
+#define DMACH_I2S0_OUT		S3C64XX_DMA_CHAN("i2s0_tx")
+#define DMACH_I2S0_IN		S3C64XX_DMA_CHAN("i2s0_rx")
+#define DMACH_SPI0_TX		S3C64XX_DMA_CHAN("spi0_tx")
+#define DMACH_SPI0_RX		S3C64XX_DMA_CHAN("spi0_rx")
+#define DMACH_HSI_I2SV40_TX	S3C64XX_DMA_CHAN("i2s2_tx")
+#define DMACH_HSI_I2SV40_RX	S3C64XX_DMA_CHAN("i2s2_rx")
+
+/* DMA1/SDMA1 */
+#define DMACH_PCM1_TX		S3C64XX_DMA_CHAN("pcm1_tx")
+#define DMACH_PCM1_RX		S3C64XX_DMA_CHAN("pcm1_rx")
+#define DMACH_I2S1_OUT		S3C64XX_DMA_CHAN("i2s1_tx")
+#define DMACH_I2S1_IN		S3C64XX_DMA_CHAN("i2s1_rx")
+#define DMACH_SPI1_TX		S3C64XX_DMA_CHAN("spi1_tx")
+#define DMACH_SPI1_RX		S3C64XX_DMA_CHAN("spi1_rx")
+#define DMACH_AC97_PCMOUT	S3C64XX_DMA_CHAN("ac97_out")
+#define DMACH_AC97_PCMIN	S3C64XX_DMA_CHAN("ac97_in")
+#define DMACH_AC97_MICIN	S3C64XX_DMA_CHAN("ac97_mic")
+#define DMACH_PWM		S3C64XX_DMA_CHAN("pwm")
+#define DMACH_IRDA		S3C64XX_DMA_CHAN("irda")
+#define DMACH_EXTERNAL		S3C64XX_DMA_CHAN("external")
+#define DMACH_SECURITY_RX	S3C64XX_DMA_CHAN("sec_rx")
+#define DMACH_SECURITY_TX	S3C64XX_DMA_CHAN("sec_tx")
 
-/* see mach-s3c2410/dma.h for notes on dma channel numbers */
-
-/* Note, for the S3C64XX architecture we keep the DMACH_
- * defines in the order they are allocated to [S]DMA0/[S]DMA1
- * so that is easy to do DHACH_ -> DMA controller conversion
- */
 enum dma_ch {
-	/* DMA0/SDMA0 */
-	DMACH_UART0 = 0,
-	DMACH_UART0_SRC2,
-	DMACH_UART1,
-	DMACH_UART1_SRC2,
-	DMACH_UART2,
-	DMACH_UART2_SRC2,
-	DMACH_UART3,
-	DMACH_UART3_SRC2,
-	DMACH_PCM0_TX,
-	DMACH_PCM0_RX,
-	DMACH_I2S0_OUT,
-	DMACH_I2S0_IN,
-	DMACH_SPI0_TX,
-	DMACH_SPI0_RX,
-	DMACH_HSI_I2SV40_TX,
-	DMACH_HSI_I2SV40_RX,
+	DMACH_MAX = 32
+};
 
-	/* DMA1/SDMA1 */
-	DMACH_PCM1_TX = 16,
-	DMACH_PCM1_RX,
-	DMACH_I2S1_OUT,
-	DMACH_I2S1_IN,
-	DMACH_SPI1_TX,
-	DMACH_SPI1_RX,
-	DMACH_AC97_PCMOUT,
-	DMACH_AC97_PCMIN,
-	DMACH_AC97_MICIN,
-	DMACH_PWM,
-	DMACH_IRDA,
-	DMACH_EXTERNAL,
-	DMACH_RES1,
-	DMACH_RES2,
-	DMACH_SECURITY_RX,	/* SDMA1 only */
-	DMACH_SECURITY_TX,	/* SDMA1 only */
-	DMACH_MAX		/* the end */
+struct s3c2410_dma_client {
+	char	*name;
 };
 
 static inline bool samsung_dma_has_circular(void)
@@ -65,67 +62,10 @@ static inline bool samsung_dma_has_circular(void)
 
 static inline bool samsung_dma_is_dmadev(void)
 {
-	return false;
+	return true;
 }
-#define S3C2410_DMAF_CIRCULAR		(1 << 0)
-
-#include <plat/dma.h>
-
-#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
-
-struct s3c64xx_dma_buff;
-
-/** s3c64xx_dma_buff - S3C64XX DMA buffer descriptor
- * @next: Pointer to next buffer in queue or ring.
- * @pw: Client provided identifier
- * @lli: Pointer to hardware descriptor this buffer is associated with.
- * @lli_dma: Hardare address of the descriptor.
- */
-struct s3c64xx_dma_buff {
-	struct s3c64xx_dma_buff *next;
-
-	void			*pw;
-	struct pl080s_lli	*lli;
-	dma_addr_t		 lli_dma;
-};
-
-struct s3c64xx_dmac;
-
-struct s3c2410_dma_chan {
-	unsigned char		 number;      /* number of this dma channel */
-	unsigned char		 in_use;      /* channel allocated */
-	unsigned char		 bit;	      /* bit for enable/disable/etc */
-	unsigned char		 hw_width;
-	unsigned char		 peripheral;
-
-	unsigned int		 flags;
-	enum dma_data_direction	 source;
-
-
-	dma_addr_t		dev_addr;
-
-	struct s3c2410_dma_client *client;
-	struct s3c64xx_dmac	*dmac;		/* pointer to controller */
-
-	void __iomem		*regs;
-
-	/* cdriver callbacks */
-	s3c2410_dma_cbfn_t	 callback_fn;	/* buffer done callback */
-	s3c2410_dma_opfn_t	 op_fn;		/* channel op callback */
-
-	/* buffer list and information */
-	struct s3c64xx_dma_buff	*curr;		/* current dma buffer */
-	struct s3c64xx_dma_buff	*next;		/* next buffer to load */
-	struct s3c64xx_dma_buff	*end;		/* end of queue */
-
-	/* note, when channel is running in circular mode, curr is the
-	 * first buffer enqueued, end is the last and curr is where the
-	 * last buffer-done event is set-at. The buffers are not freed
-	 * and the last buffer hardware descriptor points back to the
-	 * first.
-	 */
-};
 
-#include <plat/dma-core.h>
+#include <linux/amba/pl08x.h>
+#include <plat/dma-ops.h>
 
 #endif /* __ASM_ARCH_IRQ_H */

+ 244 - 0
arch/arm/mach-s3c64xx/pl080.c

@@ -0,0 +1,244 @@
+/*
+ * Samsung's S3C64XX generic DMA support using amba-pl08x driver.
+ *
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.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/kernel.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl080.h>
+#include <linux/amba/pl08x.h>
+#include <linux/of.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include "regs-sys.h"
+
+static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd)
+{
+	return cd->min_signal;
+}
+
+static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch)
+{
+}
+
+/*
+ * DMA0
+ */
+
+static struct pl08x_channel_data s3c64xx_dma0_info[] = {
+	{
+		.bus_id = "uart0_tx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart0_rx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart1_tx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart1_rx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart2_tx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart2_rx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart3_tx",
+		.min_signal = 6,
+		.max_signal = 6,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "uart3_rx",
+		.min_signal = 7,
+		.max_signal = 7,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "pcm0_tx",
+		.min_signal = 8,
+		.max_signal = 8,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "pcm0_rx",
+		.min_signal = 9,
+		.max_signal = 9,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s0_tx",
+		.min_signal = 10,
+		.max_signal = 10,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s0_rx",
+		.min_signal = 11,
+		.max_signal = 11,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "spi0_tx",
+		.min_signal = 12,
+		.max_signal = 12,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "spi0_rx",
+		.min_signal = 13,
+		.max_signal = 13,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s2_tx",
+		.min_signal = 14,
+		.max_signal = 14,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s2_rx",
+		.min_signal = 15,
+		.max_signal = 15,
+		.periph_buses = PL08X_AHB2,
+	}
+};
+
+struct pl08x_platform_data s3c64xx_dma0_plat_data = {
+	.memcpy_channel = {
+		.bus_id = "memcpy",
+		.cctl_memcpy =
+			(PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT |
+			PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT |
+			PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT |
+			PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT |
+			PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE |
+			PL080_CONTROL_PROT_SYS),
+	},
+	.lli_buses = PL08X_AHB1,
+	.mem_buses = PL08X_AHB1,
+	.get_xfer_signal = pl08x_get_xfer_signal,
+	.put_xfer_signal = pl08x_put_xfer_signal,
+	.slave_channels = s3c64xx_dma0_info,
+	.num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info),
+};
+
+static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0,
+			0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data);
+
+/*
+ * DMA1
+ */
+
+static struct pl08x_channel_data s3c64xx_dma1_info[] = {
+	{
+		.bus_id = "pcm1_tx",
+		.min_signal = 0,
+		.max_signal = 0,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "pcm1_rx",
+		.min_signal = 1,
+		.max_signal = 1,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s1_tx",
+		.min_signal = 2,
+		.max_signal = 2,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "i2s1_rx",
+		.min_signal = 3,
+		.max_signal = 3,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "spi1_tx",
+		.min_signal = 4,
+		.max_signal = 4,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "spi1_rx",
+		.min_signal = 5,
+		.max_signal = 5,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ac97_out",
+		.min_signal = 6,
+		.max_signal = 6,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ac97_in",
+		.min_signal = 7,
+		.max_signal = 7,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "ac97_mic",
+		.min_signal = 8,
+		.max_signal = 8,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "pwm",
+		.min_signal = 9,
+		.max_signal = 9,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "irda",
+		.min_signal = 10,
+		.max_signal = 10,
+		.periph_buses = PL08X_AHB2,
+	}, {
+		.bus_id = "external",
+		.min_signal = 11,
+		.max_signal = 11,
+		.periph_buses = PL08X_AHB2,
+	},
+};
+
+struct pl08x_platform_data s3c64xx_dma1_plat_data = {
+	.memcpy_channel = {
+		.bus_id = "memcpy",
+		.cctl_memcpy =
+			(PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT |
+			PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT |
+			PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT |
+			PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT |
+			PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE |
+			PL080_CONTROL_PROT_SYS),
+	},
+	.lli_buses = PL08X_AHB1,
+	.mem_buses = PL08X_AHB1,
+	.get_xfer_signal = pl08x_get_xfer_signal,
+	.put_xfer_signal = pl08x_put_xfer_signal,
+	.slave_channels = s3c64xx_dma1_info,
+	.num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info),
+};
+
+static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0,
+			0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data);
+
+static int __init s3c64xx_pl080_init(void)
+{
+	/* Set all DMA configuration to be DMA, not SDMA */
+	writel(0xffffff, S3C64XX_SDMA_SEL);
+
+	if (of_have_populated_dt())
+		return 0;
+
+	amba_device_register(&s3c64xx_dma0_device, &iomem_resource);
+	amba_device_register(&s3c64xx_dma1_device, &iomem_resource);
+
+	return 0;
+}
+arch_initcall(s3c64xx_pl080_init);

+ 8 - 2
arch/arm/plat-samsung/devs.c

@@ -1468,6 +1468,8 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
 #if defined(CONFIG_PL330_DMA)
 	pd.filter = pl330_filter;
+#elif defined(CONFIG_S3C64XX_PL080)
+	pd.filter = pl08x_filter_id;
 #elif defined(CONFIG_S3C24XX_DMAC)
 	pd.filter = s3c24xx_dma_filter;
 #endif
@@ -1509,8 +1511,10 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA)
 	pd.filter = pl330_filter;
+#elif defined(CONFIG_S3C64XX_PL080)
+	pd.filter = pl08x_filter_id;
 #endif
 
 	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
@@ -1550,8 +1554,10 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA)
 	pd.filter = pl330_filter;
+#elif defined(CONFIG_S3C64XX_PL080)
+	pd.filter = pl08x_filter_id;
 #endif
 
 	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);

+ 7 - 1
arch/arm/plat-samsung/dma-ops.c

@@ -18,6 +18,12 @@
 
 #include <mach/dma.h>
 
+#if defined(CONFIG_PL330_DMA)
+#define dma_filter pl330_filter
+#elif defined(CONFIG_S3C64XX_PL080)
+#define dma_filter pl08x_filter_id
+#endif
+
 static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
 				struct samsung_dma_req *param,
 				struct device *dev, char *ch_name)
@@ -30,7 +36,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
 	if (dev->of_node)
 		return (unsigned)dma_request_slave_channel(dev, ch_name);
 	else
-		return (unsigned)dma_request_channel(mask, pl330_filter,
+		return (unsigned)dma_request_channel(mask, dma_filter,
 							(void *)dma_ch);
 }
 

+ 2 - 2
drivers/clk/samsung/clk-s3c64xx.c

@@ -331,8 +331,8 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
 	ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
 	ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
 	ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
-	ALIAS(HCLK_DMA1, NULL, "dma1"),
-	ALIAS(HCLK_DMA0, NULL, "dma0"),
+	ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"),
+	ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"),
 	ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
 	ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
 	ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"),

+ 89 - 3
drivers/mfd/twl6040.c

@@ -44,6 +44,54 @@
 #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
 #define TWL6040_NUM_SUPPLIES	(2)
 
+static struct reg_default twl6040_defaults[] = {
+	{ 0x01, 0x4B }, /* REG_ASICID	(ro) */
+	{ 0x02, 0x00 }, /* REG_ASICREV	(ro) */
+	{ 0x03, 0x00 }, /* REG_INTID	*/
+	{ 0x04, 0x00 }, /* REG_INTMR	*/
+	{ 0x05, 0x00 }, /* REG_NCPCTRL	*/
+	{ 0x06, 0x00 }, /* REG_LDOCTL	*/
+	{ 0x07, 0x60 }, /* REG_HPPLLCTL	*/
+	{ 0x08, 0x00 }, /* REG_LPPLLCTL	*/
+	{ 0x09, 0x4A }, /* REG_LPPLLDIV	*/
+	{ 0x0A, 0x00 }, /* REG_AMICBCTL	*/
+	{ 0x0B, 0x00 }, /* REG_DMICBCTL	*/
+	{ 0x0C, 0x00 }, /* REG_MICLCTL	*/
+	{ 0x0D, 0x00 }, /* REG_MICRCTL	*/
+	{ 0x0E, 0x00 }, /* REG_MICGAIN	*/
+	{ 0x0F, 0x1B }, /* REG_LINEGAIN	*/
+	{ 0x10, 0x00 }, /* REG_HSLCTL	*/
+	{ 0x11, 0x00 }, /* REG_HSRCTL	*/
+	{ 0x12, 0x00 }, /* REG_HSGAIN	*/
+	{ 0x13, 0x00 }, /* REG_EARCTL	*/
+	{ 0x14, 0x00 }, /* REG_HFLCTL	*/
+	{ 0x15, 0x00 }, /* REG_HFLGAIN	*/
+	{ 0x16, 0x00 }, /* REG_HFRCTL	*/
+	{ 0x17, 0x00 }, /* REG_HFRGAIN	*/
+	{ 0x18, 0x00 }, /* REG_VIBCTLL	*/
+	{ 0x19, 0x00 }, /* REG_VIBDATL	*/
+	{ 0x1A, 0x00 }, /* REG_VIBCTLR	*/
+	{ 0x1B, 0x00 }, /* REG_VIBDATR	*/
+	{ 0x1C, 0x00 }, /* REG_HKCTL1	*/
+	{ 0x1D, 0x00 }, /* REG_HKCTL2	*/
+	{ 0x1E, 0x00 }, /* REG_GPOCTL	*/
+	{ 0x1F, 0x00 }, /* REG_ALB	*/
+	{ 0x20, 0x00 }, /* REG_DLB	*/
+	/* 0x28, REG_TRIM1 */
+	/* 0x29, REG_TRIM2 */
+	/* 0x2A, REG_TRIM3 */
+	/* 0x2B, REG_HSOTRIM */
+	/* 0x2C, REG_HFOTRIM */
+	{ 0x2D, 0x08 }, /* REG_ACCCTL	*/
+	{ 0x2E, 0x00 }, /* REG_STATUS	(ro) */
+};
+
+struct reg_default twl6040_patch[] = {
+	/* Select I2C bus access to dual access registers */
+	{ TWL6040_REG_ACCCTL, 0x09 },
+};
+
+
 static bool twl6040_has_vibra(struct device_node *node)
 {
 #ifdef CONFIG_OF
@@ -238,6 +286,9 @@ int twl6040_power(struct twl6040 *twl6040, int on)
 		if (twl6040->power_count++)
 			goto out;
 
+		/* Allow writes to the chip */
+		regcache_cache_only(twl6040->regmap, false);
+
 		if (gpio_is_valid(twl6040->audpwron)) {
 			/* use automatic power-up sequence */
 			ret = twl6040_power_up_automatic(twl6040);
@@ -253,6 +304,10 @@ int twl6040_power(struct twl6040 *twl6040, int on)
 				goto out;
 			}
 		}
+
+		/* Sync with the HW */
+		regcache_sync(twl6040->regmap);
+
 		/* Default PLL configuration after power up */
 		twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
 		twl6040->sysclk = 19200000;
@@ -279,6 +334,11 @@ int twl6040_power(struct twl6040 *twl6040, int on)
 			/* use manual power-down sequence */
 			twl6040_power_down_manual(twl6040);
 		}
+
+		/* Set regmap to cache only and mark it as dirty */
+		regcache_cache_only(twl6040->regmap, true);
+		regcache_mark_dirty(twl6040->regmap);
+
 		twl6040->sysclk = 0;
 		twl6040->mclk = 0;
 	}
@@ -490,9 +550,24 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg)
 static bool twl6040_volatile_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
-	case TWL6040_REG_VIBCTLL:
-	case TWL6040_REG_VIBCTLR:
-	case TWL6040_REG_INTMR:
+	case TWL6040_REG_ASICID:
+	case TWL6040_REG_ASICREV:
+	case TWL6040_REG_INTID:
+	case TWL6040_REG_LPPLLCTL:
+	case TWL6040_REG_HPPLLCTL:
+	case TWL6040_REG_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool twl6040_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TWL6040_REG_ASICID:
+	case TWL6040_REG_ASICREV:
+	case TWL6040_REG_STATUS:
 		return false;
 	default:
 		return true;
@@ -502,10 +577,15 @@ static bool twl6040_volatile_reg(struct device *dev, unsigned int reg)
 static struct regmap_config twl6040_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
+
+	.reg_defaults = twl6040_defaults,
+	.num_reg_defaults = ARRAY_SIZE(twl6040_defaults),
+
 	.max_register = TWL6040_REG_STATUS, /* 0x2e */
 
 	.readable_reg = twl6040_readable_reg,
 	.volatile_reg = twl6040_volatile_reg,
+	.writeable_reg = twl6040_writeable_reg,
 
 	.cache_type = REGCACHE_RBTREE,
 };
@@ -624,6 +704,8 @@ static int twl6040_probe(struct i2c_client *client,
 
 	/* dual-access registers controlled by I2C only */
 	twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);
+	regmap_register_patch(twl6040->regmap, twl6040_patch,
+			      ARRAY_SIZE(twl6040_patch));
 
 	/*
 	 * The main functionality of twl6040 to provide audio on OMAP4+ systems.
@@ -656,6 +738,10 @@ static int twl6040_probe(struct i2c_client *client,
 	cell->name = "twl6040-gpo";
 	children++;
 
+	/* The chip is powered down so mark regmap to cache only and dirty */
+	regcache_cache_only(twl6040->regmap, true);
+	regcache_mark_dirty(twl6040->regmap);
+
 	ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children,
 			      NULL, 0, NULL);
 	if (ret)

+ 135 - 4
drivers/mfd/wm5110-tables.c

@@ -14,6 +14,7 @@
 
 #include <linux/mfd/arizona/core.h>
 #include <linux/mfd/arizona/registers.h>
+#include <linux/device.h>
 
 #include "arizona.h"
 
@@ -524,6 +525,7 @@ static const struct reg_default wm5110_reg_default[] = {
 	{ 0x00000300, 0x0000 },    /* R768   - Input Enables */
 	{ 0x00000308, 0x0000 },    /* R776   - Input Rate */
 	{ 0x00000309, 0x0022 },    /* R777   - Input Volume Ramp */
+	{ 0x0000030C, 0x0002 },    /* R780   - HPF Control */
 	{ 0x00000310, 0x2080 },    /* R784   - IN1L Control */
 	{ 0x00000311, 0x0180 },    /* R785   - ADC Digital Volume 1L */
 	{ 0x00000312, 0x0000 },    /* R786   - DMIC1L Control */
@@ -545,6 +547,7 @@ static const struct reg_default wm5110_reg_default[] = {
 	{ 0x00000328, 0x2000 },    /* R808   - IN4L Control */
 	{ 0x00000329, 0x0180 },    /* R809   - ADC Digital Volume 4L */
 	{ 0x0000032A, 0x0000 },    /* R810   - DMIC4L Control */
+	{ 0x0000032C, 0x0000 },    /* R812   - IN4R Control */
 	{ 0x0000032D, 0x0180 },    /* R813   - ADC Digital Volume 4R */
 	{ 0x0000032E, 0x0000 },    /* R814   - DMIC4R Control */
 	{ 0x00000400, 0x0000 },    /* R1024  - Output Enables 1 */
@@ -598,6 +601,7 @@ static const struct reg_default wm5110_reg_default[] = {
 	{ 0x0000043D, 0x0180 },    /* R1085  - DAC Digital Volume 6R */
 	{ 0x0000043E, 0x0080 },    /* R1086  - DAC Volume Limit 6R */
 	{ 0x0000043F, 0x0800 },    /* R1087  - Noise Gate Select 6R */
+	{ 0x00000440, 0x8FFF },    /* R1088  - DRE Enable */
 	{ 0x00000450, 0x0000 },    /* R1104  - DAC AEC Control 1 */
 	{ 0x00000458, 0x0000 },    /* R1112  - Noise Gate Control */
 	{ 0x00000480, 0x0040 },    /* R1152  - Class W ANC Threshold 1 */
@@ -882,6 +886,38 @@ static const struct reg_default wm5110_reg_default[] = {
 	{ 0x0000074D, 0x0080 },    /* R1869  - AIF2TX2MIX Input 3 Volume */
 	{ 0x0000074E, 0x0000 },    /* R1870  - AIF2TX2MIX Input 4 Source */
 	{ 0x0000074F, 0x0080 },    /* R1871  - AIF2TX2MIX Input 4 Volume */
+	{ 0x00000750, 0x0000 },    /* R1872  - AIF2TX3MIX Input 1 Source */
+	{ 0x00000751, 0x0080 },    /* R1873  - AIF2TX3MIX Input 1 Volume */
+	{ 0x00000752, 0x0000 },    /* R1874  - AIF2TX3MIX Input 2 Source */
+	{ 0x00000753, 0x0080 },    /* R1875  - AIF2TX3MIX Input 2 Volume */
+	{ 0x00000754, 0x0000 },    /* R1876  - AIF2TX3MIX Input 3 Source */
+	{ 0x00000755, 0x0080 },    /* R1877  - AIF2TX3MIX Input 3 Volume */
+	{ 0x00000756, 0x0000 },    /* R1878  - AIF2TX3MIX Input 4 Source */
+	{ 0x00000757, 0x0080 },    /* R1879  - AIF2TX3MIX Input 4 Volume */
+	{ 0x00000758, 0x0000 },    /* R1880  - AIF2TX4MIX Input 1 Source */
+	{ 0x00000759, 0x0080 },    /* R1881  - AIF2TX4MIX Input 1 Volume */
+	{ 0x0000075A, 0x0000 },    /* R1882  - AIF2TX4MIX Input 2 Source */
+	{ 0x0000075B, 0x0080 },    /* R1883  - AIF2TX4MIX Input 2 Volume */
+	{ 0x0000075C, 0x0000 },    /* R1884  - AIF2TX4MIX Input 3 Source */
+	{ 0x0000075D, 0x0080 },    /* R1885  - AIF2TX4MIX Input 3 Volume */
+	{ 0x0000075E, 0x0000 },    /* R1886  - AIF2TX4MIX Input 4 Source */
+	{ 0x0000075F, 0x0080 },    /* R1887  - AIF2TX4MIX Input 4 Volume */
+	{ 0x00000760, 0x0000 },    /* R1888  - AIF2TX5MIX Input 1 Source */
+	{ 0x00000761, 0x0080 },    /* R1889  - AIF2TX5MIX Input 1 Volume */
+	{ 0x00000762, 0x0000 },    /* R1890  - AIF2TX5MIX Input 2 Source */
+	{ 0x00000763, 0x0080 },    /* R1891  - AIF2TX5MIX Input 2 Volume */
+	{ 0x00000764, 0x0000 },    /* R1892  - AIF2TX5MIX Input 3 Source */
+	{ 0x00000765, 0x0080 },    /* R1893  - AIF2TX5MIX Input 3 Volume */
+	{ 0x00000766, 0x0000 },    /* R1894  - AIF2TX5MIX Input 4 Source */
+	{ 0x00000767, 0x0080 },    /* R1895  - AIF2TX5MIX Input 4 Volume */
+	{ 0x00000768, 0x0000 },    /* R1896  - AIF2TX6MIX Input 1 Source */
+	{ 0x00000769, 0x0080 },    /* R1897  - AIF2TX6MIX Input 1 Volume */
+	{ 0x0000076A, 0x0000 },    /* R1898  - AIF2TX6MIX Input 2 Source */
+	{ 0x0000076B, 0x0080 },    /* R1899  - AIF2TX6MIX Input 2 Volume */
+	{ 0x0000076C, 0x0000 },    /* R1900  - AIF2TX6MIX Input 3 Source */
+	{ 0x0000076D, 0x0080 },    /* R1901  - AIF2TX6MIX Input 3 Volume */
+	{ 0x0000076E, 0x0000 },    /* R1902  - AIF2TX6MIX Input 4 Source */
+	{ 0x0000076F, 0x0080 },    /* R1903  - AIF2TX6MIX Input 4 Volume */
 	{ 0x00000780, 0x0000 },    /* R1920  - AIF3TX1MIX Input 1 Source */
 	{ 0x00000781, 0x0080 },    /* R1921  - AIF3TX1MIX Input 1 Volume */
 	{ 0x00000782, 0x0000 },    /* R1922  - AIF3TX1MIX Input 2 Source */
@@ -1342,6 +1378,64 @@ static const struct reg_default wm5110_reg_default[] = {
 	{ 0x00001404, 0x0000 },    /* R5124  - DSP4 Status 1 */
 };
 
+static bool wm5110_is_rev_b_adsp_memory(unsigned int reg)
+{
+	if ((reg >= 0x100000 && reg < 0x103000) ||
+	    (reg >= 0x180000 && reg < 0x181000) ||
+	    (reg >= 0x190000 && reg < 0x192000) ||
+	    (reg >= 0x1a8000 && reg < 0x1a9000) ||
+	    (reg >= 0x200000 && reg < 0x209000) ||
+	    (reg >= 0x280000 && reg < 0x281000) ||
+	    (reg >= 0x290000 && reg < 0x29a000) ||
+	    (reg >= 0x2a8000 && reg < 0x2aa000) ||
+	    (reg >= 0x300000 && reg < 0x30f000) ||
+	    (reg >= 0x380000 && reg < 0x382000) ||
+	    (reg >= 0x390000 && reg < 0x39e000) ||
+	    (reg >= 0x3a8000 && reg < 0x3b6000) ||
+	    (reg >= 0x400000 && reg < 0x403000) ||
+	    (reg >= 0x480000 && reg < 0x481000) ||
+	    (reg >= 0x490000 && reg < 0x492000) ||
+	    (reg >= 0x4a8000 && reg < 0x4a9000))
+		return true;
+	else
+		return false;
+}
+
+static bool wm5110_is_rev_d_adsp_memory(unsigned int reg)
+{
+	if ((reg >= 0x100000 && reg < 0x106000) ||
+	    (reg >= 0x180000 && reg < 0x182000) ||
+	    (reg >= 0x190000 && reg < 0x198000) ||
+	    (reg >= 0x1a8000 && reg < 0x1aa000) ||
+	    (reg >= 0x200000 && reg < 0x20f000) ||
+	    (reg >= 0x280000 && reg < 0x282000) ||
+	    (reg >= 0x290000 && reg < 0x29c000) ||
+	    (reg >= 0x2a6000 && reg < 0x2b4000) ||
+	    (reg >= 0x300000 && reg < 0x30f000) ||
+	    (reg >= 0x380000 && reg < 0x382000) ||
+	    (reg >= 0x390000 && reg < 0x3a2000) ||
+	    (reg >= 0x3a6000 && reg < 0x3b4000) ||
+	    (reg >= 0x400000 && reg < 0x406000) ||
+	    (reg >= 0x480000 && reg < 0x482000) ||
+	    (reg >= 0x490000 && reg < 0x498000) ||
+	    (reg >= 0x4a8000 && reg < 0x4aa000))
+		return true;
+	else
+		return false;
+}
+
+static bool wm5110_is_adsp_memory(struct device *dev, unsigned int reg)
+{
+	struct arizona *arizona = dev_get_drvdata(dev);
+
+	switch (arizona->rev) {
+	case 0 ... 2:
+		return wm5110_is_rev_b_adsp_memory(reg);
+	default:
+		return wm5110_is_rev_d_adsp_memory(reg);
+	}
+}
+
 static bool wm5110_readable_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -1460,6 +1554,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_INPUT_ENABLES_STATUS:
 	case ARIZONA_INPUT_RATE:
 	case ARIZONA_INPUT_VOLUME_RAMP:
+	case ARIZONA_HPF_CONTROL:
 	case ARIZONA_IN1L_CONTROL:
 	case ARIZONA_ADC_DIGITAL_VOLUME_1L:
 	case ARIZONA_DMIC1L_CONTROL:
@@ -1481,6 +1576,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_IN4L_CONTROL:
 	case ARIZONA_ADC_DIGITAL_VOLUME_4L:
 	case ARIZONA_DMIC4L_CONTROL:
+	case ARIZONA_IN4R_CONTROL:
 	case ARIZONA_ADC_DIGITAL_VOLUME_4R:
 	case ARIZONA_DMIC4R_CONTROL:
 	case ARIZONA_OUTPUT_ENABLES_1:
@@ -1536,6 +1632,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_DAC_DIGITAL_VOLUME_6R:
 	case ARIZONA_DAC_VOLUME_LIMIT_6R:
 	case ARIZONA_NOISE_GATE_SELECT_6R:
+	case ARIZONA_DRE_ENABLE:
 	case ARIZONA_DAC_AEC_CONTROL_1:
 	case ARIZONA_NOISE_GATE_CONTROL:
 	case ARIZONA_PDM_SPK1_CTRL_1:
@@ -1820,6 +1917,38 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
 	case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
 	case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
+	case ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE:
+	case ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME:
+	case ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE:
+	case ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME:
+	case ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE:
+	case ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME:
+	case ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE:
+	case ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME:
+	case ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE:
+	case ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME:
+	case ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE:
+	case ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME:
+	case ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE:
+	case ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME:
+	case ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE:
+	case ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME:
+	case ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE:
+	case ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME:
+	case ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE:
+	case ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME:
+	case ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE:
+	case ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME:
+	case ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE:
+	case ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME:
+	case ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE:
+	case ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME:
+	case ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE:
+	case ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME:
+	case ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE:
+	case ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME:
+	case ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE:
+	case ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME:
 	case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE:
 	case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME:
 	case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE:
@@ -2331,7 +2460,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
 	case ARIZONA_DSP4_SCRATCH_3:
 		return true;
 	default:
-		return false;
+		return wm5110_is_adsp_memory(dev, reg);
 	}
 }
 
@@ -2407,16 +2536,18 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
 	case ARIZONA_DSP4_SCRATCH_3:
 		return true;
 	default:
-		return false;
+		return wm5110_is_adsp_memory(dev, reg);
 	}
 }
 
+#define WM5110_MAX_REGISTER 0x4a9fff
+
 const struct regmap_config wm5110_spi_regmap = {
 	.reg_bits = 32,
 	.pad_bits = 16,
 	.val_bits = 16,
 
-	.max_register = ARIZONA_DSP1_STATUS_2,
+	.max_register = WM5110_MAX_REGISTER,
 	.readable_reg = wm5110_readable_register,
 	.volatile_reg = wm5110_volatile_register,
 
@@ -2430,7 +2561,7 @@ const struct regmap_config wm5110_i2c_regmap = {
 	.reg_bits = 32,
 	.val_bits = 16,
 
-	.max_register = ARIZONA_DSP1_STATUS_2,
+	.max_register = WM5110_MAX_REGISTER,
 	.readable_reg = wm5110_readable_register,
 	.volatile_reg = wm5110_volatile_register,
 

+ 1 - 1
drivers/spi/Kconfig

@@ -395,7 +395,7 @@ config SPI_S3C24XX_FIQ
 config SPI_S3C64XX
 	tristate "Samsung S3C64XX series type SPI"
 	depends on PLAT_SAMSUNG
-	select S3C64XX_DMA if ARCH_S3C64XX
+	select S3C64XX_PL080 if ARCH_S3C64XX
 	help
 	  SPI driver for Samsung S3C64XX and newer SoCs.
 

+ 162 - 0
include/linux/mfd/arizona/registers.h

@@ -139,6 +139,7 @@
 #define ARIZONA_INPUT_ENABLES_STATUS             0x301
 #define ARIZONA_INPUT_RATE                       0x308
 #define ARIZONA_INPUT_VOLUME_RAMP                0x309
+#define ARIZONA_HPF_CONTROL                      0x30C
 #define ARIZONA_IN1L_CONTROL                     0x310
 #define ARIZONA_ADC_DIGITAL_VOLUME_1L            0x311
 #define ARIZONA_DMIC1L_CONTROL                   0x312
@@ -160,6 +161,7 @@
 #define ARIZONA_IN4L_CONTROL                     0x328
 #define ARIZONA_ADC_DIGITAL_VOLUME_4L            0x329
 #define ARIZONA_DMIC4L_CONTROL                   0x32A
+#define ARIZONA_IN4R_CONTROL                     0x32C
 #define ARIZONA_ADC_DIGITAL_VOLUME_4R            0x32D
 #define ARIZONA_DMIC4R_CONTROL                   0x32E
 #define ARIZONA_OUTPUT_ENABLES_1                 0x400
@@ -511,6 +513,38 @@
 #define ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME        0x74D
 #define ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE        0x74E
 #define ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME        0x74F
+#define ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE        0x750
+#define ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME        0x751
+#define ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE        0x752
+#define ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME        0x753
+#define ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE        0x754
+#define ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME        0x755
+#define ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE        0x756
+#define ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME        0x757
+#define ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE        0x758
+#define ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME        0x759
+#define ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE        0x75A
+#define ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME        0x75B
+#define ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE        0x75C
+#define ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME        0x75D
+#define ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE        0x75E
+#define ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME        0x75F
+#define ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE        0x760
+#define ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME        0x761
+#define ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE        0x762
+#define ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME        0x763
+#define ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE        0x764
+#define ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME        0x765
+#define ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE        0x766
+#define ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME        0x767
+#define ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE        0x768
+#define ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME        0x769
+#define ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE        0x76A
+#define ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME        0x76B
+#define ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE        0x76C
+#define ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME        0x76D
+#define ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE        0x76E
+#define ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME        0x76F
 #define ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE        0x780
 #define ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME        0x781
 #define ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE        0x782
@@ -2292,9 +2326,19 @@
 #define ARIZONA_IN_VI_RAMP_SHIFT                      0  /* IN_VI_RAMP - [2:0] */
 #define ARIZONA_IN_VI_RAMP_WIDTH                      3  /* IN_VI_RAMP - [2:0] */
 
+/*
+ * R780 (0x30C) - HPF Control
+ */
+#define ARIZONA_IN_HPF_CUT_MASK                  0x0007  /* IN_HPF_CUT [2:0] */
+#define ARIZONA_IN_HPF_CUT_SHIFT                      0  /* IN_HPF_CUT [2:0] */
+#define ARIZONA_IN_HPF_CUT_WIDTH                      3  /* IN_HPF_CUT [2:0] */
+
 /*
  * R784 (0x310) - IN1L Control
  */
+#define ARIZONA_IN1L_HPF_MASK                    0x8000  /* IN1L_HPF - [15] */
+#define ARIZONA_IN1L_HPF_SHIFT                       15  /* IN1L_HPF - [15] */
+#define ARIZONA_IN1L_HPF_WIDTH                        1  /* IN1L_HPF - [15] */
 #define ARIZONA_IN1_OSR_MASK                     0x6000  /* IN1_OSR - [14:13] */
 #define ARIZONA_IN1_OSR_SHIFT                        13  /* IN1_OSR - [14:13] */
 #define ARIZONA_IN1_OSR_WIDTH                         2  /* IN1_OSR - [14:13] */
@@ -2333,6 +2377,9 @@
 /*
  * R788 (0x314) - IN1R Control
  */
+#define ARIZONA_IN1R_HPF_MASK                    0x8000  /* IN1R_HPF - [15] */
+#define ARIZONA_IN1R_HPF_SHIFT                       15  /* IN1R_HPF - [15] */
+#define ARIZONA_IN1R_HPF_WIDTH                        1  /* IN1R_HPF - [15] */
 #define ARIZONA_IN1R_PGA_VOL_MASK                0x00FE  /* IN1R_PGA_VOL - [7:1] */
 #define ARIZONA_IN1R_PGA_VOL_SHIFT                    1  /* IN1R_PGA_VOL - [7:1] */
 #define ARIZONA_IN1R_PGA_VOL_WIDTH                    7  /* IN1R_PGA_VOL - [7:1] */
@@ -2362,6 +2409,9 @@
 /*
  * R792 (0x318) - IN2L Control
  */
+#define ARIZONA_IN2L_HPF_MASK                    0x8000  /* IN2L_HPF - [15] */
+#define ARIZONA_IN2L_HPF_SHIFT                       15  /* IN2L_HPF - [15] */
+#define ARIZONA_IN2L_HPF_WIDTH                        1  /* IN2L_HPF - [15] */
 #define ARIZONA_IN2_OSR_MASK                     0x6000  /* IN2_OSR - [14:13] */
 #define ARIZONA_IN2_OSR_SHIFT                        13  /* IN2_OSR - [14:13] */
 #define ARIZONA_IN2_OSR_WIDTH                         2  /* IN2_OSR - [14:13] */
@@ -2400,6 +2450,9 @@
 /*
  * R796 (0x31C) - IN2R Control
  */
+#define ARIZONA_IN2R_HPF_MASK                    0x8000  /* IN2R_HPF - [15] */
+#define ARIZONA_IN2R_HPF_SHIFT                       15  /* IN2R_HPF - [15] */
+#define ARIZONA_IN2R_HPF_WIDTH                        1  /* IN2R_HPF - [15] */
 #define ARIZONA_IN2R_PGA_VOL_MASK                0x00FE  /* IN2R_PGA_VOL - [7:1] */
 #define ARIZONA_IN2R_PGA_VOL_SHIFT                    1  /* IN2R_PGA_VOL - [7:1] */
 #define ARIZONA_IN2R_PGA_VOL_WIDTH                    7  /* IN2R_PGA_VOL - [7:1] */
@@ -2429,6 +2482,9 @@
 /*
  * R800 (0x320) - IN3L Control
  */
+#define ARIZONA_IN3L_HPF_MASK                    0x8000  /* IN3L_HPF - [15] */
+#define ARIZONA_IN3L_HPF_SHIFT                       15  /* IN3L_HPF - [15] */
+#define ARIZONA_IN3L_HPF_WIDTH                        1  /* IN3L_HPF - [15] */
 #define ARIZONA_IN3_OSR_MASK                     0x6000  /* IN3_OSR - [14:13] */
 #define ARIZONA_IN3_OSR_SHIFT                        13  /* IN3_OSR - [14:13] */
 #define ARIZONA_IN3_OSR_WIDTH                         2  /* IN3_OSR - [14:13] */
@@ -2467,6 +2523,9 @@
 /*
  * R804 (0x324) - IN3R Control
  */
+#define ARIZONA_IN3R_HPF_MASK                    0x8000  /* IN3R_HPF - [15] */
+#define ARIZONA_IN3R_HPF_SHIFT                       15  /* IN3R_HPF - [15] */
+#define ARIZONA_IN3R_HPF_WIDTH                        1  /* IN3R_HPF - [15] */
 #define ARIZONA_IN3R_PGA_VOL_MASK                0x00FE  /* IN3R_PGA_VOL - [7:1] */
 #define ARIZONA_IN3R_PGA_VOL_SHIFT                    1  /* IN3R_PGA_VOL - [7:1] */
 #define ARIZONA_IN3R_PGA_VOL_WIDTH                    7  /* IN3R_PGA_VOL - [7:1] */
@@ -2496,6 +2555,9 @@
 /*
  * R808 (0x328) - IN4 Control
  */
+#define ARIZONA_IN4L_HPF_MASK                    0x8000  /* IN4L_HPF - [15] */
+#define ARIZONA_IN4L_HPF_SHIFT                       15  /* IN4L_HPF - [15] */
+#define ARIZONA_IN4L_HPF_WIDTH                        1  /* IN4L_HPF - [15] */
 #define ARIZONA_IN4_OSR_MASK                     0x6000  /* IN4_OSR - [14:13] */
 #define ARIZONA_IN4_OSR_SHIFT                        13  /* IN4_OSR - [14:13] */
 #define ARIZONA_IN4_OSR_WIDTH                         2  /* IN4_OSR - [14:13] */
@@ -2525,6 +2587,13 @@
 #define ARIZONA_IN4L_DMIC_DLY_SHIFT                   0  /* IN4L_DMIC_DLY - [5:0] */
 #define ARIZONA_IN4L_DMIC_DLY_WIDTH                   6  /* IN4L_DMIC_DLY - [5:0] */
 
+/*
+ * R812 (0x32C) - IN4R Control
+ */
+#define ARIZONA_IN4R_HPF_MASK                    0x8000  /* IN4R_HPF - [15] */
+#define ARIZONA_IN4R_HPF_SHIFT                       15  /* IN4R_HPF - [15] */
+#define ARIZONA_IN4R_HPF_WIDTH                        1  /* IN4R_HPF - [15] */
+
 /*
  * R813 (0x32D) - ADC Digital Volume 4R
  */
@@ -3138,6 +3207,10 @@
 /*
  * R1088 (0x440) - DRE Enable
  */
+#define ARIZONA_DRE3R_ENA                        0x0020  /* DRE3R_ENA */
+#define ARIZONA_DRE3R_ENA_MASK                   0x0020  /* DRE3R_ENA */
+#define ARIZONA_DRE3R_ENA_SHIFT                       5  /* DRE3R_ENA */
+#define ARIZONA_DRE3R_ENA_WIDTH                       1  /* DRE3R_ENA */
 #define ARIZONA_DRE3L_ENA                        0x0010  /* DRE3L_ENA */
 #define ARIZONA_DRE3L_ENA_MASK                   0x0010  /* DRE3L_ENA */
 #define ARIZONA_DRE3L_ENA_SHIFT                       4  /* DRE3L_ENA */
@@ -3725,6 +3798,35 @@
 #define ARIZONA_AIF2TX2_SLOT_SHIFT                    0  /* AIF2TX2_SLOT - [5:0] */
 #define ARIZONA_AIF2TX2_SLOT_WIDTH                    6  /* AIF2TX2_SLOT - [5:0] */
 
+/*
+ * R1355 (0x54B) - AIF2 Frame Ctrl 5
+ */
+#define ARIZONA_AIF2TX3_SLOT_MASK                0x003F  /* AIF2TX3_SLOT - [5:0] */
+#define ARIZONA_AIF2TX3_SLOT_SHIFT                    0  /* AIF2TX3_SLOT - [5:0] */
+#define ARIZONA_AIF2TX3_SLOT_WIDTH                    6  /* AIF2TX3_SLOT - [5:0] */
+
+/*
+ * R1356 (0x54C) - AIF2 Frame Ctrl 6
+ */
+#define ARIZONA_AIF2TX4_SLOT_MASK                0x003F  /* AIF2TX4_SLOT - [5:0] */
+#define ARIZONA_AIF2TX4_SLOT_SHIFT                    0  /* AIF2TX4_SLOT - [5:0] */
+#define ARIZONA_AIF2TX4_SLOT_WIDTH                    6  /* AIF2TX4_SLOT - [5:0] */
+
+
+/*
+ * R1357 (0x54D) - AIF2 Frame Ctrl 7
+ */
+#define ARIZONA_AIF2TX5_SLOT_MASK                0x003F  /* AIF2TX5_SLOT - [5:0] */
+#define ARIZONA_AIF2TX5_SLOT_SHIFT                    0  /* AIF2TX5_SLOT - [5:0] */
+#define ARIZONA_AIF2TX5_SLOT_WIDTH                    6  /* AIF2TX5_SLOT - [5:0] */
+
+/*
+ * R1358 (0x54E) - AIF2 Frame Ctrl 8
+ */
+#define ARIZONA_AIF2TX6_SLOT_MASK                0x003F  /* AIF2TX6_SLOT - [5:0] */
+#define ARIZONA_AIF2TX6_SLOT_SHIFT                    0  /* AIF2TX6_SLOT - [5:0] */
+#define ARIZONA_AIF2TX6_SLOT_WIDTH                    6  /* AIF2TX6_SLOT - [5:0] */
+
 /*
  * R1361 (0x551) - AIF2 Frame Ctrl 11
  */
@@ -3739,9 +3841,53 @@
 #define ARIZONA_AIF2RX2_SLOT_SHIFT                    0  /* AIF2RX2_SLOT - [5:0] */
 #define ARIZONA_AIF2RX2_SLOT_WIDTH                    6  /* AIF2RX2_SLOT - [5:0] */
 
+/*
+ * R1363 (0x553) - AIF2 Frame Ctrl 13
+ */
+#define ARIZONA_AIF2RX3_SLOT_MASK                0x003F  /* AIF2RX3_SLOT - [5:0] */
+#define ARIZONA_AIF2RX3_SLOT_SHIFT                    0  /* AIF2RX3_SLOT - [5:0] */
+#define ARIZONA_AIF2RX3_SLOT_WIDTH                    6  /* AIF2RX3_SLOT - [5:0] */
+
+/*
+ * R1364 (0x554) - AIF2 Frame Ctrl 14
+ */
+#define ARIZONA_AIF2RX4_SLOT_MASK                0x003F  /* AIF2RX4_SLOT - [5:0] */
+#define ARIZONA_AIF2RX4_SLOT_SHIFT                    0  /* AIF2RX4_SLOT - [5:0] */
+#define ARIZONA_AIF2RX4_SLOT_WIDTH                    6  /* AIF2RX4_SLOT - [5:0] */
+
+/*
+ * R1365 (0x555) - AIF2 Frame Ctrl 15
+ */
+#define ARIZONA_AIF2RX5_SLOT_MASK                0x003F  /* AIF2RX5_SLOT - [5:0] */
+#define ARIZONA_AIF2RX5_SLOT_SHIFT                    0  /* AIF2RX5_SLOT - [5:0] */
+#define ARIZONA_AIF2RX5_SLOT_WIDTH                    6  /* AIF2RX5_SLOT - [5:0] */
+
+/*
+ * R1366 (0x556) - AIF2 Frame Ctrl 16
+ */
+#define ARIZONA_AIF2RX6_SLOT_MASK                0x003F  /* AIF2RX6_SLOT - [5:0] */
+#define ARIZONA_AIF2RX6_SLOT_SHIFT                    0  /* AIF2RX6_SLOT - [5:0] */
+#define ARIZONA_AIF2RX6_SLOT_WIDTH                    6  /* AIF2RX6_SLOT - [5:0] */
+
 /*
  * R1369 (0x559) - AIF2 Tx Enables
  */
+#define ARIZONA_AIF2TX6_ENA                      0x0020  /* AIF2TX6_ENA */
+#define ARIZONA_AIF2TX6_ENA_MASK                 0x0020  /* AIF2TX6_ENA */
+#define ARIZONA_AIF2TX6_ENA_SHIFT                     5  /* AIF2TX6_ENA */
+#define ARIZONA_AIF2TX6_ENA_WIDTH                     1  /* AIF2TX6_ENA */
+#define ARIZONA_AIF2TX5_ENA                      0x0010  /* AIF2TX5_ENA */
+#define ARIZONA_AIF2TX5_ENA_MASK                 0x0010  /* AIF2TX5_ENA */
+#define ARIZONA_AIF2TX5_ENA_SHIFT                     4  /* AIF2TX5_ENA */
+#define ARIZONA_AIF2TX5_ENA_WIDTH                     1  /* AIF2TX5_ENA */
+#define ARIZONA_AIF2TX4_ENA                      0x0008  /* AIF2TX4_ENA */
+#define ARIZONA_AIF2TX4_ENA_MASK                 0x0008  /* AIF2TX4_ENA */
+#define ARIZONA_AIF2TX4_ENA_SHIFT                     3  /* AIF2TX4_ENA */
+#define ARIZONA_AIF2TX4_ENA_WIDTH                     1  /* AIF2TX4_ENA */
+#define ARIZONA_AIF2TX3_ENA                      0x0004  /* AIF2TX3_ENA */
+#define ARIZONA_AIF2TX3_ENA_MASK                 0x0004  /* AIF2TX3_ENA */
+#define ARIZONA_AIF2TX3_ENA_SHIFT                     2  /* AIF2TX3_ENA */
+#define ARIZONA_AIF2TX3_ENA_WIDTH                     1  /* AIF2TX3_ENA */
 #define ARIZONA_AIF2TX2_ENA                      0x0002  /* AIF2TX2_ENA */
 #define ARIZONA_AIF2TX2_ENA_MASK                 0x0002  /* AIF2TX2_ENA */
 #define ARIZONA_AIF2TX2_ENA_SHIFT                     1  /* AIF2TX2_ENA */
@@ -3754,6 +3900,22 @@
 /*
  * R1370 (0x55A) - AIF2 Rx Enables
  */
+#define ARIZONA_AIF2RX6_ENA                      0x0020  /* AIF2RX6_ENA */
+#define ARIZONA_AIF2RX6_ENA_MASK                 0x0020  /* AIF2RX6_ENA */
+#define ARIZONA_AIF2RX6_ENA_SHIFT                     5  /* AIF2RX6_ENA */
+#define ARIZONA_AIF2RX6_ENA_WIDTH                     1  /* AIF2RX6_ENA */
+#define ARIZONA_AIF2RX5_ENA                      0x0010  /* AIF2RX5_ENA */
+#define ARIZONA_AIF2RX5_ENA_MASK                 0x0010  /* AIF2RX5_ENA */
+#define ARIZONA_AIF2RX5_ENA_SHIFT                     4  /* AIF2RX5_ENA */
+#define ARIZONA_AIF2RX5_ENA_WIDTH                     1  /* AIF2RX5_ENA */
+#define ARIZONA_AIF2RX4_ENA                      0x0008  /* AIF2RX4_ENA */
+#define ARIZONA_AIF2RX4_ENA_MASK                 0x0008  /* AIF2RX4_ENA */
+#define ARIZONA_AIF2RX4_ENA_SHIFT                     3  /* AIF2RX4_ENA */
+#define ARIZONA_AIF2RX4_ENA_WIDTH                     1  /* AIF2RX4_ENA */
+#define ARIZONA_AIF2RX3_ENA                      0x0004  /* AIF2RX3_ENA */
+#define ARIZONA_AIF2RX3_ENA_MASK                 0x0004  /* AIF2RX3_ENA */
+#define ARIZONA_AIF2RX3_ENA_SHIFT                     2  /* AIF2RX3_ENA */
+#define ARIZONA_AIF2RX3_ENA_WIDTH                     1  /* AIF2RX3_ENA */
 #define ARIZONA_AIF2RX2_ENA                      0x0002  /* AIF2RX2_ENA */
 #define ARIZONA_AIF2RX2_ENA_MASK                 0x0002  /* AIF2RX2_ENA */
 #define ARIZONA_AIF2RX2_ENA_SHIFT                     1  /* AIF2RX2_ENA */

+ 2 - 4
include/linux/platform_data/asoc-ti-mcbsp.h

@@ -1,6 +1,4 @@
 /*
- * arch/arm/plat-omap/include/mach/mcbsp.h
- *
  * Defines for Multi-Channel Buffered Serial Port
  *
  * Copyright (C) 2002 RidgeRun, Inc.
@@ -21,8 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#ifndef __ASM_ARCH_OMAP_MCBSP_H
-#define __ASM_ARCH_OMAP_MCBSP_H
+#ifndef __ASOC_TI_MCBSP_H
+#define __ASOC_TI_MCBSP_H
 
 #include <linux/spinlock.h>
 #include <linux/clk.h>

+ 1 - 0
include/linux/platform_data/davinci_asp.h

@@ -92,6 +92,7 @@ enum {
 	MCASP_VERSION_1 = 0,	/* DM646x */
 	MCASP_VERSION_2,	/* DA8xx/OMAPL1x */
 	MCASP_VERSION_3,        /* TI81xx/AM33xx */
+	MCASP_VERSION_4,	/* DRA7xxx */
 };
 
 enum mcbsp_clk_input_pin {

+ 4 - 10
include/sound/cs42l52.h

@@ -16,17 +16,11 @@ struct cs42l52_platform_data {
 	/* MICBIAS Level. Check datasheet Pg48 */
 	unsigned int micbias_lvl;
 
-	/* MICA mode selection 0=Single 1=Differential */
-	unsigned int mica_cfg;
+	/* MICA mode selection Differential or Single-ended */
+	bool mica_diff_cfg;
 
-	/* MICB mode selection 0=Single 1=Differential */
-	unsigned int micb_cfg;
-
-	/* MICA Select 0=MIC1A 1=MIC2A */
-	unsigned int mica_sel;
-
-	/* MICB Select 0=MIC2A 1=MIC2B */
-	unsigned int micb_sel;
+	/* MICB mode selection Differential or Single-ended */
+	bool micb_diff_cfg;
 
 	/* Charge Pump Freq. Check datasheet Pg73 */
 	unsigned int chgfreq;

+ 12 - 0
include/sound/pcm_params.h

@@ -354,4 +354,16 @@ params_period_bytes(const struct snd_pcm_hw_params *p)
 		params_channels(p)) / 8;
 }
 
+static inline int
+params_width(const struct snd_pcm_hw_params *p)
+{
+	return snd_pcm_format_width(params_format(p));
+}
+
+static inline int
+params_physical_width(const struct snd_pcm_hw_params *p)
+{
+	return snd_pcm_format_physical_width(params_format(p));
+}
+
 #endif /* __SOUND_PCM_PARAMS_H */

+ 2 - 1
include/sound/rcar_snd.h

@@ -18,7 +18,7 @@
 #define RSND_GEN1_ADG	1
 #define RSND_GEN1_SSI	2
 
-#define RSND_GEN2_SRU	0
+#define RSND_GEN2_SCU	0
 #define RSND_GEN2_ADG	1
 #define RSND_GEN2_SSIU	2
 #define RSND_GEN2_SSI	3
@@ -58,6 +58,7 @@ struct rsnd_ssi_platform_info {
 
 struct rsnd_scu_platform_info {
 	u32 flags;
+	u32 convert_rate; /* sampling rate convert */
 };
 
 /*

+ 11 - 4
include/sound/soc.h

@@ -334,9 +334,7 @@ struct snd_soc_jack_pin;
 #include <sound/soc-dapm.h>
 #include <sound/soc-dpcm.h>
 
-#ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
-#endif
 
 typedef int (*hw_write_t)(void *,const char* ,int);
 
@@ -446,6 +444,17 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 			struct snd_soc_jack_gpio *gpios);
 void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
 			struct snd_soc_jack_gpio *gpios);
+#else
+static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
+					 struct snd_soc_jack_gpio *gpios)
+{
+	return 0;
+}
+
+static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+					   struct snd_soc_jack_gpio *gpios)
+{
+}
 #endif
 
 /* codec register bit access */
@@ -580,7 +589,6 @@ struct snd_soc_jack_zone {
  *		       to provide more complex checks (eg, reading an
  *		       ADC).
  */
-#ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio {
 	unsigned int gpio;
 	const char *name;
@@ -594,7 +602,6 @@ struct snd_soc_jack_gpio {
 
 	int (*jack_status_check)(void);
 };
-#endif
 
 struct snd_soc_jack {
 	struct mutex mutex;

+ 0 - 1
include/sound/spear_dma.h

@@ -29,7 +29,6 @@ struct spear_dma_data {
 	dma_addr_t addr;
 	u32 max_burst;
 	enum dma_slave_buswidth addr_width;
-	bool (*filter)(struct dma_chan *chan, void *slave);
 };
 
 #endif /* SPEAR_DMA_H */

+ 3 - 1
sound/soc/Kconfig

@@ -31,8 +31,10 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
 	select SND_DMAENGINE_PCM
 
 # All the supported SoCs
+source "sound/soc/adi/Kconfig"
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
+source "sound/soc/bcm/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/cirrus/Kconfig"
 source "sound/soc/davinci/Kconfig"
@@ -42,7 +44,7 @@ source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
-source "sound/soc/mid-x86/Kconfig"
+source "sound/soc/intel/Kconfig"
 source "sound/soc/mxs/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/samsung/Kconfig"

+ 3 - 1
sound/soc/Makefile

@@ -8,15 +8,17 @@ endif
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= generic/
+obj-$(CONFIG_SND_SOC)	+= adi/
 obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
+obj-$(CONFIG_SND_SOC)	+= bcm/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= cirrus/
 obj-$(CONFIG_SND_SOC)	+= davinci/
 obj-$(CONFIG_SND_SOC)	+= dwc/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
-obj-$(CONFIG_SND_SOC)	+= mid-x86/
+obj-$(CONFIG_SND_SOC)	+= intel/
 obj-$(CONFIG_SND_SOC)	+= mxs/
 obj-$(CONFIG_SND_SOC)	+= nuc900/
 obj-$(CONFIG_SND_SOC)	+= omap/

+ 21 - 0
sound/soc/adi/Kconfig

@@ -0,0 +1,21 @@
+config SND_SOC_ADI
+	tristate "Audio support for Analog Devices reference designs"
+	depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST
+	help
+	  Audio support for various reference designs by Analog Devices.
+
+config SND_SOC_ADI_AXI_I2S
+	tristate "AXI-I2S support"
+	depends on SND_SOC_ADI
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select REGMAP_MMIO
+	help
+	  ASoC driver for the Analog Devices AXI-I2S softcore peripheral.
+
+config SND_SOC_ADI_AXI_SPDIF
+	tristate "AXI-SPDIF support"
+	depends on SND_SOC_ADI
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select REGMAP_MMIO
+	help
+	  ASoC driver for the Analog Devices AXI-SPDIF softcore peripheral.

+ 5 - 0
sound/soc/adi/Makefile

@@ -0,0 +1,5 @@
+snd-soc-adi-axi-i2s-objs := axi-i2s.o
+snd-soc-adi-axi-spdif-objs := axi-spdif.o
+
+obj-$(CONFIG_SND_SOC_ADI_AXI_I2S) += snd-soc-adi-axi-i2s.o
+obj-$(CONFIG_SND_SOC_ADI_AXI_SPDIF) += snd-soc-adi-axi-spdif.o

+ 277 - 0
sound/soc/adi/axi-i2s.c

@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2012-2013, Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#define AXI_I2S_REG_RESET	0x00
+#define AXI_I2S_REG_CTRL	0x04
+#define AXI_I2S_REG_CLK_CTRL	0x08
+#define AXI_I2S_REG_STATUS	0x10
+
+#define AXI_I2S_REG_RX_FIFO	0x28
+#define AXI_I2S_REG_TX_FIFO	0x2C
+
+#define AXI_I2S_RESET_GLOBAL	BIT(0)
+#define AXI_I2S_RESET_TX_FIFO	BIT(1)
+#define AXI_I2S_RESET_RX_FIFO	BIT(2)
+
+#define AXI_I2S_CTRL_TX_EN	BIT(0)
+#define AXI_I2S_CTRL_RX_EN	BIT(1)
+
+/* The frame size is configurable, but for now we always set it 64 bit */
+#define AXI_I2S_BITS_PER_FRAME 64
+
+struct axi_i2s {
+	struct regmap *regmap;
+	struct clk *clk;
+	struct clk *clk_ref;
+
+	struct snd_soc_dai_driver dai_driver;
+
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
+	struct snd_dmaengine_dai_dma_data playback_dma_data;
+
+	struct snd_ratnum ratnum;
+	struct snd_pcm_hw_constraint_ratnums rate_constraints;
+};
+
+static int axi_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+	struct snd_soc_dai *dai)
+{
+	struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		mask = AXI_I2S_CTRL_RX_EN;
+	else
+		mask = AXI_I2S_CTRL_TX_EN;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		val = mask;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, AXI_I2S_REG_CTRL, mask, val);
+
+	return 0;
+}
+
+static int axi_i2s_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int bclk_div, word_size;
+	unsigned int bclk_rate;
+
+	bclk_rate = params_rate(params) * AXI_I2S_BITS_PER_FRAME;
+
+	word_size = AXI_I2S_BITS_PER_FRAME / 2 - 1;
+	bclk_div = DIV_ROUND_UP(clk_get_rate(i2s->clk_ref), bclk_rate) / 2 - 1;
+
+	regmap_write(i2s->regmap, AXI_I2S_REG_CLK_CTRL, (word_size << 16) |
+		bclk_div);
+
+	return 0;
+}
+
+static int axi_i2s_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	uint32_t mask;
+	int ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		mask = AXI_I2S_RESET_RX_FIFO;
+	else
+		mask = AXI_I2S_RESET_TX_FIFO;
+
+	regmap_write(i2s->regmap, AXI_I2S_REG_RESET, mask);
+
+	ret = snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+			   SNDRV_PCM_HW_PARAM_RATE,
+			   &i2s->rate_constraints);
+	if (ret)
+		return ret;
+
+	return clk_prepare_enable(i2s->clk_ref);
+}
+
+static void axi_i2s_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	clk_disable_unprepare(i2s->clk_ref);
+}
+
+static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+	struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
+		&i2s->capture_dma_data);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
+	.startup = axi_i2s_startup,
+	.shutdown = axi_i2s_shutdown,
+	.trigger = axi_i2s_trigger,
+	.hw_params = axi_i2s_hw_params,
+};
+
+static struct snd_soc_dai_driver axi_i2s_dai = {
+	.probe = axi_i2s_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
+	},
+	.ops = &axi_i2s_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver axi_i2s_component = {
+	.name = "axi-i2s",
+};
+
+static const struct regmap_config axi_i2s_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = AXI_I2S_REG_STATUS,
+};
+
+static int axi_i2s_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct axi_i2s *i2s;
+	void __iomem *base;
+	int ret;
+
+	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, i2s);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+		&axi_i2s_regmap_config);
+	if (IS_ERR(i2s->regmap))
+		return PTR_ERR(i2s->regmap);
+
+	i2s->clk = devm_clk_get(&pdev->dev, "axi");
+	if (IS_ERR(i2s->clk))
+		return PTR_ERR(i2s->clk);
+
+	i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
+	if (IS_ERR(i2s->clk_ref))
+		return PTR_ERR(i2s->clk_ref);
+
+	ret = clk_prepare_enable(i2s->clk);
+	if (ret)
+		return ret;
+
+	i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO;
+	i2s->playback_dma_data.addr_width = 4;
+	i2s->playback_dma_data.maxburst = 1;
+
+	i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO;
+	i2s->capture_dma_data.addr_width = 4;
+	i2s->capture_dma_data.maxburst = 1;
+
+	i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME;
+	i2s->ratnum.den_step = 1;
+	i2s->ratnum.den_min = 1;
+	i2s->ratnum.den_max = 64;
+
+	i2s->rate_constraints.rats = &i2s->ratnum;
+	i2s->rate_constraints.nrats = 1;
+
+	regmap_write(i2s->regmap, AXI_I2S_REG_RESET, AXI_I2S_RESET_GLOBAL);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &axi_i2s_component,
+					 &axi_i2s_dai, 1);
+	if (ret)
+		goto err_clk_disable;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+			SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+	if (ret)
+		goto err_clk_disable;
+
+err_clk_disable:
+	clk_disable_unprepare(i2s->clk);
+	return ret;
+}
+
+static int axi_i2s_dev_remove(struct platform_device *pdev)
+{
+	struct axi_i2s *i2s = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(i2s->clk);
+
+	return 0;
+}
+
+static const struct of_device_id axi_i2s_of_match[] = {
+	{ .compatible = "adi,axi-i2s-1.00.a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, axi_i2s_of_match);
+
+static struct platform_driver axi_i2s_driver = {
+	.driver = {
+		.name = "axi-i2s",
+		.owner = THIS_MODULE,
+		.of_match_table = axi_i2s_of_match,
+	},
+	.probe = axi_i2s_probe,
+	.remove = axi_i2s_dev_remove,
+};
+module_platform_driver(axi_i2s_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("AXI I2S driver");
+MODULE_LICENSE("GPL");

+ 272 - 0
sound/soc/adi/axi-spdif.c

@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2012-2013, Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+#define AXI_SPDIF_REG_CTRL	0x0
+#define AXI_SPDIF_REG_STAT	0x4
+#define AXI_SPDIF_REG_TX_FIFO	0xc
+
+#define AXI_SPDIF_CTRL_TXDATA BIT(1)
+#define AXI_SPDIF_CTRL_TXEN BIT(0)
+#define AXI_SPDIF_CTRL_CLKDIV_OFFSET 8
+#define AXI_SPDIF_CTRL_CLKDIV_MASK (0xff << 8)
+
+#define AXI_SPDIF_FREQ_44100	(0x0 << 6)
+#define AXI_SPDIF_FREQ_48000	(0x1 << 6)
+#define AXI_SPDIF_FREQ_32000	(0x2 << 6)
+#define AXI_SPDIF_FREQ_NA	(0x3 << 6)
+
+struct axi_spdif {
+	struct regmap *regmap;
+	struct clk *clk;
+	struct clk *clk_ref;
+
+	struct snd_dmaengine_dai_dma_data dma_data;
+
+	struct snd_ratnum ratnum;
+	struct snd_pcm_hw_constraint_ratnums rate_constraints;
+};
+
+static int axi_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+	struct snd_soc_dai *dai)
+{
+	struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+	unsigned int val;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		val = AXI_SPDIF_CTRL_TXDATA;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+		AXI_SPDIF_CTRL_TXDATA, val);
+
+	return 0;
+}
+
+static int axi_spdif_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate = params_rate(params);
+	unsigned int clkdiv, stat;
+
+	switch (params_rate(params)) {
+	case 32000:
+		stat = AXI_SPDIF_FREQ_32000;
+		break;
+	case 44100:
+		stat = AXI_SPDIF_FREQ_44100;
+		break;
+	case 48000:
+		stat = AXI_SPDIF_FREQ_48000;
+		break;
+	default:
+		stat = AXI_SPDIF_FREQ_NA;
+		break;
+	}
+
+	clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(spdif->clk_ref),
+			rate * 64 * 2) - 1;
+	clkdiv <<= AXI_SPDIF_CTRL_CLKDIV_OFFSET;
+
+	regmap_write(spdif->regmap, AXI_SPDIF_REG_STAT, stat);
+	regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+		AXI_SPDIF_CTRL_CLKDIV_MASK, clkdiv);
+
+	return 0;
+}
+
+static int axi_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
+
+	return 0;
+}
+
+static int axi_spdif_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+	int ret;
+
+	ret = snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+			   SNDRV_PCM_HW_PARAM_RATE,
+			   &spdif->rate_constraints);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(spdif->clk_ref);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+		AXI_SPDIF_CTRL_TXEN, AXI_SPDIF_CTRL_TXEN);
+
+	return 0;
+}
+
+static void axi_spdif_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+	regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+		AXI_SPDIF_CTRL_TXEN, 0);
+
+	clk_disable_unprepare(spdif->clk_ref);
+}
+
+static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
+	.startup = axi_spdif_startup,
+	.shutdown = axi_spdif_shutdown,
+	.trigger = axi_spdif_trigger,
+	.hw_params = axi_spdif_hw_params,
+};
+
+static struct snd_soc_dai_driver axi_spdif_dai = {
+	.probe = axi_spdif_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &axi_spdif_dai_ops,
+};
+
+static const struct snd_soc_component_driver axi_spdif_component = {
+	.name = "axi-spdif",
+};
+
+static const struct regmap_config axi_spdif_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = AXI_SPDIF_REG_STAT,
+};
+
+static int axi_spdif_probe(struct platform_device *pdev)
+{
+	struct axi_spdif *spdif;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+	if (!spdif)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, spdif);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	spdif->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					    &axi_spdif_regmap_config);
+	if (IS_ERR(spdif->regmap))
+		return PTR_ERR(spdif->regmap);
+
+	spdif->clk = devm_clk_get(&pdev->dev, "axi");
+	if (IS_ERR(spdif->clk))
+		return PTR_ERR(spdif->clk);
+
+	spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
+	if (IS_ERR(spdif->clk_ref))
+		return PTR_ERR(spdif->clk_ref);
+
+	ret = clk_prepare_enable(spdif->clk);
+	if (ret)
+		return ret;
+
+	spdif->dma_data.addr = res->start + AXI_SPDIF_REG_TX_FIFO;
+	spdif->dma_data.addr_width = 4;
+	spdif->dma_data.maxburst = 1;
+
+	spdif->ratnum.num = clk_get_rate(spdif->clk_ref) / 128;
+	spdif->ratnum.den_step = 1;
+	spdif->ratnum.den_min = 1;
+	spdif->ratnum.den_max = 64;
+
+	spdif->rate_constraints.rats = &spdif->ratnum;
+	spdif->rate_constraints.nrats = 1;
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &axi_spdif_component,
+					 &axi_spdif_dai, 1);
+	if (ret)
+		goto err_clk_disable;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+			SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+	if (ret)
+		goto err_clk_disable;
+
+	return 0;
+
+err_clk_disable:
+	clk_disable_unprepare(spdif->clk);
+	return ret;
+}
+
+static int axi_spdif_dev_remove(struct platform_device *pdev)
+{
+	struct axi_spdif *spdif = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(spdif->clk);
+
+	return 0;
+}
+
+static const struct of_device_id axi_spdif_of_match[] = {
+	{ .compatible = "adi,axi-spdif-tx-1.00.a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, axi_spdif_of_match);
+
+static struct platform_driver axi_spdif_driver = {
+	.driver = {
+		.name = "axi-spdif",
+		.owner = THIS_MODULE,
+		.of_match_table = axi_spdif_of_match,
+	},
+	.probe = axi_spdif_probe,
+	.remove = axi_spdif_dev_remove,
+};
+module_platform_driver(axi_spdif_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("AXI SPDIF driver");
+MODULE_LICENSE("GPL");

+ 0 - 2
sound/soc/atmel/sam9x5_wm8731.c

@@ -155,8 +155,6 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
 	of_node_put(codec_np);
 	of_node_put(cpu_np);
 
-	platform_set_drvdata(pdev, card);
-
 	ret = snd_soc_register_card(card);
 	if (ret) {
 		dev_err(&pdev->dev,

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

@@ -65,19 +65,10 @@ struct au1xpsc_audio_dmadata {
 #define AU1XPSC_PERIOD_MIN_BYTES	1024
 #define AU1XPSC_BUFFER_MIN_BYTES	65536
 
-#define AU1XPSC_PCM_FMTS					\
-	(SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_U8 |	\
-	 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |	\
-	 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |	\
-	 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |	\
-	 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE |	\
-	 0)
-
 /* PCM hardware DMA capabilities - platform specific */
 static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
 	.info		  = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
 			    SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
-	.formats	  = AU1XPSC_PCM_FMTS,
 	.period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
 	.period_bytes_max = 4096 * 1024 - 1,
 	.periods_min	  = 2,

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

@@ -21,14 +21,6 @@
 
 #include "psc.h"
 
-#define ALCHEMY_PCM_FMTS					\
-	(SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_U8 |	\
-	 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |	\
-	 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |	\
-	 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |	\
-	 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE |	\
-	 0)
-
 struct pcm_period {
 	u32 start;
 	u32 relative_end;	/* relative to start of buffer */
@@ -171,12 +163,6 @@ static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
 static const struct snd_pcm_hardware alchemy_pcm_hardware = {
 	.info		  = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
 			    SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
-	.formats	  = ALCHEMY_PCM_FMTS,
-	.rates		  = SNDRV_PCM_RATE_8000_192000,
-	.rate_min	  = SNDRV_PCM_RATE_8000,
-	.rate_max	  = SNDRV_PCM_RATE_192000,
-	.channels_min	  = 2,
-	.channels_max	  = 2,
 	.period_bytes_min = 1024,
 	.period_bytes_max = 16 * 1024 - 1,
 	.periods_min	  = 4,

+ 10 - 0
sound/soc/bcm/Kconfig

@@ -0,0 +1,10 @@
+config SND_BCM2835_SOC_I2S
+	tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
+	depends on ARCH_BCM2835 || COMPILE_TEST
+	select SND_SOC_DMAENGINE_PCM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select REGMAP_MMIO
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the BCM2835 I2S interface. You will also need
+	  to select the audio interfaces to support below.

+ 5 - 0
sound/soc/bcm/Makefile

@@ -0,0 +1,5 @@
+# BCM2835 Platform Support
+snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o
+
+obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
+

+ 879 - 0
sound/soc/bcm/bcm2835-i2s.c

@@ -0,0 +1,879 @@
+/*
+ * ALSA SoC I2S Audio Layer for Broadcom BCM2835 SoC
+ *
+ * Author:	Florian Meier <florian.meier@koalo.de>
+ *		Copyright 2013
+ *
+ * Based on
+ *	Raspberry Pi PCM I2S ALSA Driver
+ *	Copyright (c) by Phil Poole 2013
+ *
+ *	ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ *      Vladimir Barinov, <vbarinov@embeddedalley.com>
+ *	Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ *	OMAP ALSA SoC DAI driver using McBSP port
+ *	Copyright (C) 2008 Nokia Corporation
+ *	Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *		 Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ *	Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
+ *	Author: Timur Tabi <timur@freescale.com>
+ *	Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+/* Clock registers */
+#define BCM2835_CLK_PCMCTL_REG  0x00
+#define BCM2835_CLK_PCMDIV_REG  0x04
+
+/* Clock register settings */
+#define BCM2835_CLK_PASSWD		(0x5a000000)
+#define BCM2835_CLK_PASSWD_MASK	(0xff000000)
+#define BCM2835_CLK_MASH(v)		((v) << 9)
+#define BCM2835_CLK_FLIP		BIT(8)
+#define BCM2835_CLK_BUSY		BIT(7)
+#define BCM2835_CLK_KILL		BIT(5)
+#define BCM2835_CLK_ENAB		BIT(4)
+#define BCM2835_CLK_SRC(v)		(v)
+
+#define BCM2835_CLK_SHIFT		(12)
+#define BCM2835_CLK_DIVI(v)		((v) << BCM2835_CLK_SHIFT)
+#define BCM2835_CLK_DIVF(v)		(v)
+#define BCM2835_CLK_DIVF_MASK		(0xFFF)
+
+enum {
+	BCM2835_CLK_MASH_0 = 0,
+	BCM2835_CLK_MASH_1,
+	BCM2835_CLK_MASH_2,
+	BCM2835_CLK_MASH_3,
+};
+
+enum {
+	BCM2835_CLK_SRC_GND = 0,
+	BCM2835_CLK_SRC_OSC,
+	BCM2835_CLK_SRC_DBG0,
+	BCM2835_CLK_SRC_DBG1,
+	BCM2835_CLK_SRC_PLLA,
+	BCM2835_CLK_SRC_PLLC,
+	BCM2835_CLK_SRC_PLLD,
+	BCM2835_CLK_SRC_HDMI,
+};
+
+/* Most clocks are not useable (freq = 0) */
+static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = {
+	[BCM2835_CLK_SRC_GND]		= 0,
+	[BCM2835_CLK_SRC_OSC]		= 19200000,
+	[BCM2835_CLK_SRC_DBG0]		= 0,
+	[BCM2835_CLK_SRC_DBG1]		= 0,
+	[BCM2835_CLK_SRC_PLLA]		= 0,
+	[BCM2835_CLK_SRC_PLLC]		= 0,
+	[BCM2835_CLK_SRC_PLLD]		= 500000000,
+	[BCM2835_CLK_SRC_HDMI]		= 0,
+};
+
+/* I2S registers */
+#define BCM2835_I2S_CS_A_REG		0x00
+#define BCM2835_I2S_FIFO_A_REG		0x04
+#define BCM2835_I2S_MODE_A_REG		0x08
+#define BCM2835_I2S_RXC_A_REG		0x0c
+#define BCM2835_I2S_TXC_A_REG		0x10
+#define BCM2835_I2S_DREQ_A_REG		0x14
+#define BCM2835_I2S_INTEN_A_REG	0x18
+#define BCM2835_I2S_INTSTC_A_REG	0x1c
+#define BCM2835_I2S_GRAY_REG		0x20
+
+/* I2S register settings */
+#define BCM2835_I2S_STBY		BIT(25)
+#define BCM2835_I2S_SYNC		BIT(24)
+#define BCM2835_I2S_RXSEX		BIT(23)
+#define BCM2835_I2S_RXF		BIT(22)
+#define BCM2835_I2S_TXE		BIT(21)
+#define BCM2835_I2S_RXD		BIT(20)
+#define BCM2835_I2S_TXD		BIT(19)
+#define BCM2835_I2S_RXR		BIT(18)
+#define BCM2835_I2S_TXW		BIT(17)
+#define BCM2835_I2S_CS_RXERR		BIT(16)
+#define BCM2835_I2S_CS_TXERR		BIT(15)
+#define BCM2835_I2S_RXSYNC		BIT(14)
+#define BCM2835_I2S_TXSYNC		BIT(13)
+#define BCM2835_I2S_DMAEN		BIT(9)
+#define BCM2835_I2S_RXTHR(v)		((v) << 7)
+#define BCM2835_I2S_TXTHR(v)		((v) << 5)
+#define BCM2835_I2S_RXCLR		BIT(4)
+#define BCM2835_I2S_TXCLR		BIT(3)
+#define BCM2835_I2S_TXON		BIT(2)
+#define BCM2835_I2S_RXON		BIT(1)
+#define BCM2835_I2S_EN			(1)
+
+#define BCM2835_I2S_CLKDIS		BIT(28)
+#define BCM2835_I2S_PDMN		BIT(27)
+#define BCM2835_I2S_PDME		BIT(26)
+#define BCM2835_I2S_FRXP		BIT(25)
+#define BCM2835_I2S_FTXP		BIT(24)
+#define BCM2835_I2S_CLKM		BIT(23)
+#define BCM2835_I2S_CLKI		BIT(22)
+#define BCM2835_I2S_FSM		BIT(21)
+#define BCM2835_I2S_FSI		BIT(20)
+#define BCM2835_I2S_FLEN(v)		((v) << 10)
+#define BCM2835_I2S_FSLEN(v)		(v)
+
+#define BCM2835_I2S_CHWEX		BIT(15)
+#define BCM2835_I2S_CHEN		BIT(14)
+#define BCM2835_I2S_CHPOS(v)		((v) << 4)
+#define BCM2835_I2S_CHWID(v)		(v)
+#define BCM2835_I2S_CH1(v)		((v) << 16)
+#define BCM2835_I2S_CH2(v)		(v)
+
+#define BCM2835_I2S_TX_PANIC(v)	((v) << 24)
+#define BCM2835_I2S_RX_PANIC(v)	((v) << 16)
+#define BCM2835_I2S_TX(v)		((v) << 8)
+#define BCM2835_I2S_RX(v)		(v)
+
+#define BCM2835_I2S_INT_RXERR		BIT(3)
+#define BCM2835_I2S_INT_TXERR		BIT(2)
+#define BCM2835_I2S_INT_RXR		BIT(1)
+#define BCM2835_I2S_INT_TXW		BIT(0)
+
+/* I2S DMA interface */
+/* FIXME: Needs IOMMU support */
+#define BCM2835_VCMMU_SHIFT		(0x7E000000 - 0x20000000)
+
+/* General device struct */
+struct bcm2835_i2s_dev {
+	struct device				*dev;
+	struct snd_dmaengine_dai_dma_data	dma_data[2];
+	unsigned int				fmt;
+	unsigned int				bclk_ratio;
+
+	struct regmap *i2s_regmap;
+	struct regmap *clk_regmap;
+};
+
+static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
+{
+	/* Start the clock if in master mode */
+	unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+
+	switch (master) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBS_CFM:
+		regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+			BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+			BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
+		break;
+	default:
+		break;
+	}
+}
+
+static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev)
+{
+	uint32_t clkreg;
+	int timeout = 1000;
+
+	/* Stop clock */
+	regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+			BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+			BCM2835_CLK_PASSWD);
+
+	/* Wait for the BUSY flag going down */
+	while (--timeout) {
+		regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
+		if (!(clkreg & BCM2835_CLK_BUSY))
+			break;
+	}
+
+	if (!timeout) {
+		/* KILL the clock */
+		dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n");
+		regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+			BCM2835_CLK_KILL | BCM2835_CLK_PASSWD_MASK,
+			BCM2835_CLK_KILL | BCM2835_CLK_PASSWD);
+	}
+}
+
+static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
+				    bool tx, bool rx)
+{
+	int timeout = 1000;
+	uint32_t syncval;
+	uint32_t csreg;
+	uint32_t i2s_active_state;
+	uint32_t clkreg;
+	uint32_t clk_active_state;
+	uint32_t off;
+	uint32_t clr;
+
+	off =  tx ? BCM2835_I2S_TXON : 0;
+	off |= rx ? BCM2835_I2S_RXON : 0;
+
+	clr =  tx ? BCM2835_I2S_TXCLR : 0;
+	clr |= rx ? BCM2835_I2S_RXCLR : 0;
+
+	/* Backup the current state */
+	regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+	i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON);
+
+	regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
+	clk_active_state = clkreg & BCM2835_CLK_ENAB;
+
+	/* Start clock if not running */
+	if (!clk_active_state) {
+		regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+			BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+			BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
+	}
+
+	/* Stop I2S module */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0);
+
+	/*
+	 * Clear the FIFOs
+	 * Requires at least 2 PCM clock cycles to take effect
+	 */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, clr, clr);
+
+	/* Wait for 2 PCM clock cycles */
+
+	/*
+	 * Toggle the SYNC flag. After 2 PCM clock cycles it can be read back
+	 * FIXME: This does not seem to work for slave mode!
+	 */
+	regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &syncval);
+	syncval &= BCM2835_I2S_SYNC;
+
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+			BCM2835_I2S_SYNC, ~syncval);
+
+	/* Wait for the SYNC flag changing it's state */
+	while (--timeout) {
+		regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+		if ((csreg & BCM2835_I2S_SYNC) != syncval)
+			break;
+	}
+
+	if (!timeout)
+		dev_err(dev->dev, "I2S SYNC error!\n");
+
+	/* Stop clock if it was not running before */
+	if (!clk_active_state)
+		bcm2835_i2s_stop_clock(dev);
+
+	/* Restore I2S state */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+			BCM2835_I2S_RXON | BCM2835_I2S_TXON, i2s_active_state);
+}
+
+static int bcm2835_i2s_set_dai_fmt(struct snd_soc_dai *dai,
+				      unsigned int fmt)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	dev->fmt = fmt;
+	return 0;
+}
+
+static int bcm2835_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+				      unsigned int ratio)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	dev->bclk_ratio = ratio;
+	return 0;
+}
+
+static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	unsigned int sampling_rate = params_rate(params);
+	unsigned int data_length, data_delay, bclk_ratio;
+	unsigned int ch1pos, ch2pos, mode, format;
+	unsigned int mash = BCM2835_CLK_MASH_1;
+	unsigned int divi, divf, target_frequency;
+	int clk_src = -1;
+	unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+	bool bit_master =	(master == SND_SOC_DAIFMT_CBS_CFS
+					|| master == SND_SOC_DAIFMT_CBS_CFM);
+
+	bool frame_master =	(master == SND_SOC_DAIFMT_CBS_CFS
+					|| master == SND_SOC_DAIFMT_CBM_CFS);
+	uint32_t csreg;
+
+	/*
+	 * If a stream is already enabled,
+	 * the registers are already set properly.
+	 */
+	regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+
+	if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
+		return 0;
+
+	/*
+	 * Adjust the data length according to the format.
+	 * We prefill the half frame length with an integer
+	 * divider of 2400 as explained at the clock settings.
+	 * Maybe it is overwritten there, if the Integer mode
+	 * does not apply.
+	 */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		data_length = 16;
+		bclk_ratio = 40;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		data_length = 32;
+		bclk_ratio = 80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* If bclk_ratio already set, use that one. */
+	if (dev->bclk_ratio)
+		bclk_ratio = dev->bclk_ratio;
+
+	/*
+	 * Clock Settings
+	 *
+	 * The target frequency of the bit clock is
+	 *	sampling rate * frame length
+	 *
+	 * Integer mode:
+	 * Sampling rates that are multiples of 8000 kHz
+	 * can be driven by the oscillator of 19.2 MHz
+	 * with an integer divider as long as the frame length
+	 * is an integer divider of 19200000/8000=2400 as set up above.
+	 * This is no longer possible if the sampling rate
+	 * is too high (e.g. 192 kHz), because the oscillator is too slow.
+	 *
+	 * MASH mode:
+	 * For all other sampling rates, it is not possible to
+	 * have an integer divider. Approximate the clock
+	 * with the MASH module that induces a slight frequency
+	 * variance. To minimize that it is best to have the fastest
+	 * clock here. That is PLLD with 500 MHz.
+	 */
+	target_frequency = sampling_rate * bclk_ratio;
+	clk_src = BCM2835_CLK_SRC_OSC;
+	mash = BCM2835_CLK_MASH_0;
+
+	if (bcm2835_clk_freq[clk_src] % target_frequency == 0
+			&& bit_master && frame_master) {
+		divi = bcm2835_clk_freq[clk_src] / target_frequency;
+		divf = 0;
+	} else {
+		uint64_t dividend;
+
+		if (!dev->bclk_ratio) {
+			/*
+			 * Overwrite bclk_ratio, because the
+			 * above trick is not needed or can
+			 * not be used.
+			 */
+			bclk_ratio = 2 * data_length;
+		}
+
+		target_frequency = sampling_rate * bclk_ratio;
+
+		clk_src = BCM2835_CLK_SRC_PLLD;
+		mash = BCM2835_CLK_MASH_1;
+
+		dividend = bcm2835_clk_freq[clk_src];
+		dividend <<= BCM2835_CLK_SHIFT;
+		do_div(dividend, target_frequency);
+		divi = dividend >> BCM2835_CLK_SHIFT;
+		divf = dividend & BCM2835_CLK_DIVF_MASK;
+	}
+
+	/* Set clock divider */
+	regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
+			| BCM2835_CLK_DIVI(divi)
+			| BCM2835_CLK_DIVF(divf));
+
+	/* Setup clock, but don't start it yet */
+	regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
+			| BCM2835_CLK_MASH(mash)
+			| BCM2835_CLK_SRC(clk_src));
+
+	/* Setup the frame format */
+	format = BCM2835_I2S_CHEN;
+
+	if (data_length > 24)
+		format |= BCM2835_I2S_CHWEX;
+
+	format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
+
+	switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		data_delay = 1;
+		break;
+	default:
+		/*
+		 * TODO
+		 * Others are possible but are not implemented at the moment.
+		 */
+		dev_err(dev->dev, "%s:bad format\n", __func__);
+		return -EINVAL;
+	}
+
+	ch1pos = data_delay;
+	ch2pos = bclk_ratio / 2 + data_delay;
+
+	switch (params_channels(params)) {
+	case 2:
+		format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format);
+		format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos));
+		format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set format for both streams.
+	 * We cannot set another frame length
+	 * (and therefore word length) anyway,
+	 * so the format will be the same.
+	 */
+	regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
+	regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);
+
+	/* Setup the I2S mode */
+	mode = 0;
+
+	if (data_length <= 16) {
+		/*
+		 * Use frame packed mode (2 channels per 32 bit word)
+		 * We cannot set another frame length in the second stream
+		 * (and therefore word length) anyway,
+		 * so the format will be the same.
+		 */
+		mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP;
+	}
+
+	mode |= BCM2835_I2S_FLEN(bclk_ratio - 1);
+	mode |= BCM2835_I2S_FSLEN(bclk_ratio / 2);
+
+	/* Master or slave? */
+	switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		/*
+		 * CODEC is bit clock master
+		 * CPU is frame master
+		 */
+		mode |= BCM2835_I2S_CLKM;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		/*
+		 * CODEC is frame master
+		 * CPU is bit clock master
+		 */
+		mode |= BCM2835_I2S_FSM;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* CODEC is master */
+		mode |= BCM2835_I2S_CLKM;
+		mode |= BCM2835_I2S_FSM;
+		break;
+	default:
+		dev_err(dev->dev, "%s:bad master\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Invert clocks?
+	 *
+	 * The BCM approach seems to be inverted to the classical I2S approach.
+	 */
+	switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		/* None. Therefore, both for BCM */
+		mode |= BCM2835_I2S_CLKI;
+		mode |= BCM2835_I2S_FSI;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		/* Both. Therefore, none for BCM */
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		/*
+		 * Invert only frame sync. Therefore,
+		 * invert only bit clock for BCM
+		 */
+		mode |= BCM2835_I2S_CLKI;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		/*
+		 * Invert only bit clock. Therefore,
+		 * invert only frame sync for BCM
+		 */
+		mode |= BCM2835_I2S_FSI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_write(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, mode);
+
+	/* Setup the DMA parameters */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+			BCM2835_I2S_RXTHR(1)
+			| BCM2835_I2S_TXTHR(1)
+			| BCM2835_I2S_DMAEN, 0xffffffff);
+
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG,
+			  BCM2835_I2S_TX_PANIC(0x10)
+			| BCM2835_I2S_RX_PANIC(0x30)
+			| BCM2835_I2S_TX(0x30)
+			| BCM2835_I2S_RX(0x20), 0xffffffff);
+
+	/* Clear FIFOs */
+	bcm2835_i2s_clear_fifos(dev, true, true);
+
+	return 0;
+}
+
+static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	uint32_t cs_reg;
+
+	bcm2835_i2s_start_clock(dev);
+
+	/*
+	 * Clear both FIFOs if the one that should be started
+	 * is not empty at the moment. This should only happen
+	 * after overrun. Otherwise, hw_params would have cleared
+	 * the FIFO.
+	 */
+	regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &cs_reg);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+			&& !(cs_reg & BCM2835_I2S_TXE))
+		bcm2835_i2s_clear_fifos(dev, true, false);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
+			&& (cs_reg & BCM2835_I2S_RXD))
+		bcm2835_i2s_clear_fifos(dev, false, true);
+
+	return 0;
+}
+
+static void bcm2835_i2s_stop(struct bcm2835_i2s_dev *dev,
+		struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	uint32_t mask;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		mask = BCM2835_I2S_RXON;
+	else
+		mask = BCM2835_I2S_TXON;
+
+	regmap_update_bits(dev->i2s_regmap,
+			BCM2835_I2S_CS_A_REG, mask, 0);
+
+	/* Stop also the clock when not SND_SOC_DAIFMT_CONT */
+	if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT))
+		bcm2835_i2s_stop_clock(dev);
+}
+
+static int bcm2835_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	uint32_t mask;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		bcm2835_i2s_start_clock(dev);
+
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			mask = BCM2835_I2S_RXON;
+		else
+			mask = BCM2835_I2S_TXON;
+
+		regmap_update_bits(dev->i2s_regmap,
+				BCM2835_I2S_CS_A_REG, mask, mask);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		bcm2835_i2s_stop(dev, substream, dai);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm2835_i2s_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	if (dai->active)
+		return 0;
+
+	/* Should this still be running stop it */
+	bcm2835_i2s_stop_clock(dev);
+
+	/* Enable PCM block */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+			BCM2835_I2S_EN, BCM2835_I2S_EN);
+
+	/*
+	 * Disable STBY.
+	 * Requires at least 4 PCM clock cycles to take effect.
+	 */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+			BCM2835_I2S_STBY, BCM2835_I2S_STBY);
+
+	return 0;
+}
+
+static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	bcm2835_i2s_stop(dev, substream, dai);
+
+	/* If both streams are stopped, disable module and clock */
+	if (dai->active)
+		return;
+
+	/* Disable the module */
+	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+			BCM2835_I2S_EN, 0);
+
+	/*
+	 * Stopping clock is necessary, because stop does
+	 * not stop the clock when SND_SOC_DAIFMT_CONT
+	 */
+	bcm2835_i2s_stop_clock(dev);
+}
+
+static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
+	.startup	= bcm2835_i2s_startup,
+	.shutdown	= bcm2835_i2s_shutdown,
+	.prepare	= bcm2835_i2s_prepare,
+	.trigger	= bcm2835_i2s_trigger,
+	.hw_params	= bcm2835_i2s_hw_params,
+	.set_fmt	= bcm2835_i2s_set_dai_fmt,
+	.set_bclk_ratio	= bcm2835_i2s_set_dai_bclk_ratio
+};
+
+static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai,
+			&dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+			&dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver bcm2835_i2s_dai = {
+	.name	= "bcm2835-i2s",
+	.probe	= bcm2835_i2s_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates =	SNDRV_PCM_RATE_8000_192000,
+		.formats =	SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S32_LE
+		},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates =	SNDRV_PCM_RATE_8000_192000,
+		.formats =	SNDRV_PCM_FMTBIT_S16_LE
+				| SNDRV_PCM_FMTBIT_S32_LE
+		},
+	.ops = &bcm2835_i2s_dai_ops,
+	.symmetric_rates = 1
+};
+
+static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BCM2835_I2S_CS_A_REG:
+	case BCM2835_I2S_FIFO_A_REG:
+	case BCM2835_I2S_INTSTC_A_REG:
+	case BCM2835_I2S_GRAY_REG:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BCM2835_I2S_FIFO_A_REG:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BCM2835_CLK_PCMCTL_REG:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config bcm2835_regmap_config[] = {
+	{
+		.reg_bits = 32,
+		.reg_stride = 4,
+		.val_bits = 32,
+		.max_register = BCM2835_I2S_GRAY_REG,
+		.precious_reg = bcm2835_i2s_precious_reg,
+		.volatile_reg = bcm2835_i2s_volatile_reg,
+		.cache_type = REGCACHE_RBTREE,
+	},
+	{
+		.reg_bits = 32,
+		.reg_stride = 4,
+		.val_bits = 32,
+		.max_register = BCM2835_CLK_PCMDIV_REG,
+		.volatile_reg = bcm2835_clk_volatile_reg,
+		.cache_type = REGCACHE_RBTREE,
+	},
+};
+
+static const struct snd_soc_component_driver bcm2835_i2s_component = {
+	.name		= "bcm2835-i2s-comp",
+};
+
+static int bcm2835_i2s_probe(struct platform_device *pdev)
+{
+	struct bcm2835_i2s_dev *dev;
+	int i;
+	int ret;
+	struct regmap *regmap[2];
+	struct resource *mem[2];
+
+	/* Request both ioareas */
+	for (i = 0; i <= 1; i++) {
+		void __iomem *base;
+
+		mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		base = devm_ioremap_resource(&pdev->dev, mem[i]);
+		if (IS_ERR(base))
+			return PTR_ERR(base);
+
+		regmap[i] = devm_regmap_init_mmio(&pdev->dev, base,
+					    &bcm2835_regmap_config[i]);
+		if (IS_ERR(regmap[i]))
+			return PTR_ERR(regmap[i]);
+	}
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev),
+			   GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->i2s_regmap = regmap[0];
+	dev->clk_regmap = regmap[1];
+
+	/* Set the DMA address */
+	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+		(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+					  + BCM2835_VCMMU_SHIFT;
+
+	dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+		(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+					  + BCM2835_VCMMU_SHIFT;
+
+	/* Set the bus width */
+	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
+		DMA_SLAVE_BUSWIDTH_4_BYTES;
+	dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width =
+		DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+	/* Set burst */
+	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2;
+	dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2;
+
+	/* BCLK ratio - use default */
+	dev->bclk_ratio = 0;
+
+	/* Store the pdev */
+	dev->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, dev);
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&bcm2835_i2s_component, &bcm2835_i2s_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id bcm2835_i2s_of_match[] = {
+	{ .compatible = "brcm,bcm2835-i2s", },
+	{},
+};
+
+static struct platform_driver bcm2835_i2s_driver = {
+	.probe		= bcm2835_i2s_probe,
+	.driver		= {
+		.name	= "bcm2835-i2s",
+		.owner	= THIS_MODULE,
+		.of_match_table = bcm2835_i2s_of_match,
+	},
+};
+
+module_platform_driver(bcm2835_i2s_driver);
+
+MODULE_ALIAS("platform:bcm2835-i2s");
+MODULE_DESCRIPTION("BCM2835 I2S interface");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");

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

@@ -107,7 +107,6 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
 #endif
 				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
 
-	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
 	.period_bytes_min	= 32,
 	.period_bytes_max	= 0x10000,
 	.periods_min		= 1,

+ 0 - 3
sound/soc/blackfin/bf5xx-i2s-pcm.c

@@ -52,9 +52,6 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_INTERLEAVED |
 				   SNDRV_PCM_INFO_MMAP_VALID |
 				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
-	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
-				   SNDRV_PCM_FMTBIT_S24_LE |
-				   SNDRV_PCM_FMTBIT_S32_LE,
 	.period_bytes_min	= 32,
 	.period_bytes_max	= 0x10000,
 	.periods_min		= 1,

+ 1 - 1
sound/soc/cirrus/edb93xx.c

@@ -63,7 +63,7 @@ static struct snd_soc_ops edb93xx_ops = {
 static struct snd_soc_dai_link edb93xx_dai = {
 	.name		= "CS4271",
 	.stream_name	= "CS4271 HiFi",
-	.platform_name	= "ep93xx-pcm-audio",
+	.platform_name	= "ep93xx-i2s",
 	.cpu_dai_name	= "ep93xx-i2s",
 	.codec_name	= "spi0.0",
 	.codec_dai_name	= "cs4271-hifi",

+ 18 - 2
sound/soc/cirrus/ep93xx-ac97.c

@@ -19,11 +19,14 @@
 #include <linux/slab.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/soc.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
 
+#include "ep93xx-pcm.h"
+
 /*
  * Per channel (1-4) registers.
  */
@@ -95,6 +98,8 @@ struct ep93xx_ac97_info {
 	struct device		*dev;
 	void __iomem		*regs;
 	struct completion	done;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
 
 /* currently ALSA only supports a single AC97 device */
@@ -315,8 +320,13 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
 
 static int ep93xx_ac97_dai_probe(struct snd_soc_dai *dai)
 {
-	dai->playback_dma_data = &ep93xx_ac97_pcm_out;
-	dai->capture_dma_data = &ep93xx_ac97_pcm_in;
+	struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
+
+	info->dma_params_tx.filter_data = &ep93xx_ac97_pcm_out;
+	info->dma_params_rx.filter_data = &ep93xx_ac97_pcm_in;
+
+	dai->playback_dma_data = &info->dma_params_tx;
+	dai->capture_dma_data = &info->dma_params_rx;
 
 	return 0;
 }
@@ -394,8 +404,14 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
 	if (ret)
 		goto fail;
 
+	ret = devm_ep93xx_pcm_platform_register(&pdev->dev);
+	if (ret)
+		goto fail_unregister;
+
 	return 0;
 
+fail_unregister:
+	snd_soc_unregister_component(&pdev->dev);
 fail:
 	ep93xx_ac97_info = NULL;
 	snd_soc_set_ac97_ops(NULL);

+ 20 - 2
sound/soc/cirrus/ep93xx-i2s.c

@@ -21,6 +21,7 @@
 #include <linux/io.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
@@ -30,6 +31,8 @@
 #include <mach/ep93xx-regs.h>
 #include <linux/platform_data/dma-ep93xx.h>
 
+#include "ep93xx-pcm.h"
+
 #define EP93XX_I2S_TXCLKCFG		0x00
 #define EP93XX_I2S_RXCLKCFG		0x04
 #define EP93XX_I2S_GLCTRL		0x0C
@@ -61,6 +64,8 @@ struct ep93xx_i2s_info {
 	struct clk			*sclk;
 	struct clk			*lrclk;
 	void __iomem			*regs;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
 
 static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
@@ -140,8 +145,15 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
 
 static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
 {
-	dai->playback_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-	dai->capture_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
+	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+	info->dma_params_tx.filter_data =
+		&ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+	info->dma_params_rx.filter_data =
+		&ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+	dai->playback_dma_data = &info->dma_params_tx;
+	dai->capture_dma_data = &info->dma_params_rx;
 
 	return 0;
 }
@@ -405,8 +417,14 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
 	if (err)
 		goto fail_put_lrclk;
 
+	err = devm_ep93xx_pcm_platform_register(&pdev->dev);
+	if (err)
+		goto fail_unregister;
+
 	return 0;
 
+fail_unregister:
+	snd_soc_unregister_component(&pdev->dev);
 fail_put_lrclk:
 	clk_put(info->lrclk);
 fail_put_sclk:

+ 5 - 43
sound/soc/cirrus/ep93xx-pcm.c

@@ -23,20 +23,13 @@
 
 #include <linux/platform_data/dma-ep93xx.h>
 
+#include "ep93xx-pcm.h"
+
 static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
 	.info			= (SNDRV_PCM_INFO_MMAP		|
 				   SNDRV_PCM_INFO_MMAP_VALID	|
 				   SNDRV_PCM_INFO_INTERLEAVED	|
 				   SNDRV_PCM_INFO_BLOCK_TRANSFER),
-				   
-	.rates			= SNDRV_PCM_RATE_8000_192000,
-	.rate_min		= SNDRV_PCM_RATE_8000,
-	.rate_max		= SNDRV_PCM_RATE_192000,
-	
-	.formats		= (SNDRV_PCM_FMTBIT_S16_LE |
-				   SNDRV_PCM_FMTBIT_S24_LE |
-				   SNDRV_PCM_FMTBIT_S32_LE),
-	
 	.buffer_bytes_max	= 131072,
 	.period_bytes_min	= 32,
 	.period_bytes_max	= 32768,
@@ -57,53 +50,22 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
 	return false;
 }
 
-static struct dma_chan *ep93xx_compat_request_channel(
-	struct snd_soc_pcm_runtime *rtd,
-	struct snd_pcm_substream *substream)
-{
-	struct snd_dmaengine_dai_dma_data *dma_data;
-
-	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	return snd_dmaengine_pcm_request_channel(ep93xx_pcm_dma_filter,
-						 dma_data);
-}
-
 static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
 	.pcm_hardware = &ep93xx_pcm_hardware,
 	.compat_filter_fn = ep93xx_pcm_dma_filter,
-	.compat_request_channel = ep93xx_compat_request_channel,
 	.prealloc_buffer_size = 131072,
 };
 
-static int ep93xx_soc_platform_probe(struct platform_device *pdev)
+int devm_ep93xx_pcm_platform_register(struct device *dev)
 {
-	return snd_dmaengine_pcm_register(&pdev->dev,
+	return devm_snd_dmaengine_pcm_register(dev,
 		&ep93xx_dmaengine_pcm_config,
 		SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
 		SND_DMAENGINE_PCM_FLAG_NO_DT |
 		SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
-
-static int ep93xx_soc_platform_remove(struct platform_device *pdev)
-{
-	snd_dmaengine_pcm_unregister(&pdev->dev);
-	return 0;
-}
-
-static struct platform_driver ep93xx_pcm_driver = {
-	.driver = {
-			.name = "ep93xx-pcm-audio",
-			.owner = THIS_MODULE,
-	},
-
-	.probe = ep93xx_soc_platform_probe,
-	.remove = ep93xx_soc_platform_remove,
-};
-
-module_platform_driver(ep93xx_pcm_driver);
+EXPORT_SYMBOL_GPL(devm_ep93xx_pcm_platform_register);
 
 MODULE_AUTHOR("Ryan Mallon");
 MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ep93xx-pcm-audio");

+ 22 - 0
sound/soc/cirrus/ep93xx-pcm.h

@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION.  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/>.
+ */
+
+#ifndef __EP93XX_PCM_H__
+#define __EP93XX_PCM_H__
+
+int devm_ep93xx_pcm_platform_register(struct device *dev);
+
+#endif

+ 1 - 1
sound/soc/cirrus/simone.c

@@ -27,7 +27,7 @@ static struct snd_soc_dai_link simone_dai = {
 	.cpu_dai_name	= "ep93xx-ac97",
 	.codec_dai_name	= "ac97-hifi",
 	.codec_name	= "ac97-codec",
-	.platform_name	= "ep93xx-pcm-audio",
+	.platform_name	= "ep93xx-ac97",
 };
 
 static struct snd_soc_card snd_soc_simone = {

+ 1 - 1
sound/soc/cirrus/snappercl15.c

@@ -83,7 +83,7 @@ static struct snd_soc_dai_link snappercl15_dai = {
 	.cpu_dai_name	= "ep93xx-i2s",
 	.codec_dai_name	= "tlv320aic23-hifi",
 	.codec_name	= "tlv320aic23-codec.0-001a",
-	.platform_name	=  "ep93xx-pcm-audio",
+	.platform_name	= "ep93xx-i2s",
 	.init		= snappercl15_tlv320aic23_init,
 	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
 			  SND_SOC_DAIFMT_CBS_CFS,

+ 2 - 0
sound/soc/codecs/Kconfig

@@ -163,8 +163,10 @@ config SND_SOC_WM_HUBS
 config SND_SOC_WM_ADSP
 	tristate
 	default y if SND_SOC_WM5102=y
+	default y if SND_SOC_WM5110=y
 	default y if SND_SOC_WM2200=y
 	default m if SND_SOC_WM5102=m
+	default m if SND_SOC_WM5110=m
 	default m if SND_SOC_WM2200=m
 
 config SND_SOC_AB8500_CODEC

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

@@ -179,6 +179,8 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_FORMAT_S32_LE:
 		word_len = AD1836_WORD_LEN_24;
 		break;
+	default:
+		return -EINVAL;
 	}
 
 	regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,

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

@@ -413,7 +413,7 @@ static struct spi_driver ad193x_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 
 static const struct regmap_config ad193x_i2c_regmap_config = {
 	.val_bits = 8,
@@ -470,7 +470,7 @@ static int __init ad193x_modinit(void)
 {
 	int ret;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret =  i2c_add_driver(&ad193x_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
@@ -495,7 +495,7 @@ static void __exit ad193x_modexit(void)
 	spi_unregister_driver(&ad193x_spi_driver);
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&ad193x_i2c_driver);
 #endif
 }

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

@@ -939,7 +939,7 @@ static struct spi_driver adav80x_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static const struct regmap_config adav80x_i2c_regmap_config = {
 	.val_bits = 8,
 	.pad_bits = 1,
@@ -985,7 +985,7 @@ static int __init adav80x_init(void)
 {
 	int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&adav80x_i2c_driver);
 	if (ret)
 		return ret;
@@ -1001,7 +1001,7 @@ module_init(adav80x_init);
 
 static void __exit adav80x_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&adav80x_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

+ 25 - 13
sound/soc/codecs/ak4641.c

@@ -17,6 +17,7 @@
 #include <linux/gpio.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -30,6 +31,7 @@
 
 /* codec private data */
 struct ak4641_priv {
+	struct regmap *regmap;
 	unsigned int sysclk;
 	int deemph;
 	int playback_fs;
@@ -38,12 +40,12 @@ struct ak4641_priv {
 /*
  * ak4641 register cache
  */
-static const u8 ak4641_reg[AK4641_CACHEREGNUM] = {
-	0x00, 0x80, 0x00, 0x80,
-	0x02, 0x00, 0x11, 0x05,
-	0x00, 0x00, 0x36, 0x10,
-	0x00, 0x00, 0x57, 0x00,
-	0x88, 0x88, 0x08, 0x08
+static const struct reg_default ak4641_reg_defaults[] = {
+	{  0, 0x00 }, {  1, 0x80 }, {  2, 0x00 }, {  3, 0x80 },
+	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x11 }, {  7, 0x05 },
+	{  8, 0x00 }, {  9, 0x00 }, { 10, 0x36 }, { 11, 0x10 },
+	{ 12, 0x00 }, { 13, 0x00 }, { 14, 0x57 }, { 15, 0x00 },
+	{ 16, 0x88 }, { 17, 0x88 }, { 18, 0x08 }, { 19, 0x08 }
 };
 
 static const int deemph_settings[] = {44100, 0, 48000, 32000};
@@ -396,6 +398,7 @@ static int ak4641_mute(struct snd_soc_dai *dai, int mute)
 static int ak4641_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 	struct ak4641_platform_data *pdata = codec->dev->platform_data;
 	int ret;
 
@@ -417,7 +420,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
 				gpio_set_value(pdata->gpio_npdn, 1);
 			mdelay(1);
 
-			ret = snd_soc_cache_sync(codec);
+			ret = regcache_sync(ak4641->regmap);
 			if (ret) {
 				dev_err(codec->dev,
 					"Failed to sync cache: %d\n", ret);
@@ -433,7 +436,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
 			gpio_set_value(pdata->gpio_npdn, 0);
 		if (pdata && gpio_is_valid(pdata->gpio_power))
 			gpio_set_value(pdata->gpio_power, 0);
-		codec->cache_sync = 1;
+		regcache_mark_dirty(ak4641->regmap);
 		break;
 	}
 	codec->dapm.bias_level = level;
@@ -518,7 +521,7 @@ static int ak4641_probe(struct snd_soc_codec *codec)
 {
 	int ret;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -550,12 +553,17 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
 	.dapm_routes		= ak4641_audio_map,
 	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
 	.set_bias_level		= ak4641_set_bias_level,
-	.reg_cache_size		= ARRAY_SIZE(ak4641_reg),
-	.reg_word_size		= sizeof(u8),
-	.reg_cache_default	= ak4641_reg,
-	.reg_cache_step		= 1,
 };
 
+static const struct regmap_config ak4641_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4641_BTIF,
+	.reg_defaults = ak4641_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4641_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
 
 static int ak4641_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
@@ -569,6 +577,10 @@ static int ak4641_i2c_probe(struct i2c_client *i2c,
 	if (!ak4641)
 		return -ENOMEM;
 
+	ak4641->regmap = devm_regmap_init_i2c(i2c, &ak4641_regmap);
+	if (IS_ERR(ak4641->regmap))
+		return PTR_ERR(ak4641->regmap);
+
 	if (pdata) {
 		if (gpio_is_valid(pdata->gpio_power)) {
 			ret = gpio_request_one(pdata->gpio_power,

+ 62 - 76
sound/soc/codecs/ak4642.c

@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/of_device.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
@@ -198,30 +199,30 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
 /*
  * ak4642 register cache
  */
-static const u8 ak4642_reg[] = {
-	0x00, 0x00, 0x01, 0x00,
-	0x02, 0x00, 0x00, 0x00,
-	0xe1, 0xe1, 0x18, 0x00,
-	0xe1, 0x18, 0x11, 0x08,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00,
+static const struct reg_default ak4642_reg[] = {
+	{  0, 0x00 }, {  1, 0x00 }, {  2, 0x01 }, {  3, 0x00 },
+	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x00 }, {  7, 0x00 },
+	{  8, 0xe1 }, {  9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
+	{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0x08 },
+	{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
+	{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
+	{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
+	{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
+	{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
+	{ 36, 0x00 },
 };
 
-static const u8 ak4648_reg[] = {
-	0x00, 0x00, 0x01, 0x00,
-	0x02, 0x00, 0x00, 0x00,
-	0xe1, 0xe1, 0x18, 0x00,
-	0xe1, 0x18, 0x11, 0xb8,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x88, 0x88, 0x08,
+static const struct reg_default ak4648_reg[] = {
+	{  0, 0x00 }, {  1, 0x00 }, {  2, 0x01 }, {  3, 0x00 },
+	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x00 }, {  7, 0x00 },
+	{  8, 0xe1 }, {  9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
+	{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0xb8 },
+	{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
+	{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
+	{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
+	{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
+	{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
+	{ 36, 0x00 }, { 37, 0x88 }, { 38, 0x88 }, { 39, 0x08 },
 };
 
 static int ak4642_dai_startup(struct snd_pcm_substream *substream,
@@ -454,7 +455,10 @@ static struct snd_soc_dai_driver ak4642_dai = {
 
 static int ak4642_resume(struct snd_soc_codec *codec)
 {
-	snd_soc_cache_sync(codec);
+	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+
+	regcache_mark_dirty(regmap);
+	regcache_sync(regmap);
 	return 0;
 }
 
@@ -463,15 +467,12 @@ static int ak4642_probe(struct snd_soc_codec *codec)
 {
 	int ret;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
 	}
 
-	snd_soc_add_codec_controls(codec, ak4642_snd_controls,
-			     ARRAY_SIZE(ak4642_snd_controls));
-
 	ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
@@ -488,55 +489,59 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
 	.remove			= ak4642_remove,
 	.resume			= ak4642_resume,
 	.set_bias_level		= ak4642_set_bias_level,
-	.reg_cache_default	= ak4642_reg,			/* ak4642 reg */
-	.reg_cache_size		= ARRAY_SIZE(ak4642_reg),	/* ak4642 reg */
-	.reg_word_size		= sizeof(u8),
+	.controls		= ak4642_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
 	.dapm_widgets		= ak4642_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
 	.dapm_routes		= ak4642_intercon,
 	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
-	.probe			= ak4642_probe,
-	.remove			= ak4642_remove,
-	.resume			= ak4642_resume,
-	.set_bias_level		= ak4642_set_bias_level,
-	.reg_cache_default	= ak4648_reg,			/* ak4648 reg */
-	.reg_cache_size		= ARRAY_SIZE(ak4648_reg),	/* ak4648 reg */
-	.reg_word_size		= sizeof(u8),
-	.dapm_widgets		= ak4642_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
-	.dapm_routes		= ak4642_intercon,
-	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+static const struct regmap_config ak4642_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= ARRAY_SIZE(ak4642_reg) + 1,
+	.reg_defaults		= ak4642_reg,
+	.num_reg_defaults	= ARRAY_SIZE(ak4642_reg),
+};
+
+static const struct regmap_config ak4648_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= ARRAY_SIZE(ak4648_reg) + 1,
+	.reg_defaults		= ak4648_reg,
+	.num_reg_defaults	= ARRAY_SIZE(ak4648_reg),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static struct of_device_id ak4642_of_match[];
 static int ak4642_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
 	struct device_node *np = i2c->dev.of_node;
-	const struct snd_soc_codec_driver *driver;
+	const struct regmap_config *regmap_config = NULL;
+	struct regmap *regmap;
 
-	driver = NULL;
 	if (np) {
 		const struct of_device_id *of_id;
 
 		of_id = of_match_device(ak4642_of_match, &i2c->dev);
 		if (of_id)
-			driver = of_id->data;
+			regmap_config = of_id->data;
 	} else {
-		driver = (struct snd_soc_codec_driver *)id->driver_data;
+		regmap_config = (const struct regmap_config *)id->driver_data;
 	}
 
-	if (!driver) {
-		dev_err(&i2c->dev, "no driver\n");
+	if (!regmap_config) {
+		dev_err(&i2c->dev, "Unknown device type\n");
 		return -EINVAL;
 	}
 
+	regmap = devm_regmap_init_i2c(i2c, regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
 	return snd_soc_register_codec(&i2c->dev,
-				      driver, &ak4642_dai, 1);
+				      &soc_codec_dev_ak4642, &ak4642_dai, 1);
 }
 
 static int ak4642_i2c_remove(struct i2c_client *client)
@@ -546,17 +551,17 @@ static int ak4642_i2c_remove(struct i2c_client *client)
 }
 
 static struct of_device_id ak4642_of_match[] = {
-	{ .compatible = "asahi-kasei,ak4642",	.data = &soc_codec_dev_ak4642},
-	{ .compatible = "asahi-kasei,ak4643",	.data = &soc_codec_dev_ak4642},
-	{ .compatible = "asahi-kasei,ak4648",	.data = &soc_codec_dev_ak4648},
+	{ .compatible = "asahi-kasei,ak4642",	.data = &ak4642_regmap},
+	{ .compatible = "asahi-kasei,ak4643",	.data = &ak4642_regmap},
+	{ .compatible = "asahi-kasei,ak4648",	.data = &ak4648_regmap},
 	{},
 };
 MODULE_DEVICE_TABLE(of, ak4642_of_match);
 
 static const struct i2c_device_id ak4642_i2c_id[] = {
-	{ "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 },
-	{ "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 },
-	{ "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 },
+	{ "ak4642", (kernel_ulong_t)&ak4642_regmap },
+	{ "ak4643", (kernel_ulong_t)&ak4642_regmap },
+	{ "ak4648", (kernel_ulong_t)&ak4648_regmap },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
@@ -571,27 +576,8 @@ static struct i2c_driver ak4642_i2c_driver = {
 	.remove		= ak4642_i2c_remove,
 	.id_table	= ak4642_i2c_id,
 };
-#endif
-
-static int __init ak4642_modinit(void)
-{
-	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	ret = i2c_add_driver(&ak4642_i2c_driver);
-#endif
-	return ret;
 
-}
-module_init(ak4642_modinit);
-
-static void __exit ak4642_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&ak4642_i2c_driver);
-#endif
-
-}
-module_exit(ak4642_exit);
+module_i2c_driver(ak4642_i2c_driver);
 
 MODULE_DESCRIPTION("Soc AK4642 driver");
 MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");

+ 130 - 74
sound/soc/codecs/arizona.c

@@ -93,7 +93,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (!priv->spk_ena && manual_ena) {
-			snd_soc_write(codec, 0x4f5, 0x25a);
+			regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
 			priv->spk_ena_pending = true;
 		}
 		break;
@@ -105,12 +105,13 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 			return -EBUSY;
 		}
 
-		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
-				    1 << w->shift, 1 << w->shift);
+		regmap_update_bits_async(arizona->regmap,
+					 ARIZONA_OUTPUT_ENABLES_1,
+					 1 << w->shift, 1 << w->shift);
 
 		if (priv->spk_ena_pending) {
 			msleep(75);
-			snd_soc_write(codec, 0x4f5, 0xda);
+			regmap_write_async(arizona->regmap, 0x4f5, 0xda);
 			priv->spk_ena_pending = false;
 			priv->spk_ena++;
 		}
@@ -119,16 +120,19 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 		if (manual_ena) {
 			priv->spk_ena--;
 			if (!priv->spk_ena)
-				snd_soc_write(codec, 0x4f5, 0x25a);
+				regmap_write_async(arizona->regmap,
+						   0x4f5, 0x25a);
 		}
 
-		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
-				    1 << w->shift, 0);
+		regmap_update_bits_async(arizona->regmap,
+					 ARIZONA_OUTPUT_ENABLES_1,
+					 1 << w->shift, 0);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		if (manual_ena) {
 			if (!priv->spk_ena)
-				snd_soc_write(codec, 0x4f5, 0x0da);
+				regmap_write_async(arizona->regmap,
+						   0x4f5, 0x0da);
 		}
 		break;
 	}
@@ -292,6 +296,10 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
 	"AIF1RX8",
 	"AIF2RX1",
 	"AIF2RX2",
+	"AIF2RX3",
+	"AIF2RX4",
+	"AIF2RX5",
+	"AIF2RX6",
 	"AIF3RX1",
 	"AIF3RX2",
 	"SLIMRX1",
@@ -395,6 +403,10 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
 	0x27,
 	0x28,  /* AIF2RX1 */
 	0x29,
+	0x2a,
+	0x2b,
+	0x2c,
+	0x2d,
 	0x30,  /* AIF3RX1 */
 	0x31,
 	0x38,  /* SLIMRX1 */
@@ -486,6 +498,22 @@ const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
 EXPORT_SYMBOL_GPL(arizona_rate_val);
 
 
+const struct soc_enum arizona_isrc_fsh[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
+			      ARIZONA_ISRC1_FSH_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
+			      ARIZONA_ISRC2_FSH_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
+			      ARIZONA_ISRC3_FSH_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
+
 const struct soc_enum arizona_isrc_fsl[] = {
 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
 			      ARIZONA_ISRC1_FSL_SHIFT, 0xf,
@@ -502,6 +530,13 @@ const struct soc_enum arizona_isrc_fsl[] = {
 };
 EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
 
+const struct soc_enum arizona_asrc_rate1 =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
+			      ARIZONA_ASRC_RATE1_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE - 1,
+			      arizona_rate_text, arizona_rate_val);
+EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
+
 static const char *arizona_vol_ramp_text[] = {
 	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
 	"15ms/6dB", "30ms/6dB",
@@ -560,6 +595,16 @@ const struct soc_enum arizona_ng_hold =
 			4, arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
+static const char * const arizona_in_hpf_cut_text[] = {
+	"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
+};
+
+const struct soc_enum arizona_in_hpf_cut_enum =
+	SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
+			ARRAY_SIZE(arizona_in_hpf_cut_text),
+			arizona_in_hpf_cut_text);
+EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
+
 static const char * const arizona_in_dmic_osr_text[] = {
 	"1.536MHz", "3.072MHz", "6.144MHz",
 };
@@ -669,6 +714,7 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 		   int event)
 {
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+	struct arizona *arizona = priv->arizona;
 	unsigned int mask = 1 << w->shift;
 	unsigned int val;
 
@@ -691,7 +737,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 	if (priv->arizona->hpdet_magic)
 		val = 0;
 
-	snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
+	regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
+				 mask, val);
 
 	return arizona_out_ev(w, kcontrol, event);
 }
@@ -846,6 +893,8 @@ EXPORT_SYMBOL_GPL(arizona_set_sysclk);
 static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_codec *codec = dai->codec;
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
 	int lrclk, bclk, mode, base;
 
 	base = dai->driver->base;
@@ -902,17 +951,19 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
-			    ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
-			    bclk);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
-			    ARIZONA_AIF1TX_LRCLK_INV |
-			    ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
-			    ARIZONA_AIF1RX_LRCLK_INV |
-			    ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
-			    ARIZONA_AIF1_FMT_MASK, mode);
+	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
+				 ARIZONA_AIF1_BCLK_INV |
+				 ARIZONA_AIF1_BCLK_MSTR,
+				 bclk);
+	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
+				 ARIZONA_AIF1TX_LRCLK_INV |
+				 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
+	regmap_update_bits_async(arizona->regmap,
+				 base + ARIZONA_AIF_RX_PIN_CTRL,
+				 ARIZONA_AIF1RX_LRCLK_INV |
+				 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
+	regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
+			   ARIZONA_AIF1_FMT_MASK, mode);
 
 	return 0;
 }
@@ -1164,18 +1215,22 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 	if (ret != 0)
 		return ret;
 
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
-			    ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
-			    ARIZONA_AIF1TX_BCPF_MASK, lrclk);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
-			    ARIZONA_AIF1RX_BCPF_MASK, lrclk);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
-			    ARIZONA_AIF1TX_WL_MASK |
-			    ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
-	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
-			    ARIZONA_AIF1RX_WL_MASK |
-			    ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
+	regmap_update_bits_async(arizona->regmap,
+				 base + ARIZONA_AIF_BCLK_CTRL,
+				 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
+	regmap_update_bits_async(arizona->regmap,
+				 base + ARIZONA_AIF_TX_BCLK_RATE,
+				 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
+	regmap_update_bits_async(arizona->regmap,
+				 base + ARIZONA_AIF_RX_BCLK_RATE,
+				 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
+	regmap_update_bits_async(arizona->regmap,
+				 base + ARIZONA_AIF_FRAME_CTRL_1,
+				 ARIZONA_AIF1TX_WL_MASK |
+				 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
+	regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
+			   ARIZONA_AIF1RX_WL_MASK |
+			   ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
 
 	return 0;
 }
@@ -1428,31 +1483,31 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
 			      struct arizona_fll_cfg *cfg, int source,
 			      bool sync)
 {
-	regmap_update_bits(arizona->regmap, base + 3,
-			   ARIZONA_FLL1_THETA_MASK, cfg->theta);
-	regmap_update_bits(arizona->regmap, base + 4,
-			   ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
-	regmap_update_bits(arizona->regmap, base + 5,
-			   ARIZONA_FLL1_FRATIO_MASK,
-			   cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
-	regmap_update_bits(arizona->regmap, base + 6,
-			   ARIZONA_FLL1_CLK_REF_DIV_MASK |
-			   ARIZONA_FLL1_CLK_REF_SRC_MASK,
-			   cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
-			   source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
+	regmap_update_bits_async(arizona->regmap, base + 3,
+				 ARIZONA_FLL1_THETA_MASK, cfg->theta);
+	regmap_update_bits_async(arizona->regmap, base + 4,
+				 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
+	regmap_update_bits_async(arizona->regmap, base + 5,
+				 ARIZONA_FLL1_FRATIO_MASK,
+				 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
+	regmap_update_bits_async(arizona->regmap, base + 6,
+				 ARIZONA_FLL1_CLK_REF_DIV_MASK |
+				 ARIZONA_FLL1_CLK_REF_SRC_MASK,
+				 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
+				 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
 
 	if (sync)
-		regmap_update_bits(arizona->regmap, base + 0x7,
-				   ARIZONA_FLL1_GAIN_MASK,
-				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+		regmap_update_bits_async(arizona->regmap, base + 0x7,
+					 ARIZONA_FLL1_GAIN_MASK,
+					 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
 	else
-		regmap_update_bits(arizona->regmap, base + 0x9,
-				   ARIZONA_FLL1_GAIN_MASK,
-				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+		regmap_update_bits_async(arizona->regmap, base + 0x9,
+					 ARIZONA_FLL1_GAIN_MASK,
+					 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
 
-	regmap_update_bits(arizona->regmap, base + 2,
-			   ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
-			   ARIZONA_FLL1_CTRL_UPD | cfg->n);
+	regmap_update_bits_async(arizona->regmap, base + 2,
+				 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
+				 ARIZONA_FLL1_CTRL_UPD | cfg->n);
 }
 
 static bool arizona_is_enabled_fll(struct arizona_fll *fll)
@@ -1485,9 +1540,9 @@ static void arizona_enable_fll(struct arizona_fll *fll,
 	 */
 	if (fll->ref_src >= 0 && fll->ref_freq &&
 	    fll->ref_src != fll->sync_src) {
-		regmap_update_bits(arizona->regmap, fll->base + 5,
-				   ARIZONA_FLL1_OUTDIV_MASK,
-				   ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+		regmap_update_bits_async(arizona->regmap, fll->base + 5,
+					 ARIZONA_FLL1_OUTDIV_MASK,
+					 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
 
 		arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
 				  false);
@@ -1497,15 +1552,15 @@ static void arizona_enable_fll(struct arizona_fll *fll,
 			use_sync = true;
 		}
 	} else if (fll->sync_src >= 0) {
-		regmap_update_bits(arizona->regmap, fll->base + 5,
-				   ARIZONA_FLL1_OUTDIV_MASK,
-				   sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+		regmap_update_bits_async(arizona->regmap, fll->base + 5,
+					 ARIZONA_FLL1_OUTDIV_MASK,
+					 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
 
 		arizona_apply_fll(arizona, fll->base, sync,
 				  fll->sync_src, false);
 
-		regmap_update_bits(arizona->regmap, fll->base + 0x11,
-				   ARIZONA_FLL1_SYNC_ENA, 0);
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
+					 ARIZONA_FLL1_SYNC_ENA, 0);
 	} else {
 		arizona_fll_err(fll, "No clocks provided\n");
 		return;
@@ -1516,11 +1571,12 @@ static void arizona_enable_fll(struct arizona_fll *fll,
 	 * sync source.
 	 */
 	if (use_sync && fll->sync_freq > 100000)
-		regmap_update_bits(arizona->regmap, fll->base + 0x17,
-				   ARIZONA_FLL1_SYNC_BW, 0);
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
+					 ARIZONA_FLL1_SYNC_BW, 0);
 	else
-		regmap_update_bits(arizona->regmap, fll->base + 0x17,
-				   ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
+					 ARIZONA_FLL1_SYNC_BW,
+					 ARIZONA_FLL1_SYNC_BW);
 
 	if (!arizona_is_enabled_fll(fll))
 		pm_runtime_get(arizona->dev);
@@ -1528,14 +1584,14 @@ static void arizona_enable_fll(struct arizona_fll *fll,
 	/* Clear any pending completions */
 	try_wait_for_completion(&fll->ok);
 
-	regmap_update_bits(arizona->regmap, fll->base + 1,
-			   ARIZONA_FLL1_FREERUN, 0);
-	regmap_update_bits(arizona->regmap, fll->base + 1,
-			   ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_FREERUN, 0);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
 	if (use_sync)
-		regmap_update_bits(arizona->regmap, fll->base + 0x11,
-				   ARIZONA_FLL1_SYNC_ENA,
-				   ARIZONA_FLL1_SYNC_ENA);
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
+					 ARIZONA_FLL1_SYNC_ENA,
+					 ARIZONA_FLL1_SYNC_ENA);
 
 	ret = wait_for_completion_timeout(&fll->ok,
 					  msecs_to_jiffies(250));
@@ -1548,8 +1604,8 @@ static void arizona_disable_fll(struct arizona_fll *fll)
 	struct arizona *arizona = fll->arizona;
 	bool change;
 
-	regmap_update_bits(arizona->regmap, fll->base + 1,
-			   ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
 	regmap_update_bits_check(arizona->regmap, fll->base + 1,
 				 ARIZONA_FLL1_ENA, 0, &change);
 	regmap_update_bits(arizona->regmap, fll->base + 0x11,

+ 4 - 1
sound/soc/codecs/arizona.h

@@ -81,7 +81,7 @@ struct arizona_priv {
 	unsigned int spk_ena_pending:1;
 };
 
-#define ARIZONA_NUM_MIXER_INPUTS 99
+#define ARIZONA_NUM_MIXER_INPUTS 103
 
 extern const unsigned int arizona_mixer_tlv[];
 extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
@@ -186,6 +186,8 @@ extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
 extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
 
 extern const struct soc_enum arizona_isrc_fsl[];
+extern const struct soc_enum arizona_isrc_fsh[];
+extern const struct soc_enum arizona_asrc_rate1;
 
 extern const struct soc_enum arizona_in_vi_ramp;
 extern const struct soc_enum arizona_in_vd_ramp;
@@ -199,6 +201,7 @@ extern const struct soc_enum arizona_lhpf3_mode;
 extern const struct soc_enum arizona_lhpf4_mode;
 
 extern const struct soc_enum arizona_ng_hold;
+extern const struct soc_enum arizona_in_hpf_cut_enum;
 extern const struct soc_enum arizona_in_dmic_osr[];
 
 extern int arizona_in_ev(struct snd_soc_dapm_widget *w,

+ 4 - 4
sound/soc/codecs/cs4271.c

@@ -675,7 +675,7 @@ static struct spi_driver cs4271_spi_driver = {
 };
 #endif /* defined(CONFIG_SPI_MASTER) */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static const struct i2c_device_id cs4271_i2c_id[] = {
 	{"cs4271", 0},
 	{}
@@ -728,7 +728,7 @@ static struct i2c_driver cs4271_i2c_driver = {
 	.probe		= cs4271_i2c_probe,
 	.remove		= cs4271_i2c_remove,
 };
-#endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */
+#endif /* IS_ENABLED(CONFIG_I2C) */
 
 /*
  * We only register our serial bus driver here without
@@ -741,7 +741,7 @@ static int __init cs4271_modinit(void)
 {
 	int ret;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#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);
@@ -767,7 +767,7 @@ static void __exit cs4271_modexit(void)
 	spi_unregister_driver(&cs4271_spi_driver);
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&cs4271_i2c_driver);
 #endif
 }

+ 75 - 30
sound/soc/codecs/cs42l52.c

@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
@@ -50,7 +50,7 @@ struct  cs42l52_private {
 	u8 mclksel;
 	u32 mclk;
 	u8 flags;
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
 	struct input_dev *beep;
 	struct work_struct beep_work;
 	int beep_rate;
@@ -233,7 +233,7 @@ static const struct soc_enum mic_bias_level_enum =
 	SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0,
 			ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
 
-static const char * const cs42l52_mic_text[] = { "Single", "Differential" };
+static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
 
 static const struct soc_enum mica_enum =
 	SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
@@ -243,12 +243,6 @@ static const struct soc_enum micb_enum =
 	SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
 			ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
 
-static const struct snd_kcontrol_new mica_mux =
-	SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum);
-
-static const struct snd_kcontrol_new micb_mux =
-	SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum);
-
 static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
 
 static const struct soc_enum digital_output_mux_enum =
@@ -531,6 +525,30 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
 
 };
 
+static const struct snd_kcontrol_new cs42l52_mica_controls[] = {
+	SOC_ENUM("MICA Select", mica_enum),
+};
+
+static const struct snd_kcontrol_new cs42l52_micb_controls[] = {
+	SOC_ENUM("MICB Select", micb_enum),
+};
+
+static int cs42l52_add_mic_controls(struct snd_soc_codec *codec)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l52_platform_data *pdata = &cs42l52->pdata;
+
+	if (!pdata->mica_diff_cfg)
+		snd_soc_add_codec_controls(codec, cs42l52_mica_controls,
+				     ARRAY_SIZE(cs42l52_mica_controls));
+
+	if (!pdata->micb_diff_cfg)
+		snd_soc_add_codec_controls(codec, cs42l52_micb_controls,
+				     ARRAY_SIZE(cs42l52_micb_controls));
+
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
 
 	SND_SOC_DAPM_INPUT("AIN1L"),
@@ -550,9 +568,6 @@ static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL,  0,
 			SND_SOC_NOPM, 0, 0),
 
-	SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux),
-	SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux),
-
 	SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
 	SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
 	SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
@@ -953,7 +968,7 @@ static int cs42l52_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
 static int beep_rates[] = {
 	261, 522, 585, 667, 706, 774, 889, 1000,
 	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1110,6 +1125,8 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
 	}
 	regcache_cache_only(cs42l52->regmap, true);
 
+	cs42l52_add_mic_controls(codec);
+
 	cs42l52_init_beep(codec);
 
 	cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1176,6 +1193,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 	int ret;
 	unsigned int devid = 0;
 	unsigned int reg;
+	u32 val32;
 
 	cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
 			       GFP_KERNEL);
@@ -1189,9 +1207,39 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
 		return ret;
 	}
-
-	if (pdata)
+	if (pdata) {
+		cs42l52->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev,
+				     sizeof(struct cs42l52_platform_data),
+				GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&i2c_client->dev, "could not allocate pdata\n");
+			return -ENOMEM;
+		}
+		if (i2c_client->dev.of_node) {
+			if (of_property_read_bool(i2c_client->dev.of_node,
+				"cirrus,mica-differential-cfg"))
+				pdata->mica_diff_cfg = true;
+
+			if (of_property_read_bool(i2c_client->dev.of_node,
+				"cirrus,micb-differential-cfg"))
+				pdata->micb_diff_cfg = true;
+
+			if (of_property_read_u32(i2c_client->dev.of_node,
+				"cirrus,micbias-lvl", &val32) >= 0)
+				pdata->micbias_lvl = val32;
+
+			if (of_property_read_u32(i2c_client->dev.of_node,
+				"cirrus,chgfreq-divisor", &val32) >= 0)
+				pdata->chgfreq = val32;
+
+			pdata->reset_gpio =
+				of_get_named_gpio(i2c_client->dev.of_node,
+						"cirrus,reset-gpio", 0);
+		}
 		cs42l52->pdata = *pdata;
+	}
 
 	if (cs42l52->pdata.reset_gpio) {
 		ret = gpio_request_one(cs42l52->pdata.reset_gpio,
@@ -1227,29 +1275,18 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 			reg & 0xFF);
 
 	/* Set Platform Data */
-	if (cs42l52->pdata.mica_cfg)
+	if (cs42l52->pdata.mica_diff_cfg)
 		regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
 				   CS42L52_MIC_CTL_TYPE_MASK,
-				cs42l52->pdata.mica_cfg <<
+				cs42l52->pdata.mica_diff_cfg <<
 				CS42L52_MIC_CTL_TYPE_SHIFT);
 
-	if (cs42l52->pdata.micb_cfg)
+	if (cs42l52->pdata.micb_diff_cfg)
 		regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
 				   CS42L52_MIC_CTL_TYPE_MASK,
-				cs42l52->pdata.micb_cfg <<
+				cs42l52->pdata.micb_diff_cfg <<
 				CS42L52_MIC_CTL_TYPE_SHIFT);
 
-	if (cs42l52->pdata.mica_sel)
-		regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
-				   CS42L52_MIC_CTL_MIC_SEL_MASK,
-				cs42l52->pdata.mica_sel <<
-				CS42L52_MIC_CTL_MIC_SEL_SHIFT);
-	if (cs42l52->pdata.micb_sel)
-		regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
-				   CS42L52_MIC_CTL_MIC_SEL_MASK,
-				cs42l52->pdata.micb_sel <<
-				CS42L52_MIC_CTL_MIC_SEL_SHIFT);
-
 	if (cs42l52->pdata.chgfreq)
 		regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP,
 				   CS42L52_CHARGE_PUMP_MASK,
@@ -1274,6 +1311,13 @@ static int cs42l52_i2c_remove(struct i2c_client *client)
 	return 0;
 }
 
+static const struct of_device_id cs42l52_of_match[] = {
+	{ .compatible = "cirrus,cs42l52", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs42l52_of_match);
+
+
 static const struct i2c_device_id cs42l52_id[] = {
 	{ "cs42l52", 0 },
 	{ }
@@ -1284,6 +1328,7 @@ static struct i2c_driver cs42l52_i2c_driver = {
 	.driver = {
 		.name = "cs42l52",
 		.owner = THIS_MODULE,
+		.of_match_table = cs42l52_of_match,
 	},
 	.id_table = cs42l52_id,
 	.probe =    cs42l52_i2c_probe,

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

@@ -1188,7 +1188,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
 	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 
 static struct reg_default da7210_regmap_i2c_patch[] = {
 
@@ -1362,7 +1362,7 @@ static struct spi_driver da7210_spi_driver = {
 static int __init da7210_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&da7210_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)
@@ -1378,7 +1378,7 @@ module_init(da7210_modinit);
 
 static void __exit da7210_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&da7210_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

+ 11 - 1
sound/soc/codecs/hdmi.c

@@ -20,6 +20,7 @@
  */
 #include <linux/module.h>
 #include <sound/soc.h>
+#include <linux/of_device.h>
 
 #define DRV_NAME "hdmi-audio-codec"
 
@@ -44,7 +45,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
 			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
 			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
-			SNDRV_PCM_FMTBIT_S24_LE,
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.capture = {
 		.stream_name = "Capture",
@@ -60,6 +61,14 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
 
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id hdmi_audio_codec_ids[] = {
+	{ .compatible = "linux,hdmi-audio", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids);
+#endif
+
 static struct snd_soc_codec_driver hdmi_codec = {
 	.dapm_widgets = hdmi_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
@@ -83,6 +92,7 @@ static struct platform_driver hdmi_codec_driver = {
 	.driver		= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(hdmi_audio_codec_ids),
 	},
 
 	.probe		= hdmi_codec_probe,

+ 24 - 52
sound/soc/codecs/sgtl5000.c

@@ -115,6 +115,7 @@ struct sgtl5000_priv {
 	struct ldo_regulator *ldo;
 	struct regmap *regmap;
 	struct clk *mclk;
+	int revision;
 };
 
 /*
@@ -1285,41 +1286,45 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
 
 	sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
 
-	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
-			sgtl5000->supplies);
-
-	if (ret) {
-		ldo_regulator_remove(codec);
-		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-		return ret;
-	}
-
 	dev_info(codec->dev, "Using internal LDO instead of VDDD\n");
 	return 0;
 }
 
 static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
 {
-	int reg;
 	int ret;
-	int rev;
 	int i;
 	int external_vddd = 0;
 	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct regulator *vddd;
 
 	for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++)
 		sgtl5000->supplies[i].supply = supply_names[i];
 
-	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
-				sgtl5000->supplies);
-	if (!ret)
-		external_vddd = 1;
-	else {
+	/* External VDDD only works before revision 0x11 */
+	if (sgtl5000->revision < 0x11) {
+		vddd = regulator_get_optional(codec->dev, "VDDD");
+		if (IS_ERR(vddd)) {
+			/* See if it's just not registered yet */
+			if (PTR_ERR(vddd) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+		} else {
+			external_vddd = 1;
+			regulator_put(vddd);
+		}
+	}
+
+	if (!external_vddd) {
 		ret = sgtl5000_replace_vddd_with_ldo(codec);
 		if (ret)
 			return ret;
 	}
 
+	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
+				 sgtl5000->supplies);
+	if (ret)
+		goto err_ldo_remove;
+
 	ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
 					sgtl5000->supplies);
 	if (ret)
@@ -1328,47 +1333,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
 	/* wait for all power rails bring up */
 	udelay(10);
 
-	/*
-	 * workaround for revision 0x11 and later,
-	 * roll back to use internal LDO
-	 */
-
-	ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
-	if (ret)
-		goto err_regulator_disable;
-
-	rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
-
-	if (external_vddd && rev >= 0x11) {
-		/* disable all regulator first */
-		regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
-					sgtl5000->supplies);
-		/* free VDDD regulator */
-		regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
-					sgtl5000->supplies);
-
-		ret = sgtl5000_replace_vddd_with_ldo(codec);
-		if (ret)
-			return ret;
-
-		ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
-						sgtl5000->supplies);
-		if (ret)
-			goto err_regulator_free;
-
-		/* wait for all power rails bring up */
-		udelay(10);
-	}
-
 	return 0;
 
-err_regulator_disable:
-	regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
-				sgtl5000->supplies);
 err_regulator_free:
 	regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
 				sgtl5000->supplies);
-	if (external_vddd)
+err_ldo_remove:
+	if (!external_vddd)
 		ldo_regulator_remove(codec);
 	return ret;
 
@@ -1566,6 +1537,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 
 	rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
 	dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
+	sgtl5000->revision = rev;
 
 	i2c_set_clientdata(client, sgtl5000);
 

+ 4 - 4
sound/soc/codecs/ssm2518.c

@@ -549,13 +549,13 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		right_slot = 0;
 	} else {
 		/* We assume the left channel < right channel */
-		left_slot = ffs(tx_mask);
-		tx_mask &= ~(1 << tx_mask);
+		left_slot = __ffs(tx_mask);
+		tx_mask &= ~(1 << left_slot);
 		if (tx_mask == 0) {
 			right_slot = left_slot;
 		} else {
-			right_slot = ffs(tx_mask);
-			tx_mask &= ~(1 << tx_mask);
+			right_slot = __ffs(tx_mask);
+			tx_mask &= ~(1 << right_slot);
 		}
 	}
 

+ 5 - 51
sound/soc/codecs/ssm2602.c

@@ -53,8 +53,6 @@ enum ssm2602_type {
 struct ssm2602_priv {
 	unsigned int sysclk;
 	struct snd_pcm_hw_constraint_list *sysclk_constraints;
-	struct snd_pcm_substream *master_substream;
-	struct snd_pcm_substream *slave_substream;
 
 	struct regmap *regmap;
 
@@ -277,11 +275,6 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
 	unsigned int iface;
 
-	if (substream == ssm2602->slave_substream) {
-		dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
-		return 0;
-	}
-
 	if (srate < 0)
 		return srate;
 
@@ -314,33 +307,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	struct snd_pcm_runtime *master_runtime;
-
-	/* The DAI has shared clocks so if we already have a playback or
-	 * capture going then constrain this substream to match it.
-	 * TODO: the ssm2602 allows pairs of non-matching PB/REC rates
-	 */
-	if (ssm2602->master_substream) {
-		master_runtime = ssm2602->master_substream->runtime;
-		dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
-			master_runtime->sample_bits,
-			master_runtime->rate);
-
-		if (master_runtime->rate != 0)
-			snd_pcm_hw_constraint_minmax(substream->runtime,
-						     SNDRV_PCM_HW_PARAM_RATE,
-						     master_runtime->rate,
-						     master_runtime->rate);
-
-		if (master_runtime->sample_bits != 0)
-			snd_pcm_hw_constraint_minmax(substream->runtime,
-						     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-						     master_runtime->sample_bits,
-						     master_runtime->sample_bits);
-
-		ssm2602->slave_substream = substream;
-	} else
-		ssm2602->master_substream = substream;
 
 	if (ssm2602->sysclk_constraints) {
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -351,19 +317,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static void ssm2602_shutdown(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-
-	if (ssm2602->master_substream == substream)
-		ssm2602->master_substream = ssm2602->slave_substream;
-
-	ssm2602->slave_substream = NULL;
-}
-
-
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
@@ -530,7 +483,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 static const struct snd_soc_dai_ops ssm2602_dai_ops = {
 	.startup	= ssm2602_startup,
 	.hw_params	= ssm2602_hw_params,
-	.shutdown	= ssm2602_shutdown,
 	.digital_mute	= ssm2602_mute,
 	.set_sysclk	= ssm2602_set_dai_sysclk,
 	.set_fmt	= ssm2602_set_dai_fmt,
@@ -551,6 +503,8 @@ static struct snd_soc_dai_driver ssm2602_dai = {
 		.rates = SSM2602_RATES,
 		.formats = SSM2602_FORMATS,},
 	.ops = &ssm2602_dai_ops,
+	.symmetric_rates = 1,
+	.symmetric_samplebits = 1,
 };
 
 static int ssm2602_suspend(struct snd_soc_codec *codec)
@@ -730,7 +684,7 @@ static struct spi_driver ssm2602_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 /*
  * ssm2602 2 wire address is determined by GPIO5
  * state during powerup.
@@ -797,7 +751,7 @@ static int __init ssm2602_modinit(void)
 		return ret;
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&ssm2602_i2c_driver);
 	if (ret)
 		return ret;
@@ -813,7 +767,7 @@ static void __exit ssm2602_exit(void)
 	spi_unregister_driver(&ssm2602_spi_driver);
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&ssm2602_i2c_driver);
 #endif
 }

+ 83 - 43
sound/soc/codecs/tlv320aic3x.c

@@ -350,16 +350,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 			 DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
 			 0, 118, 1, output_stage_tlv),
 
-	SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
-			 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
-			 0, 118, 1, output_stage_tlv),
-	SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
-			 PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
-			 0, 118, 1, output_stage_tlv),
-	SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
-			 DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
-			 0, 118, 1, output_stage_tlv),
-
 	SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
 			 LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
 			 0, 118, 1, output_stage_tlv),
@@ -383,7 +373,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 	/* Output pin mute controls */
 	SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
 		     0x01, 0),
-	SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
 	SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
 		     0x01, 0),
 	SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
@@ -412,6 +401,20 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 	SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
 };
 
+static const struct snd_kcontrol_new aic3x_mono_controls[] = {
+	SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+			 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+			 PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
+			 DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+};
+
 /*
  * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
  */
@@ -565,9 +568,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 	SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
 
-	/* Mono Output */
-	SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
-
 	/* Inputs to Left ADC */
 	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
 	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
@@ -626,9 +626,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 	SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
 			   &aic3x_right_line_mixer_controls[0],
 			   ARRAY_SIZE(aic3x_right_line_mixer_controls)),
-	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
-			   &aic3x_mono_mixer_controls[0],
-			   ARRAY_SIZE(aic3x_mono_mixer_controls)),
 	SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
 			   &aic3x_left_hp_mixer_controls[0],
 			   ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
@@ -644,7 +641,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 
 	SND_SOC_DAPM_OUTPUT("LLOUT"),
 	SND_SOC_DAPM_OUTPUT("RLOUT"),
-	SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
 	SND_SOC_DAPM_OUTPUT("HPLOUT"),
 	SND_SOC_DAPM_OUTPUT("HPROUT"),
 	SND_SOC_DAPM_OUTPUT("HPLCOM"),
@@ -666,6 +662,17 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("Detection"),
 };
 
+static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
+	/* Mono Output */
+	SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_mono_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_mono_mixer_controls)),
+
+	SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
+};
+
 static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
 	/* Class-D outputs */
 	SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
@@ -754,17 +761,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"Right Line Out", NULL, "Right DAC Mux"},
 	{"RLOUT", NULL, "Right Line Out"},
 
-	/* Mono Output */
-	{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
-	{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
-	{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
-	{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
-	{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
-	{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
-
-	{"Mono Out", NULL, "Mono Mixer"},
-	{"MONO_LOUT", NULL, "Mono Out"},
-
 	/* Left HP Output */
 	{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
 	{"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
@@ -820,6 +816,18 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"HPRCOM", NULL, "Right HP Com"},
 };
 
+static const struct snd_soc_dapm_route intercon_mono[] = {
+	/* Mono Output */
+	{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+	{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONO_LOUT", NULL, "Mono Out"},
+};
+
 static const struct snd_soc_dapm_route intercon_3007[] = {
 	/* Class-D outputs */
 	{"Left Class-D Out", NULL, "Left Line Out"},
@@ -833,11 +841,20 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
 	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-	if (aic3x->model == AIC3X_MODEL_3007) {
+	switch (aic3x->model) {
+	case AIC3X_MODEL_3X:
+	case AIC3X_MODEL_33:
+		snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
+			ARRAY_SIZE(aic3x_dapm_mono_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_mono,
+					ARRAY_SIZE(intercon_mono));
+		break;
+	case AIC3X_MODEL_3007:
 		snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
 			ARRAY_SIZE(aic3007_dapm_widgets));
 		snd_soc_dapm_add_routes(dapm, intercon_3007,
 					ARRAY_SIZE(intercon_3007));
+		break;
 	}
 
 	return 0;
@@ -1218,6 +1235,24 @@ static int aic3x_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
+static void aic3x_mono_init(struct snd_soc_codec *codec)
+{
+	/* DAC to Mono Line Out default volume and route to Output mixer */
+	snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+
+	/* unmute all outputs */
+	snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
+
+	/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
+	snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+
+	/* Line2 to Mono Out default volume, disconnect from Output Mixer */
+	snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+}
+
 /*
  * initialise the AIC3X driver
  * register the mixer and dsp interfaces with the kernel
@@ -1241,14 +1276,10 @@ static int aic3x_init(struct snd_soc_codec *codec)
 	/* DAC to Line Out default volume and route to Output mixer */
 	snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 	snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-	/* DAC to Mono Line Out default volume and route to Output mixer */
-	snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-	snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 
 	/* unmute all outputs */
 	snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE);
 	snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE);
-	snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
 	snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE);
 	snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE);
 	snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE);
@@ -1269,9 +1300,6 @@ static int aic3x_init(struct snd_soc_codec *codec)
 	/* PGA to Line Out default volume, disconnect from Output Mixer */
 	snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
 	snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
-	/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
-	snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
 
 	/* Line2 to HP Bypass default volume, disconnect from Output Mixer */
 	snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
@@ -1281,12 +1309,15 @@ static int aic3x_init(struct snd_soc_codec *codec)
 	/* Line2 Line Out default volume, disconnect from Output Mixer */
 	snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
 	snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
-	/* Line2 to Mono Out default volume, disconnect from Output Mixer */
-	snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
 
-	if (aic3x->model == AIC3X_MODEL_3007) {
+	switch (aic3x->model) {
+	case AIC3X_MODEL_3X:
+	case AIC3X_MODEL_33:
+		aic3x_mono_init(codec);
+		break;
+	case AIC3X_MODEL_3007:
 		snd_soc_write(codec, CLASSD_CTRL, 0);
+		break;
 	}
 
 	return 0;
@@ -1343,8 +1374,17 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 			      (aic3x->setup->gpio_func[1] & 0xf) << 4);
 	}
 
-	if (aic3x->model == AIC3X_MODEL_3007)
-		snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
+	switch (aic3x->model) {
+	case AIC3X_MODEL_3X:
+	case AIC3X_MODEL_33:
+		snd_soc_add_codec_controls(codec, aic3x_mono_controls,
+				ARRAY_SIZE(aic3x_mono_controls));
+		break;
+	case AIC3X_MODEL_3007:
+		snd_soc_add_codec_controls(codec,
+				&aic3x_classd_amp_gain_ctrl, 1);
+		break;
+	}
 
 	/* set mic bias voltage */
 	switch (aic3x->micbias_vg) {

+ 66 - 161
sound/soc/codecs/twl6040.c

@@ -72,6 +72,7 @@ struct twl6040_data {
 	int hs_power_mode_locked;
 	bool dl1_unmuted;
 	bool dl2_unmuted;
+	u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1];
 	unsigned int clk_in;
 	unsigned int sysclk;
 	struct twl6040_jack_data hs_jack;
@@ -79,75 +80,6 @@ struct twl6040_data {
 	struct mutex mutex;
 };
 
-/*
- * twl6040 register cache & default register settings
- */
-static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
-	0x00, /* not used	0x00	*/
-	0x4B, /* REG_ASICID	0x01 (ro) */
-	0x00, /* REG_ASICREV	0x02 (ro) */
-	0x00, /* REG_INTID	0x03	*/
-	0x00, /* REG_INTMR	0x04	*/
-	0x00, /* REG_NCPCTRL	0x05	*/
-	0x00, /* REG_LDOCTL	0x06	*/
-	0x60, /* REG_HPPLLCTL	0x07	*/
-	0x00, /* REG_LPPLLCTL	0x08	*/
-	0x4A, /* REG_LPPLLDIV	0x09	*/
-	0x00, /* REG_AMICBCTL	0x0A	*/
-	0x00, /* REG_DMICBCTL	0x0B	*/
-	0x00, /* REG_MICLCTL	0x0C	*/
-	0x00, /* REG_MICRCTL	0x0D	*/
-	0x00, /* REG_MICGAIN	0x0E	*/
-	0x1B, /* REG_LINEGAIN	0x0F	*/
-	0x00, /* REG_HSLCTL	0x10	*/
-	0x00, /* REG_HSRCTL	0x11	*/
-	0x00, /* REG_HSGAIN	0x12	*/
-	0x00, /* REG_EARCTL	0x13	*/
-	0x00, /* REG_HFLCTL	0x14	*/
-	0x00, /* REG_HFLGAIN	0x15	*/
-	0x00, /* REG_HFRCTL	0x16	*/
-	0x00, /* REG_HFRGAIN	0x17	*/
-	0x00, /* REG_VIBCTLL	0x18	*/
-	0x00, /* REG_VIBDATL	0x19	*/
-	0x00, /* REG_VIBCTLR	0x1A	*/
-	0x00, /* REG_VIBDATR	0x1B	*/
-	0x00, /* REG_HKCTL1	0x1C	*/
-	0x00, /* REG_HKCTL2	0x1D	*/
-	0x00, /* REG_GPOCTL	0x1E	*/
-	0x00, /* REG_ALB	0x1F	*/
-	0x00, /* REG_DLB	0x20	*/
-	0x00, /* not used	0x21	*/
-	0x00, /* not used	0x22	*/
-	0x00, /* not used	0x23	*/
-	0x00, /* not used	0x24	*/
-	0x00, /* not used	0x25	*/
-	0x00, /* not used	0x26	*/
-	0x00, /* not used	0x27	*/
-	0x00, /* REG_TRIM1	0x28	*/
-	0x00, /* REG_TRIM2	0x29	*/
-	0x00, /* REG_TRIM3	0x2A	*/
-	0x00, /* REG_HSOTRIM	0x2B	*/
-	0x00, /* REG_HFOTRIM	0x2C	*/
-	0x09, /* REG_ACCCTL	0x2D	*/
-	0x00, /* REG_STATUS	0x2E (ro) */
-};
-
-/* List of registers to be restored after power up */
-static const int twl6040_restore_list[] = {
-	TWL6040_REG_MICLCTL,
-	TWL6040_REG_MICRCTL,
-	TWL6040_REG_MICGAIN,
-	TWL6040_REG_LINEGAIN,
-	TWL6040_REG_HSLCTL,
-	TWL6040_REG_HSRCTL,
-	TWL6040_REG_HSGAIN,
-	TWL6040_REG_EARCTL,
-	TWL6040_REG_HFLCTL,
-	TWL6040_REG_HFLGAIN,
-	TWL6040_REG_HFRCTL,
-	TWL6040_REG_HFRGAIN,
-};
-
 /* set of rates for each pll: low-power and high-performance */
 static unsigned int lp_rates[] = {
 	8000,
@@ -174,53 +106,33 @@ static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
 	{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
 };
 
-/*
- * read twl6040 register cache
- */
-static inline unsigned int twl6040_read_reg_cache(struct snd_soc_codec *codec,
-						unsigned int reg)
-{
-	u8 *cache = codec->reg_cache;
-
-	if (reg >= TWL6040_CACHEREGNUM)
-		return -EIO;
-
-	return cache[reg];
-}
-
-/*
- * write twl6040 register cache
- */
-static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
-						u8 reg, u8 value)
-{
-	u8 *cache = codec->reg_cache;
-
-	if (reg >= TWL6040_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-/*
- * read from twl6040 hardware register
- */
-static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
-			unsigned int reg)
+static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
 {
+	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 	struct twl6040 *twl6040 = codec->control_data;
 	u8 value;
 
 	if (reg >= TWL6040_CACHEREGNUM)
 		return -EIO;
 
-	value = twl6040_reg_read(twl6040, reg);
-	twl6040_write_reg_cache(codec, reg, value);
+	switch (reg) {
+	case TWL6040_REG_HSLCTL:
+	case TWL6040_REG_HSRCTL:
+	case TWL6040_REG_EARCTL:
+	case TWL6040_REG_HFLCTL:
+	case TWL6040_REG_HFRCTL:
+		value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL];
+		break;
+	default:
+		value = twl6040_reg_read(twl6040, reg);
+		break;
+	}
 
 	return value;
 }
 
-static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
-				    unsigned int reg)
+static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
+				  unsigned int reg)
 {
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
@@ -238,9 +150,24 @@ static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
 	}
 }
 
-/*
- * write to the twl6040 register space
- */
+static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
+					     u8 reg, u8 value)
+{
+	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (reg) {
+	case TWL6040_REG_HSLCTL:
+	case TWL6040_REG_HSRCTL:
+	case TWL6040_REG_EARCTL:
+	case TWL6040_REG_HFLCTL:
+	case TWL6040_REG_HFRCTL:
+		priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value;
+		break;
+	default:
+		break;
+	}
+}
+
 static int twl6040_write(struct snd_soc_codec *codec,
 			unsigned int reg, unsigned int value)
 {
@@ -249,8 +176,8 @@ static int twl6040_write(struct snd_soc_codec *codec,
 	if (reg >= TWL6040_CACHEREGNUM)
 		return -EIO;
 
-	twl6040_write_reg_cache(codec, reg, value);
-	if (twl6040_is_path_unmuted(codec, reg))
+	twl6040_update_dl12_cache(codec, reg, value);
+	if (twl6040_can_write_to_chip(codec, reg))
 		return twl6040_reg_write(twl6040, reg, value);
 	else
 		return 0;
@@ -258,45 +185,27 @@ static int twl6040_write(struct snd_soc_codec *codec,
 
 static void twl6040_init_chip(struct snd_soc_codec *codec)
 {
-	struct twl6040 *twl6040 = codec->control_data;
-	u8 val;
-
-	/* Update reg_cache: ASICREV, and TRIM values */
-	val = twl6040_get_revid(twl6040);
-	twl6040_write_reg_cache(codec, TWL6040_REG_ASICREV, val);
-
-	twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM1);
-	twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM2);
-	twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM3);
-	twl6040_read_reg_volatile(codec, TWL6040_REG_HSOTRIM);
-	twl6040_read_reg_volatile(codec, TWL6040_REG_HFOTRIM);
+	twl6040_read(codec, TWL6040_REG_TRIM1);
+	twl6040_read(codec, TWL6040_REG_TRIM2);
+	twl6040_read(codec, TWL6040_REG_TRIM3);
+	twl6040_read(codec, TWL6040_REG_HSOTRIM);
+	twl6040_read(codec, TWL6040_REG_HFOTRIM);
 
 	/* Change chip defaults */
 	/* No imput selected for microphone amplifiers */
-	twl6040_write_reg_cache(codec, TWL6040_REG_MICLCTL, 0x18);
-	twl6040_write_reg_cache(codec, TWL6040_REG_MICRCTL, 0x18);
+	twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18);
+	twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);
 
 	/*
 	 * We need to lower the default gain values, so the ramp code
 	 * can work correctly for the first playback.
 	 * This reduces the pop noise heard at the first playback.
 	 */
-	twl6040_write_reg_cache(codec, TWL6040_REG_HSGAIN, 0xff);
-	twl6040_write_reg_cache(codec, TWL6040_REG_EARCTL, 0x1e);
-	twl6040_write_reg_cache(codec, TWL6040_REG_HFLGAIN, 0x1d);
-	twl6040_write_reg_cache(codec, TWL6040_REG_HFRGAIN, 0x1d);
-	twl6040_write_reg_cache(codec, TWL6040_REG_LINEGAIN, 0);
-}
-
-static void twl6040_restore_regs(struct snd_soc_codec *codec)
-{
-	u8 *cache = codec->reg_cache;
-	int reg, i;
-
-	for (i = 0; i < ARRAY_SIZE(twl6040_restore_list); i++) {
-		reg = twl6040_restore_list[i];
-		twl6040_write(codec, reg, cache[reg]);
-	}
+	twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff);
+	twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e);
+	twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d);
+	twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d);
+	twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);
 }
 
 /* set headset dac and driver power mode */
@@ -305,8 +214,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 	int hslctl, hsrctl;
 	int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
 
-	hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
-	hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+	hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
+	hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
 
 	if (high_perf) {
 		hslctl &= ~mask;
@@ -333,8 +242,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 	 * Both HS DAC need to be turned on (before the HS driver) and off at
 	 * the same time.
 	 */
-	hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
-	hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+	hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
+	hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		hslctl |= TWL6040_HSDACENA;
 		hsrctl |= TWL6040_HSDACENA;
@@ -379,7 +288,7 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
 	mutex_lock(&priv->mutex);
 
 	/* Sync status */
-	status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS);
+	status = twl6040_read(codec, TWL6040_REG_STATUS);
 	if (status & TWL6040_PLUGCOMP)
 		snd_soc_jack_report(jack, report, report);
 	else
@@ -431,7 +340,7 @@ static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
 	unsigned int val;
 
 	/* Do not allow changes while Input/FF efect is running */
-	val = twl6040_read_reg_volatile(codec, e->reg);
+	val = twl6040_read(codec, e->reg);
 	if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
 		return -EBUSY;
 
@@ -656,7 +565,7 @@ int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
 	if (unlikely(trim >= TWL6040_TRIM_INVAL))
 		return -EINVAL;
 
-	return twl6040_read_reg_cache(codec, TWL6040_REG_TRIM1 + trim);
+	return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);
 }
 EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
 
@@ -931,8 +840,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
 
 		priv->codec_powered = 1;
 
-		twl6040_restore_regs(codec);
-
 		/* Set external boost GPO */
 		twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
 		break;
@@ -1053,9 +960,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
 
 	switch (id) {
 	case TWL6040_DAI_DL1:
-		hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
-		hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
-		earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL);
+		hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
+		hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
+		earctl = twl6040_read(codec, TWL6040_REG_EARCTL);
 
 		if (mute) {
 			/* Power down drivers and DACs */
@@ -1071,8 +978,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
 		priv->dl1_unmuted = !mute;
 		break;
 	case TWL6040_DAI_DL2:
-		hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL);
-		hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL);
+		hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL);
+		hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);
 
 		if (mute) {
 			/* Power down drivers and DACs */
@@ -1209,6 +1116,7 @@ static int twl6040_resume(struct snd_soc_codec *codec)
 static int twl6040_probe(struct snd_soc_codec *codec)
 {
 	struct twl6040_data *priv;
+	struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
 	struct platform_device *pdev = container_of(codec->dev,
 						   struct platform_device, dev);
 	int ret = 0;
@@ -1220,7 +1128,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 	snd_soc_codec_set_drvdata(codec, priv);
 
 	priv->codec = codec;
-	codec->control_data = dev_get_drvdata(codec->dev->parent);
+	codec->control_data = twl6040;
 
 	priv->plug_irq = platform_get_irq(pdev, 0);
 	if (priv->plug_irq < 0) {
@@ -1240,10 +1148,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 		return ret;
 	}
 
+	twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	twl6040_init_chip(codec);
 
-	/* power on device */
-	return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
 }
 
 static int twl6040_remove(struct snd_soc_codec *codec)
@@ -1261,12 +1169,9 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
 	.remove = twl6040_remove,
 	.suspend = twl6040_suspend,
 	.resume = twl6040_resume,
-	.read = twl6040_read_reg_cache,
+	.read = twl6040_read,
 	.write = twl6040_write,
 	.set_bias_level = twl6040_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(twl6040_reg),
-	.reg_word_size = sizeof(u8),
-	.reg_cache_default = twl6040_reg,
 	.ignore_pmdown_time = true,
 
 	.controls = twl6040_snd_controls,

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

@@ -794,7 +794,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
 	.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int uda1380_i2c_probe(struct i2c_client *i2c,
 			     const struct i2c_device_id *id)
 {
@@ -840,7 +840,7 @@ static struct i2c_driver uda1380_i2c_driver = {
 static int __init uda1380_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&uda1380_i2c_driver);
 	if (ret != 0)
 		pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
@@ -851,7 +851,7 @@ module_init(uda1380_modinit);
 
 static void __exit uda1380_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&uda1380_i2c_driver);
 #endif
 }

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

@@ -601,8 +601,8 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMU:
 		if (patch)
 			for (i = 0; i < patch_size; i++)
-				regmap_write(regmap, patch[i].reg,
-					     patch[i].def);
+				regmap_write_async(regmap, patch[i].reg,
+						   patch[i].def);
 		break;
 
 	default:

+ 373 - 6
sound/soc/codecs/wm5110.c

@@ -30,13 +30,51 @@
 #include <linux/mfd/arizona/registers.h>
 
 #include "arizona.h"
+#include "wm_adsp.h"
 #include "wm5110.h"
 
+#define WM5110_NUM_ADSP 4
+
 struct wm5110_priv {
 	struct arizona_priv core;
 	struct arizona_fll fll[2];
 };
 
+static const struct wm_adsp_region wm5110_dsp1_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x100000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x180000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x190000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x1a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp2_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x200000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x290000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp3_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x300000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x390000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp4_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x400000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x480000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x490000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x4a8000 },
+};
+
+static const struct wm_adsp_region *wm5110_dsp_regions[] = {
+	wm5110_dsp1_regions,
+	wm5110_dsp2_regions,
+	wm5110_dsp3_regions,
+	wm5110_dsp4_regions,
+};
+
 static const struct reg_default wm5110_sysclk_revd_patch[] = {
 	{ 0x3093, 0x1001 },
 	{ 0x30E3, 0x1301 },
@@ -67,8 +105,8 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMU:
 		if (patch)
 			for (i = 0; i < patch_size; i++)
-				regmap_write(regmap, patch[i].reg,
-					     patch[i].def);
+				regmap_write_async(regmap, patch[i].reg,
+						   patch[i].def);
 		break;
 
 	default:
@@ -117,6 +155,25 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
 SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
 		     ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
 
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+	   ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+	   ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL,
+	   ARIZONA_IN3L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL,
+	   ARIZONA_IN3R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL,
+	   ARIZONA_IN4L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL,
+	   ARIZONA_IN4R_HPF_SHIFT, 1, 0),
+
 SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
 	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
 SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
@@ -220,6 +277,14 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
+SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
 ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
@@ -285,6 +350,13 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
 SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
 	   ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
 
+SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+	   ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+	   ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
+	   ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0),
+
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
 
@@ -318,6 +390,10 @@ ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
@@ -347,6 +423,22 @@ ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
 
+ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP4L, ARIZONA_DSP4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP4R, ARIZONA_DSP4RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP4, ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE);
+
 ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
 
@@ -377,6 +469,10 @@ ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
 
 ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
 
 ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
@@ -395,6 +491,36 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
 
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
 static const char *wm5110_aec_loopback_texts[] = {
 	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
 	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
@@ -535,6 +661,65 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
 SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
 		 NULL, 0),
 
+WM_ADSP2("DSP1", 0),
+WM_ADSP2("DSP2", 1),
+WM_ADSP2("DSP3", 2),
+WM_ADSP2("DSP4", 3),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
 SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
 		       &wm5110_aec_loopback_mux),
@@ -577,11 +762,27 @@ SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
 		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
 		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
 
 SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
 		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
 		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
 
 SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
 		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
@@ -719,6 +920,10 @@ ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
 
 ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
 ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
 
 ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
 ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
@@ -737,6 +942,41 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
 ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
 ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
 
+ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+ARIZONA_DSP_WIDGETS(DSP4, "DSP4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
 SND_SOC_DAPM_OUTPUT("HPOUT1L"),
 SND_SOC_DAPM_OUTPUT("HPOUT1R"),
 SND_SOC_DAPM_OUTPUT("HPOUT2L"),
@@ -780,6 +1020,10 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
 	{ name, "AIF1RX8", "AIF1RX8" }, \
 	{ name, "AIF2RX1", "AIF2RX1" }, \
 	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF2RX3", "AIF2RX3" }, \
+	{ name, "AIF2RX4", "AIF2RX4" }, \
+	{ name, "AIF2RX5", "AIF2RX5" }, \
+	{ name, "AIF2RX6", "AIF2RX6" }, \
 	{ name, "AIF3RX1", "AIF3RX1" }, \
 	{ name, "AIF3RX2", "AIF3RX2" }, \
 	{ name, "SLIMRX1", "SLIMRX1" }, \
@@ -805,7 +1049,55 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
 	{ name, "ASRC1L", "ASRC1L" }, \
 	{ name, "ASRC1R", "ASRC1R" }, \
 	{ name, "ASRC2L", "ASRC2L" }, \
-	{ name, "ASRC2R", "ASRC2R" }
+	{ name, "ASRC2R", "ASRC2R" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1DEC3", "ISRC1DEC3" }, \
+	{ name, "ISRC1DEC4", "ISRC1DEC4" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC1INT3", "ISRC1INT3" }, \
+	{ name, "ISRC1INT4", "ISRC1INT4" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2DEC3", "ISRC2DEC3" }, \
+	{ name, "ISRC2DEC4", "ISRC2DEC4" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }, \
+	{ name, "ISRC2INT3", "ISRC2INT3" }, \
+	{ name, "ISRC2INT4", "ISRC2INT4" }, \
+	{ name, "ISRC3DEC1", "ISRC3DEC1" }, \
+	{ name, "ISRC3DEC2", "ISRC3DEC2" }, \
+	{ name, "ISRC3DEC3", "ISRC3DEC3" }, \
+	{ name, "ISRC3DEC4", "ISRC3DEC4" }, \
+	{ name, "ISRC3INT1", "ISRC3INT1" }, \
+	{ name, "ISRC3INT2", "ISRC3INT2" }, \
+	{ name, "ISRC3INT3", "ISRC3INT3" }, \
+	{ name, "ISRC3INT4", "ISRC3INT4" }, \
+	{ name, "DSP1.1", "DSP1" }, \
+	{ name, "DSP1.2", "DSP1" }, \
+	{ name, "DSP1.3", "DSP1" }, \
+	{ name, "DSP1.4", "DSP1" }, \
+	{ name, "DSP1.5", "DSP1" }, \
+	{ name, "DSP1.6", "DSP1" }, \
+	{ name, "DSP2.1", "DSP2" }, \
+	{ name, "DSP2.2", "DSP2" }, \
+	{ name, "DSP2.3", "DSP2" }, \
+	{ name, "DSP2.4", "DSP2" }, \
+	{ name, "DSP2.5", "DSP2" }, \
+	{ name, "DSP2.6", "DSP2" }, \
+	{ name, "DSP3.1", "DSP3" }, \
+	{ name, "DSP3.2", "DSP3" }, \
+	{ name, "DSP3.3", "DSP3" }, \
+	{ name, "DSP3.4", "DSP3" }, \
+	{ name, "DSP3.5", "DSP3" }, \
+	{ name, "DSP3.6", "DSP3" }, \
+	{ name, "DSP4.1", "DSP4" }, \
+	{ name, "DSP4.2", "DSP4" }, \
+	{ name, "DSP4.3", "DSP4" }, \
+	{ name, "DSP4.4", "DSP4" }, \
+	{ name, "DSP4.5", "DSP4" }, \
+	{ name, "DSP4.6", "DSP4" }
 
 static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	{ "AIF2 Capture", NULL, "DBVDD2" },
@@ -877,9 +1169,17 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 
 	{ "AIF2 Capture", NULL, "AIF2TX1" },
 	{ "AIF2 Capture", NULL, "AIF2TX2" },
+	{ "AIF2 Capture", NULL, "AIF2TX3" },
+	{ "AIF2 Capture", NULL, "AIF2TX4" },
+	{ "AIF2 Capture", NULL, "AIF2TX5" },
+	{ "AIF2 Capture", NULL, "AIF2TX6" },
 
 	{ "AIF2RX1", NULL, "AIF2 Playback" },
 	{ "AIF2RX2", NULL, "AIF2 Playback" },
+	{ "AIF2RX3", NULL, "AIF2 Playback" },
+	{ "AIF2RX4", NULL, "AIF2 Playback" },
+	{ "AIF2RX5", NULL, "AIF2 Playback" },
+	{ "AIF2RX6", NULL, "AIF2 Playback" },
 
 	{ "AIF3 Capture", NULL, "AIF3TX1" },
 	{ "AIF3 Capture", NULL, "AIF3TX2" },
@@ -963,6 +1263,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 
 	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
 	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+	ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+	ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+	ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+	ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
 
 	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
 	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
@@ -999,6 +1303,41 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
 	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
 
+	ARIZONA_DSP_ROUTES("DSP1"),
+	ARIZONA_DSP_ROUTES("DSP2"),
+	ARIZONA_DSP_ROUTES("DSP3"),
+	ARIZONA_DSP_ROUTES("DSP4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+	ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+	ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+	ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+	ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+	ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+	ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+	ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
 	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
 	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
 	{ "HPOUT1L", NULL, "OUT1L" },
@@ -1095,14 +1434,14 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 		.playback = {
 			.stream_name = "AIF2 Playback",
 			.channels_min = 1,
-			.channels_max = 2,
+			.channels_max = 6,
 			.rates = WM5110_RATES,
 			.formats = WM5110_FORMATS,
 		},
 		.capture = {
 			 .stream_name = "AIF2 Capture",
 			 .channels_min = 1,
-			 .channels_max = 2,
+			 .channels_max = 6,
 			 .rates = WM5110_RATES,
 			 .formats = WM5110_FORMATS,
 		 },
@@ -1204,6 +1543,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
 	arizona_init_spk(codec);
 	arizona_init_gpio(codec);
 
+	ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8);
+	if (ret != 0)
+		return ret;
+
 	snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
 	priv->core.arizona->dapm = &codec->dapm;
@@ -1258,7 +1601,7 @@ static int wm5110_probe(struct platform_device *pdev)
 {
 	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
 	struct wm5110_priv *wm5110;
-	int i;
+	int i, ret;
 
 	wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv),
 			      GFP_KERNEL);
@@ -1269,6 +1612,24 @@ static int wm5110_probe(struct platform_device *pdev)
 	wm5110->core.arizona = arizona;
 	wm5110->core.num_inputs = 8;
 
+	for (i = 0; i < WM5110_NUM_ADSP; i++) {
+		wm5110->core.adsp[i].part = "wm5110";
+		wm5110->core.adsp[i].num = i + 1;
+		wm5110->core.adsp[i].type = WMFW_ADSP2;
+		wm5110->core.adsp[i].dev = arizona->dev;
+		wm5110->core.adsp[i].regmap = arizona->regmap;
+
+		wm5110->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1
+			+ (0x100 * i);
+		wm5110->core.adsp[i].mem = wm5110_dsp_regions[i];
+		wm5110->core.adsp[i].num_mems
+			= ARRAY_SIZE(wm5110_dsp1_regions);
+
+		ret = wm_adsp2_init(&wm5110->core.adsp[i], false);
+		if (ret != 0)
+			return ret;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
 		wm5110->fll[i].vco_mult = 3;
 
@@ -1279,6 +1640,12 @@ static int wm5110_probe(struct platform_device *pdev)
 			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
 			 &wm5110->fll[1]);
 
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
 	for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++)
 		arizona_init_dai(&wm5110->core, i);
 

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

@@ -684,7 +684,7 @@ static struct spi_driver wm8510_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8510_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -735,7 +735,7 @@ static struct i2c_driver wm8510_i2c_driver = {
 static int __init wm8510_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8510_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
@@ -755,7 +755,7 @@ module_init(wm8510_modinit);
 
 static void __exit wm8510_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8510_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -452,7 +452,7 @@ static const struct regmap_config wm8523_regmap = {
 	.volatile_reg = wm8523_volatile_register,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8523_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -555,7 +555,7 @@ static struct i2c_driver wm8523_i2c_driver = {
 static int __init wm8523_modinit(void)
 {
 	int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8523_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n",
@@ -568,7 +568,7 @@ module_init(wm8523_modinit);
 
 static void __exit wm8523_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8523_i2c_driver);
 #endif
 }

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

@@ -941,7 +941,7 @@ static const struct regmap_config wm8580_regmap = {
 	.volatile_reg = wm8580_volatile,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8580_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -1003,7 +1003,7 @@ static int __init wm8580_modinit(void)
 {
 	int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8580_i2c_driver);
 	if (ret != 0) {
 		pr_err("Failed to register WM8580 I2C driver: %d\n", ret);
@@ -1016,7 +1016,7 @@ module_init(wm8580_modinit);
 
 static void __exit wm8580_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8580_i2c_driver);
 #endif
 }

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

@@ -469,7 +469,7 @@ static struct spi_driver wm8711_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8711_i2c_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
@@ -520,7 +520,7 @@ static struct i2c_driver wm8711_i2c_driver = {
 static int __init wm8711_modinit(void)
 {
 	int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8711_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
@@ -540,7 +540,7 @@ module_init(wm8711_modinit);
 
 static void __exit wm8711_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8711_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -320,7 +320,7 @@ static struct spi_driver wm8728_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8728_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -371,7 +371,7 @@ static struct i2c_driver wm8728_i2c_driver = {
 static int __init wm8728_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8728_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
@@ -391,7 +391,7 @@ module_init(wm8728_modinit);
 
 static void __exit wm8728_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8728_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -732,7 +732,7 @@ static struct spi_driver wm8731_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8731_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -791,7 +791,7 @@ static struct i2c_driver wm8731_i2c_driver = {
 static int __init wm8731_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8731_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
@@ -811,7 +811,7 @@ module_init(wm8731_modinit);
 
 static void __exit wm8731_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8731_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -500,7 +500,7 @@ static const struct regmap_config wm8741_regmap = {
 	.readable_reg = wm8741_readable,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8741_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -617,7 +617,7 @@ static int __init wm8741_modinit(void)
 {
 	int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8741_i2c_driver);
 	if (ret != 0)
 		pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
@@ -639,7 +639,7 @@ static void __exit wm8741_exit(void)
 #if defined(CONFIG_SPI_MASTER)
 	spi_unregister_driver(&wm8741_spi_driver);
 #endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8741_i2c_driver);
 #endif
 }

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

@@ -816,7 +816,7 @@ static struct spi_driver wm8750_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8750_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -868,7 +868,7 @@ static struct i2c_driver wm8750_i2c_driver = {
 static int __init wm8750_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8750_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
@@ -888,7 +888,7 @@ module_init(wm8750_modinit);
 
 static void __exit wm8750_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8750_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -1596,7 +1596,7 @@ static struct spi_driver wm8753_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8753_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -1653,7 +1653,7 @@ static struct i2c_driver wm8753_i2c_driver = {
 static int __init wm8753_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8753_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
@@ -1673,7 +1673,7 @@ module_init(wm8753_modinit);
 
 static void __exit wm8753_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8753_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -532,7 +532,7 @@ static struct spi_driver wm8776_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8776_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -584,7 +584,7 @@ static struct i2c_driver wm8776_i2c_driver = {
 static int __init wm8776_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8776_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
@@ -604,7 +604,7 @@ module_init(wm8776_modinit);
 
 static void __exit wm8776_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8776_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -739,7 +739,7 @@ static struct spi_driver wm8804_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8804_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -791,7 +791,7 @@ static int __init wm8804_modinit(void)
 {
 	int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8804_i2c_driver);
 	if (ret) {
 		printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
@@ -811,7 +811,7 @@ module_init(wm8804_modinit);
 
 static void __exit wm8804_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8804_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -1288,7 +1288,7 @@ static struct spi_driver wm8900_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8900_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -1338,7 +1338,7 @@ static struct i2c_driver wm8900_i2c_driver = {
 static int __init wm8900_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8900_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
@@ -1358,7 +1358,7 @@ module_init(wm8900_modinit);
 
 static void __exit wm8900_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8900_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

+ 128 - 93
sound/soc/codecs/wm8940.c

@@ -28,7 +28,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -41,78 +41,116 @@
 
 struct wm8940_priv {
 	unsigned int sysclk;
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 };
 
-static int wm8940_volatile_register(struct snd_soc_codec *codec,
-				    unsigned int reg)
+static bool wm8940_volatile_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case WM8940_SOFTRESET:
-		return 1;
+		return true;
 	default:
-		return 0;
+		return false;
+	}
+}
+
+static bool wm8940_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8940_SOFTRESET:
+	case WM8940_POWER1:
+	case WM8940_POWER2:
+	case WM8940_POWER3:
+	case WM8940_IFACE:
+	case WM8940_COMPANDINGCTL:
+	case WM8940_CLOCK:
+	case WM8940_ADDCNTRL:
+	case WM8940_GPIO:
+	case WM8940_CTLINT:
+	case WM8940_DAC:
+	case WM8940_DACVOL:
+	case WM8940_ADC:
+	case WM8940_ADCVOL:
+	case WM8940_NOTCH1:
+	case WM8940_NOTCH2:
+	case WM8940_NOTCH3:
+	case WM8940_NOTCH4:
+	case WM8940_NOTCH5:
+	case WM8940_NOTCH6:
+	case WM8940_NOTCH7:
+	case WM8940_NOTCH8:
+	case WM8940_DACLIM1:
+	case WM8940_DACLIM2:
+	case WM8940_ALC1:
+	case WM8940_ALC2:
+	case WM8940_ALC3:
+	case WM8940_NOISEGATE:
+	case WM8940_PLLN:
+	case WM8940_PLLK1:
+	case WM8940_PLLK2:
+	case WM8940_PLLK3:
+	case WM8940_ALC4:
+	case WM8940_INPUTCTL:
+	case WM8940_PGAGAIN:
+	case WM8940_ADCBOOST:
+	case WM8940_OUTPUTCTL:
+	case WM8940_SPKMIX:
+	case WM8940_SPKVOL:
+	case WM8940_MONOMIX:
+		return true;
+	default:
+		return false;
 	}
 }
 
-static u16 wm8940_reg_defaults[] = {
-	0x8940, /* Soft Reset */
-	0x0000, /* Power 1 */
-	0x0000, /* Power 2 */
-	0x0000, /* Power 3 */
-	0x0010, /* Interface Control */
-	0x0000, /* Companding Control */
-	0x0140, /* Clock Control */
-	0x0000, /* Additional Controls */
-	0x0000, /* GPIO Control */
-	0x0002, /* Auto Increment Control */
-	0x0000, /* DAC Control */
-	0x00FF, /* DAC Volume */
-	0,
-	0,
-	0x0100, /* ADC Control */
-	0x00FF, /* ADC Volume */
-	0x0000, /* Notch Filter 1 Control 1 */
-	0x0000, /* Notch Filter 1 Control 2 */
-	0x0000, /* Notch Filter 2 Control 1 */
-	0x0000, /* Notch Filter 2 Control 2 */
-	0x0000, /* Notch Filter 3 Control 1 */
-	0x0000, /* Notch Filter 3 Control 2 */
-	0x0000, /* Notch Filter 4 Control 1 */
-	0x0000, /* Notch Filter 4 Control 2 */
-	0x0032, /* DAC Limit Control 1 */
-	0x0000, /* DAC Limit Control 2 */
-	0,
-	0,
-	0,
-	0,
-	0,
-	0,
-	0x0038, /* ALC Control 1 */
-	0x000B, /* ALC Control 2 */
-	0x0032, /* ALC Control 3 */
-	0x0000, /* Noise Gate */
-	0x0041, /* PLLN */
-	0x000C, /* PLLK1 */
-	0x0093, /* PLLK2 */
-	0x00E9, /* PLLK3 */
-	0,
-	0,
-	0x0030, /* ALC Control 4 */
-	0,
-	0x0002, /* Input Control */
-	0x0050, /* PGA Gain */
-	0,
-	0x0002, /* ADC Boost Control */
-	0,
-	0x0002, /* Output Control */
-	0x0000, /* Speaker Mixer Control */
-	0,
-	0,
-	0,
-	0x0079, /* Speaker Volume */
-	0,
-	0x0000, /* Mono Mixer Control */
+static const struct reg_default wm8940_reg_defaults[] = {
+	{  0x1, 0x0000 }, /* Power 1 */
+	{  0x2, 0x0000 }, /* Power 2 */
+	{  0x3, 0x0000 }, /* Power 3 */
+	{  0x4, 0x0010 }, /* Interface Control */
+	{  0x5, 0x0000 }, /* Companding Control */
+	{  0x6, 0x0140 }, /* Clock Control */
+	{  0x7, 0x0000 }, /* Additional Controls */
+	{  0x8, 0x0000 }, /* GPIO Control */
+	{  0x9, 0x0002 }, /* Auto Increment Control */
+	{  0xa, 0x0000 }, /* DAC Control */
+	{  0xb, 0x00FF }, /* DAC Volume */
+
+	{  0xe, 0x0100 }, /* ADC Control */
+	{  0xf, 0x00FF }, /* ADC Volume */
+	{ 0x10, 0x0000 }, /* Notch Filter 1 Control 1 */
+	{ 0x11, 0x0000 }, /* Notch Filter 1 Control 2 */
+	{ 0x12, 0x0000 }, /* Notch Filter 2 Control 1 */
+	{ 0x13, 0x0000 }, /* Notch Filter 2 Control 2 */
+	{ 0x14, 0x0000 }, /* Notch Filter 3 Control 1 */
+	{ 0x15, 0x0000 }, /* Notch Filter 3 Control 2 */
+	{ 0x16, 0x0000 }, /* Notch Filter 4 Control 1 */
+	{ 0x17, 0x0000 }, /* Notch Filter 4 Control 2 */
+	{ 0x18, 0x0032 }, /* DAC Limit Control 1 */
+	{ 0x19, 0x0000 }, /* DAC Limit Control 2 */
+
+	{ 0x20, 0x0038 }, /* ALC Control 1 */
+	{ 0x21, 0x000B }, /* ALC Control 2 */
+	{ 0x22, 0x0032 }, /* ALC Control 3 */
+	{ 0x23, 0x0000 }, /* Noise Gate */
+	{ 0x24, 0x0041 }, /* PLLN */
+	{ 0x25, 0x000C }, /* PLLK1 */
+	{ 0x26, 0x0093 }, /* PLLK2 */
+	{ 0x27, 0x00E9 }, /* PLLK3 */
+
+	{ 0x2a, 0x0030 }, /* ALC Control 4 */
+
+	{ 0x2c, 0x0002 }, /* Input Control */
+	{ 0x2d, 0x0050 }, /* PGA Gain */
+
+	{ 0x2f, 0x0002 }, /* ADC Boost Control */
+
+	{ 0x31, 0x0002 }, /* Output Control */
+	{ 0x32, 0x0000 }, /* Speaker Mixer Control */
+
+	{ 0x36, 0x0079 }, /* Speaker Volume */
+
+	{ 0x38, 0x0000 }, /* Mono Mixer Control */
 };
 
 static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
@@ -264,7 +302,7 @@ static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("AUX"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
 	/* Mono output mixer */
 	{"Mono Mixer", "PCM Playback Switch", "DAC"},
 	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@@ -296,21 +334,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"ADC", NULL, "Boost Mixer"},
 };
 
-static int wm8940_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	int ret;
-
-	ret = snd_soc_dapm_new_controls(dapm, wm8940_dapm_widgets,
-					ARRAY_SIZE(wm8940_dapm_widgets));
-	if (ret)
-		goto error_ret;
-	ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-error_ret:
-	return ret;
-}
-
 #define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
 
 static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -446,6 +469,7 @@ static int wm8940_mute(struct snd_soc_dai *dai, int mute)
 static int wm8940_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
+	struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
 	u16 val;
 	u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
 	int ret = 0;
@@ -469,7 +493,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			ret = snd_soc_cache_sync(codec);
+			ret = regcache_sync(wm8940->regmap);
 			if (ret < 0) {
 				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
 				return ret;
@@ -684,12 +708,11 @@ static int wm8940_resume(struct snd_soc_codec *codec)
 
 static int wm8940_probe(struct snd_soc_codec *codec)
 {
-	struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
 	struct wm8940_setup_data *pdata = codec->dev->platform_data;
 	int ret;
 	u16 reg;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -716,11 +739,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
 			return ret;
 	}
 
-	ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls,
-			     ARRAY_SIZE(wm8940_snd_controls));
-	if (ret)
-		return ret;
-	ret = wm8940_add_widgets(codec);
 	return ret;
 }
 
@@ -736,10 +754,24 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
 	.suspend =	wm8940_suspend,
 	.resume =	wm8940_resume,
 	.set_bias_level = wm8940_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8940_reg_defaults,
-	.volatile_register = wm8940_volatile_register,
+	.controls =     wm8940_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8940_snd_controls),
+	.dapm_widgets = wm8940_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets),
+	.dapm_routes =  wm8940_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes),
+};
+
+static const struct regmap_config wm8940_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8940_MONOMIX,
+	.reg_defaults = wm8940_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults),
+
+	.readable_reg = wm8940_readable_register,
+	.volatile_reg = wm8940_volatile_register,
 };
 
 static int wm8940_i2c_probe(struct i2c_client *i2c,
@@ -753,8 +785,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
 	if (wm8940 == NULL)
 		return -ENOMEM;
 
+	wm8940->regmap = devm_regmap_init_i2c(i2c, &wm8940_regmap);
+	if (IS_ERR(wm8940->regmap))
+		return PTR_ERR(wm8940->regmap);
+
 	i2c_set_clientdata(i2c, wm8940);
-	wm8940->control_type = SND_SOC_I2C;
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8940, &wm8940_dai, 1);

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

@@ -74,7 +74,7 @@ struct wm8962_priv {
 	struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
 	struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
 
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
 	struct input_dev *beep;
 	struct work_struct beep_work;
 	int beep_rate;
@@ -3121,7 +3121,7 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 }
 EXPORT_SYMBOL_GPL(wm8962_mic_detect);
 
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
 static int beep_rates[] = {
 	500, 1000, 2000, 4000,
 };

+ 33 - 21
sound/soc/codecs/wm8974.c

@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -27,22 +28,22 @@
 
 #include "wm8974.h"
 
-static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0050, 0x0000, 0x0140, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x00ff,
-	0x0000, 0x0000, 0x0100, 0x00ff,
-	0x0000, 0x0000, 0x012c, 0x002c,
-	0x002c, 0x002c, 0x002c, 0x0000,
-	0x0032, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0038, 0x000b, 0x0032, 0x0000,
-	0x0008, 0x000c, 0x0093, 0x00e9,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0003, 0x0010, 0x0000, 0x0000,
-	0x0000, 0x0002, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0039, 0x0000,
-	0x0000,
+static const struct reg_default wm8974_reg_defaults[] = {
+	{  0, 0x0000 }, {  1, 0x0000 }, {  2, 0x0000 }, {  3, 0x0000 },
+	{  4, 0x0050 }, {  5, 0x0000 }, {  6, 0x0140 }, {  7, 0x0000 },
+	{  8, 0x0000 }, {  9, 0x0000 }, { 10, 0x0000 }, { 11, 0x00ff },
+	{ 12, 0x0000 }, { 13, 0x0000 }, { 14, 0x0100 }, { 15, 0x00ff },
+	{ 16, 0x0000 }, { 17, 0x0000 }, { 18, 0x012c }, { 19, 0x002c },
+	{ 20, 0x002c }, { 21, 0x002c }, { 22, 0x002c }, { 23, 0x0000 },
+	{ 24, 0x0032 }, { 25, 0x0000 }, { 26, 0x0000 }, { 27, 0x0000 },
+	{ 28, 0x0000 }, { 29, 0x0000 }, { 30, 0x0000 }, { 31, 0x0000 },
+	{ 32, 0x0038 }, { 33, 0x000b }, { 34, 0x0032 }, { 35, 0x0000 },
+	{ 36, 0x0008 }, { 37, 0x000c }, { 38, 0x0093 }, { 39, 0x00e9 },
+	{ 40, 0x0000 }, { 41, 0x0000 }, { 42, 0x0000 }, { 43, 0x0000 },
+	{ 44, 0x0003 }, { 45, 0x0010 }, { 46, 0x0000 }, { 47, 0x0000 },
+	{ 48, 0x0000 }, { 49, 0x0002 }, { 50, 0x0000 }, { 51, 0x0000 },
+	{ 52, 0x0000 }, { 53, 0x0000 }, { 54, 0x0039 }, { 55, 0x0000 },
+	{ 56, 0x0000 },
 };
 
 #define WM8974_POWER1_BIASEN  0x08
@@ -514,7 +515,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
 		power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
 
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			snd_soc_cache_sync(codec);
+			regcache_sync(dev_get_regmap(codec->dev, NULL));
 
 			/* Initial cap charge at VMID 5k */
 			snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
@@ -579,11 +580,20 @@ static int wm8974_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
+static const struct regmap_config wm8974_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8974_MONOMIX,
+	.reg_defaults = wm8974_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
+};
+
 static int wm8974_probe(struct snd_soc_codec *codec)
 {
 	int ret = 0;
 
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -613,9 +623,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
 	.suspend = 	wm8974_suspend,
 	.resume =	wm8974_resume,
 	.set_bias_level = wm8974_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8974_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8974_reg,
 
 	.controls = wm8974_snd_controls,
 	.num_controls = ARRAY_SIZE(wm8974_snd_controls),
@@ -628,8 +635,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
 static int wm8974_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
+	struct regmap *regmap;
 	int ret;
 
+	regmap = devm_regmap_init_i2c(i2c, &wm8974_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8974, &wm8974_dai, 1);
 

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

@@ -1148,7 +1148,7 @@ static struct spi_driver wm8985_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8985_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -1201,7 +1201,7 @@ static int __init wm8985_modinit(void)
 {
 	int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8985_i2c_driver);
 	if (ret) {
 		printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
@@ -1221,7 +1221,7 @@ module_init(wm8985_modinit);
 
 static void __exit wm8985_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8985_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -912,7 +912,7 @@ static struct spi_driver wm8988_spi_driver = {
 };
 #endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8988_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -964,7 +964,7 @@ static struct i2c_driver wm8988_i2c_driver = {
 static int __init wm8988_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8988_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
@@ -984,7 +984,7 @@ module_init(wm8988_modinit);
 
 static void __exit wm8988_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8988_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

+ 105 - 153
sound/soc/codecs/wm8990.c

@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -30,13 +31,12 @@
 
 /* codec private data */
 struct wm8990_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	unsigned int sysclk;
 	unsigned int pcmclk;
 };
 
-static int wm8990_volatile_register(struct snd_soc_codec *codec,
-				    unsigned int reg)
+static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case WM8990_RESET:
@@ -46,71 +46,69 @@ static int wm8990_volatile_register(struct snd_soc_codec *codec,
 	}
 }
 
-static const u16 wm8990_reg[] = {
-	0x8990,     /* R0  - Reset */
-	0x0000,     /* R1  - Power Management (1) */
-	0x6000,     /* R2  - Power Management (2) */
-	0x0000,     /* R3  - Power Management (3) */
-	0x4050,     /* R4  - Audio Interface (1) */
-	0x4000,     /* R5  - Audio Interface (2) */
-	0x01C8,     /* R6  - Clocking (1) */
-	0x0000,     /* R7  - Clocking (2) */
-	0x0040,     /* R8  - Audio Interface (3) */
-	0x0040,     /* R9  - Audio Interface (4) */
-	0x0004,     /* R10 - DAC CTRL */
-	0x00C0,     /* R11 - Left DAC Digital Volume */
-	0x00C0,     /* R12 - Right DAC Digital Volume */
-	0x0000,     /* R13 - Digital Side Tone */
-	0x0100,     /* R14 - ADC CTRL */
-	0x00C0,     /* R15 - Left ADC Digital Volume */
-	0x00C0,     /* R16 - Right ADC Digital Volume */
-	0x0000,     /* R17 */
-	0x0000,     /* R18 - GPIO CTRL 1 */
-	0x1000,     /* R19 - GPIO1 & GPIO2 */
-	0x1010,     /* R20 - GPIO3 & GPIO4 */
-	0x1010,     /* R21 - GPIO5 & GPIO6 */
-	0x8000,     /* R22 - GPIOCTRL 2 */
-	0x0800,     /* R23 - GPIO_POL */
-	0x008B,     /* R24 - Left Line Input 1&2 Volume */
-	0x008B,     /* R25 - Left Line Input 3&4 Volume */
-	0x008B,     /* R26 - Right Line Input 1&2 Volume */
-	0x008B,     /* R27 - Right Line Input 3&4 Volume */
-	0x0000,     /* R28 - Left Output Volume */
-	0x0000,     /* R29 - Right Output Volume */
-	0x0066,     /* R30 - Line Outputs Volume */
-	0x0022,     /* R31 - Out3/4 Volume */
-	0x0079,     /* R32 - Left OPGA Volume */
-	0x0079,     /* R33 - Right OPGA Volume */
-	0x0003,     /* R34 - Speaker Volume */
-	0x0003,     /* R35 - ClassD1 */
-	0x0000,     /* R36 */
-	0x0100,     /* R37 - ClassD3 */
-	0x0079,     /* R38 - ClassD4 */
-	0x0000,     /* R39 - Input Mixer1 */
-	0x0000,     /* R40 - Input Mixer2 */
-	0x0000,     /* R41 - Input Mixer3 */
-	0x0000,     /* R42 - Input Mixer4 */
-	0x0000,     /* R43 - Input Mixer5 */
-	0x0000,     /* R44 - Input Mixer6 */
-	0x0000,     /* R45 - Output Mixer1 */
-	0x0000,     /* R46 - Output Mixer2 */
-	0x0000,     /* R47 - Output Mixer3 */
-	0x0000,     /* R48 - Output Mixer4 */
-	0x0000,     /* R49 - Output Mixer5 */
-	0x0000,     /* R50 - Output Mixer6 */
-	0x0180,     /* R51 - Out3/4 Mixer */
-	0x0000,     /* R52 - Line Mixer1 */
-	0x0000,     /* R53 - Line Mixer2 */
-	0x0000,     /* R54 - Speaker Mixer */
-	0x0000,     /* R55 - Additional Control */
-	0x0000,     /* R56 - AntiPOP1 */
-	0x0000,     /* R57 - AntiPOP2 */
-	0x0000,     /* R58 - MICBIAS */
-	0x0000,     /* R59 */
-	0x0008,     /* R60 - PLL1 */
-	0x0031,     /* R61 - PLL2 */
-	0x0026,     /* R62 - PLL3 */
-	0x0000,	    /* R63 - Driver internal */
+static const struct reg_default wm8990_reg_defaults[] = {
+	{  1, 0x0000 },     /* R1  - Power Management (1) */
+	{  2, 0x6000 },     /* R2  - Power Management (2) */
+	{  3, 0x0000 },     /* R3  - Power Management (3) */
+	{  4, 0x4050 },     /* R4  - Audio Interface (1) */
+	{  5, 0x4000 },     /* R5  - Audio Interface (2) */
+	{  6, 0x01C8 },     /* R6  - Clocking (1) */
+	{  7, 0x0000 },     /* R7  - Clocking (2) */
+	{  8, 0x0040 },     /* R8  - Audio Interface (3) */
+	{  9, 0x0040 },     /* R9  - Audio Interface (4) */
+	{ 10, 0x0004 },     /* R10 - DAC CTRL */
+	{ 11, 0x00C0 },     /* R11 - Left DAC Digital Volume */
+	{ 12, 0x00C0 },     /* R12 - Right DAC Digital Volume */
+	{ 13, 0x0000 },     /* R13 - Digital Side Tone */
+	{ 14, 0x0100 },     /* R14 - ADC CTRL */
+	{ 15, 0x00C0 },     /* R15 - Left ADC Digital Volume */
+	{ 16, 0x00C0 },     /* R16 - Right ADC Digital Volume */
+
+	{ 18, 0x0000 },     /* R18 - GPIO CTRL 1 */
+	{ 19, 0x1000 },     /* R19 - GPIO1 & GPIO2 */
+	{ 20, 0x1010 },     /* R20 - GPIO3 & GPIO4 */
+	{ 21, 0x1010 },     /* R21 - GPIO5 & GPIO6 */
+	{ 22, 0x8000 },     /* R22 - GPIOCTRL 2 */
+	{ 23, 0x0800 },     /* R23 - GPIO_POL */
+	{ 24, 0x008B },     /* R24 - Left Line Input 1&2 Volume */
+	{ 25, 0x008B },     /* R25 - Left Line Input 3&4 Volume */
+	{ 26, 0x008B },     /* R26 - Right Line Input 1&2 Volume */
+	{ 27, 0x008B },     /* R27 - Right Line Input 3&4 Volume */
+	{ 28, 0x0000 },     /* R28 - Left Output Volume */
+	{ 29, 0x0000 },     /* R29 - Right Output Volume */
+	{ 30, 0x0066 },     /* R30 - Line Outputs Volume */
+	{ 31, 0x0022 },     /* R31 - Out3/4 Volume */
+	{ 32, 0x0079 },     /* R32 - Left OPGA Volume */
+	{ 33, 0x0079 },     /* R33 - Right OPGA Volume */
+	{ 34, 0x0003 },     /* R34 - Speaker Volume */
+	{ 35, 0x0003 },     /* R35 - ClassD1 */
+
+	{ 37, 0x0100 },     /* R37 - ClassD3 */
+	{ 38, 0x0079 },     /* R38 - ClassD4 */
+	{ 39, 0x0000 },     /* R39 - Input Mixer1 */
+	{ 40, 0x0000 },     /* R40 - Input Mixer2 */
+	{ 41, 0x0000 },     /* R41 - Input Mixer3 */
+	{ 42, 0x0000 },     /* R42 - Input Mixer4 */
+	{ 43, 0x0000 },     /* R43 - Input Mixer5 */
+	{ 44, 0x0000 },     /* R44 - Input Mixer6 */
+	{ 45, 0x0000 },     /* R45 - Output Mixer1 */
+	{ 46, 0x0000 },     /* R46 - Output Mixer2 */
+	{ 47, 0x0000 },     /* R47 - Output Mixer3 */
+	{ 48, 0x0000 },     /* R48 - Output Mixer4 */
+	{ 49, 0x0000 },     /* R49 - Output Mixer5 */
+	{ 50, 0x0000 },     /* R50 - Output Mixer6 */
+	{ 51, 0x0180 },     /* R51 - Out3/4 Mixer */
+	{ 52, 0x0000 },     /* R52 - Line Mixer1 */
+	{ 53, 0x0000 },     /* R53 - Line Mixer2 */
+	{ 54, 0x0000 },     /* R54 - Speaker Mixer */
+	{ 55, 0x0000 },     /* R55 - Additional Control */
+	{ 56, 0x0000 },     /* R56 - AntiPOP1 */
+	{ 57, 0x0000 },     /* R57 - AntiPOP2 */
+	{ 58, 0x0000 },     /* R58 - MICBIAS */
+
+	{ 60, 0x0008 },     /* R60 - PLL1 */
+	{ 61, 0x0031 },     /* R61 - PLL2 */
+	{ 62, 0x0026 },     /* R62 - PLL3 */
 };
 
 #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
@@ -376,32 +374,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
  * _DAPM_ Controls
  */
 
-static int inmixer_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	u16 reg, fakepower;
-
-	reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2);
-	fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS);
-
-	if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
-		(1 << WM8990_AINLMUX_PWR_BIT))) {
-		reg |= WM8990_AINL_ENA;
-	} else {
-		reg &= ~WM8990_AINL_ENA;
-	}
-
-	if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) |
-		(1 << WM8990_AINRMUX_PWR_BIT))) {
-		reg |= WM8990_AINR_ENA;
-	} else {
-		reg &= ~WM8990_AINR_ENA;
-	}
-	snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
-
-	return 0;
-}
-
 static int outmixer_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -656,6 +628,11 @@ SND_SOC_DAPM_INPUT("RIN1"),
 SND_SOC_DAPM_INPUT("RIN2"),
 SND_SOC_DAPM_INPUT("Internal ADC Source"),
 
+SND_SOC_DAPM_SUPPLY("INL", WM8990_POWER_MANAGEMENT_2, WM8990_AINL_ENA_BIT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("INR", WM8990_POWER_MANAGEMENT_2, WM8990_AINR_ENA_BIT, 0,
+		    NULL, 0),
+
 /* DACs */
 SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2,
 	WM8990_ADCL_ENA_BIT, 0),
@@ -677,26 +654,20 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT,
 	ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)),
 
 /* INMIXL */
-SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0,
+SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
 	&wm8990_dapm_inmixl_controls[0],
-	ARRAY_SIZE(wm8990_dapm_inmixl_controls),
-	inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	ARRAY_SIZE(wm8990_dapm_inmixl_controls)),
 
 /* AINLMUX */
-SND_SOC_DAPM_MUX_E("AINLMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0,
-	&wm8990_dapm_ainlmux_controls, inmixer_event,
-	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainlmux_controls),
 
 /* INMIXR */
-SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0,
+SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
 	&wm8990_dapm_inmixr_controls[0],
-	ARRAY_SIZE(wm8990_dapm_inmixr_controls),
-	inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	ARRAY_SIZE(wm8990_dapm_inmixr_controls)),
 
 /* AINRMUX */
-SND_SOC_DAPM_MUX_E("AINRMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0,
-	&wm8990_dapm_ainrmux_controls, inmixer_event,
-	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainrmux_controls),
 
 /* Output Side */
 /* DACs */
@@ -787,7 +758,7 @@ SND_SOC_DAPM_OUTPUT("RON"),
 SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8990_dapm_routes[] = {
 	/* Make DACs turn on when playing even if not mixed into any outputs */
 	{"Internal DAC Sink", NULL, "Left DAC"},
 	{"Internal DAC Sink", NULL, "Right DAC"},
@@ -796,6 +767,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Left ADC", NULL, "Internal ADC Source"},
 	{"Right ADC", NULL, "Internal ADC Source"},
 
+	{"AINLMUX", NULL, "INL"},
+	{"INMIXL", NULL, "INL"},
+	{"AINRMUX", NULL, "INR"},
+	{"INMIXR", NULL, "INR"},
+
 	/* Input Side */
 	/* LIN12 PGA */
 	{"LIN12 PGA", "LIN1 Switch", "LIN1"},
@@ -912,18 +888,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"RON", NULL, "RONMIX"},
 };
 
-static int wm8990_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8990_dapm_widgets,
-				  ARRAY_SIZE(wm8990_dapm_widgets));
-	/* set up the WM8990 audio map */
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 /* PLL divisors */
 struct _pll_div {
 	u32 div2;
@@ -1148,6 +1112,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
 static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
+	struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
 	switch (level) {
@@ -1162,7 +1127,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			ret = snd_soc_cache_sync(codec);
+			ret = regcache_sync(wm8990->regmap);
 			if (ret < 0) {
 				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
 				return ret;
@@ -1260,7 +1225,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
 		snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
 
-		codec->cache_sync = 1;
+		regcache_mark_dirty(wm8990->regmap);
 		break;
 	}
 
@@ -1329,7 +1294,7 @@ static int wm8990_probe(struct snd_soc_codec *codec)
 {
 	int ret;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -1352,10 +1317,6 @@ static int wm8990_probe(struct snd_soc_codec *codec)
 	snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
 	snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
-	snd_soc_add_codec_controls(codec, wm8990_snd_controls,
-				ARRAY_SIZE(wm8990_snd_controls));
-	wm8990_add_widgets(codec);
-
 	return 0;
 }
 
@@ -1372,13 +1333,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
 	.suspend =	wm8990_suspend,
 	.resume =	wm8990_resume,
 	.set_bias_level = wm8990_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8990_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8990_reg,
-	.volatile_register = wm8990_volatile_register,
+	.controls =	wm8990_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8990_snd_controls),
+	.dapm_widgets = wm8990_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets),
+	.dapm_routes =	wm8990_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes),
+};
+
+static const struct regmap_config wm8990_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8990_PLL3,
+	.volatile_reg = wm8990_volatile_register,
+	.reg_defaults = wm8990_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int wm8990_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -1420,29 +1393,8 @@ static struct i2c_driver wm8990_i2c_driver = {
 	.remove =   wm8990_i2c_remove,
 	.id_table = wm8990_i2c_id,
 };
-#endif
 
-static int __init wm8990_modinit(void)
-{
-	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	ret = i2c_add_driver(&wm8990_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
-		       ret);
-	}
-#endif
-	return ret;
-}
-module_init(wm8990_modinit);
-
-static void __exit wm8990_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&wm8990_i2c_driver);
-#endif
-}
-module_exit(wm8990_exit);
+module_i2c_driver(wm8990_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8990 driver");
 MODULE_AUTHOR("Liam Girdwood");

+ 0 - 9
sound/soc/codecs/wm8990.h

@@ -78,7 +78,6 @@
 #define WM8990_PLL1                             0x3C
 #define WM8990_PLL2                             0x3D
 #define WM8990_PLL3                             0x3E
-#define WM8990_INTDRIVBITS			0x3F
 
 #define WM8990_EXT_ACCESS_ENA			0x75
 #define WM8990_EXT_CTL1				0x7a
@@ -818,14 +817,6 @@
  */
 #define WM8990_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */
 
-/*
- * R63 (0x3F) - Internal Driver Bits
- */
-#define WM8990_INMIXL_PWR_BIT			0
-#define WM8990_AINLMUX_PWR_BIT			1
-#define WM8990_INMIXR_PWR_BIT			2
-#define WM8990_AINRMUX_PWR_BIT			3
-
 #define WM8990_MCLK_DIV 0
 #define WM8990_DACCLK_DIV 1
 #define WM8990_ADCCLK_DIV 2

+ 153 - 140
sound/soc/codecs/wm8991.c

@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -31,77 +32,84 @@
 #include "wm8991.h"
 
 struct wm8991_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	unsigned int pcmclk;
 };
 
-static const u16 wm8991_reg_defs[] = {
-	0x8991,     /* R0  - Reset */
-	0x0000,     /* R1  - Power Management (1) */
-	0x6000,     /* R2  - Power Management (2) */
-	0x0000,     /* R3  - Power Management (3) */
-	0x4050,     /* R4  - Audio Interface (1) */
-	0x4000,     /* R5  - Audio Interface (2) */
-	0x01C8,     /* R6  - Clocking (1) */
-	0x0000,     /* R7  - Clocking (2) */
-	0x0040,     /* R8  - Audio Interface (3) */
-	0x0040,     /* R9  - Audio Interface (4) */
-	0x0004,     /* R10 - DAC CTRL */
-	0x00C0,     /* R11 - Left DAC Digital Volume */
-	0x00C0,     /* R12 - Right DAC Digital Volume */
-	0x0000,     /* R13 - Digital Side Tone */
-	0x0100,     /* R14 - ADC CTRL */
-	0x00C0,     /* R15 - Left ADC Digital Volume */
-	0x00C0,     /* R16 - Right ADC Digital Volume */
-	0x0000,     /* R17 */
-	0x0000,     /* R18 - GPIO CTRL 1 */
-	0x1000,     /* R19 - GPIO1 & GPIO2 */
-	0x1010,     /* R20 - GPIO3 & GPIO4 */
-	0x1010,     /* R21 - GPIO5 & GPIO6 */
-	0x8000,     /* R22 - GPIOCTRL 2 */
-	0x0800,     /* R23 - GPIO_POL */
-	0x008B,     /* R24 - Left Line Input 1&2 Volume */
-	0x008B,     /* R25 - Left Line Input 3&4 Volume */
-	0x008B,     /* R26 - Right Line Input 1&2 Volume */
-	0x008B,     /* R27 - Right Line Input 3&4 Volume */
-	0x0000,     /* R28 - Left Output Volume */
-	0x0000,     /* R29 - Right Output Volume */
-	0x0066,     /* R30 - Line Outputs Volume */
-	0x0022,     /* R31 - Out3/4 Volume */
-	0x0079,     /* R32 - Left OPGA Volume */
-	0x0079,     /* R33 - Right OPGA Volume */
-	0x0003,     /* R34 - Speaker Volume */
-	0x0003,     /* R35 - ClassD1 */
-	0x0000,     /* R36 */
-	0x0100,     /* R37 - ClassD3 */
-	0x0000,     /* R38 */
-	0x0000,     /* R39 - Input Mixer1 */
-	0x0000,     /* R40 - Input Mixer2 */
-	0x0000,     /* R41 - Input Mixer3 */
-	0x0000,     /* R42 - Input Mixer4 */
-	0x0000,     /* R43 - Input Mixer5 */
-	0x0000,     /* R44 - Input Mixer6 */
-	0x0000,     /* R45 - Output Mixer1 */
-	0x0000,     /* R46 - Output Mixer2 */
-	0x0000,     /* R47 - Output Mixer3 */
-	0x0000,     /* R48 - Output Mixer4 */
-	0x0000,     /* R49 - Output Mixer5 */
-	0x0000,     /* R50 - Output Mixer6 */
-	0x0180,     /* R51 - Out3/4 Mixer */
-	0x0000,     /* R52 - Line Mixer1 */
-	0x0000,     /* R53 - Line Mixer2 */
-	0x0000,     /* R54 - Speaker Mixer */
-	0x0000,     /* R55 - Additional Control */
-	0x0000,     /* R56 - AntiPOP1 */
-	0x0000,     /* R57 - AntiPOP2 */
-	0x0000,     /* R58 - MICBIAS */
-	0x0000,     /* R59 */
-	0x0008,     /* R60 - PLL1 */
-	0x0031,     /* R61 - PLL2 */
-	0x0026,     /* R62 - PLL3 */
+static const struct reg_default wm8991_reg_defaults[] = {
+	{  1, 0x0000 },     /* R1  - Power Management (1) */
+	{  2, 0x6000 },     /* R2  - Power Management (2) */
+	{  3, 0x0000 },     /* R3  - Power Management (3) */
+	{  4, 0x4050 },     /* R4  - Audio Interface (1) */
+	{  5, 0x4000 },     /* R5  - Audio Interface (2) */
+	{  6, 0x01C8 },     /* R6  - Clocking (1) */
+	{  7, 0x0000 },     /* R7  - Clocking (2) */
+	{  8, 0x0040 },     /* R8  - Audio Interface (3) */
+	{  9, 0x0040 },     /* R9  - Audio Interface (4) */
+	{ 10, 0x0004 },     /* R10 - DAC CTRL */
+	{ 11, 0x00C0 },     /* R11 - Left DAC Digital Volume */
+	{ 12, 0x00C0 },     /* R12 - Right DAC Digital Volume */
+	{ 13, 0x0000 },     /* R13 - Digital Side Tone */
+	{ 14, 0x0100 },     /* R14 - ADC CTRL */
+	{ 15, 0x00C0 },     /* R15 - Left ADC Digital Volume */
+	{ 16, 0x00C0 },     /* R16 - Right ADC Digital Volume */
+
+	{ 18, 0x0000 },     /* R18 - GPIO CTRL 1 */
+	{ 19, 0x1000 },     /* R19 - GPIO1 & GPIO2 */
+	{ 20, 0x1010 },     /* R20 - GPIO3 & GPIO4 */
+	{ 21, 0x1010 },     /* R21 - GPIO5 & GPIO6 */
+	{ 22, 0x8000 },     /* R22 - GPIOCTRL 2 */
+	{ 23, 0x0800 },     /* R23 - GPIO_POL */
+	{ 24, 0x008B },     /* R24 - Left Line Input 1&2 Volume */
+	{ 25, 0x008B },     /* R25 - Left Line Input 3&4 Volume */
+	{ 26, 0x008B },     /* R26 - Right Line Input 1&2 Volume */
+	{ 27, 0x008B },     /* R27 - Right Line Input 3&4 Volume */
+	{ 28, 0x0000 },     /* R28 - Left Output Volume */
+	{ 29, 0x0000 },     /* R29 - Right Output Volume */
+	{ 30, 0x0066 },     /* R30 - Line Outputs Volume */
+	{ 31, 0x0022 },     /* R31 - Out3/4 Volume */
+	{ 32, 0x0079 },     /* R32 - Left OPGA Volume */
+	{ 33, 0x0079 },     /* R33 - Right OPGA Volume */
+	{ 34, 0x0003 },     /* R34 - Speaker Volume */
+	{ 35, 0x0003 },     /* R35 - ClassD1 */
+
+	{ 37, 0x0100 },     /* R37 - ClassD3 */
+
+	{ 39, 0x0000 },     /* R39 - Input Mixer1 */
+	{ 40, 0x0000 },     /* R40 - Input Mixer2 */
+	{ 41, 0x0000 },     /* R41 - Input Mixer3 */
+	{ 42, 0x0000 },     /* R42 - Input Mixer4 */
+	{ 43, 0x0000 },     /* R43 - Input Mixer5 */
+	{ 44, 0x0000 },     /* R44 - Input Mixer6 */
+	{ 45, 0x0000 },     /* R45 - Output Mixer1 */
+	{ 46, 0x0000 },     /* R46 - Output Mixer2 */
+	{ 47, 0x0000 },     /* R47 - Output Mixer3 */
+	{ 48, 0x0000 },     /* R48 - Output Mixer4 */
+	{ 49, 0x0000 },     /* R49 - Output Mixer5 */
+	{ 50, 0x0000 },     /* R50 - Output Mixer6 */
+	{ 51, 0x0180 },     /* R51 - Out3/4 Mixer */
+	{ 52, 0x0000 },     /* R52 - Line Mixer1 */
+	{ 53, 0x0000 },     /* R53 - Line Mixer2 */
+	{ 54, 0x0000 },     /* R54 - Speaker Mixer */
+	{ 55, 0x0000 },     /* R55 - Additional Control */
+	{ 56, 0x0000 },     /* R56 - AntiPOP1 */
+	{ 57, 0x0000 },     /* R57 - AntiPOP2 */
+	{ 58, 0x0000 },     /* R58 - MICBIAS */
+
+	{ 60, 0x0008 },     /* R60 - PLL1 */
+	{ 61, 0x0031 },     /* R61 - PLL2 */
+	{ 62, 0x0026 },     /* R62 - PLL3 */
 };
 
-#define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0)
+static bool wm8991_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8991_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
 
 static const unsigned int rec_mix_tlv[] = {
 	TLV_DB_RANGE_HEAD(1),
@@ -374,30 +382,6 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
 /*
  * _DAPM_ Controls
  */
-static int inmixer_event(struct snd_soc_dapm_widget *w,
-			 struct snd_kcontrol *kcontrol, int event)
-{
-	u16 reg, fakepower;
-
-	reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2);
-	fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS);
-
-	if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) |
-			 (1 << WM8991_AINLMUX_PWR_BIT)))
-		reg |= WM8991_AINL_ENA;
-	else
-		reg &= ~WM8991_AINL_ENA;
-
-	if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) |
-			 (1 << WM8991_AINRMUX_PWR_BIT)))
-		reg |= WM8991_AINR_ENA;
-	else
-		reg &= ~WM8991_AINR_ENA;
-
-	snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
-	return 0;
-}
-
 static int outmixer_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
@@ -655,6 +639,11 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("RIN2"),
 	SND_SOC_DAPM_INPUT("Internal ADC Source"),
 
+	SND_SOC_DAPM_SUPPLY("INL", WM8991_POWER_MANAGEMENT_2,
+			    WM8991_AINL_ENA_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("INR", WM8991_POWER_MANAGEMENT_2,
+			    WM8991_AINR_ENA_BIT, 0, NULL, 0),
+
 	/* DACs */
 	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,
 		WM8991_ADCL_ENA_BIT, 0),
@@ -676,26 +665,22 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
 		ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),
 
 	/* INMIXL */
-	SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0,
+	SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
 		&wm8991_dapm_inmixl_controls[0],
-		ARRAY_SIZE(wm8991_dapm_inmixl_controls),
-		inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+		ARRAY_SIZE(wm8991_dapm_inmixl_controls)),
 
 	/* AINLMUX */
-	SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0,
-		&wm8991_dapm_ainlmux_controls, inmixer_event,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0,
+		&wm8991_dapm_ainlmux_controls),
 
 	/* INMIXR */
-	SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0,
+	SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
 		&wm8991_dapm_inmixr_controls[0],
-		ARRAY_SIZE(wm8991_dapm_inmixr_controls),
-		inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+		ARRAY_SIZE(wm8991_dapm_inmixr_controls)),
 
 	/* AINRMUX */
-	SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0,
-		&wm8991_dapm_ainrmux_controls, inmixer_event,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0,
+		&wm8991_dapm_ainrmux_controls),
 
 	/* Output Side */
 	/* DACs */
@@ -787,7 +772,7 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
 	SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8991_dapm_routes[] = {
 	/* Make DACs turn on when playing even if not mixed into any outputs */
 	{"Internal DAC Sink", NULL, "Left DAC"},
 	{"Internal DAC Sink", NULL, "Right DAC"},
@@ -797,6 +782,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Right ADC", NULL, "Internal ADC Source"},
 
 	/* Input Side */
+	{"INMIXL", NULL, "INL"},
+	{"AINLMUX", NULL, "INL"},
+	{"INMIXR", NULL, "INR"},
+	{"AINRMUX", NULL, "INR"},
 	/* LIN12 PGA */
 	{"LIN12 PGA", "LIN1 Switch", "LIN1"},
 	{"LIN12 PGA", "LIN2 Switch", "LIN2"},
@@ -1129,6 +1118,7 @@ static int wm8991_mute(struct snd_soc_dai *dai, int mute)
 static int wm8991_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
+	struct wm8991_priv *wm8991 = snd_soc_codec_get_drvdata(codec);
 	u16 val;
 
 	switch (level) {
@@ -1144,7 +1134,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			snd_soc_cache_sync(codec);
+			regcache_sync(wm8991->regmap);
 			/* Enable all output discharge bits */
 			snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
 				      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
@@ -1232,7 +1222,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
 		snd_soc_write(codec, WM8991_ANTIPOP2, 0x0);
-		codec->cache_sync = 1;
+		regcache_mark_dirty(wm8991->regmap);
 		break;
 	}
 
@@ -1266,44 +1256,14 @@ static int wm8991_probe(struct snd_soc_codec *codec)
 
 	wm8991 = snd_soc_codec_get_drvdata(codec);
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
 		return ret;
 	}
 
-	ret = wm8991_reset(codec);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
-		return ret;
-	}
-
 	wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4,
-			    WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
-
-	snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2,
-			    WM8991_GPIO1_SEL_MASK, 1);
-
-	snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1,
-			    WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
-			    WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
-
-	snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2,
-			    WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
-
-	snd_soc_write(codec, WM8991_DAC_CTRL, 0);
-	snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-	snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
-
-	snd_soc_add_codec_controls(codec, wm8991_snd_controls,
-			     ARRAY_SIZE(wm8991_snd_controls));
-
-	snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets,
-				  ARRAY_SIZE(wm8991_dapm_widgets));
-	snd_soc_dapm_add_routes(&codec->dapm, audio_map,
-				ARRAY_SIZE(audio_map));
 	return 0;
 }
 
@@ -1352,24 +1312,77 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
 	.suspend = wm8991_suspend,
 	.resume = wm8991_resume,
 	.set_bias_level = wm8991_set_bias_level,
-	.reg_cache_size = WM8991_MAX_REGISTER + 1,
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8991_reg_defs
+	.controls = wm8991_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8991_snd_controls),
+	.dapm_widgets = wm8991_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets),
+	.dapm_routes = wm8991_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes),
+};
+
+static const struct regmap_config wm8991_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8991_PLL3,
+	.volatile_reg = wm8991_volatile,
+	.reg_defaults = wm8991_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
 };
 
 static int wm8991_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
 	struct wm8991_priv *wm8991;
+	unsigned int val;
 	int ret;
 
 	wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);
 	if (!wm8991)
 		return -ENOMEM;
 
-	wm8991->control_type = SND_SOC_I2C;
+	wm8991->regmap = devm_regmap_init_i2c(i2c, &wm8991_regmap);
+	if (IS_ERR(wm8991->regmap))
+		return PTR_ERR(wm8991->regmap);
+
 	i2c_set_clientdata(i2c, wm8991);
 
+	ret = regmap_read(wm8991->regmap, WM8991_RESET, &val);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret);
+		return ret;
+	}
+	if (val != 0x8991) {
+		dev_err(&i2c->dev, "Device with ID %x is not a WM8991\n", val);
+		return -EINVAL;
+	}
+
+	ret = regmap_write(wm8991->regmap, WM8991_RESET, 0);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	regmap_update_bits(wm8991->regmap, WM8991_AUDIO_INTERFACE_4,
+			   WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
+
+	regmap_update_bits(wm8991->regmap, WM8991_GPIO1_GPIO2,
+			   WM8991_GPIO1_SEL_MASK, 1);
+
+	regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_1,
+			   WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
+			   WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
+
+	regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_2,
+			   WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
+
+	regmap_write(wm8991->regmap, WM8991_DAC_CTRL, 0);
+	regmap_write(wm8991->regmap, WM8991_LEFT_OUTPUT_VOLUME,
+		     0x50 | (1<<8));
+	regmap_write(wm8991->regmap, WM8991_RIGHT_OUTPUT_VOLUME,
+		     0x50 | (1<<8));
+
 	ret = snd_soc_register_codec(&i2c->dev,
 				     &soc_codec_dev_wm8991, &wm8991_dai, 1);
 

+ 0 - 9
sound/soc/codecs/wm8991.h

@@ -76,7 +76,6 @@
 #define WM8991_PLL1                             0x3C
 #define WM8991_PLL2                             0x3D
 #define WM8991_PLL3                             0x3E
-#define WM8991_INTDRIVBITS			0x3F
 
 #define WM8991_REGISTER_COUNT                   60
 #define WM8991_MAX_REGISTER                     0x3F
@@ -807,14 +806,6 @@
  */
 #define WM8991_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */
 
-/*
- * R63 (0x3F) - Internal Driver Bits
- */
-#define WM8991_INMIXL_PWR_BIT			0
-#define WM8991_AINLMUX_PWR_BIT			1
-#define WM8991_INMIXR_PWR_BIT			2
-#define WM8991_AINRMUX_PWR_BIT			3
-
 #define WM8991_MCLK_DIV 0
 #define WM8991_DACCLK_DIV 1
 #define WM8991_ADCCLK_DIV 2

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

@@ -4077,12 +4077,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,
 			   wm8994_temp_shut, "Thermal shutdown", codec);
 
-	ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
-				 wm_hubs_dcs_done, "DC servo done",
-				 &wm8994->hubs);
-	if (ret == 0)
-		wm8994->hubs.dcs_done_irq = true;
-
 	switch (control->type) {
 	case WM8994:
 		if (wm8994->micdet_irq) {
@@ -4313,6 +4307,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	}
 
 	wm_hubs_add_analogue_routes(codec, 0, 0);
+	ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
+				 wm_hubs_dcs_done, "DC servo done",
+				 &wm8994->hubs);
+	if (ret == 0)
+		wm8994->hubs.dcs_done_irq = true;
 	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
 	switch (control->type) {

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

@@ -2293,7 +2293,7 @@ static struct spi_driver wm8995_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8995_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -2350,7 +2350,7 @@ static int __init wm8995_modinit(void)
 {
 	int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	ret = i2c_add_driver(&wm8995_i2c_driver);
 	if (ret) {
 		printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n",
@@ -2371,7 +2371,7 @@ module_init(wm8995_modinit);
 
 static void __exit wm8995_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 	i2c_del_driver(&wm8995_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)

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

@@ -103,8 +103,8 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMU:
 		if (patch)
 			for (i = 0; i < patch_size; i++)
-				regmap_write(regmap, patch[i].reg,
-					     patch[i].def);
+				regmap_write_async(regmap, patch[i].reg,
+						   patch[i].def);
 		break;
 	default:
 		break;

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

@@ -1326,7 +1326,7 @@ static const struct regmap_config wm9081_regmap = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm9081_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {

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

@@ -1286,6 +1286,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
 					reg = wm_adsp_region_to_reg(mem,
 								    reg);
 					reg += offset;
+					break;
 				}
 			}
 
@@ -1468,8 +1469,8 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
 	unsigned int val;
 	int ret, count;
 
-	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-				 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
 	if (ret != 0)
 		return ret;
 
@@ -1492,7 +1493,6 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
 	}
 
 	adsp_dbg(dsp, "RAM ready after %d polls\n", count);
-	adsp_info(dsp, "RAM ready after %d polls\n", count);
 
 	return 0;
 }
@@ -1525,9 +1525,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		val = (val & ARIZONA_SYSCLK_FREQ_MASK)
 			>> ARIZONA_SYSCLK_FREQ_SHIFT;
 
-		ret = regmap_update_bits(dsp->regmap,
-					 dsp->base + ADSP2_CLOCKING,
-					 ADSP2_CLK_SEL_MASK, val);
+		ret = regmap_update_bits_async(dsp->regmap,
+					       dsp->base + ADSP2_CLOCKING,
+					       ADSP2_CLK_SEL_MASK, val);
 		if (ret != 0) {
 			adsp_err(dsp, "Failed to set clock rate: %d\n",
 				 ret);
@@ -1590,10 +1590,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		if (ret != 0)
 			goto err;
 
-		ret = regmap_update_bits(dsp->regmap,
-					 dsp->base + ADSP2_CONTROL,
-					 ADSP2_CORE_ENA | ADSP2_START,
-					 ADSP2_CORE_ENA | ADSP2_START);
+		ret = regmap_update_bits_async(dsp->regmap,
+					       dsp->base + ADSP2_CONTROL,
+					       ADSP2_CORE_ENA | ADSP2_START,
+					       ADSP2_CORE_ENA | ADSP2_START);
 		if (ret != 0)
 			goto err;
 

+ 12 - 17
sound/soc/davinci/Kconfig

@@ -1,11 +1,6 @@
 config SND_DAVINCI_SOC
-	tristate "SoC Audio for the TI DAVINCI or AM33XX chip"
-	depends on ARCH_DAVINCI || SOC_AM33XX
-	help
-	  Platform driver for daVinci or AM33xx
-	  Say Y or M if you want to add support for codecs attached to
-	  the DAVINCI AC97, I2S, or McASP interface. You will also need
-	  to select the audio interfaces to support below.
+	tristate "SoC Audio for TI DAVINCI or AM33XX/AM43XX chips"
+	depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX
 
 config SND_DAVINCI_SOC_I2S
 	tristate
@@ -16,11 +11,15 @@ config SND_DAVINCI_SOC_MCASP
 config SND_DAVINCI_SOC_VCIF
 	tristate
 
+config SND_DAVINCI_SOC_GENERIC_EVM
+	tristate
+	select SND_SOC_TLV320AIC3X
+	select SND_DAVINCI_SOC_MCASP
+
 config SND_AM33XX_SOC_EVM
 	tristate "SoC Audio for the AM33XX chip based boards"
 	depends on SND_DAVINCI_SOC && SOC_AM33XX
-	select SND_SOC_TLV320AIC3X
-	select SND_DAVINCI_SOC_MCASP
+	select SND_DAVINCI_SOC_GENERIC_EVM
 	help
 	  Say Y or M if you want to add support for SoC audio on AM33XX
 	  boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
@@ -31,8 +30,7 @@ config SND_DAVINCI_SOC_EVM
 	tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
 	depends on SND_DAVINCI_SOC
 	depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
-	select SND_DAVINCI_SOC_I2S
-	select SND_SOC_TLV320AIC3X
+	select SND_DAVINCI_SOC_GENERIC_EVM
 	help
 	  Say Y if you want to add support for SoC audio on TI
 	  DaVinci DM6446, DM355 or DM365 EVM platforms.
@@ -59,8 +57,7 @@ endchoice
 config  SND_DM6467_SOC_EVM
 	tristate "SoC Audio support for DaVinci DM6467 EVM"
 	depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
-	select SND_DAVINCI_SOC_MCASP
-	select SND_SOC_TLV320AIC3X
+	select SND_DAVINCI_SOC_GENERIC_EVM
 	select SND_SOC_SPDIF
 
 	help
@@ -69,8 +66,7 @@ config  SND_DM6467_SOC_EVM
 config  SND_DA830_SOC_EVM
 	tristate "SoC Audio support for DA830/OMAP-L137 EVM"
 	depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
-	select SND_DAVINCI_SOC_MCASP
-	select SND_SOC_TLV320AIC3X
+	select SND_DAVINCI_SOC_GENERIC_EVM
 
 	help
 	  Say Y if you want to add support for SoC audio on TI
@@ -79,8 +75,7 @@ config  SND_DA830_SOC_EVM
 config  SND_DA850_SOC_EVM
 	tristate "SoC Audio support for DA850/OMAP-L138 EVM"
 	depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
-	select SND_DAVINCI_SOC_MCASP
-	select SND_SOC_TLV320AIC3X
+	select SND_DAVINCI_SOC_GENERIC_EVM
 	help
 	  Say Y if you want to add support for SoC audio on TI
 	  DA850/OMAP-L138 EVM

+ 2 - 6
sound/soc/davinci/Makefile

@@ -9,11 +9,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
 obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
 obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
 
-# DAVINCI Machine Support
+# Generic DAVINCI/AM33xx Machine Support
 snd-soc-evm-objs := davinci-evm.o
 
-obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_AM33XX_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o

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