Merge remote-tracking branches 'asoc/topic/ad1836', 'asoc/topic/ad193x', 'asoc/topic...
authorMark Brown <broonie@linaro.org>
Thu, 2 Jan 2014 13:01:55 +0000 (13:01 +0000)
committerMark Brown <broonie@linaro.org>
Thu, 2 Jan 2014 13:01:55 +0000 (13:01 +0000)
167 files changed:
Documentation/devicetree/bindings/sound/adi,axi-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/bcm2835-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs42l52.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
Documentation/devicetree/bindings/sound/fsl-sai.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/max98090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/simple-card.txt
arch/arm/Kconfig
arch/arm/mach-s3c64xx/Kconfig
arch/arm/mach-s3c64xx/Makefile
arch/arm/mach-s3c64xx/common.h
arch/arm/mach-s3c64xx/dma.c [deleted file]
arch/arm/mach-s3c64xx/include/mach/dma.h
arch/arm/mach-s3c64xx/pl080.c [new file with mode: 0644]
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/dma-ops.c
drivers/clk/samsung/clk-s3c64xx.c
drivers/mfd/twl6040.c
drivers/mfd/wm5110-tables.c
drivers/spi/Kconfig
include/linux/mfd/arizona/registers.h
include/linux/platform_data/asoc-ti-mcbsp.h
include/linux/platform_data/davinci_asp.h
include/sound/cs42l52.h
include/sound/pcm_params.h
include/sound/rcar_snd.h
include/sound/soc.h
include/sound/spear_dma.h
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/adi/Kconfig [new file with mode: 0644]
sound/soc/adi/Makefile [new file with mode: 0644]
sound/soc/adi/axi-i2s.c [new file with mode: 0644]
sound/soc/adi/axi-spdif.c [new file with mode: 0644]
sound/soc/atmel/sam9x5_wm8731.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/dma.c
sound/soc/bcm/Kconfig [new file with mode: 0644]
sound/soc/bcm/Makefile [new file with mode: 0644]
sound/soc/bcm/bcm2835-i2s.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/cirrus/edb93xx.c
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/cirrus/ep93xx-pcm.c
sound/soc/cirrus/ep93xx-pcm.h [new file with mode: 0644]
sound/soc/cirrus/simone.c
sound/soc/cirrus/snappercl15.c
sound/soc/codecs/Kconfig
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/da7210.c
sound/soc/codecs/hdmi.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8990.h
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8991.h
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm_adsp.c
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_sai.c [new file with mode: 0644]
sound/soc/fsl/fsl_sai.h [new file with mode: 0644]
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_ssi.h
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm.h
sound/soc/fsl/imx-spdif.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig [moved from sound/soc/mid-x86/Kconfig with 100% similarity]
sound/soc/intel/Makefile [moved from sound/soc/mid-x86/Makefile with 100% similarity]
sound/soc/intel/mfld_machine.c [moved from sound/soc/mid-x86/mfld_machine.c with 100% similarity]
sound/soc/intel/sst_dsp.h [moved from sound/soc/mid-x86/sst_dsp.h with 100% similarity]
sound/soc/intel/sst_platform.c [moved from sound/soc/mid-x86/sst_platform.c with 100% similarity]
sound/soc/intel/sst_platform.h [moved from sound/soc/mid-x86/sst_platform.h with 100% similarity]
sound/soc/jz4740/Kconfig
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/jz4740-pcm.c [deleted file]
sound/soc/jz4740/jz4740-pcm.h [deleted file]
sound/soc/jz4740/qi_lb60.c
sound/soc/mxs/mxs-pcm.c
sound/soc/mxs/mxs-pcm.h
sound/soc/mxs/mxs-saif.c
sound/soc/omap/mcbsp.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/pxa/Kconfig
sound/soc/pxa/mmp-pcm.c
sound/soc/s6000/s6000-pcm.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/ac97.c
sound/soc/samsung/dma.c
sound/soc/samsung/dma.h
sound/soc/samsung/dmaengine.c [new file with mode: 0644]
sound/soc/samsung/i2s.c
sound/soc/samsung/idma.c
sound/soc/samsung/pcm.c
sound/soc/samsung/regs-ac97.h
sound/soc/samsung/regs-iis.h
sound/soc/sh/fsi.c
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/scu.c
sound/soc/sh/rcar/ssi.c
sound/soc/spear/spdif_in.c
sound/soc/spear/spdif_out.c
sound/soc/spear/spear_pcm.c
sound/soc/spear/spear_pcm.h [new file with mode: 0644]
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra_max98090.c [new file with mode: 0644]
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_wm9712.c
sound/soc/txx9/txx9aclc.c

diff --git a/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt b/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt
new file mode 100644 (file)
index 0000000..5875ca4
--- /dev/null
@@ -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";
+       };
diff --git a/Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt b/Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt
new file mode 100644 (file)
index 0000000..46f3449
--- /dev/null
@@ -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";
+       };
diff --git a/Documentation/devicetree/bindings/sound/bcm2835-i2s.txt b/Documentation/devicetree/bindings/sound/bcm2835-i2s.txt
new file mode 100644 (file)
index 0000000..65783de
--- /dev/null
@@ -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";
+};
diff --git a/Documentation/devicetree/bindings/sound/cs42l52.txt b/Documentation/devicetree/bindings/sound/cs42l52.txt
new file mode 100644 (file)
index 0000000..bc03c93
--- /dev/null
@@ -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>;
+};
index ed785b3f67beacb6973ff1758b1b0d5b9b5f16dd..569b26c4a81ee25e1f141329f90903dcb28ab4e4 100644 (file)
@@ -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:
 
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt
new file mode 100644 (file)
index 0000000..98611a6
--- /dev/null
@@ -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;
+};
diff --git a/Documentation/devicetree/bindings/sound/hdmi.txt b/Documentation/devicetree/bindings/sound/hdmi.txt
new file mode 100644 (file)
index 0000000..31af7bc
--- /dev/null
@@ -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";
+       };
diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt
new file mode 100644 (file)
index 0000000..e4c8b36
--- /dev/null
@@ -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>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
new file mode 100644 (file)
index 0000000..9c7c55c
--- /dev/null
@@ -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";
+};
index 769a346f890c2813083e922030b71f866f94db54..2ee80c76ca6452e51a00e29a92a950ab89ca2eca 100644 (file)
@@ -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>;
index c1f1a7eee953de4378b1f74bd4907c969f96dceb..ba0e23234ecfef1663d3bfb07effacc1924b02f3 100644 (file)
@@ -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
index 2cb8dc55b50ecbc4aa612ab805b52f03efec3eb9..7094bccbae913ae953594a51e900ce13f8e4137d 100644 (file)
@@ -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
index 6faedcffce040d0cfc041c9d3b559ff1be94a207..58069a702a435046ae627bff9ab4e8c689b1aa3c 100644 (file)
@@ -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
 
index bd3bd562011e1515198e924627fd7165f57cb3dd..7043e7a3a67ed868f9e4465d7afae197619dcdc9 100644 (file)
@@ -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 */
diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c
deleted file mode 100644 (file)
index 7e22c21..0000000
+++ /dev/null
@@ -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);
index fe1a98cf0e4c7cb3a63311efec61f507e9ebf8e2..059b1fc8503727d7c84139ce7c2311cbc1a7ab8a 100644 (file)
 #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 */
diff --git a/arch/arm/mach-s3c64xx/pl080.c b/arch/arm/mach-s3c64xx/pl080.c
new file mode 100644 (file)
index 0000000..901a984
--- /dev/null
@@ -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);
index 99a3590f034949cc45bc99df724857e096888e51..ac07e871f6a781594ffae471516527e7ea090941 100644 (file)
@@ -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);
index ec0d731b0e7b88ed8bc7b2937528545c15f60f6e..886326ee6f6c373c36d16fddef48b9ce58d5f7c9 100644 (file)
 
 #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);
 }
 
index 7d2c84265947a1b2e85ebf92c8c6e9cb8d9303f8..8e27aee6887eed36c2ebaf7c82bd705672ab5784 100644 (file)
@@ -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"),
index 0779d5ab9ab1538631981aff4994743a5b96b008..51b6df1a794974664f03471aa94bc00e9837b330 100644 (file)
 #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)
index bf8b3b5ad1fe65d03eb067881599c5cbc1418a32..abd6713de7b030c50a2b5ff11ec3ed7ab3b1d576 100644 (file)
@@ -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,
 
index eb1f1ef5fa2eb69db729b6061b2d96c85aaf968b..e2dd2fbec5ee869f014db05a2fe8b3b616ac9d75 100644 (file)
@@ -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.
 
index cb49417f8ba9261ba436fef11851274f9df977d0..22916c0f1ca44ae9a99b48a6cba856978a54edc2 100644 (file)
 #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
 #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
 #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
 #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] */
 /*
  * 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] */
 /*
  * 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] */
 /*
  * 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] */
 /*
  * 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] */
 /*
  * 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] */
 /*
  * 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] */
 #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
  */
 /*
  * 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 */
 #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
  */
 #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 */
 /*
  * 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 */
index c78d90b28b19f4646ad9ab113ec3e8ad2d0f8ef1..3c73c045f8da961dd8a3ddb6d5c17a169b2a2b42 100644 (file)
@@ -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>
index 689a856b86f90e1329515cf1ad9b80d3e2e7cdf5..5245992b036734dd4c96f1c544539e070d058b64 100644 (file)
@@ -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 {
index 7c2be4a51894484e8a05fe08d11751c1cc7e04ab..bbabf84bdb443114fcd33d4b3a4bbc3172385a8b 100644 (file)
@@ -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;
index 37ae12e0ab06d323ab50f78a97225392f6541dbf..6b1c78f05fab49f3617dcef673d98c70a8fd256b 100644 (file)
@@ -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 */
index 12afab18945d056709df7495b75b0da6c0155426..e147498abe5090ac348a2e9497d18e4bd10bd9d2 100644 (file)
@@ -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 */
 };
 
 /*
index 1cda7d343d16edd43f4f430078d0333b74405bd0..5a049d969c59cd0712940501974e4b23292f0b9c 100644 (file)
@@ -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;
index 1b365bfdfb3720714736ed33a7a544f8d46f7456..65aca51fe255e487f4a3b36e5708b5159b089c03 100644 (file)
@@ -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 */
index 5138b8493051fd54c674fe26ea87d9d5fd1411c6..d62ce483a443a5298688f51462e807e6ea1b2cb4 100644 (file)
@@ -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"
index 8b9e70105dd28f5ccceabad1cd2ea414a97640a1..62a1822e77bf6f42410fd68c6d539c8cf97c922f 100644 (file)
@@ -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/
diff --git a/sound/soc/adi/Kconfig b/sound/soc/adi/Kconfig
new file mode 100644 (file)
index 0000000..dd763f5
--- /dev/null
@@ -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.
diff --git a/sound/soc/adi/Makefile b/sound/soc/adi/Makefile
new file mode 100644 (file)
index 0000000..64456c1
--- /dev/null
@@ -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
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c
new file mode 100644 (file)
index 0000000..7f91a86
--- /dev/null
@@ -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");
diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c
new file mode 100644 (file)
index 0000000..8db7a99
--- /dev/null
@@ -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");
index 7d6a9055874b822bb440eab72a66dc5c034127ed..3188036a18f004ad5e68f56ef4c10e3757c43f06 100644 (file)
@@ -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,
index 3b4eafaf30d3177d223f1a28c4374e55d32e8e68..17a24d804734f7539b456751708a206c9925319f 100644 (file)
@@ -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,
index befd1074f9bdbd9b008dc6324b5669a7f8a549c7..e920b60bf6c2f9fe2a43cc515ba4dec69a977127 100644 (file)
 
 #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,
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
new file mode 100644 (file)
index 0000000..3d82a29
--- /dev/null
@@ -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.
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile
new file mode 100644 (file)
index 0000000..bc816b7
--- /dev/null
@@ -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
+
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
new file mode 100644 (file)
index 0000000..2685fe4
--- /dev/null
@@ -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");
index 1d4c676eb6cc696e78f6722525923c91e3afe936..cdb8ee75ded924de68bbf33b168af3489c0fadcc 100644 (file)
@@ -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,
index 2a5b43417fd5a5810ac36d1cc258f97987e9066a..a3881c4381c9151771ffca5e5133ef01707ba9ea 100644 (file)
@@ -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,
index c43fb214558a78f4bfef1c51ba316e860e3f3e13..4f900efc437c7ac136ecc3ed35ab3969c059d035 100644 (file)
@@ -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",
index efa75b5086a4b00e83802d476c87aae0a6914d0e..f30dadf85b9963a71629df4be96ec8f1fb05c3bb 100644 (file)
 #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);
index a57643d6402f08ef5613aedd72ba005b4181ac77..943145f9d1b6f4a6ce521e99197baadc0fc2ba8c 100644 (file)
@@ -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:
index cfe517e6800969ab64c91c563c7b5839fc46da66..5f664471d99ee480fd38bd723e65d8023462973c 100644 (file)
 
 #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");
diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
new file mode 100644 (file)
index 0000000..b7a12a2
--- /dev/null
@@ -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
index 4d094d00c34a295645642abc0923d1d221c05967..822a19a89e742e96d28b29a22f28a74d9c4a9298 100644 (file)
@@ -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 = {
index 69041074f2c1a5df2083a2794ef9fd660113d6d7..29238a7476dd87e002d7500d0fffb3f37eada3d0 100644 (file)
@@ -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,
index b33b45dfceec54b205c512ca01638d947df56f66..983d087aa92aa83125903dc18cd420f57c2009eb 100644 (file)
@@ -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
index 9a92b7962f41b67e3ba8461d1a88c584ef4822b0..d7c983862cf0a4ca19bb3db19652f5e2c579900b 100644 (file)
@@ -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,
index aea7e52cf714117a445347cbe528f6732d2bd662..12c27eb363dd13c54b9b1f9b297d02eff9643ef5 100644 (file)
@@ -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
 }
index 14a7c169d004ebf97fabbbccfd8df0434327c639..f7bf4555274982864478b43af4a710350662d7dc 100644 (file)
@@ -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)
index 49cc5f6d6dba41cd1d45712fc15037d8031ddaf5..94cbe508dd3748723197f7443f5a6ed8524b2b14 100644 (file)
@@ -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,
index 090d499bb7ebca49d34fd2ac3142b782f8f46a1b..1f646c6e90c6b3ff688e0fd2582fcb1268679bb1 100644 (file)
@@ -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>");
index fea991031be18a05eab28e4922b10a2e472b5ea9..e4295fee8f13673f15f9811a9516ba84bb548584 100644 (file)
@@ -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,
index 9e81b6392692cbd78e7e9ad7b263fcd00c214a1d..10b398477203a43be5365eab324a0cfba805a1e4 100644 (file)
@@ -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,
index f6e953454bc0856ffccb87ec6680a670d3e90cbd..ce05fd93dc748c3cc8e1405b1d50296f5e9780e3 100644 (file)
@@ -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
 }
index 8b427c97708365e5e1e40aad701f740b62c365be..0bac6d5a4ac8fac7c00e3a909f044a499f11761b 100644 (file)
@@ -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,
index 9c12314565024fcb80d5091a6fc57a6dddf0555b..8166dcb2e4a393300b3210d0bcdf3dab5358cba9 100644 (file)
@@ -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)
index 68342b121c966aa7c90ace1384bbfbefe4737ab7..9cb1c7d3e1dca6dafbeaf1247c2bccf073212061 100644 (file)
@@ -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,
index 1f4093f3f3a19219318eb0f3c407d8f302ce34d3..0fcbe90f3ef24520dbbd74092829d892b287ca1c 100644 (file)
@@ -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);
 
index 95aed552139a1a363bd54d8d88bc7a97486beb81..cc8debce752f73055a3253f5ac0928803fbc1091 100644 (file)
@@ -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);
                }
        }
 
index 492644e67ace909d2f6b71c7685259955f76661d..c6dd48561884036c857c445034c3052a04b43a27 100644 (file)
@@ -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
 }
index 546d16b7d38f87cd456e35286dbf3b9a8eab4b33..470fbfb4b3861314b6ecc74dfd95d5c2cd8b0d89 100644 (file)
@@ -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) {
index f2f4bcb2ff71527b6dde8b264be2c99de7bf4c37..0afe8bef6765645ef75a9454f929c20b0d3c86b4 100644 (file)
@@ -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,
index fd0a314bc209a4005e8b3488930b6b7d3215526f..726df6d43c2b69227adc503e38397f977db4f220 100644 (file)
@@ -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
 }
index a08e8bf6d07cb7db76cf8075d2e61d2ec2464b18..ce9c8e14d4bd105cfc33991604a06440e67ca1f0 100644 (file)
@@ -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:
index 0ab2dc296474373e1e407abf0762afeeffead4c6..22bd7dd80bbafad2bf8449d4504cbc4219c5855f 100644 (file)
 #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);
 
index 6ed5433943eaae4716f54a75f7b4cf4d9fd83fc2..7df7d45727559e98501eef2500b3cc610ee8a4b0 100644 (file)
@@ -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)
index 139bf9ac94078152470fc639816a328eac8dbfa6..74d106dc76676d5481ae367ad2c5115e8d7df32a 100644 (file)
@@ -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
 }
index 08a414b57b1ea8179819adc03dd300233f24d72e..318989acbbe5fbb97878856ccab46330422f6bdf 100644 (file)
@@ -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
 }
index 5b428b060d418da78286a605060c4cb4c019801b..d99f948c513cd80bf56f96f6657ce20224f2fb0d 100644 (file)
@@ -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)
index c6a292dcded0c11eda10c5dfa8fd70e2be84ec0c..cd89033e84c08a1d290cb012cee545273b35badd 100644 (file)
@@ -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)
index bc7472c968e37300edfdd38f9108bee0af77bb4f..029720366ff8f65f7d6b208216f7cba64b6523af 100644 (file)
@@ -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)
index b18813cc7ba9f06c87b399834abbceac5d3b9f49..2895c8d3b5e4cce600114dcab949f28b82cf2c7e 100644 (file)
@@ -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
 }
index 50d5ff616232676bb094054d44a0c1076ddba0ab..78616a638a55ad4a76f11559f08c6dc4bdb708f6 100644 (file)
@@ -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)
index d96ebf52d953e850016184f4615f2faf979a738d..be85da93a2682fb89c7c668042f772fc08ca7452 100644 (file)
@@ -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)
index 942d58e455f384f9b8c5cdc83363c861ff5366b5..ef824672523206a1a3f5d593647a20ae5487b941 100644 (file)
@@ -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)
index 1704b1e119cb021db8fced2be8482c5da40810d9..9bc8206a68071267cbb18856dc5c9722930af147 100644 (file)
@@ -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)
index 734209e252c3c7cc049b9f982de6539154aa67ab..e98bc7038a086b39231ecbb5196fb7a40fc92d1e 100644 (file)
@@ -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)
index b1591c61c254ebc1f12d0a19e682e45df632ed77..b404c26c1753407c849c61fdc5ac2db5254deaf0 100644 (file)
@@ -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>
 
 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);
index 0f17ed3e29f41dc9d7ddebb505b7fad8fc545b02..97db3b45b4113ad5fe7f7d42dd0e4e018b8c8c51 100644 (file)
@@ -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,
 };
index a2d01d10a5dd8866747b335a027ed3049c9c71d3..15f45c7bd8334971bb63235ade92a26cb82c2f57 100644 (file)
@@ -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>
 
 #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);
 
index 18f2babe1090bf0ee061cf169c5f0f8e867dafd3..271b517911a4bc0d4d6003356afcf7a1cc317bed 100644 (file)
@@ -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)
index 39b9acceb595185d60821270073d9e5895305baa..a55e1c2c382edde43985e2213f0502564bf8e17b 100644 (file)
@@ -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)
index 4f05fb88bddf1394509b9eb14c7b746909074873..0ccd4d8d043bbcf0d0f689bc947c93545d88b16b 100644 (file)
@@ -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>
 
 /* 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");
index 77c98a4bfe9cdf34876e30866e73046d50748c85..0e9c78040c4c5cbfd1c7c6d5cc9cf844e5d95333 100644 (file)
@@ -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
  */
 #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
index 3a39df7a38295a36a28d7865405cb7c0096089d1..dba0306c42a5c54aa459cc4fe1593b08c92a5abf 100644 (file)
@@ -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>
 #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);
 
index 07707d8d7e20e8ef2625f4986c3b24f70285bc5a..08ed383303c02b94e13d62a4fd4a2aa782bf969a 100644 (file)
@@ -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
  */
 #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
index 86426a117b07923dd4f89aa4811cb5d5dc21b907..b9be9cbc460391d4530e970e3c77a0521109c2a2 100644 (file)
@@ -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) {
index da2899e6c4018fae6cd0a2411b58027f4048b6e4..4300caff17838b59d195ba629b1e0c94b3eb3574 100644 (file)
@@ -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)
index 1392bb3c92540366c9a28817891567bfcfd45601..555115ee2159eadd3083f522d8cd682000216a48 100644 (file)
@@ -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;
index 630b3d776ec27133cd54f2c3dd440ae304c83417..0982c1d38ec458205628b2fdd52ccc87a499db97 100644 (file)
@@ -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)
 {
index 4fbcab63e61f1c5d8b4843fdec5c6d3dbfa498ed..fb0c678939bf2eb12a4ad2dd12c2b262366fb3eb 100644 (file)
@@ -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;
 
index 95970f5db3eca228df66a55f5e357f14b26209c9..a8ec1fc3e4d09a72ad1e36dca4859208d56e5e7e 100644 (file)
@@ -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
index bc81e79fc301b8357cddd5edf7e707beb33a0723..744d4d9a018466c77709a0d18e40afdb26aac063 100644 (file)
@@ -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
index 623eb5e7c08981c08f31f2d51863c0426c1a7416..70ff3772079f2186cdf2967c1c050ff95f37350b 100644 (file)
 
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
-#include "davinci-mcasp.h"
 
 struct snd_soc_card_drvdata_davinci {
        unsigned sysclk;
 };
 
-#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
-               SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
 static int evm_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
@@ -48,16 +45,6 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
        unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
                           snd_soc_card_get_drvdata(soc_card))->sysclk;
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock */
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
        if (ret < 0)
@@ -71,24 +58,10 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       /* set cpu DAI configuration */
-       return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
-}
-
 static struct snd_soc_ops evm_ops = {
        .hw_params = evm_hw_params,
 };
 
-static struct snd_soc_ops evm_spdif_ops = {
-       .hw_params = evm_spdif_hw_params,
-};
-
 /* davinci-evm machine dapm widgets */
 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -165,6 +138,8 @@ static struct snd_soc_dai_link dm6446_evm_dai = {
        .platform_name = "davinci-mcbsp",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
 };
 
 static struct snd_soc_dai_link dm355_evm_dai = {
@@ -176,6 +151,8 @@ static struct snd_soc_dai_link dm355_evm_dai = {
        .platform_name = "davinci-mcbsp.1",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
 };
 
 static struct snd_soc_dai_link dm365_evm_dai = {
@@ -184,10 +161,12 @@ static struct snd_soc_dai_link dm365_evm_dai = {
        .stream_name = "AIC3X",
        .cpu_dai_name = "davinci-mcbsp",
        .codec_dai_name = "tlv320aic3x-hifi",
-       .init = evm_aic3x_init,
        .codec_name = "tlv320aic3x-codec.1-0018",
-       .ops = &evm_ops,
        .platform_name = "davinci-mcbsp",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
 #elif defined(CONFIG_SND_DM365_VOICE_CODEC)
        .name = "Voice Codec - CQ93VC",
        .stream_name = "CQ93",
@@ -208,6 +187,8 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
                .codec_name = "tlv320aic3x-codec.0-001a",
                .init = evm_aic3x_init,
                .ops = &evm_ops,
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                          SND_SOC_DAIFMT_IB_NF,
        },
        {
                .name = "McASP",
@@ -216,7 +197,8 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
                .codec_dai_name = "dit-hifi",
                .codec_name = "spdif_dit",
                .platform_name = "davinci-mcasp.1",
-               .ops = &evm_spdif_ops,
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                          SND_SOC_DAIFMT_IB_NF,
        },
 };
 
@@ -229,6 +211,8 @@ static struct snd_soc_dai_link da830_evm_dai = {
        .platform_name = "davinci-mcasp.1",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
 };
 
 static struct snd_soc_dai_link da850_evm_dai = {
@@ -240,6 +224,8 @@ static struct snd_soc_dai_link da850_evm_dai = {
        .platform_name = "davinci-mcasp.0",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
 };
 
 /* davinci dm6446 evm audio machine driver */
@@ -336,6 +322,8 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
        .codec_dai_name = "tlv320aic3x-hifi",
        .ops            = &evm_ops,
        .init           = evm_aic3x_init,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
 };
 
 static const struct of_device_id davinci_evm_dt_ids[] = {
index 71e14bb3a8cd11b4465567d088a05820e0ecdb74..b7858bfa0295357bc5d3ca6d1328932595167b9e 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "davinci-pcm.h"
 #include "davinci-mcasp.h"
 
-/*
- * McASP register definitions
- */
-#define DAVINCI_MCASP_PID_REG          0x00
-#define DAVINCI_MCASP_PWREMUMGT_REG    0x04
-
-#define DAVINCI_MCASP_PFUNC_REG                0x10
-#define DAVINCI_MCASP_PDIR_REG         0x14
-#define DAVINCI_MCASP_PDOUT_REG                0x18
-#define DAVINCI_MCASP_PDSET_REG                0x1c
-
-#define DAVINCI_MCASP_PDCLR_REG                0x20
-
-#define DAVINCI_MCASP_TLGC_REG         0x30
-#define DAVINCI_MCASP_TLMR_REG         0x34
-
-#define DAVINCI_MCASP_GBLCTL_REG       0x44
-#define DAVINCI_MCASP_AMUTE_REG                0x48
-#define DAVINCI_MCASP_LBCTL_REG                0x4c
-
-#define DAVINCI_MCASP_TXDITCTL_REG     0x50
-
-#define DAVINCI_MCASP_GBLCTLR_REG      0x60
-#define DAVINCI_MCASP_RXMASK_REG       0x64
-#define DAVINCI_MCASP_RXFMT_REG                0x68
-#define DAVINCI_MCASP_RXFMCTL_REG      0x6c
-
-#define DAVINCI_MCASP_ACLKRCTL_REG     0x70
-#define DAVINCI_MCASP_AHCLKRCTL_REG    0x74
-#define DAVINCI_MCASP_RXTDM_REG                0x78
-#define DAVINCI_MCASP_EVTCTLR_REG      0x7c
-
-#define DAVINCI_MCASP_RXSTAT_REG       0x80
-#define DAVINCI_MCASP_RXTDMSLOT_REG    0x84
-#define DAVINCI_MCASP_RXCLKCHK_REG     0x88
-#define DAVINCI_MCASP_REVTCTL_REG      0x8c
-
-#define DAVINCI_MCASP_GBLCTLX_REG      0xa0
-#define DAVINCI_MCASP_TXMASK_REG       0xa4
-#define DAVINCI_MCASP_TXFMT_REG                0xa8
-#define DAVINCI_MCASP_TXFMCTL_REG      0xac
-
-#define DAVINCI_MCASP_ACLKXCTL_REG     0xb0
-#define DAVINCI_MCASP_AHCLKXCTL_REG    0xb4
-#define DAVINCI_MCASP_TXTDM_REG                0xb8
-#define DAVINCI_MCASP_EVTCTLX_REG      0xbc
-
-#define DAVINCI_MCASP_TXSTAT_REG       0xc0
-#define DAVINCI_MCASP_TXTDMSLOT_REG    0xc4
-#define DAVINCI_MCASP_TXCLKCHK_REG     0xc8
-#define DAVINCI_MCASP_XEVTCTL_REG      0xcc
-
-/* Left(even TDM Slot) Channel Status Register File */
-#define DAVINCI_MCASP_DITCSRA_REG      0x100
-/* Right(odd TDM slot) Channel Status Register File */
-#define DAVINCI_MCASP_DITCSRB_REG      0x118
-/* Left(even TDM slot) User Data Register File */
-#define DAVINCI_MCASP_DITUDRA_REG      0x130
-/* Right(odd TDM Slot) User Data Register File */
-#define DAVINCI_MCASP_DITUDRB_REG      0x148
-
-/* Serializer n Control Register */
-#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
-#define DAVINCI_MCASP_XRSRCTL_REG(n)   (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
-                                               (n << 2))
-
-/* Transmit Buffer for Serializer n */
-#define DAVINCI_MCASP_TXBUF_REG                0x200
-/* Receive Buffer for Serializer n */
-#define DAVINCI_MCASP_RXBUF_REG                0x280
-
-/* McASP FIFO Registers */
-#define DAVINCI_MCASP_WFIFOCTL         (0x1010)
-#define DAVINCI_MCASP_WFIFOSTS         (0x1014)
-#define DAVINCI_MCASP_RFIFOCTL         (0x1018)
-#define DAVINCI_MCASP_RFIFOSTS         (0x101C)
-#define MCASP_VER3_WFIFOCTL            (0x1000)
-#define MCASP_VER3_WFIFOSTS            (0x1004)
-#define MCASP_VER3_RFIFOCTL            (0x1008)
-#define MCASP_VER3_RFIFOSTS            (0x100C)
-
-/*
- * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
- *     Register Bits
- */
-#define MCASP_FREE     BIT(0)
-#define MCASP_SOFT     BIT(1)
-
-/*
- * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
- */
-#define AXR(n)         (1<<n)
-#define PFUNC_AMUTE    BIT(25)
-#define ACLKX          BIT(26)
-#define AHCLKX         BIT(27)
-#define AFSX           BIT(28)
-#define ACLKR          BIT(29)
-#define AHCLKR         BIT(30)
-#define AFSR           BIT(31)
-
-/*
- * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
- */
-#define AXR(n)         (1<<n)
-#define PDIR_AMUTE     BIT(25)
-#define ACLKX          BIT(26)
-#define AHCLKX         BIT(27)
-#define AFSX           BIT(28)
-#define ACLKR          BIT(29)
-#define AHCLKR         BIT(30)
-#define AFSR           BIT(31)
-
-/*
- * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
- */
-#define DITEN  BIT(0)  /* Transmit DIT mode enable/disable */
-#define VA     BIT(2)
-#define VB     BIT(3)
-
-/*
- * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
- */
-#define TXROT(val)     (val)
-#define TXSEL          BIT(3)
-#define TXSSZ(val)     (val<<4)
-#define TXPBIT(val)    (val<<8)
-#define TXPAD(val)     (val<<13)
-#define TXORD          BIT(15)
-#define FSXDLY(val)    (val<<16)
-
-/*
- * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
- */
-#define RXROT(val)     (val)
-#define RXSEL          BIT(3)
-#define RXSSZ(val)     (val<<4)
-#define RXPBIT(val)    (val<<8)
-#define RXPAD(val)     (val<<13)
-#define RXORD          BIT(15)
-#define FSRDLY(val)    (val<<16)
-
-/*
- * DAVINCI_MCASP_TXFMCTL_REG -  Transmit Frame Control Register Bits
- */
-#define FSXPOL         BIT(0)
-#define AFSXE          BIT(1)
-#define FSXDUR         BIT(4)
-#define FSXMOD(val)    (val<<7)
-
-/*
- * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
- */
-#define FSRPOL         BIT(0)
-#define AFSRE          BIT(1)
-#define FSRDUR         BIT(4)
-#define FSRMOD(val)    (val<<7)
-
-/*
- * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
- */
-#define ACLKXDIV(val)  (val)
-#define ACLKXE         BIT(5)
-#define TX_ASYNC       BIT(6)
-#define ACLKXPOL       BIT(7)
-#define ACLKXDIV_MASK  0x1f
-
-/*
- * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
- */
-#define ACLKRDIV(val)  (val)
-#define ACLKRE         BIT(5)
-#define RX_ASYNC       BIT(6)
-#define ACLKRPOL       BIT(7)
-#define ACLKRDIV_MASK  0x1f
-
-/*
- * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
- *     Register Bits
- */
-#define AHCLKXDIV(val) (val)
-#define AHCLKXPOL      BIT(14)
-#define AHCLKXE                BIT(15)
-#define AHCLKXDIV_MASK 0xfff
+struct davinci_mcasp {
+       struct davinci_pcm_dma_params dma_params[2];
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       void __iomem *base;
+       u32 fifo_base;
+       struct device *dev;
 
-/*
- * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
- *     Register Bits
- */
-#define AHCLKRDIV(val) (val)
-#define AHCLKRPOL      BIT(14)
-#define AHCLKRE                BIT(15)
-#define AHCLKRDIV_MASK 0xfff
+       /* McASP specific data */
+       int     tdm_slots;
+       u8      op_mode;
+       u8      num_serializer;
+       u8      *serial_dir;
+       u8      version;
+       u16     bclk_lrclk_ratio;
+       int     streams;
 
-/*
- * DAVINCI_MCASP_XRSRCTL_BASE_REG -  Serializer Control Register Bits
- */
-#define MODE(val)      (val)
-#define DISMOD         (val)(val<<2)
-#define TXSTATE                BIT(4)
-#define RXSTATE                BIT(5)
-#define SRMOD_MASK     3
-#define SRMOD_INACTIVE 0
-
-/*
- * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
- */
-#define LBEN           BIT(0)
-#define LBORD          BIT(1)
-#define LBGENMODE(val) (val<<2)
+       /* McASP FIFO related */
+       u8      txnumevt;
+       u8      rxnumevt;
 
-/*
- * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
- */
-#define TXTDMS(n)      (1<<n)
-
-/*
- * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
- */
-#define RXTDMS(n)      (1<<n)
-
-/*
- * DAVINCI_MCASP_GBLCTL_REG -  Global Control Register Bits
- */
-#define RXCLKRST       BIT(0)  /* Receiver Clock Divider Reset */
-#define RXHCLKRST      BIT(1)  /* Receiver High Frequency Clock Divider */
-#define RXSERCLR       BIT(2)  /* Receiver Serializer Clear */
-#define RXSMRST                BIT(3)  /* Receiver State Machine Reset */
-#define RXFSRST                BIT(4)  /* Frame Sync Generator Reset */
-#define TXCLKRST       BIT(8)  /* Transmitter Clock Divider Reset */
-#define TXHCLKRST      BIT(9)  /* Transmitter High Frequency Clock Divider*/
-#define TXSERCLR       BIT(10) /* Transmit Serializer Clear */
-#define TXSMRST                BIT(11) /* Transmitter State Machine Reset */
-#define TXFSRST                BIT(12) /* Frame Sync Generator Reset */
+       bool    dat_port;
 
-/*
- * DAVINCI_MCASP_AMUTE_REG -  Mute Control Register Bits
- */
-#define MUTENA(val)    (val)
-#define MUTEINPOL      BIT(2)
-#define MUTEINENA      BIT(3)
-#define MUTEIN         BIT(4)
-#define MUTER          BIT(5)
-#define MUTEX          BIT(6)
-#define MUTEFSR                BIT(7)
-#define MUTEFSX                BIT(8)
-#define MUTEBADCLKR    BIT(9)
-#define MUTEBADCLKX    BIT(10)
-#define MUTERXDMAERR   BIT(11)
-#define MUTETXDMAERR   BIT(12)
-
-/*
- * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
- */
-#define RXDATADMADIS   BIT(0)
-
-/*
- * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
- */
-#define TXDATADMADIS   BIT(0)
-
-/*
- * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
- */
-#define FIFO_ENABLE    BIT(16)
-#define NUMEVT_MASK    (0xFF << 8)
-#define NUMDMA_MASK    (0xFF)
-
-#define DAVINCI_MCASP_NUM_SERIALIZER   16
+#ifdef CONFIG_PM_SLEEP
+       struct {
+               u32     txfmtctl;
+               u32     rxfmtctl;
+               u32     txfmt;
+               u32     rxfmt;
+               u32     aclkxctl;
+               u32     aclkrctl;
+               u32     pdir;
+       } context;
+#endif
+};
 
-static inline void mcasp_set_bits(void __iomem *reg, u32 val)
+static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
+                                 u32 val)
 {
+       void __iomem *reg = mcasp->base + offset;
        __raw_writel(__raw_readl(reg) | val, reg);
 }
 
-static inline void mcasp_clr_bits(void __iomem *reg, u32 val)
+static inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
+                                 u32 val)
 {
+       void __iomem *reg = mcasp->base + offset;
        __raw_writel((__raw_readl(reg) & ~(val)), reg);
 }
 
-static inline void mcasp_mod_bits(void __iomem *reg, u32 val, u32 mask)
+static inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
+                                 u32 val, u32 mask)
 {
+       void __iomem *reg = mcasp->base + offset;
        __raw_writel((__raw_readl(reg) & ~mask) | val, reg);
 }
 
-static inline void mcasp_set_reg(void __iomem *reg, u32 val)
+static inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
+                                u32 val)
 {
-       __raw_writel(val, reg);
+       __raw_writel(val, mcasp->base + offset);
 }
 
-static inline u32 mcasp_get_reg(void __iomem *reg)
+static inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
 {
-       return (unsigned int)__raw_readl(reg);
+       return (u32)__raw_readl(mcasp->base + offset);
 }
 
-static inline void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
+static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
 {
        int i = 0;
 
-       mcasp_set_bits(regs, val);
+       mcasp_set_bits(mcasp, ctl_reg, val);
 
        /* programming GBLCTL needs to read back from GBLCTL and verfiy */
        /* loop count is to avoid the lock-up */
        for (i = 0; i < 1000; i++) {
-               if ((mcasp_get_reg(regs) & val) == val)
+               if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
                        break;
        }
 
-       if (i == 1000 && ((mcasp_get_reg(regs) & val) != val))
+       if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
                printk(KERN_ERR "GBLCTL write error\n");
 }
 
-static void mcasp_start_rx(struct davinci_audio_dev *dev)
+static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
 {
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
+       u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+       u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
 
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
+       return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
+}
 
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+static void mcasp_start_rx(struct davinci_mcasp *mcasp)
+{
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
+
+       /*
+        * When ASYNC == 0 the transmit and receive sections operate
+        * synchronously from the transmit clock and frame sync. We need to make
+        * sure that the TX signlas are enabled when starting reception.
+        */
+       if (mcasp_is_synchronous(mcasp)) {
+               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+       }
+
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
+
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
+
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+
+       if (mcasp_is_synchronous(mcasp))
+               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
 }
 
-static void mcasp_start_tx(struct davinci_audio_dev *dev)
+static void mcasp_start_tx(struct davinci_mcasp *mcasp)
 {
        u8 offset = 0, i;
        u32 cnt;
 
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
 
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
-       mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
-       for (i = 0; i < dev->num_serializer; i++) {
-               if (dev->serial_dir[i] == TX_MODE) {
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
+       for (i = 0; i < mcasp->num_serializer; i++) {
+               if (mcasp->serial_dir[i] == TX_MODE) {
                        offset = i;
                        break;
                }
@@ -383,156 +180,140 @@ static void mcasp_start_tx(struct davinci_audio_dev *dev)
 
        /* wait for TX ready */
        cnt = 0;
-       while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_XRSRCTL_REG(offset)) &
+       while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) &
                 TXSTATE) && (cnt < 100000))
                cnt++;
 
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
 }
 
-static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
+static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
 {
+       u32 reg;
+
+       mcasp->streams++;
+
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (dev->txnumevt) {    /* enable FIFO */
-                       switch (dev->version) {
-                       case MCASP_VERSION_3:
-                               mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,
-                                                               FIFO_ENABLE);
-                               mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL,
-                                                               FIFO_ENABLE);
-                               break;
-                       default:
-                               mcasp_clr_bits(dev->base +
-                                       DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
-                               mcasp_set_bits(dev->base +
-                                       DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
-                       }
+               if (mcasp->txnumevt) {  /* enable FIFO */
+                       reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+                       mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+                       mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
                }
-               mcasp_start_tx(dev);
+               mcasp_start_tx(mcasp);
        } else {
-               if (dev->rxnumevt) {    /* enable FIFO */
-                       switch (dev->version) {
-                       case MCASP_VERSION_3:
-                               mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,
-                                                               FIFO_ENABLE);
-                               mcasp_set_bits(dev->base + MCASP_VER3_RFIFOCTL,
-                                                               FIFO_ENABLE);
-                               break;
-                       default:
-                               mcasp_clr_bits(dev->base +
-                                       DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
-                               mcasp_set_bits(dev->base +
-                                       DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
-                       }
+               if (mcasp->rxnumevt) {  /* enable FIFO */
+                       reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+                       mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+                       mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
                }
-               mcasp_start_rx(dev);
+               mcasp_start_rx(mcasp);
        }
 }
 
-static void mcasp_stop_rx(struct davinci_audio_dev *dev)
+static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
 {
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, 0);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+       /*
+        * In synchronous mode stop the TX clocks if no other stream is
+        * running
+        */
+       if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
 }
 
-static void mcasp_stop_tx(struct davinci_audio_dev *dev)
+static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
 {
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+       u32 val = 0;
+
+       /*
+        * In synchronous mode keep TX clocks running if the capture stream is
+        * still running.
+        */
+       if (mcasp_is_synchronous(mcasp) && mcasp->streams)
+               val =  TXHCLKRST | TXCLKRST | TXFSRST;
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
 }
 
-static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
+static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
 {
+       u32 reg;
+
+       mcasp->streams--;
+
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (dev->txnumevt) {    /* disable FIFO */
-                       switch (dev->version) {
-                       case MCASP_VERSION_3:
-                               mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,
-                                                               FIFO_ENABLE);
-                               break;
-                       default:
-                               mcasp_clr_bits(dev->base +
-                                       DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
-                       }
+               if (mcasp->txnumevt) {  /* disable FIFO */
+                       reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+                       mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
                }
-               mcasp_stop_tx(dev);
+               mcasp_stop_tx(mcasp);
        } else {
-               if (dev->rxnumevt) {    /* disable FIFO */
-                       switch (dev->version) {
-                       case MCASP_VERSION_3:
-                               mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,
-                                                               FIFO_ENABLE);
-                       break;
-
-                       default:
-                               mcasp_clr_bits(dev->base +
-                                       DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
-                       }
+               if (mcasp->rxnumevt) {  /* disable FIFO */
+                       reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+                       mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
                }
-               mcasp_stop_rx(dev);
+               mcasp_stop_rx(mcasp);
        }
 }
 
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
-       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
-       void __iomem *base = dev->base;
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_AC97:
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
                break;
        default:
                /* configure a full-word SYNC pulse (LRCLK) */
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
 
                /* make 1st data bit occur one ACLK cycle after the frame sync */
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
                break;
        }
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
                /* codec is clock and frame slave */
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
-                               ACLKX | ACLKR);
-               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
-                               AFSX | AFSR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG,
-                               ACLKX | ACLKR);
-               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
-                               AFSX | AFSR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* codec is clock and frame master */
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG,
-                               ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
+                              ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
                break;
 
        default:
@@ -541,35 +322,35 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_IB_NF:
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
        case SND_SOC_DAIFMT_NB_IF:
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
        case SND_SOC_DAIFMT_IB_IF:
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
        case SND_SOC_DAIFMT_NB_NF:
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
        default:
@@ -581,25 +362,25 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
 static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
 {
-       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
        switch (div_id) {
        case 0:         /* MCLK divider */
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG,
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
                               AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG,
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
                               AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
                break;
 
        case 1:         /* BCLK divider */
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG,
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
                               ACLKXDIV(div - 1), ACLKXDIV_MASK);
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKRCTL_REG,
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
                               ACLKRDIV(div - 1), ACLKRDIV_MASK);
                break;
 
        case 2:         /* BCLK/LRCLK ratio */
-               dev->bclk_lrclk_ratio = div;
+               mcasp->bclk_lrclk_ratio = div;
                break;
 
        default:
@@ -612,22 +393,22 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
 static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                                    unsigned int freq, int dir)
 {
-       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
        if (dir == SND_SOC_CLOCK_OUT) {
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
        } else {
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
        }
 
        return 0;
 }
 
-static int davinci_config_channel_size(struct davinci_audio_dev *dev,
+static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
                                       int word_length)
 {
        u32 fmt;
@@ -644,71 +425,68 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
         * both left and right channels), so it has to be divided by number of
         * tdm-slots (for I2S - divided by 2).
         */
-       if (dev->bclk_lrclk_ratio)
-               word_length = dev->bclk_lrclk_ratio / dev->tdm_slots;
+       if (mcasp->bclk_lrclk_ratio)
+               word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
 
        /* mapping of the XSSZ bit-field as described in the datasheet */
        fmt = (word_length >> 1) - 1;
 
-       if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
-                               RXSSZ(fmt), RXSSZ(0x0F));
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
-                               TXSSZ(fmt), TXSSZ(0x0F));
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
-                               TXROT(tx_rotate), TXROT(7));
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
-                               RXROT(rx_rotate), RXROT(7));
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
-                               mask);
+       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
+                              RXSSZ(0x0F));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
+                              TXSSZ(0x0F));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+                              TXROT(7));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
+                              RXROT(7));
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
        }
 
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
 
        return 0;
 }
 
-static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
+static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
                                    int channels)
 {
        int i;
        u8 tx_ser = 0;
        u8 rx_ser = 0;
        u8 ser;
-       u8 slots = dev->tdm_slots;
+       u8 slots = mcasp->tdm_slots;
        u8 max_active_serializers = (channels + slots - 1) / slots;
+       u32 reg;
        /* Default configuration */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
+       if (mcasp->version != MCASP_VERSION_4)
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 
        /* All PINS as McASP */
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
 
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG,
-                               TXDATADMADIS);
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
        } else {
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
-               mcasp_clr_bits(dev->base + DAVINCI_MCASP_REVTCTL_REG,
-                               RXDATADMADIS);
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
        }
 
-       for (i = 0; i < dev->num_serializer; i++) {
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
-                                       dev->serial_dir[i]);
-               if (dev->serial_dir[i] == TX_MODE &&
+       for (i = 0; i < mcasp->num_serializer; i++) {
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                              mcasp->serial_dir[i]);
+               if (mcasp->serial_dir[i] == TX_MODE &&
                                        tx_ser < max_active_serializers) {
-                       mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
-                                       AXR(i));
+                       mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
                        tx_ser++;
-               } else if (dev->serial_dir[i] == RX_MODE &&
+               } else if (mcasp->serial_dir[i] == RX_MODE &&
                                        rx_ser < max_active_serializers) {
-                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
-                                       AXR(i));
+                       mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
                        rx_ser++;
                } else {
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
-                                       SRMOD_INACTIVE, SRMOD_MASK);
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                                      SRMOD_INACTIVE, SRMOD_MASK);
                }
        }
 
@@ -718,127 +496,113 @@ static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
                ser = rx_ser;
 
        if (ser < max_active_serializers) {
-               dev_warn(dev->dev, "stream has more channels (%d) than are "
+               dev_warn(mcasp->dev, "stream has more channels (%d) than are "
                        "enabled in mcasp (%d)\n", channels, ser * slots);
                return -EINVAL;
        }
 
-       if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (dev->txnumevt * tx_ser > 64)
-                       dev->txnumevt = 1;
+       if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (mcasp->txnumevt * tx_ser > 64)
+                       mcasp->txnumevt = 1;
 
-               switch (dev->version) {
-               case MCASP_VERSION_3:
-                       mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, tx_ser,
-                                                               NUMDMA_MASK);
-                       mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL,
-                               ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
-                       break;
-               default:
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
-                                                       tx_ser, NUMDMA_MASK);
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
-                               ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
-               }
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+               mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK);
+               mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8),
+                              NUMEVT_MASK);
        }
 
-       if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
-               if (dev->rxnumevt * rx_ser > 64)
-                       dev->rxnumevt = 1;
-               switch (dev->version) {
-               case MCASP_VERSION_3:
-                       mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, rx_ser,
-                                                               NUMDMA_MASK);
-                       mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL,
-                               ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
-                       break;
-               default:
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
-                                                       rx_ser, NUMDMA_MASK);
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
-                               ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
-               }
+       if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
+               if (mcasp->rxnumevt * rx_ser > 64)
+                       mcasp->rxnumevt = 1;
+
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+               mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK);
+               mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8),
+                              NUMEVT_MASK);
        }
 
        return 0;
 }
 
-static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
+static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
 {
        int i, active_slots;
        u32 mask = 0;
+       u32 busel = 0;
 
-       active_slots = (dev->tdm_slots > 31) ? 32 : dev->tdm_slots;
+       active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
        for (i = 0; i < active_slots; i++)
                mask |= (1 << i);
 
-       mcasp_clr_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+       mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+
+       if (!mcasp->dat_port)
+               busel = TXSEL;
 
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* bit stream is MSB first  with no delay */
                /* DSP_B mode */
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask);
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD);
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
 
-               if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32))
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
-                                       FSXMOD(dev->tdm_slots), FSXMOD(0x1FF));
+               if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                                      FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
                else
                        printk(KERN_ERR "playback tdm slot %d not supported\n",
-                               dev->tdm_slots);
+                               mcasp->tdm_slots);
        } else {
                /* bit stream is MSB first with no delay */
                /* DSP_B mode */
-               mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD);
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
 
-               if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32))
-                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG,
-                                       FSRMOD(dev->tdm_slots), FSRMOD(0x1FF));
+               if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+                                      FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
                else
                        printk(KERN_ERR "capture tdm slot %d not supported\n",
-                               dev->tdm_slots);
+                               mcasp->tdm_slots);
        }
 }
 
 /* S/PDIF */
-static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
+static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
 {
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
-                                               TXROT(6) | TXSSZ(15));
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
 
        /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
-                                               AFSXE | FSXMOD(0x180));
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
 
        /* Set the TX tdm : for all the slots */
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
 
        /* Set the TX clock controls : div = 1 and internal */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG,
-                                               ACLKXE | TX_ASYNC);
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
 
-       mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
+       mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
 
        /* Only 44100 and 48000 are valid, both have the same setting */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
 
        /* Enable the DIT */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
 }
 
 static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params,
                                        struct snd_soc_dai *cpu_dai)
 {
-       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
        struct davinci_pcm_dma_params *dma_params =
-                                       &dev->dma_params[substream->stream];
+                                       &mcasp->dma_params[substream->stream];
+       struct snd_dmaengine_dai_dma_data *dma_data =
+                                       &mcasp->dma_data[substream->stream];
        int word_length;
        u8 fifo_level;
-       u8 slots = dev->tdm_slots;
+       u8 slots = mcasp->tdm_slots;
        u8 active_serializers;
        int channels;
        struct snd_interval *pcm_channels = hw_param_interval(params,
@@ -847,17 +611,17 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 
        active_serializers = (channels + slots - 1) / slots;
 
-       if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
+       if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL)
                return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_level = dev->txnumevt * active_serializers;
+               fifo_level = mcasp->txnumevt * active_serializers;
        else
-               fifo_level = dev->rxnumevt * active_serializers;
+               fifo_level = mcasp->rxnumevt * active_serializers;
 
-       if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
-               davinci_hw_dit_param(dev);
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               davinci_hw_dit_param(mcasp);
        else
-               davinci_hw_param(dev, substream->stream);
+               davinci_hw_param(mcasp, substream->stream);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
@@ -891,13 +655,15 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       if (dev->version == MCASP_VERSION_2 && !fifo_level)
+       if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
                dma_params->acnt = 4;
        else
                dma_params->acnt = dma_params->data_type;
 
        dma_params->fifo_level = fifo_level;
-       davinci_config_channel_size(dev, word_length);
+       dma_data->maxburst = fifo_level;
+
+       davinci_config_channel_size(mcasp, word_length);
 
        return 0;
 }
@@ -905,29 +671,29 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
                                     int cmd, struct snd_soc_dai *cpu_dai)
 {
-       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
        int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ret = pm_runtime_get_sync(dev->dev);
+               ret = pm_runtime_get_sync(mcasp->dev);
                if (IS_ERR_VALUE(ret))
-                       dev_err(dev->dev, "pm_runtime_get_sync() failed\n");
-               davinci_mcasp_start(dev, substream->stream);
+                       dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n");
+               davinci_mcasp_start(mcasp, substream->stream);
                break;
 
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               davinci_mcasp_stop(dev, substream->stream);
-               ret = pm_runtime_put_sync(dev->dev);
+               davinci_mcasp_stop(mcasp, substream->stream);
+               ret = pm_runtime_put_sync(mcasp->dev);
                if (IS_ERR_VALUE(ret))
-                       dev_err(dev->dev, "pm_runtime_put_sync() failed\n");
+                       dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n");
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               davinci_mcasp_stop(dev, substream->stream);
+               davinci_mcasp_stop(mcasp, substream->stream);
                break;
 
        default:
@@ -940,9 +706,14 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
 static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
-       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       if (mcasp->version == MCASP_VERSION_4)
+               snd_soc_dai_set_dma_data(dai, substream,
+                                       &mcasp->dma_data[substream->stream]);
+       else
+               snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params);
 
-       snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
        return 0;
 }
 
@@ -955,6 +726,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .set_sysclk     = davinci_mcasp_set_sysclk,
 };
 
+#define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
+
 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
                                SNDRV_PCM_FMTBIT_U8 | \
                                SNDRV_PCM_FMTBIT_S16_LE | \
@@ -985,7 +758,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 
        },
        {
-               "davinci-mcasp.1",
+               .name           = "davinci-mcasp.1",
                .playback       = {
                        .channels_min   = 1,
                        .channels_max   = 384,
@@ -1016,13 +789,20 @@ static struct snd_platform_data da830_mcasp_pdata = {
        .version = MCASP_VERSION_2,
 };
 
-static struct snd_platform_data omap2_mcasp_pdata = {
+static struct snd_platform_data am33xx_mcasp_pdata = {
        .tx_dma_offset = 0,
        .rx_dma_offset = 0,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_3,
 };
 
+static struct snd_platform_data dra7_mcasp_pdata = {
+       .tx_dma_offset = 0x200,
+       .rx_dma_offset = 0x284,
+       .asp_chan_q = EVENTQ_0,
+       .version = MCASP_VERSION_4,
+};
+
 static const struct of_device_id mcasp_dt_ids[] = {
        {
                .compatible = "ti,dm646x-mcasp-audio",
@@ -1034,12 +814,56 @@ static const struct of_device_id mcasp_dt_ids[] = {
        },
        {
                .compatible = "ti,am33xx-mcasp-audio",
-               .data = &omap2_mcasp_pdata,
+               .data = &am33xx_mcasp_pdata,
+       },
+       {
+               .compatible = "ti,dra7-mcasp-audio",
+               .data = &dra7_mcasp_pdata,
        },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
 
+static int mcasp_reparent_fck(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct clk *gfclk, *parent_clk;
+       const char *parent_name;
+       int ret;
+
+       if (!node)
+               return 0;
+
+       parent_name = of_get_property(node, "fck_parent", NULL);
+       if (!parent_name)
+               return 0;
+
+       gfclk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(gfclk)) {
+               dev_err(&pdev->dev, "failed to get fck\n");
+               return PTR_ERR(gfclk);
+       }
+
+       parent_clk = clk_get(NULL, parent_name);
+       if (IS_ERR(parent_clk)) {
+               dev_err(&pdev->dev, "failed to get parent clock\n");
+               ret = PTR_ERR(parent_clk);
+               goto err1;
+       }
+
+       ret = clk_set_parent(gfclk, parent_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to reparent fck\n");
+               goto err2;
+       }
+
+err2:
+       clk_put(parent_clk);
+err1:
+       clk_put(gfclk);
+       return ret;
+}
+
 static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                                                struct platform_device *pdev)
 {
@@ -1152,7 +976,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        struct davinci_pcm_dma_params *dma_data;
        struct resource *mem, *ioarea, *res, *dat;
        struct snd_platform_data *pdata;
-       struct davinci_audio_dev *dev;
+       struct davinci_mcasp *mcasp;
        int ret;
 
        if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -1160,9 +984,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),
+       mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
                           GFP_KERNEL);
-       if (!dev)
+       if (!mcasp)
                return  -ENOMEM;
 
        pdata = davinci_mcasp_set_pdata_from_of(pdev);
@@ -1173,7 +997,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
        if (!mem) {
-               dev_warn(dev->dev,
+               dev_warn(mcasp->dev,
                         "\"mpu\" mem resource not found, using index 0\n");
                mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                if (!mem) {
@@ -1197,32 +1021,39 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                return ret;
        }
 
-       dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
-       if (!dev->base) {
+       mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!mcasp->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
                goto err_release_clk;
        }
 
-       dev->op_mode = pdata->op_mode;
-       dev->tdm_slots = pdata->tdm_slots;
-       dev->num_serializer = pdata->num_serializer;
-       dev->serial_dir = pdata->serial_dir;
-       dev->version = pdata->version;
-       dev->txnumevt = pdata->txnumevt;
-       dev->rxnumevt = pdata->rxnumevt;
-       dev->dev = &pdev->dev;
+       mcasp->op_mode = pdata->op_mode;
+       mcasp->tdm_slots = pdata->tdm_slots;
+       mcasp->num_serializer = pdata->num_serializer;
+       mcasp->serial_dir = pdata->serial_dir;
+       mcasp->version = pdata->version;
+       mcasp->txnumevt = pdata->txnumevt;
+       mcasp->rxnumevt = pdata->rxnumevt;
+
+       mcasp->dev = &pdev->dev;
 
        dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
-       if (!dat)
-               dat = mem;
+       if (dat)
+               mcasp->dat_port = true;
 
-       dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data->asp_chan_q = pdata->asp_chan_q;
        dma_data->ram_chan_q = pdata->ram_chan_q;
        dma_data->sram_pool = pdata->sram_pool;
        dma_data->sram_size = pdata->sram_size_playback;
-       dma_data->dma_addr = dat->start + pdata->tx_dma_offset;
+       if (dat)
+               dma_data->dma_addr = dat->start;
+       else
+               dma_data->dma_addr = mem->start + pdata->tx_dma_offset;
+
+       /* Unconditional dmaengine stuff */
+       mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (res)
@@ -1230,12 +1061,26 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        else
                dma_data->channel = pdata->tx_dma_channel;
 
-       dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+       dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
        dma_data->asp_chan_q = pdata->asp_chan_q;
        dma_data->ram_chan_q = pdata->ram_chan_q;
        dma_data->sram_pool = pdata->sram_pool;
        dma_data->sram_size = pdata->sram_size_capture;
-       dma_data->dma_addr = dat->start + pdata->rx_dma_offset;
+       if (dat)
+               dma_data->dma_addr = dat->start;
+       else
+               dma_data->dma_addr = mem->start + pdata->rx_dma_offset;
+
+       /* Unconditional dmaengine stuff */
+       mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr;
+
+       if (mcasp->version < MCASP_VERSION_3) {
+               mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
+               /* dma_data->dma_addr is pointing to the data port address */
+               mcasp->dat_port = true;
+       } else {
+               mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (res)
@@ -1243,17 +1088,26 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        else
                dma_data->channel = pdata->rx_dma_channel;
 
-       dev_set_drvdata(&pdev->dev, dev);
+       /* Unconditional dmaengine stuff */
+       mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
+       mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+
+       dev_set_drvdata(&pdev->dev, mcasp);
+
+       mcasp_reparent_fck(pdev);
+
        ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
                                         &davinci_mcasp_dai[pdata->op_mode], 1);
 
        if (ret != 0)
                goto err_release_clk;
 
-       ret = davinci_soc_platform_register(&pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_component;
+       if (mcasp->version != MCASP_VERSION_4) {
+               ret = davinci_soc_platform_register(&pdev->dev);
+               if (ret) {
+                       dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+                       goto err_unregister_component;
+               }
        }
 
        return 0;
@@ -1268,9 +1122,11 @@ err_release_clk:
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
+       struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_component(&pdev->dev);
-       davinci_soc_platform_unregister(&pdev->dev);
+       if (mcasp->version != MCASP_VERSION_4)
+               davinci_soc_platform_unregister(&pdev->dev);
 
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -1281,32 +1137,30 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int davinci_mcasp_suspend(struct device *dev)
 {
-       struct davinci_audio_dev *a = dev_get_drvdata(dev);
-       void __iomem *base = a->base;
+       struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
 
-       a->context.txfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_TXFMCTL_REG);
-       a->context.rxfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_RXFMCTL_REG);
-       a->context.txfmt = mcasp_get_reg(base + DAVINCI_MCASP_TXFMT_REG);
-       a->context.rxfmt = mcasp_get_reg(base + DAVINCI_MCASP_RXFMT_REG);
-       a->context.aclkxctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKXCTL_REG);
-       a->context.aclkrctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKRCTL_REG);
-       a->context.pdir = mcasp_get_reg(base + DAVINCI_MCASP_PDIR_REG);
+       mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
+       mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+       mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
+       mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
+       mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+       mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
+       mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
 
        return 0;
 }
 
 static int davinci_mcasp_resume(struct device *dev)
 {
-       struct davinci_audio_dev *a = dev_get_drvdata(dev);
-       void __iomem *base = a->base;
-
-       mcasp_set_reg(base + DAVINCI_MCASP_TXFMCTL_REG, a->context.txfmtctl);
-       mcasp_set_reg(base + DAVINCI_MCASP_RXFMCTL_REG, a->context.rxfmtctl);
-       mcasp_set_reg(base + DAVINCI_MCASP_TXFMT_REG, a->context.txfmt);
-       mcasp_set_reg(base + DAVINCI_MCASP_RXFMT_REG, a->context.rxfmt);
-       mcasp_set_reg(base + DAVINCI_MCASP_ACLKXCTL_REG, a->context.aclkxctl);
-       mcasp_set_reg(base + DAVINCI_MCASP_ACLKRCTL_REG, a->context.aclkrctl);
-       mcasp_set_reg(base + DAVINCI_MCASP_PDIR_REG, a->context.pdir);
+       struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir);
 
        return 0;
 }
index a2e27e1c32f3b28a8600ea0bb5325a35f7fe9741..8fed757d60876310ea4138e69a5575feed7cea60 100644 (file)
 #ifndef DAVINCI_MCASP_H
 #define DAVINCI_MCASP_H
 
-#include <linux/io.h>
-#include <linux/platform_data/davinci_asp.h>
-
-#include "davinci-pcm.h"
-
-#define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
-#define DAVINCI_MCASP_I2S_DAI  0
-#define DAVINCI_MCASP_DIT_DAI  1
-
-struct davinci_audio_dev {
-       struct davinci_pcm_dma_params dma_params[2];
-       void __iomem *base;
-       struct device *dev;
-
-       /* McASP specific data */
-       int     tdm_slots;
-       u8      op_mode;
-       u8      num_serializer;
-       u8      *serial_dir;
-       u8      version;
-       u16     bclk_lrclk_ratio;
-
-       /* McASP FIFO related */
-       u8      txnumevt;
-       u8      rxnumevt;
-
-#ifdef CONFIG_PM_SLEEP
-       struct {
-               u32     txfmtctl;
-               u32     rxfmtctl;
-               u32     txfmt;
-               u32     rxfmt;
-               u32     aclkxctl;
-               u32     aclkrctl;
-               u32     pdir;
-       } context;
-#endif
-};
+/*
+ * McASP register definitions
+ */
+#define DAVINCI_MCASP_PID_REG          0x00
+#define DAVINCI_MCASP_PWREMUMGT_REG    0x04
+
+#define DAVINCI_MCASP_PFUNC_REG                0x10
+#define DAVINCI_MCASP_PDIR_REG         0x14
+#define DAVINCI_MCASP_PDOUT_REG                0x18
+#define DAVINCI_MCASP_PDSET_REG                0x1c
+
+#define DAVINCI_MCASP_PDCLR_REG                0x20
+
+#define DAVINCI_MCASP_TLGC_REG         0x30
+#define DAVINCI_MCASP_TLMR_REG         0x34
+
+#define DAVINCI_MCASP_GBLCTL_REG       0x44
+#define DAVINCI_MCASP_AMUTE_REG                0x48
+#define DAVINCI_MCASP_LBCTL_REG                0x4c
+
+#define DAVINCI_MCASP_TXDITCTL_REG     0x50
+
+#define DAVINCI_MCASP_GBLCTLR_REG      0x60
+#define DAVINCI_MCASP_RXMASK_REG       0x64
+#define DAVINCI_MCASP_RXFMT_REG                0x68
+#define DAVINCI_MCASP_RXFMCTL_REG      0x6c
+
+#define DAVINCI_MCASP_ACLKRCTL_REG     0x70
+#define DAVINCI_MCASP_AHCLKRCTL_REG    0x74
+#define DAVINCI_MCASP_RXTDM_REG                0x78
+#define DAVINCI_MCASP_EVTCTLR_REG      0x7c
+
+#define DAVINCI_MCASP_RXSTAT_REG       0x80
+#define DAVINCI_MCASP_RXTDMSLOT_REG    0x84
+#define DAVINCI_MCASP_RXCLKCHK_REG     0x88
+#define DAVINCI_MCASP_REVTCTL_REG      0x8c
+
+#define DAVINCI_MCASP_GBLCTLX_REG      0xa0
+#define DAVINCI_MCASP_TXMASK_REG       0xa4
+#define DAVINCI_MCASP_TXFMT_REG                0xa8
+#define DAVINCI_MCASP_TXFMCTL_REG      0xac
+
+#define DAVINCI_MCASP_ACLKXCTL_REG     0xb0
+#define DAVINCI_MCASP_AHCLKXCTL_REG    0xb4
+#define DAVINCI_MCASP_TXTDM_REG                0xb8
+#define DAVINCI_MCASP_EVTCTLX_REG      0xbc
+
+#define DAVINCI_MCASP_TXSTAT_REG       0xc0
+#define DAVINCI_MCASP_TXTDMSLOT_REG    0xc4
+#define DAVINCI_MCASP_TXCLKCHK_REG     0xc8
+#define DAVINCI_MCASP_XEVTCTL_REG      0xcc
+
+/* Left(even TDM Slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRA_REG      0x100
+/* Right(odd TDM slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRB_REG      0x118
+/* Left(even TDM slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRA_REG      0x130
+/* Right(odd TDM Slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRB_REG      0x148
+
+/* Serializer n Control Register */
+#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
+#define DAVINCI_MCASP_XRSRCTL_REG(n)   (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
+                                               (n << 2))
+
+/* Transmit Buffer for Serializer n */
+#define DAVINCI_MCASP_TXBUF_REG                0x200
+/* Receive Buffer for Serializer n */
+#define DAVINCI_MCASP_RXBUF_REG                0x280
+
+/* McASP FIFO Registers */
+#define DAVINCI_MCASP_V2_AFIFO_BASE    (0x1010)
+#define DAVINCI_MCASP_V3_AFIFO_BASE    (0x1000)
+
+/* FIFO register offsets from AFIFO base */
+#define MCASP_WFIFOCTL_OFFSET          (0x0)
+#define MCASP_WFIFOSTS_OFFSET          (0x4)
+#define MCASP_RFIFOCTL_OFFSET          (0x8)
+#define MCASP_RFIFOSTS_OFFSET          (0xc)
+
+/*
+ * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
+ *     Register Bits
+ */
+#define MCASP_FREE     BIT(0)
+#define MCASP_SOFT     BIT(1)
+
+/*
+ * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
+ */
+#define AXR(n)         (1<<n)
+#define PFUNC_AMUTE    BIT(25)
+#define ACLKX          BIT(26)
+#define AHCLKX         BIT(27)
+#define AFSX           BIT(28)
+#define ACLKR          BIT(29)
+#define AHCLKR         BIT(30)
+#define AFSR           BIT(31)
+
+/*
+ * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ */
+#define AXR(n)         (1<<n)
+#define PDIR_AMUTE     BIT(25)
+#define ACLKX          BIT(26)
+#define AHCLKX         BIT(27)
+#define AFSX           BIT(28)
+#define ACLKR          BIT(29)
+#define AHCLKR         BIT(30)
+#define AFSR           BIT(31)
+
+/*
+ * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
+ */
+#define DITEN  BIT(0)  /* Transmit DIT mode enable/disable */
+#define VA     BIT(2)
+#define VB     BIT(3)
+
+/*
+ * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
+ */
+#define TXROT(val)     (val)
+#define TXSEL          BIT(3)
+#define TXSSZ(val)     (val<<4)
+#define TXPBIT(val)    (val<<8)
+#define TXPAD(val)     (val<<13)
+#define TXORD          BIT(15)
+#define FSXDLY(val)    (val<<16)
+
+/*
+ * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
+ */
+#define RXROT(val)     (val)
+#define RXSEL          BIT(3)
+#define RXSSZ(val)     (val<<4)
+#define RXPBIT(val)    (val<<8)
+#define RXPAD(val)     (val<<13)
+#define RXORD          BIT(15)
+#define FSRDLY(val)    (val<<16)
+
+/*
+ * DAVINCI_MCASP_TXFMCTL_REG -  Transmit Frame Control Register Bits
+ */
+#define FSXPOL         BIT(0)
+#define AFSXE          BIT(1)
+#define FSXDUR         BIT(4)
+#define FSXMOD(val)    (val<<7)
+
+/*
+ * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
+ */
+#define FSRPOL         BIT(0)
+#define AFSRE          BIT(1)
+#define FSRDUR         BIT(4)
+#define FSRMOD(val)    (val<<7)
+
+/*
+ * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
+ */
+#define ACLKXDIV(val)  (val)
+#define ACLKXE         BIT(5)
+#define TX_ASYNC       BIT(6)
+#define ACLKXPOL       BIT(7)
+#define ACLKXDIV_MASK  0x1f
+
+/*
+ * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
+ */
+#define ACLKRDIV(val)  (val)
+#define ACLKRE         BIT(5)
+#define RX_ASYNC       BIT(6)
+#define ACLKRPOL       BIT(7)
+#define ACLKRDIV_MASK  0x1f
+
+/*
+ * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
+ *     Register Bits
+ */
+#define AHCLKXDIV(val) (val)
+#define AHCLKXPOL      BIT(14)
+#define AHCLKXE                BIT(15)
+#define AHCLKXDIV_MASK 0xfff
+
+/*
+ * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
+ *     Register Bits
+ */
+#define AHCLKRDIV(val) (val)
+#define AHCLKRPOL      BIT(14)
+#define AHCLKRE                BIT(15)
+#define AHCLKRDIV_MASK 0xfff
+
+/*
+ * DAVINCI_MCASP_XRSRCTL_BASE_REG -  Serializer Control Register Bits
+ */
+#define MODE(val)      (val)
+#define DISMOD         (val)(val<<2)
+#define TXSTATE                BIT(4)
+#define RXSTATE                BIT(5)
+#define SRMOD_MASK     3
+#define SRMOD_INACTIVE 0
+
+/*
+ * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
+ */
+#define LBEN           BIT(0)
+#define LBORD          BIT(1)
+#define LBGENMODE(val) (val<<2)
+
+/*
+ * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
+ */
+#define TXTDMS(n)      (1<<n)
+
+/*
+ * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
+ */
+#define RXTDMS(n)      (1<<n)
+
+/*
+ * DAVINCI_MCASP_GBLCTL_REG -  Global Control Register Bits
+ */
+#define RXCLKRST       BIT(0)  /* Receiver Clock Divider Reset */
+#define RXHCLKRST      BIT(1)  /* Receiver High Frequency Clock Divider */
+#define RXSERCLR       BIT(2)  /* Receiver Serializer Clear */
+#define RXSMRST                BIT(3)  /* Receiver State Machine Reset */
+#define RXFSRST                BIT(4)  /* Frame Sync Generator Reset */
+#define TXCLKRST       BIT(8)  /* Transmitter Clock Divider Reset */
+#define TXHCLKRST      BIT(9)  /* Transmitter High Frequency Clock Divider*/
+#define TXSERCLR       BIT(10) /* Transmit Serializer Clear */
+#define TXSMRST                BIT(11) /* Transmitter State Machine Reset */
+#define TXFSRST                BIT(12) /* Frame Sync Generator Reset */
+
+/*
+ * DAVINCI_MCASP_AMUTE_REG -  Mute Control Register Bits
+ */
+#define MUTENA(val)    (val)
+#define MUTEINPOL      BIT(2)
+#define MUTEINENA      BIT(3)
+#define MUTEIN         BIT(4)
+#define MUTER          BIT(5)
+#define MUTEX          BIT(6)
+#define MUTEFSR                BIT(7)
+#define MUTEFSX                BIT(8)
+#define MUTEBADCLKR    BIT(9)
+#define MUTEBADCLKX    BIT(10)
+#define MUTERXDMAERR   BIT(11)
+#define MUTETXDMAERR   BIT(12)
+
+/*
+ * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
+ */
+#define RXDATADMADIS   BIT(0)
+
+/*
+ * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
+ */
+#define TXDATADMADIS   BIT(0)
+
+/*
+ * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
+ */
+#define FIFO_ENABLE    BIT(16)
+#define NUMEVT_MASK    (0xFF << 8)
+#define NUMDMA_MASK    (0xFF)
 
 #endif /* DAVINCI_MCASP_H */
index fb5d107f56034eebec7003878eceded711a51769..14145cdf8a11397494af3ac9d09454b88e774163 100644 (file)
@@ -46,33 +46,11 @@ static void print_buf_info(int slot, char *name)
 }
 #endif
 
-#define DAVINCI_PCM_FMTBITS    (\
-                               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_S24_LE |\
-                               SNDRV_PCM_FMTBIT_S24_BE |\
-                               SNDRV_PCM_FMTBIT_U24_LE |\
-                               SNDRV_PCM_FMTBIT_U24_BE |\
-                               SNDRV_PCM_FMTBIT_S32_LE |\
-                               SNDRV_PCM_FMTBIT_S32_BE |\
-                               SNDRV_PCM_FMTBIT_U32_LE |\
-                               SNDRV_PCM_FMTBIT_U32_BE)
-
 static struct snd_pcm_hardware pcm_hardware_playback = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
                 SNDRV_PCM_INFO_BATCH),
-       .formats = DAVINCI_PCM_FMTBITS,
-       .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
-       .rate_min = 8000,
-       .rate_max = 192000,
-       .channels_min = 2,
-       .channels_max = 384,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
@@ -86,12 +64,6 @@ static struct snd_pcm_hardware pcm_hardware_capture = {
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE |
                 SNDRV_PCM_INFO_BATCH),
-       .formats = DAVINCI_PCM_FMTBITS,
-       .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
-       .rate_min = 8000,
-       .rate_max = 192000,
-       .channels_min = 2,
-       .channels_max = 384,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
index 8c10b8f80acefe2c52654f74dd8904181a8da619..514c275c6108ba52d2503870c4225afdc66b6dc9 100644 (file)
@@ -1,3 +1,7 @@
+config SND_SOC_FSL_SAI
+       tristate
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+
 config SND_SOC_FSL_SSI
        tristate
 
index 8db705b0fdf9dc08d7ef793da25492bb71ce7049..aaccbee17006776a4bda27a779567d4c4c1655af 100644 (file)
@@ -10,11 +10,13 @@ obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
 snd-soc-p1022-rdk-objs := p1022_rdk.o
 obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 
-# Freescale PowerPC SSI/DMA Platform Support
+# Freescale SSI/DMA/SAI/SPDIF Support
+snd-soc-fsl-sai-objs := fsl_sai.o
 snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-spdif-objs := fsl_spdif.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
 obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
index fb9bb9eb5ca38f56d7359b6c57af772ee941675c..d570f8c81dc666fb1f6653c7e9e2a5a128b3fb5a 100644 (file)
@@ -852,7 +852,7 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
 }
 
 /**
- * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ * find_ssi_node -- returns the SSI node that points to its DMA channel node
  *
  * Although this DMA driver attempts to operate independently of the other
  * devices, it still needs to determine some information about the SSI device
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
new file mode 100644 (file)
index 0000000..5d38a67
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright 2012-2013 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 as published by the
+ * Free Software Foundation, either version 2 of the License, or(at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_sai.h"
+
+static inline u32 sai_readl(struct fsl_sai *sai,
+               const void __iomem *addr)
+{
+       u32 val;
+
+       val = __raw_readl(addr);
+
+       if (likely(sai->big_endian_regs))
+               val = be32_to_cpu(val);
+       else
+               val = le32_to_cpu(val);
+       rmb();
+
+       return val;
+}
+
+static inline void sai_writel(struct fsl_sai *sai,
+               u32 val, void __iomem *addr)
+{
+       wmb();
+       if (likely(sai->big_endian_regs))
+               val = cpu_to_be32(val);
+       else
+               val = cpu_to_le32(val);
+
+       __raw_writel(val, addr);
+}
+
+static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
+               int clk_id, unsigned int freq, int fsl_dir)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 val_cr2, reg_cr2;
+
+       if (fsl_dir == FSL_FMT_TRANSMITTER)
+               reg_cr2 = FSL_SAI_TCR2;
+       else
+               reg_cr2 = FSL_SAI_RCR2;
+
+       val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+       switch (clk_id) {
+       case FSL_SAI_CLK_BUS:
+               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+               val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
+               break;
+       case FSL_SAI_CLK_MAST1:
+               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+               val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
+               break;
+       case FSL_SAI_CLK_MAST2:
+               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+               val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
+               break;
+       case FSL_SAI_CLK_MAST3:
+               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+               val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
+               break;
+       default:
+               return -EINVAL;
+       }
+       sai_writel(sai, val_cr2, sai->base + reg_cr2);
+
+       return 0;
+}
+
+static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
+
+       if (dir == SND_SOC_CLOCK_IN)
+               return 0;
+
+       ret = clk_prepare_enable(sai->clk);
+       if (ret)
+               return ret;
+
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+                                       FSL_FMT_TRANSMITTER);
+       if (ret) {
+               dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
+               goto err_clk;
+       }
+
+       ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+                                       FSL_FMT_RECEIVER);
+       if (ret) {
+               dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
+               goto err_clk;
+       }
+
+err_clk:
+       clk_disable_unprepare(sai->clk);
+
+       return ret;
+}
+
+static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
+                               unsigned int fmt, int fsl_dir)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
+
+       if (fsl_dir == FSL_FMT_TRANSMITTER) {
+               reg_cr2 = FSL_SAI_TCR2;
+               reg_cr4 = FSL_SAI_TCR4;
+       } else {
+               reg_cr2 = FSL_SAI_RCR2;
+               reg_cr4 = FSL_SAI_RCR4;
+       }
+
+       val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+       val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+
+       if (sai->big_endian_data)
+               val_cr4 &= ~FSL_SAI_CR4_MF;
+       else
+               val_cr4 |= FSL_SAI_CR4_MF;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               val_cr4 |= FSL_SAI_CR4_FSE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_IF:
+               val_cr4 |= FSL_SAI_CR4_FSP;
+               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               val_cr4 &= ~FSL_SAI_CR4_FSP;
+               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               val_cr4 |= FSL_SAI_CR4_FSP;
+               val_cr2 |= FSL_SAI_CR2_BCP;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+               val_cr4 &= ~FSL_SAI_CR4_FSP;
+               val_cr2 |= FSL_SAI_CR2_BCP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+               val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
+               val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       sai_writel(sai, val_cr2, sai->base + reg_cr2);
+       sai_writel(sai, val_cr4, sai->base + reg_cr4);
+
+       return 0;
+}
+
+static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
+
+       ret = clk_prepare_enable(sai->clk);
+       if (ret)
+               return ret;
+
+       ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
+       if (ret) {
+               dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
+               goto err_clk;
+       }
+
+       ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
+       if (ret) {
+               dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
+               goto err_clk;
+       }
+
+err_clk:
+       clk_disable_unprepare(sai->clk);
+
+       return ret;
+}
+
+static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params,
+               struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
+       unsigned int channels = params_channels(params);
+       u32 word_width = snd_pcm_format_width(params_format(params));
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               reg_cr4 = FSL_SAI_TCR4;
+               reg_cr5 = FSL_SAI_TCR5;
+               reg_mr = FSL_SAI_TMR;
+       } else {
+               reg_cr4 = FSL_SAI_RCR4;
+               reg_cr5 = FSL_SAI_RCR5;
+               reg_mr = FSL_SAI_RMR;
+       }
+
+       val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+       val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
+       val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
+
+       val_cr5 = sai_readl(sai, sai->base + reg_cr5);
+       val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
+       val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
+       val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+
+       val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+       val_cr5 |= FSL_SAI_CR5_WNW(word_width);
+       val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+
+       val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+       if (sai->big_endian_data)
+               val_cr5 |= FSL_SAI_CR5_FBT(0);
+       else
+               val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
+
+       val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
+       val_mr = ~0UL - ((1 << channels) - 1);
+
+       sai_writel(sai, val_cr4, sai->base + reg_cr4);
+       sai_writel(sai, val_cr5, sai->base + reg_cr5);
+       sai_writel(sai, val_mr, sai->base + reg_mr);
+
+       return 0;
+}
+
+static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
+               struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3;
+
+       val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2);
+       val_cr2 &= ~FSL_SAI_CR2_SYNC;
+       sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2);
+
+       val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2);
+       val_cr2 |= FSL_SAI_CR2_SYNC;
+       sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2);
+
+       tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
+       rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               tcsr |= FSL_SAI_CSR_FRDE;
+               rcsr &= ~FSL_SAI_CSR_FRDE;
+               reg_cr3 = FSL_SAI_TCR3;
+       } else {
+               rcsr |= FSL_SAI_CSR_FRDE;
+               tcsr &= ~FSL_SAI_CSR_FRDE;
+               reg_cr3 = FSL_SAI_RCR3;
+       }
+
+       val_cr3 = sai_readl(sai, sai->base + reg_cr3);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               tcsr |= FSL_SAI_CSR_TERE;
+               rcsr |= FSL_SAI_CSR_TERE;
+               val_cr3 |= FSL_SAI_CR3_TRCE;
+
+               sai_writel(sai, val_cr3, sai->base + reg_cr3);
+               sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+               sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
+                       tcsr &= ~FSL_SAI_CSR_TERE;
+                       rcsr &= ~FSL_SAI_CSR_TERE;
+               }
+
+               val_cr3 &= ~FSL_SAI_CR3_TRCE;
+
+               sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+               sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+               sai_writel(sai, val_cr3, sai->base + reg_cr3);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int fsl_sai_startup(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+       return clk_prepare_enable(sai->clk);
+}
+
+static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+       clk_disable_unprepare(sai->clk);
+}
+
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+       .set_sysclk     = fsl_sai_set_dai_sysclk,
+       .set_fmt        = fsl_sai_set_dai_fmt,
+       .hw_params      = fsl_sai_hw_params,
+       .trigger        = fsl_sai_trigger,
+       .startup        = fsl_sai_startup,
+       .shutdown       = fsl_sai_shutdown,
+};
+
+static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+       int ret;
+
+       ret = clk_prepare_enable(sai->clk);
+       if (ret)
+               return ret;
+
+       sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
+       sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
+       sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
+       sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
+
+       clk_disable_unprepare(sai->clk);
+
+       snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+                               &sai->dma_params_rx);
+
+       snd_soc_dai_set_drvdata(cpu_dai, sai);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver fsl_sai_dai = {
+       .probe = fsl_sai_dai_probe,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = FSL_SAI_FORMATS,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = FSL_SAI_FORMATS,
+       },
+       .ops = &fsl_sai_pcm_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_component = {
+       .name           = "fsl-sai",
+};
+
+static int fsl_sai_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct fsl_sai *sai;
+       struct resource *res;
+       int ret;
+
+       sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+       if (!sai)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sai->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(sai->base))
+               return PTR_ERR(sai->base);
+
+       sai->clk = devm_clk_get(&pdev->dev, "sai");
+       if (IS_ERR(sai->clk)) {
+               dev_err(&pdev->dev, "Cannot get SAI's clock\n");
+               return PTR_ERR(sai->clk);
+       }
+
+       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
+       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
+       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+       sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+
+       sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
+       sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+
+       platform_set_drvdata(pdev, sai);
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+                       &fsl_sai_dai, 1);
+       if (ret)
+               return ret;
+
+       return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+                       SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+}
+
+static const struct of_device_id fsl_sai_ids[] = {
+       { .compatible = "fsl,vf610-sai", },
+       { /* sentinel */ }
+};
+
+static struct platform_driver fsl_sai_driver = {
+       .probe = fsl_sai_probe,
+       .driver = {
+               .name = "fsl-sai",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_sai_ids,
+       },
+};
+module_platform_driver(fsl_sai_driver);
+
+MODULE_DESCRIPTION("Freescale Soc SAI Interface");
+MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
+MODULE_ALIAS("platform:fsl-sai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
new file mode 100644 (file)
index 0000000..41bb62e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012-2013 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.
+ */
+
+#ifndef __FSL_SAI_H
+#define __FSL_SAI_H
+
+#include <sound/dmaengine_pcm.h>
+
+#define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S20_3LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE)
+
+/* SAI Transmit/Recieve Control Register */
+#define FSL_SAI_TCSR           0x00
+#define FSL_SAI_RCSR           0x80
+#define FSL_SAI_CSR_TERE       BIT(31)
+#define FSL_SAI_CSR_FWF                BIT(17)
+#define FSL_SAI_CSR_FRIE       BIT(8)
+#define FSL_SAI_CSR_FRDE       BIT(0)
+
+/* SAI Transmit Data/FIFO/MASK Register */
+#define FSL_SAI_TDR            0x20
+#define FSL_SAI_TFR            0x40
+#define FSL_SAI_TMR            0x60
+
+/* SAI Recieve Data/FIFO/MASK Register */
+#define FSL_SAI_RDR            0xa0
+#define FSL_SAI_RFR            0xc0
+#define FSL_SAI_RMR            0xe0
+
+/* SAI Transmit and Recieve Configuration 1 Register */
+#define FSL_SAI_TCR1           0x04
+#define FSL_SAI_RCR1           0x84
+
+/* SAI Transmit and Recieve Configuration 2 Register */
+#define FSL_SAI_TCR2           0x08
+#define FSL_SAI_RCR2           0x88
+#define FSL_SAI_CR2_SYNC       BIT(30)
+#define FSL_SAI_CR2_MSEL_MASK  (0xff << 26)
+#define FSL_SAI_CR2_MSEL_BUS   0
+#define FSL_SAI_CR2_MSEL_MCLK1 BIT(26)
+#define FSL_SAI_CR2_MSEL_MCLK2 BIT(27)
+#define FSL_SAI_CR2_MSEL_MCLK3 (BIT(26) | BIT(27))
+#define FSL_SAI_CR2_BCP                BIT(25)
+#define FSL_SAI_CR2_BCD_MSTR   BIT(24)
+
+/* SAI Transmit and Recieve Configuration 3 Register */
+#define FSL_SAI_TCR3           0x0c
+#define FSL_SAI_RCR3           0x8c
+#define FSL_SAI_CR3_TRCE       BIT(16)
+#define FSL_SAI_CR3_WDFL(x)    (x)
+#define FSL_SAI_CR3_WDFL_MASK  0x1f
+
+/* SAI Transmit and Recieve Configuration 4 Register */
+#define FSL_SAI_TCR4           0x10
+#define FSL_SAI_RCR4           0x90
+#define FSL_SAI_CR4_FRSZ(x)    (((x) - 1) << 16)
+#define FSL_SAI_CR4_FRSZ_MASK  (0x1f << 16)
+#define FSL_SAI_CR4_SYWD(x)    (((x) - 1) << 8)
+#define FSL_SAI_CR4_SYWD_MASK  (0x1f << 8)
+#define FSL_SAI_CR4_MF         BIT(4)
+#define FSL_SAI_CR4_FSE                BIT(3)
+#define FSL_SAI_CR4_FSP                BIT(1)
+#define FSL_SAI_CR4_FSD_MSTR   BIT(0)
+
+/* SAI Transmit and Recieve Configuration 5 Register */
+#define FSL_SAI_TCR5           0x14
+#define FSL_SAI_RCR5           0x94
+#define FSL_SAI_CR5_WNW(x)     (((x) - 1) << 24)
+#define FSL_SAI_CR5_WNW_MASK   (0x1f << 24)
+#define FSL_SAI_CR5_W0W(x)     (((x) - 1) << 16)
+#define FSL_SAI_CR5_W0W_MASK   (0x1f << 16)
+#define FSL_SAI_CR5_FBT(x)     ((x) << 8)
+#define FSL_SAI_CR5_FBT_MASK   (0x1f << 8)
+
+/* SAI type */
+#define FSL_SAI_DMA            BIT(0)
+#define FSL_SAI_USE_AC97       BIT(1)
+#define FSL_SAI_NET            BIT(2)
+#define FSL_SAI_TRA_SYN                BIT(3)
+#define FSL_SAI_REC_SYN                BIT(4)
+#define FSL_SAI_USE_I2S_SLAVE  BIT(5)
+
+#define FSL_FMT_TRANSMITTER    0
+#define FSL_FMT_RECEIVER       1
+
+/* SAI clock sources */
+#define FSL_SAI_CLK_BUS                0
+#define FSL_SAI_CLK_MAST1      1
+#define FSL_SAI_CLK_MAST2      2
+#define FSL_SAI_CLK_MAST3      3
+
+/* SAI data transfer numbers per DMA request */
+#define FSL_SAI_MAXBURST_TX 6
+#define FSL_SAI_MAXBURST_RX 6
+
+struct fsl_sai {
+       struct clk *clk;
+
+       void __iomem *base;
+
+       bool big_endian_regs;
+       bool big_endian_data;
+
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+};
+
+#endif /* __FSL_SAI_H */
index 55193a5596ca6fe4aa3b0c53170d71f4f1a6c355..4d075f1abe7803387bb01dbb39a2d66a0eac4c59 100644 (file)
@@ -1181,13 +1181,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int fsl_spdif_remove(struct platform_device *pdev)
-{
-       imx_pcm_dma_exit(pdev);
-
-       return 0;
-}
-
 static const struct of_device_id fsl_spdif_dt_ids[] = {
        { .compatible = "fsl,imx35-spdif", },
        {}
@@ -1201,7 +1194,6 @@ static struct platform_driver fsl_spdif_driver = {
                .of_match_table = fsl_spdif_dt_ids,
        },
        .probe = fsl_spdif_probe,
-       .remove = fsl_spdif_remove,
 };
 
 module_platform_driver(fsl_spdif_driver);
index 35e277379b86ce80d56737e3e0c05a5b3772fb2c..b2ebaf811599d7fd3d94ef08e0e9b9d9bb8e947e 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
@@ -119,8 +120,6 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
  * @ssi: pointer to the SSI's registers
  * @ssi_phys: physical address of the SSI registers
  * @irq: IRQ of this SSI
- * @first_stream: pointer to the stream that was opened first
- * @second_stream: pointer to second stream
  * @playback: the number of playback streams opened
  * @capture: the number of capture streams opened
  * @cpu_dai: the CPU DAI for this device
@@ -132,8 +131,6 @@ struct fsl_ssi_private {
        struct ccsr_ssi __iomem *ssi;
        dma_addr_t ssi_phys;
        unsigned int irq;
-       struct snd_pcm_substream *first_stream;
-       struct snd_pcm_substream *second_stream;
        unsigned int fifo_depth;
        struct snd_soc_dai_driver cpu_dai_drv;
        struct device_attribute dev_attr;
@@ -143,6 +140,10 @@ struct fsl_ssi_private {
        bool ssi_on_imx;
        bool imx_ac97;
        bool use_dma;
+       bool baudclk_locked;
+       u8 i2s_mode;
+       spinlock_t baudclk_lock;
+       struct clk *baudclk;
        struct clk *clk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -321,17 +322,46 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
        return ret;
 }
 
+static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
+{
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+
+       /*
+        * Setup the clock control register
+        */
+       write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+                       &ssi->stccr);
+       write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+                       &ssi->srccr);
+
+       /*
+        * Enable AC97 mode and startup the SSI
+        */
+       write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
+                       &ssi->sacnt);
+       write_ssi(0xff, &ssi->saccdis);
+       write_ssi(0x300, &ssi->saccen);
+
+       /*
+        * Enable SSI, Transmit and Receive. AC97 has to communicate with the
+        * codec before a stream is started.
+        */
+       write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
+                       CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
+
+       write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
+}
+
 static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
 {
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-       u8 i2s_mode;
        u8 wm;
        int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
 
        if (ssi_private->imx_ac97)
-               i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
+               ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
        else
-               i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+               ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
 
        /*
         * Section 16.5 of the MPC8610 reference manual says that the SSI needs
@@ -348,7 +378,7 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
        write_ssi_mask(&ssi->scr,
                CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
                CCSR_SSI_SCR_TFR_CLK_DIS |
-               i2s_mode |
+               ssi_private->i2s_mode |
                (synchronous ? CCSR_SSI_SCR_SYN : 0));
 
        write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -387,31 +417,8 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
         * because it is also running without an active substream. Normally SSI
         * is only enabled when there is a substream.
         */
-       if (ssi_private->imx_ac97) {
-               /*
-                * Setup the clock control register
-                */
-               write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
-                               &ssi->stccr);
-               write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
-                               &ssi->srccr);
-
-               /*
-                * Enable AC97 mode and startup the SSI
-                */
-               write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
-                               &ssi->sacnt);
-               write_ssi(0xff, &ssi->saccdis);
-               write_ssi(0x300, &ssi->saccen);
-
-               /*
-                * Enable SSI, Transmit and Receive
-                */
-               write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
-                               CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
-
-               write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
-       }
+       if (ssi_private->imx_ac97)
+               fsl_ssi_setup_ac97(ssi_private);
 
        return 0;
 }
@@ -431,53 +438,17 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct fsl_ssi_private *ssi_private =
                snd_soc_dai_get_drvdata(rtd->cpu_dai);
-       int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+       unsigned long flags;
 
-       /*
-        * If this is the first stream opened, then request the IRQ
-        * and initialize the SSI registers.
+       /* First, we only do fsl_ssi_setup() when SSI is going to be active.
+        * Second, fsl_ssi_setup was already called by ac97_init earlier if
+        * the driver is in ac97 mode.
         */
-       if (!ssi_private->first_stream) {
-               ssi_private->first_stream = substream;
-
-               /*
-                * fsl_ssi_setup was already called by ac97_init earlier if
-                * the driver is in ac97 mode.
-                */
-               if (!ssi_private->imx_ac97)
-                       fsl_ssi_setup(ssi_private);
-       } else {
-               if (synchronous) {
-                       struct snd_pcm_runtime *first_runtime =
-                               ssi_private->first_stream->runtime;
-                       /*
-                        * This is the second stream open, and we're in
-                        * synchronous mode, so we need to impose sample
-                        * sample size constraints. This is because STCCR is
-                        * used for playback and capture in synchronous mode,
-                        * so there's no way to specify different word
-                        * lengths.
-                        *
-                        * Note that this can cause a race condition if the
-                        * second stream is opened before the first stream is
-                        * fully initialized.  We provide some protection by
-                        * checking to make sure the first stream is
-                        * initialized, but it's not perfect.  ALSA sometimes
-                        * re-initializes the driver with a different sample
-                        * rate or size.  If the second stream is opened
-                        * before the first stream has received its final
-                        * parameters, then the second stream may be
-                        * constrained to the wrong sample rate or size.
-                        */
-                       if (first_runtime->sample_bits) {
-                               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                               SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                               first_runtime->sample_bits,
-                               first_runtime->sample_bits);
-                       }
-               }
-
-               ssi_private->second_stream = substream;
+       if (!dai->active && !ssi_private->imx_ac97) {
+               fsl_ssi_setup(ssi_private);
+               spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+               ssi_private->baudclk_locked = false;
+               spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
        }
 
        return 0;
@@ -501,6 +472,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
 {
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       unsigned int channels = params_channels(hw_params);
        unsigned int sample_size =
                snd_pcm_format_width(params_format(hw_params));
        u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
@@ -530,6 +502,248 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
        else
                write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
 
+       if (!ssi_private->imx_ac97)
+               write_ssi_mask(&ssi->scr,
+                               CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
+                               channels == 1 ? 0 : ssi_private->i2s_mode);
+
+       return 0;
+}
+
+/**
+ * fsl_ssi_set_dai_fmt - configure Digital Audio Interface Format.
+ */
+static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       u32 strcr = 0, stcr, srcr, scr, mask;
+
+       scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
+       scr |= CCSR_SSI_SCR_NET;
+
+       mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
+               CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
+               CCSR_SSI_STCR_TEFS;
+       stcr = read_ssi(&ssi->stcr) & ~mask;
+       srcr = read_ssi(&ssi->srcr) & ~mask;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_MASTER;
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               scr |= ssi_private->i2s_mode;
+
+               /* Data on rising edge of bclk, frame low, 1clk before data */
+               strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
+                       CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /* Data on rising edge of bclk, frame high */
+               strcr |= CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TSCKP;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* Data on rising edge of bclk, frame high, 1clk before data */
+               strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
+                       CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               /* Data on rising edge of bclk, frame high */
+               strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
+                       CCSR_SSI_STCR_TXBIT0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* DAI clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               /* Nothing to do for both normal cases */
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               /* Invert bit clock */
+               strcr ^= CCSR_SSI_STCR_TSCKP;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               /* Invert frame clock */
+               strcr ^= CCSR_SSI_STCR_TFSI;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               /* Invert both clocks */
+               strcr ^= CCSR_SSI_STCR_TSCKP;
+               strcr ^= CCSR_SSI_STCR_TFSI;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR;
+               scr |= CCSR_SSI_SCR_SYS_CLK_EN;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       stcr |= strcr;
+       srcr |= strcr;
+
+       if (ssi_private->cpu_dai_drv.symmetric_rates) {
+               /* Need to clear RXDIR when using SYNC mode */
+               srcr &= ~CCSR_SSI_SRCR_RXDIR;
+               scr |= CCSR_SSI_SCR_SYN;
+       }
+
+       write_ssi(stcr, &ssi->stcr);
+       write_ssi(srcr, &ssi->srcr);
+       write_ssi(scr, &ssi->scr);
+
+       return 0;
+}
+
+/**
+ * fsl_ssi_set_dai_sysclk - configure Digital Audio Interface bit clock
+ *
+ * Note: This function can be only called when using SSI as DAI master
+ *
+ * Quick instruction for parameters:
+ * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
+ * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
+ */
+static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
+       u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
+       unsigned long flags, clkrate, baudrate, tmprate;
+       u64 sub, savesub = 100000;
+
+       /* Don't apply it to any non-baudclk circumstance */
+       if (IS_ERR(ssi_private->baudclk))
+               return -EINVAL;
+
+       /* It should be already enough to divide clock by setting pm alone */
+       psr = 0;
+       div2 = 0;
+
+       factor = (div2 + 1) * (7 * psr + 1) * 2;
+
+       for (i = 0; i < 255; i++) {
+               /* The bclk rate must be smaller than 1/5 sysclk rate */
+               if (factor * (i + 1) < 5)
+                       continue;
+
+               tmprate = freq * factor * (i + 2);
+               clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
+
+               do_div(clkrate, factor);
+               afreq = (u32)clkrate / (i + 1);
+
+               if (freq == afreq)
+                       sub = 0;
+               else if (freq / afreq == 1)
+                       sub = freq - afreq;
+               else if (afreq / freq == 1)
+                       sub = afreq - freq;
+               else
+                       continue;
+
+               /* Calculate the fraction */
+               sub *= 100000;
+               do_div(sub, freq);
+
+               if (sub < savesub) {
+                       baudrate = tmprate;
+                       savesub = sub;
+                       pm = i;
+               }
+
+               /* We are lucky */
+               if (savesub == 0)
+                       break;
+       }
+
+       /* No proper pm found if it is still remaining the initial value */
+       if (pm == 999) {
+               dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
+               return -EINVAL;
+       }
+
+       stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
+               (psr ? CCSR_SSI_SxCCR_PSR : 0);
+       mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 | CCSR_SSI_SxCCR_PSR;
+
+       if (dir == SND_SOC_CLOCK_OUT || synchronous)
+               write_ssi_mask(&ssi->stccr, mask, stccr);
+       else
+               write_ssi_mask(&ssi->srccr, mask, stccr);
+
+       spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+       if (!ssi_private->baudclk_locked) {
+               ret = clk_set_rate(ssi_private->baudclk, baudrate);
+               if (ret) {
+                       spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+                       dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
+                       return -EINVAL;
+               }
+               ssi_private->baudclk_locked = true;
+       }
+       spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+
+       return 0;
+}
+
+/**
+ * fsl_ssi_set_dai_tdm_slot - set TDM slot number
+ *
+ * Note: This function can be only called when using SSI as DAI master
+ */
+static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+                               u32 rx_mask, int slots, int slot_width)
+{
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       u32 val;
+
+       /* The slot number should be >= 2 if using Network mode or I2S mode */
+       val = read_ssi(&ssi->scr) & (CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET);
+       if (val && slots < 2) {
+               dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n");
+               return -EINVAL;
+       }
+
+       write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
+                       CCSR_SSI_SxCCR_DC(slots));
+       write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
+                       CCSR_SSI_SxCCR_DC(slots));
+
+       /* The register SxMSKs needs SSI to provide essential clock due to
+        * hardware design. So we here temporarily enable SSI to set them.
+        */
+       val = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
+       write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN);
+
+       write_ssi(tx_mask, &ssi->stmsk);
+       write_ssi(rx_mask, &ssi->srmsk);
+
+       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, val);
+
        return 0;
 }
 
@@ -549,6 +763,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
        unsigned int sier_bits;
+       unsigned long flags;
 
        /*
         *  Enable only the interrupts and DMA requests
@@ -589,8 +804,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
 
                if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
-                                       (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
+                                       (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
                        write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
+                       spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+                       ssi_private->baudclk_locked = false;
+                       spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+               }
                break;
 
        default:
@@ -602,23 +821,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-/**
- * fsl_ssi_shutdown: shutdown the SSI
- *
- * Shutdown the SSI if there are no other substreams open.
- */
-static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-
-       if (ssi_private->first_stream == substream)
-               ssi_private->first_stream = ssi_private->second_stream;
-
-       ssi_private->second_stream = NULL;
-}
-
 static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
@@ -634,7 +836,9 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
        .startup        = fsl_ssi_startup,
        .hw_params      = fsl_ssi_hw_params,
-       .shutdown       = fsl_ssi_shutdown,
+       .set_fmt        = fsl_ssi_set_dai_fmt,
+       .set_sysclk     = fsl_ssi_set_dai_sysclk,
+       .set_tdm_slot   = fsl_ssi_set_dai_tdm_slot,
        .trigger        = fsl_ssi_trigger,
 };
 
@@ -642,14 +846,13 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
 static struct snd_soc_dai_driver fsl_ssi_dai_template = {
        .probe = fsl_ssi_dai_probe,
        .playback = {
-               /* The SSI does not support monaural audio. */
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = FSLSSI_I2S_RATES,
                .formats = FSLSSI_I2S_FORMATS,
        },
        .capture = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = FSLSSI_I2S_RATES,
                .formats = FSLSSI_I2S_FORMATS,
@@ -710,7 +913,6 @@ static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = {
        .startup        = fsl_ssi_startup,
-       .shutdown       = fsl_ssi_shutdown,
        .trigger        = fsl_ssi_ac97_trigger,
 };
 
@@ -935,8 +1137,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
        /* Are the RX and the TX clocks locked? */
-       if (!of_find_property(np, "fsl,ssi-asynchronous", NULL))
+       if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
                ssi_private->cpu_dai_drv.symmetric_rates = 1;
+               ssi_private->cpu_dai_drv.symmetric_channels = 1;
+               ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
+       }
 
        /* Determine the FIFO depth. */
        iprop = of_get_property(np, "fsl,fifo-depth", NULL);
@@ -946,6 +1151,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                 /* Older 8610 DTs didn't have the fifo-depth property */
                ssi_private->fifo_depth = 8;
 
+       ssi_private->baudclk_locked = false;
+       spin_lock_init(&ssi_private->baudclk_lock);
+
        if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
                u32 dma_events[2];
                ssi_private->ssi_on_imx = true;
@@ -963,6 +1171,15 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                        goto error_irqmap;
                }
 
+               /* For those SLAVE implementations, we ingore non-baudclk cases
+                * and, instead, abandon MASTER mode that needs baud clock.
+                */
+               ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
+               if (IS_ERR(ssi_private->baudclk))
+                       dev_warn(&pdev->dev, "could not get baud clock: %d\n", ret);
+               else
+                       clk_prepare_enable(ssi_private->baudclk);
+
                /*
                 * We have burstsize be "fifo_depth - 2" to match the SSI
                 * watermark setting in fsl_ssi_startup().
@@ -1102,16 +1319,17 @@ done:
        return 0;
 
 error_dai:
-       if (ssi_private->ssi_on_imx)
-               imx_pcm_dma_exit(pdev);
        snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
        device_remove_file(&pdev->dev, dev_attr);
 
 error_clk:
-       if (ssi_private->ssi_on_imx)
+       if (ssi_private->ssi_on_imx) {
+               if (!IS_ERR(ssi_private->baudclk))
+                       clk_disable_unprepare(ssi_private->baudclk);
                clk_disable_unprepare(ssi_private->clk);
+       }
 
 error_irqmap:
        irq_dispose_mapping(ssi_private->irq);
@@ -1125,12 +1343,13 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 
        if (!ssi_private->new_binding)
                platform_device_unregister(ssi_private->pdev);
-       if (ssi_private->ssi_on_imx)
-               imx_pcm_dma_exit(pdev);
        snd_soc_unregister_component(&pdev->dev);
        device_remove_file(&pdev->dev, &ssi_private->dev_attr);
-       if (ssi_private->ssi_on_imx)
+       if (ssi_private->ssi_on_imx) {
+               if (!IS_ERR(ssi_private->baudclk))
+                       clk_disable_unprepare(ssi_private->baudclk);
                clk_disable_unprepare(ssi_private->clk);
+       }
        irq_dispose_mapping(ssi_private->irq);
 
        return 0;
index e6b9a69e2a68bea799796ec0ba8d2da096498d62..e6b63240a3d71a597dfa940312b49a0c68ff976f 100644 (file)
@@ -125,7 +125,9 @@ struct ccsr_ssi {
 #define CCSR_SSI_SRCR_REFS             0x00000001
 
 /* STCCR and SRCCR */
+#define CCSR_SSI_SxCCR_DIV2_SHIFT      18
 #define CCSR_SSI_SxCCR_DIV2            0x00040000
+#define CCSR_SSI_SxCCR_PSR_SHIFT       17
 #define CCSR_SSI_SxCCR_PSR             0x00020000
 #define CCSR_SSI_SxCCR_WL_SHIFT                13
 #define CCSR_SSI_SxCCR_WL_MASK         0x0001E000
index aee23077080a219983f0dd52764d1aa4199cb15c..c5e47f866b4b756beaa515b1c29ba4177572cb10 100644 (file)
@@ -61,16 +61,11 @@ static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
 
 int imx_pcm_dma_init(struct platform_device *pdev)
 {
-       return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
+       return devm_snd_dmaengine_pcm_register(&pdev->dev,
+               &imx_dmaengine_pcm_config,
                SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
 
-void imx_pcm_dma_exit(struct platform_device *pdev)
-{
-       snd_dmaengine_pcm_unregister(&pdev->dev);
-}
-EXPORT_SYMBOL_GPL(imx_pcm_dma_exit);
-
 MODULE_LICENSE("GPL");
index 5d5b73303e1169b7f6c2254e06d66a87409050cc..c79cb27473be771d9ee355cacf52229f5da6c40d 100644 (file)
@@ -40,16 +40,11 @@ struct imx_pcm_fiq_params {
 
 #if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)
 int imx_pcm_dma_init(struct platform_device *pdev);
-void imx_pcm_dma_exit(struct platform_device *pdev);
 #else
 static inline int imx_pcm_dma_init(struct platform_device *pdev)
 {
        return -ENODEV;
 }
-
-static inline void imx_pcm_dma_exit(struct platform_device *pdev)
-{
-}
 #endif
 
 #if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_FIQ)
index e656245d24c919d25b458460245cbef0d62e2aee..e1dc40143600a05854331a539590603d0d859fed 100644 (file)
@@ -33,7 +33,6 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
                ret = -ENOMEM;
                goto end;
        }
index f5f248c91c16db7c3db5a50654bceedb0e81953f..df552fa1aa65f13faee928c63d2a8b8bf6c9eae4 100644 (file)
@@ -304,8 +304,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        scr |= SSI_SCR_RE;
                sier |= sier_bits;
 
-               if (++ssi->enabled == 1)
-                       scr |= SSI_SCR_SSIEN;
+               scr |= SSI_SCR_SSIEN;
 
                break;
 
@@ -318,7 +317,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        scr &= ~SSI_SCR_RE;
                sier &= ~sier_bits;
 
-               if (--ssi->enabled == 0)
+               if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
                        scr &= ~SSI_SCR_SSIEN;
 
                break;
@@ -536,7 +535,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
                        ret);
                goto failed_clk;
        }
-       clk_prepare_enable(ssi->clk);
+       ret = clk_prepare_enable(ssi->clk);
+       if (ret)
+               goto failed_clk;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ssi->base = devm_ioremap_resource(&pdev->dev, res);
@@ -624,9 +625,6 @@ static int imx_ssi_remove(struct platform_device *pdev)
 {
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 
-       if (!ssi->dma_init)
-               imx_pcm_dma_exit(pdev);
-
        if (!ssi->fiq_init)
                imx_pcm_fiq_exit(pdev);
 
index 560c40fc9ebbb50241e3732f3a76ece064178bf2..be6562365b6a971a08efe55e3c1d7c49f0c0a874 100644 (file)
@@ -213,7 +213,6 @@ struct imx_ssi {
 
        int fiq_init;
        int dma_init;
-       int enabled;
 };
 
 #endif /* _IMX_SSI_H */
index be7c1db5388faddcb4f6477b345ed5efba4abc9e..c0d928138c88c4eadef6243098350f09f19eaa1c 100644 (file)
@@ -25,7 +25,7 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
 
        daifmt |= set->fmt;
 
-       if (!ret && daifmt)
+       if (daifmt)
                ret = snd_soc_dai_set_fmt(dai, daifmt);
 
        if (ret == -ENOTSUPP) {
@@ -90,14 +90,29 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
         * dai->sysclk come from
         *  "clocks = <&xxx>" (if system has common clock)
         *  or "system-clock-frequency = <xxx>"
+        *  or device's module clock.
         */
-       clk = of_clk_get(np, 0);
-       if (IS_ERR(clk))
+       if (of_property_read_bool(np, "clocks")) {
+               clk = of_clk_get(np, 0);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto parse_error;
+               }
+
+               dai->sysclk = clk_get_rate(clk);
+       } else if (of_property_read_bool(np, "system-clock-frequency")) {
                of_property_read_u32(np,
                                     "system-clock-frequency",
                                     &dai->sysclk);
-       else
+       } else {
+               clk = of_clk_get(*node, 0);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto parse_error;
+               }
+
                dai->sysclk = clk_get_rate(clk);
+       }
 
        ret = 0;
 
@@ -116,12 +131,18 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 {
        struct device_node *np;
        char *name;
-       int ret = 0;
+       int ret;
 
        /* get CPU/CODEC common format via simple-audio-card,format */
        info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
                (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
 
+       /* DAPM routes */
+       ret = snd_soc_of_parse_audio_routing(&info->snd_card,
+                                       "simple-audio-routing");
+       if (ret)
+               return ret;
+
        /* CPU sub-node */
        ret = -EINVAL;
        np = of_get_child_by_name(node, "simple-audio-card,cpu");
@@ -185,6 +206,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
                if (cinfo) {
                        int ret;
+                       cinfo->snd_card.dev = &pdev->dev;
                        ret = asoc_simple_card_parse_of(np, cinfo, dev,
                                                        &of_cpu,
                                                        &of_codec,
@@ -196,6 +218,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                        }
                }
        } else {
+               cinfo->snd_card.dev = &pdev->dev;
                cinfo = pdev->dev.platform_data;
        }
 
@@ -235,16 +258,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        cinfo->snd_card.owner           = THIS_MODULE;
        cinfo->snd_card.dai_link        = &cinfo->snd_link;
        cinfo->snd_card.num_links       = 1;
-       cinfo->snd_card.dev             = &pdev->dev;
-
-       return snd_soc_register_card(&cinfo->snd_card);
-}
-
-static int asoc_simple_card_remove(struct platform_device *pdev)
-{
-       struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
 
-       return snd_soc_unregister_card(&cinfo->snd_card);
+       return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card);
 }
 
 static const struct of_device_id asoc_simple_of_match[] = {
@@ -260,7 +275,6 @@ static struct platform_driver asoc_simple_card = {
                .of_match_table = asoc_simple_of_match,
        },
        .probe          = asoc_simple_card_probe,
-       .remove         = asoc_simple_card_remove,
 };
 
 module_platform_driver(asoc_simple_card);
index 5351cba66c9e3584e39263e49137afb9260ed1ab..29f76af5d963c2fca31366e7140c21239d18a0f0 100644 (file)
@@ -1,6 +1,7 @@
 config SND_JZ4740_SOC
        tristate "SoC Audio for Ingenic JZ4740 SoC"
        depends on MACH_JZ4740 && SND_SOC
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
          the JZ4740 I2S interface. You will also need to select the audio
index 4c849a49c72ac3c6c6800aebec9292b3785be37c..8f220009e0f616e0572777c19a15c3a44c658ed8 100644 (file)
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+#include <asm/mach-jz4740/dma.h>
 
 #include "jz4740-i2s.h"
-#include "jz4740-pcm.h"
 
 #define JZ_REG_AIC_CONF                0x00
 #define JZ_REG_AIC_CTRL                0x04
@@ -89,8 +91,8 @@ struct jz4740_i2s {
        struct clk *clk_aic;
        struct clk *clk_i2s;
 
-       struct jz4740_pcm_config pcm_config_playback;
-       struct jz4740_pcm_config pcm_config_capture;
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
 };
 
 static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
@@ -233,8 +235,6 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       enum jz4740_dma_width dma_width;
-       struct jz4740_pcm_config *pcm_config;
        unsigned int sample_size;
        uint32_t ctrl;
 
@@ -243,11 +243,9 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
                sample_size = 0;
-               dma_width = JZ4740_DMA_WIDTH_8BIT;
                break;
        case SNDRV_PCM_FORMAT_S16:
                sample_size = 1;
-               dma_width = JZ4740_DMA_WIDTH_16BIT;
                break;
        default:
                return -EINVAL;
@@ -260,22 +258,13 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
                        ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
                else
                        ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
-
-               pcm_config = &i2s->pcm_config_playback;
-               pcm_config->dma_config.dst_width = dma_width;
-
        } else {
                ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
                ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
-
-               pcm_config = &i2s->pcm_config_capture;
-               pcm_config->dma_config.src_width = dma_width;
        }
 
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
-       snd_soc_dai_set_dma_data(dai, substream, pcm_config);
-
        return 0;
 }
 
@@ -342,25 +331,19 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
 
 static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 {
-       struct jz4740_dma_config *dma_config;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        /* Playback */
-       dma_config = &i2s->pcm_config_playback.dma_config;
-       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT;
-       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
-       dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
-       dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
-       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
-       i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+       dma_data = &i2s->playback_dma_data;
+       dma_data->maxburst = 16;
+       dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT;
+       dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 
        /* Capture */
-       dma_config = &i2s->pcm_config_capture.dma_config;
-       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT;
-       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
-       dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
-       dma_config->flags = JZ4740_DMA_DST_AUTOINC;
-       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
-       i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+       dma_data = &i2s->capture_dma_data;
+       dma_data->maxburst = 16;
+       dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE;
+       dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 }
 
 static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
@@ -371,6 +354,8 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
        clk_prepare_enable(i2s->clk_aic);
 
        jz4740_i2c_init_pcm_config(i2s);
+       snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
+               &i2s->capture_dma_data);
 
        conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
                (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
@@ -432,91 +417,41 @@ static const struct snd_soc_component_driver jz4740_i2s_component = {
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s;
+       struct resource *mem;
        int ret;
 
-       i2s = kzalloc(sizeof(*i2s), GFP_KERNEL);
-
+       i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
        if (!i2s)
                return -ENOMEM;
 
-       i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!i2s->mem) {
-               ret = -ENOENT;
-               goto err_free;
-       }
-
-       i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem),
-                               pdev->name);
-       if (!i2s->mem) {
-               ret = -EBUSY;
-               goto err_free;
-       }
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       i2s->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(i2s->base))
+               return PTR_ERR(i2s->base);
 
-       i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem));
-       if (!i2s->base) {
-               ret = -EBUSY;
-               goto err_release_mem_region;
-       }
+       i2s->phys_base = mem->start;
 
-       i2s->phys_base = i2s->mem->start;
+       i2s->clk_aic = devm_clk_get(&pdev->dev, "aic");
+       if (IS_ERR(i2s->clk_aic))
+               return PTR_ERR(i2s->clk_aic);
 
-       i2s->clk_aic = clk_get(&pdev->dev, "aic");
-       if (IS_ERR(i2s->clk_aic)) {
-               ret = PTR_ERR(i2s->clk_aic);
-               goto err_iounmap;
-       }
-
-       i2s->clk_i2s = clk_get(&pdev->dev, "i2s");
-       if (IS_ERR(i2s->clk_i2s)) {
-               ret = PTR_ERR(i2s->clk_i2s);
-               goto err_clk_put_aic;
-       }
+       i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s");
+       if (IS_ERR(i2s->clk_i2s))
+               return PTR_ERR(i2s->clk_i2s);
 
        platform_set_drvdata(pdev, i2s);
-       ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component,
-                                        &jz4740_i2s_dai, 1);
 
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to register DAI\n");
-               goto err_clk_put_i2s;
-       }
-
-       return 0;
-
-err_clk_put_i2s:
-       clk_put(i2s->clk_i2s);
-err_clk_put_aic:
-       clk_put(i2s->clk_aic);
-err_iounmap:
-       iounmap(i2s->base);
-err_release_mem_region:
-       release_mem_region(i2s->mem->start, resource_size(i2s->mem));
-err_free:
-       kfree(i2s);
-
-       return ret;
-}
+       ret = devm_snd_soc_register_component(&pdev->dev,
+               &jz4740_i2s_component, &jz4740_i2s_dai, 1);
+       if (ret)
+               return ret;
 
-static int jz4740_i2s_dev_remove(struct platform_device *pdev)
-{
-       struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_component(&pdev->dev);
-
-       clk_put(i2s->clk_i2s);
-       clk_put(i2s->clk_aic);
-
-       iounmap(i2s->base);
-       release_mem_region(i2s->mem->start, resource_size(i2s->mem));
-
-       kfree(i2s);
-
-       return 0;
+       return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+               SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 
 static struct platform_driver jz4740_i2s_driver = {
        .probe = jz4740_i2s_dev_probe,
-       .remove = jz4740_i2s_dev_remove,
        .driver = {
                .name = "jz4740-i2s",
                .owner = THIS_MODULE,
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
deleted file mode 100644 (file)
index 1d7ef28..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- *
- *  This program is free software; you can redistribute         it and/or modify it
- *  under  the terms of         the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the License, or (at your
- *  option) any later version.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/mach-jz4740/dma.h>
-#include "jz4740-pcm.h"
-
-struct jz4740_runtime_data {
-       unsigned long dma_period;
-       dma_addr_t dma_start;
-       dma_addr_t dma_pos;
-       dma_addr_t dma_end;
-
-       struct jz4740_dma_chan *dma;
-
-       dma_addr_t fifo_addr;
-};
-
-/* identify hardware playback capabilities */
-static const struct snd_pcm_hardware jz4740_pcm_hardware = {
-       .info = SNDRV_PCM_INFO_MMAP |
-               SNDRV_PCM_INFO_MMAP_VALID |
-               SNDRV_PCM_INFO_INTERLEAVED |
-               SNDRV_PCM_INFO_BLOCK_TRANSFER,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
-
-       .rates                  = SNDRV_PCM_RATE_8000_48000,
-       .channels_min           = 1,
-       .channels_max           = 2,
-       .period_bytes_min       = 16,
-       .period_bytes_max       = 2 * PAGE_SIZE,
-       .periods_min            = 2,
-       .periods_max            = 128,
-       .buffer_bytes_max       = 128 * 2 * PAGE_SIZE,
-       .fifo_size              = 32,
-};
-
-static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd,
-       struct snd_pcm_substream *substream)
-{
-       unsigned long count;
-
-       if (prtd->dma_pos == prtd->dma_end)
-               prtd->dma_pos = prtd->dma_start;
-
-       if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
-               count = prtd->dma_end - prtd->dma_pos;
-       else
-               count = prtd->dma_period;
-
-       jz4740_dma_disable(prtd->dma);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
-               jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr);
-       } else {
-               jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr);
-               jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
-       }
-
-       jz4740_dma_set_transfer_count(prtd->dma, count);
-
-       prtd->dma_pos += count;
-
-       jz4740_dma_enable(prtd->dma);
-}
-
-static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
-       void *dev_id)
-{
-       struct snd_pcm_substream *substream = dev_id;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct jz4740_runtime_data *prtd = runtime->private_data;
-
-       snd_pcm_period_elapsed(substream);
-
-       jz4740_pcm_start_transfer(prtd, substream);
-}
-
-static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct jz4740_runtime_data *prtd = runtime->private_data;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct jz4740_pcm_config *config;
-
-       config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       if (!config)
-               return 0;
-
-       if (!prtd->dma) {
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       prtd->dma = jz4740_dma_request(substream, "PCM Capture");
-               else
-                       prtd->dma = jz4740_dma_request(substream, "PCM Playback");
-       }
-
-       if (!prtd->dma)
-               return -EBUSY;
-
-       jz4740_dma_configure(prtd->dma, &config->dma_config);
-       prtd->fifo_addr = config->fifo_addr;
-
-       jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = params_buffer_bytes(params);
-
-       prtd->dma_period = params_period_bytes(params);
-       prtd->dma_start = runtime->dma_addr;
-       prtd->dma_pos = prtd->dma_start;
-       prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
-
-       return 0;
-}
-
-static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct jz4740_runtime_data *prtd = substream->runtime->private_data;
-
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       if (prtd->dma) {
-               jz4740_dma_free(prtd->dma);
-               prtd->dma = NULL;
-       }
-
-       return 0;
-}
-
-static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct jz4740_runtime_data *prtd = substream->runtime->private_data;
-
-       if (!prtd->dma)
-               return -EBUSY;
-
-       prtd->dma_pos = prtd->dma_start;
-
-       return 0;
-}
-
-static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct jz4740_runtime_data *prtd = runtime->private_data;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               jz4740_pcm_start_transfer(prtd, substream);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               jz4740_dma_disable(prtd->dma);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct jz4740_runtime_data *prtd = runtime->private_data;
-       unsigned long byte_offset;
-       snd_pcm_uframes_t offset;
-       struct jz4740_dma_chan *dma = prtd->dma;
-
-       /* prtd->dma_pos points to the end of the current transfer. So by
-        * subtracting prdt->dma_start we get the offset to the end of the
-        * current period in bytes. By subtracting the residue of the transfer
-        * we get the current offset in bytes. */
-       byte_offset = prtd->dma_pos - prtd->dma_start;
-       byte_offset -= jz4740_dma_get_residue(dma);
-
-       offset = bytes_to_frames(runtime, byte_offset);
-       if (offset >= runtime->buffer_size)
-               offset = 0;
-
-       return offset;
-}
-
-static int jz4740_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct jz4740_runtime_data *prtd;
-
-       prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
-       if (prtd == NULL)
-               return -ENOMEM;
-
-       snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
-
-       runtime->private_data = prtd;
-
-       return 0;
-}
-
-static int jz4740_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct jz4740_runtime_data *prtd = runtime->private_data;
-
-       kfree(prtd);
-
-       return 0;
-}
-
-static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
-       struct vm_area_struct *vma)
-{
-       return remap_pfn_range(vma, vma->vm_start,
-                       substream->dma_buffer.addr >> PAGE_SHIFT,
-                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
-
-static struct snd_pcm_ops jz4740_pcm_ops = {
-       .open           = jz4740_pcm_open,
-       .close          = jz4740_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = jz4740_pcm_hw_params,
-       .hw_free        = jz4740_pcm_hw_free,
-       .prepare        = jz4740_pcm_prepare,
-       .trigger        = jz4740_pcm_trigger,
-       .pointer        = jz4740_pcm_pointer,
-       .mmap           = jz4740_pcm_mmap,
-};
-
-static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = jz4740_pcm_hardware.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-
-       buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
-                                         &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-
-       return 0;
-}
-
-static void jz4740_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area,
-                               buf->addr);
-               buf->area = NULL;
-       }
-}
-
-static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret;
-
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = jz4740_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto err;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = jz4740_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto err;
-       }
-
-err:
-       return ret;
-}
-
-static struct snd_soc_platform_driver jz4740_soc_platform = {
-               .ops            = &jz4740_pcm_ops,
-               .pcm_new        = jz4740_pcm_new,
-               .pcm_free       = jz4740_pcm_free,
-};
-
-static int jz4740_pcm_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
-}
-
-static int jz4740_pcm_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver jz4740_pcm_driver = {
-       .probe = jz4740_pcm_probe,
-       .remove = jz4740_pcm_remove,
-       .driver = {
-               .name = "jz4740-pcm-audio",
-               .owner = THIS_MODULE,
-       },
-};
-
-module_platform_driver(jz4740_pcm_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
deleted file mode 100644 (file)
index 1220cbb..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _JZ4740_PCM_H
-#define _JZ4740_PCM_H
-
-#include <linux/dma-mapping.h>
-#include <asm/mach-jz4740/dma.h>
-
-
-struct jz4740_pcm_config {
-       struct jz4740_dma_config dma_config;
-       phys_addr_t fifo_addr;
-};
-
-#endif
index 55fd6b5df55f5d988799b93ec64995fb4c06a038..82b5f37cd2c78ab16be9eda44b751201d8b9f09d 100644 (file)
@@ -73,7 +73,7 @@ static struct snd_soc_dai_link qi_lb60_dai = {
        .name = "jz4740",
        .stream_name = "jz4740",
        .cpu_dai_name = "jz4740-i2s",
-       .platform_name = "jz4740-pcm-audio",
+       .platform_name = "jz4740-i2s",
        .codec_dai_name = "jz4740-hifi",
        .codec_name = "jz4740-codec",
        .init = qi_lb60_codec_init,
index b16abbbf7764beddd61d42514f70bd33338a7781..04a6b0d60944e1b13350dac3fd2fa708dd3c64d5 100644 (file)
@@ -56,16 +56,10 @@ static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = {
 
 int mxs_pcm_platform_register(struct device *dev)
 {
-       return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
+       return devm_snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
                SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
                SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX);
 }
 EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
 
-void mxs_pcm_platform_unregister(struct device *dev)
-{
-       snd_dmaengine_pcm_unregister(dev);
-}
-EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister);
-
 MODULE_LICENSE("GPL");
index bc685b67cac71e80c17657357c9eb388eac0ac2e..035ea0436ca5fe83a83b210ba101ad90650acca3 100644 (file)
@@ -20,6 +20,5 @@
 #define _MXS_PCM_H
 
 int mxs_pcm_platform_register(struct device *dev);
-void mxs_pcm_platform_unregister(struct device *dev);
 
 #endif
index 54e622acac330d82a92d95164ae79e89cfb461e4..231d7e7b07110d9e219788810acf70d62f1e00c6 100644 (file)
@@ -50,9 +50,9 @@ static struct mxs_saif *mxs_saif[2];
  * This also means that both SAIFs must operate at the same sample rate.
  *
  * We abstract this as each saif has a master, the master could be
- * himself or other saifs. In the generic saif driver, saif does not need
- * to know the different clkmux. Saif only needs to know who is his master
- * and operating his master to generate the proper clock rate for him.
+ * itself or other saifs. In the generic saif driver, saif does not need
+ * to know the different clkmux. Saif only needs to know who is its master
+ * and operating its master to generate the proper clock rate for it.
  * The master id is provided in mach-specific layer according to different
  * clkmux setting.
  */
@@ -76,7 +76,7 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
  * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
  * is provided by other SAIF, we provide a interface here to get its master
  * from its master_id.
- * Note that the master could be himself.
+ * Note that the master could be itself.
  */
 static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif)
 {
@@ -516,7 +516,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
                }
 
                /*
-                * If the saif's master is not himself, we also need to enable
+                * If the saif's master is not itself, we also need to enable
                 * itself clk for its internal basic logic to work.
                 */
                if (saif != master_saif) {
@@ -804,13 +804,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int mxs_saif_remove(struct platform_device *pdev)
-{
-       mxs_pcm_platform_unregister(&pdev->dev);
-
-       return 0;
-}
-
 static const struct of_device_id mxs_saif_dt_ids[] = {
        { .compatible = "fsl,imx28-saif", },
        { /* sentinel */ }
@@ -819,7 +812,6 @@ MODULE_DEVICE_TABLE(of, mxs_saif_dt_ids);
 
 static struct platform_driver mxs_saif_driver = {
        .probe = mxs_saif_probe,
-       .remove = mxs_saif_remove,
 
        .driver = {
                .name = "mxs-saif",
index 83433fdea32ad790f839edd357c14824def13c07..86c75384c3c87dd0e4c9109f737122b1888ad295 100644 (file)
@@ -36,10 +36,10 @@ static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
 
        if (mcbsp->pdata->reg_size == 2) {
                ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
-               __raw_writew((u16)val, addr);
+               writew_relaxed((u16)val, addr);
        } else {
                ((u32 *)mcbsp->reg_cache)[reg] = val;
-               __raw_writel(val, addr);
+               writel_relaxed(val, addr);
        }
 }
 
@@ -48,22 +48,22 @@ static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
        void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
 
        if (mcbsp->pdata->reg_size == 2) {
-               return !from_cache ? __raw_readw(addr) :
+               return !from_cache ? readw_relaxed(addr) :
                                     ((u16 *)mcbsp->reg_cache)[reg];
        } else {
-               return !from_cache ? __raw_readl(addr) :
+               return !from_cache ? readl_relaxed(addr) :
                                     ((u32 *)mcbsp->reg_cache)[reg];
        }
 }
 
 static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
 {
-       __raw_writel(val, mcbsp->st_data->io_base_st + reg);
+       writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
 }
 
 static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
 {
-       return __raw_readl(mcbsp->st_data->io_base_st + reg);
+       return readl_relaxed(mcbsp->st_data->io_base_st + reg);
 }
 
 #define MCBSP_READ(mcbsp, reg) \
index 12e566be3793e61eb4fdd7d9ac47a23d638bc260..1bd531d718f953c3a2cd0e533e0f4340d3713892 100644 (file)
@@ -61,12 +61,12 @@ struct omap_dmic {
 
 static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
 {
-       __raw_writel(val, dmic->io_base + reg);
+       writel_relaxed(val, dmic->io_base + reg);
 }
 
 static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
 {
-       return __raw_readl(dmic->io_base + reg);
+       return readl_relaxed(dmic->io_base + reg);
 }
 
 static inline void omap_dmic_start(struct omap_dmic *dmic)
index cd9ee167959dcc0b34512ffdf32d26208d506c31..2f5b1536477e8895238d21f400f21370a14f3041 100644 (file)
@@ -74,12 +74,12 @@ struct omap_mcpdm {
 
 static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
 {
-       __raw_writel(val, mcpdm->io_base + reg);
+       writel_relaxed(val, mcpdm->io_base + reg);
 }
 
 static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
 {
-       return __raw_readl(mcpdm->io_base + reg);
+       return readl_relaxed(mcpdm->io_base + reg);
 }
 
 #ifdef DEBUG
index b8fa9862e54c4a6c6d99c8d3b88e8204d3cd9d63..07b8b7bc9d20f4e3cceebcb3dbb16492f51ddc46 100644 (file)
@@ -45,8 +45,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
                                  SNDRV_PCM_INFO_PAUSE |
                                  SNDRV_PCM_INFO_RESUME |
                                  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                 SNDRV_PCM_FMTBIT_S32_LE,
        .period_bytes_min       = 32,
        .period_bytes_max       = 64 * 1024,
        .periods_min            = 2,
index 4db74a083db1ef792f90dde317ee9e7556eb4e1d..6473052b689963996713e44e601181ec2e14b47e 100644 (file)
@@ -11,7 +11,7 @@ config SND_PXA2XX_SOC
 config SND_MMP_SOC
        bool "Soc Audio for Marvell MMP chips"
        depends on ARCH_MMP
-       select SND_DMAENGINE_PCM
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        select SND_ARM
        help
          Say Y if you want to add support for codecs attached to
index 7929e19b0ef5970b1942da441770df909f29629e..5e8d813301731f6b99a56228efafa81dfa78126e 100644 (file)
@@ -36,14 +36,9 @@ struct mmp_dma_data {
                SNDRV_PCM_INFO_PAUSE |          \
                SNDRV_PCM_INFO_RESUME)
 
-#define MMP_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
-                        SNDRV_PCM_FMTBIT_S24_LE | \
-                        SNDRV_PCM_FMTBIT_S32_LE)
-
 static struct snd_pcm_hardware mmp_pcm_hardware[] = {
        {
                .info                   = MMP_PCM_INFO,
-               .formats                = MMP_PCM_FORMATS,
                .period_bytes_min       = 1024,
                .period_bytes_max       = 2048,
                .periods_min            = 2,
@@ -53,7 +48,6 @@ static struct snd_pcm_hardware mmp_pcm_hardware[] = {
        },
        {
                .info                   = MMP_PCM_INFO,
-               .formats                = MMP_PCM_FORMATS,
                .period_bytes_min       = 1024,
                .period_bytes_max       = 2048,
                .periods_min            = 2,
@@ -67,27 +61,15 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
 {
        struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_dmaengine_dai_dma_data *dma_params;
        struct dma_slave_config slave_config;
        int ret;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       if (!dma_params)
-               return 0;
-
-       ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
+       ret =
+           snd_dmaengine_pcm_prepare_slave_config(substream, params,
+                                                  &slave_config);
        if (ret)
                return ret;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.dst_addr     = dma_params->addr;
-               slave_config.dst_maxburst = 4;
-       } else {
-               slave_config.src_addr     = dma_params->addr;
-               slave_config.src_maxburst = 4;
-       }
-
        ret = dmaengine_slave_config(chan, &slave_config);
        if (ret)
                return ret;
index d219880815c0142dad341502405a9887977c159d..fb8461e1b1f6664c2aa151b96661c4103fbd61bd 100644 (file)
@@ -33,13 +33,6 @@ static struct snd_pcm_hardware s6000_pcm_hardware = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX),
-       .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
-       .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
-                 SNDRV_PCM_RATE_8000_192000),
-       .rate_min = 0,
-       .rate_max = 1562500,
-       .channels_min = 2,
-       .channels_max = 8,
        .buffer_bytes_max = 0x7ffffff0,
        .period_bytes_min = 16,
        .period_bytes_max = 0xfffff0,
index 37459dfd168d3d16362330cdf0ba047d29d41e97..27930fc432dcfe4b750ba3a9f2ff70bf50d78f1e 100644 (file)
@@ -1,13 +1,22 @@
 config SND_SOC_SAMSUNG
        tristate "ASoC support for Samsung"
        depends on PLAT_SAMSUNG
-       select S3C64XX_DMA if ARCH_S3C64XX
-       select S3C24XX_DMA if ARCH_S3C24XX
+       select S3C2410_DMA if ARCH_S3C24XX
+       select S3C64XX_PL080 if ARCH_S3C64XX
+       select SND_S3C_DMA if !ARCH_S3C24XX
+       select SND_S3C_DMA_LEGACY if ARCH_S3C24XX
+       select SND_SOC_GENERIC_DMAENGINE_PCM if !ARCH_S3C24XX
        help
          Say Y or M if you want to add support for codecs attached to
          the Samsung SoCs' Audio interfaces. You will also need to
          select the audio interfaces to support below.
 
+config SND_S3C_DMA
+       tristate
+
+config SND_S3C_DMA_LEGACY
+       tristate
+
 config SND_S3C24XX_I2S
        tristate
        select S3C2410_DMA
index 709f6059ad67da928245a2faf3df900552e82d44..86715d8efee66ca459adc99c2d68ca34907b1c45 100644 (file)
@@ -1,5 +1,6 @@
 # S3c24XX Platform Support
-snd-soc-s3c24xx-objs := dma.o
+snd-soc-s3c-dma-objs := dmaengine.o
+snd-soc-s3c-dma-legacy-objs := dma.o
 snd-soc-idma-objs := idma.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
@@ -9,7 +10,8 @@ snd-soc-samsung-spdif-objs := spdif.o
 snd-soc-pcm-objs := pcm.o
 snd-soc-i2s-objs := i2s.o
 
-obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o
+obj-$(CONFIG_SND_S3C_DMA) += snd-soc-s3c-dma.o
+obj-$(CONFIG_SND_S3C_DMA_LEGACY) += snd-soc-s3c-dma-legacy.o
 obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
 obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
 obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
index 350ba23a9893484edb3d0585518b7048d568e875..4a88e36c82ec1c827d7cd8658e0223991a3b621f 100644 (file)
@@ -221,24 +221,6 @@ static struct snd_ac97_bus_ops s3c_ac97_ops = {
        .reset      = s3c_ac97_cold_reset,
 };
 
-static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *params,
-                                 struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct s3c_dma_params *dma_data;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = &s3c_ac97_pcm_out;
-       else
-               dma_data = &s3c_ac97_pcm_in;
-
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
-       return 0;
-}
-
 static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
                                struct snd_soc_dai *dai)
 {
@@ -279,21 +261,6 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
-                                     struct snd_pcm_hw_params *params,
-                                     struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return -ENODEV;
-       else
-               snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
-
-       return 0;
-}
-
 static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
                                    int cmd, struct snd_soc_dai *dai)
 {
@@ -329,15 +296,27 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops s3c_ac97_dai_ops = {
-       .hw_params      = s3c_ac97_hw_params,
        .trigger        = s3c_ac97_trigger,
 };
 
 static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
-       .hw_params      = s3c_ac97_hw_mic_params,
        .trigger        = s3c_ac97_mic_trigger,
 };
 
+static int s3c_ac97_dai_probe(struct snd_soc_dai *dai)
+{
+       samsung_asoc_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
+
+       return 0;
+}
+
+static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
+{
+       samsung_asoc_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver s3c_ac97_dai[] = {
        [S3C_AC97_DAI_PCM] = {
                .name = "samsung-ac97",
@@ -354,6 +333,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
                        .channels_max = 2,
                        .rates = SNDRV_PCM_RATE_8000_48000,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .probe = s3c_ac97_dai_probe,
                .ops = &s3c_ac97_dai_ops,
        },
        [S3C_AC97_DAI_MIC] = {
@@ -365,6 +345,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
                        .channels_max = 1,
                        .rates = SNDRV_PCM_RATE_8000_48000,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .probe = s3c_ac97_mic_dai_probe,
                .ops = &s3c_ac97_mic_dai_ops,
        },
 };
index fe2748b494d4cd38c6db6ae4409d38f56819ff3f..dc09b71b7d9f766398a94592a1657f7cdbe5667a 100644 (file)
@@ -35,12 +35,6 @@ static const struct snd_pcm_hardware dma_hardware = {
                                    SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                    SNDRV_PCM_INFO_MMAP |
                                    SNDRV_PCM_INFO_MMAP_VALID,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                   SNDRV_PCM_FMTBIT_U16_LE |
-                                   SNDRV_PCM_FMTBIT_U8 |
-                                   SNDRV_PCM_FMTBIT_S8,
-       .channels_min           = 2,
-       .channels_max           = 2,
        .buffer_bytes_max       = 128*1024,
        .period_bytes_min       = PAGE_SIZE,
        .period_bytes_max       = PAGE_SIZE*2,
@@ -441,6 +435,14 @@ static struct snd_soc_platform_driver samsung_asoc_platform = {
        .pcm_free       = dma_free_dma_buffers,
 };
 
+void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
+                               struct s3c_dma_params *playback,
+                               struct s3c_dma_params *capture)
+{
+       snd_soc_dai_init_dma_data(dai, playback, capture);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
+
 int samsung_asoc_dma_platform_register(struct device *dev)
 {
        return snd_soc_register_platform(dev, &samsung_asoc_platform);
index 0e86315a3eaf11859d32ab78b1327ce1a60e39c4..225e5378014eca4395d4481c77ddf2c1632b31a3 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _S3C_AUDIO_H
 #define _S3C_AUDIO_H
 
+#include <sound/dmaengine_pcm.h>
+
 struct s3c_dma_params {
        struct s3c2410_dma_client *client;      /* stream identifier */
        int channel;                            /* Channel ID */
@@ -20,8 +22,12 @@ struct s3c_dma_params {
        unsigned ch;
        struct samsung_dma_ops *ops;
        char *ch_name;
+       struct snd_dmaengine_dai_dma_data dma_data;
 };
 
+void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
+                               struct s3c_dma_params *playback,
+                               struct s3c_dma_params *capture);
 int samsung_asoc_dma_platform_register(struct device *dev);
 void samsung_asoc_dma_platform_unregister(struct device *dev);
 
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
new file mode 100644 (file)
index 0000000..3be479d
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * dmaengine.c - Samsung dmaengine wrapper
+ *
+ * Author: Mark Brown <broonie@linaro.org>
+ * Copyright 2013 Linaro
+ *
+ * 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/module.h>
+#include <linux/amba/pl08x.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "dma.h"
+
+#ifdef CONFIG_ARCH_S3C64XX
+#define filter_fn pl08x_filter_id
+#else
+#define filter_fn NULL
+#endif
+
+static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
+       .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+       .compat_filter_fn = filter_fn,
+};
+
+void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
+                               struct s3c_dma_params *playback,
+                               struct s3c_dma_params *capture)
+{
+       struct snd_dmaengine_dai_dma_data *playback_data = NULL;
+       struct snd_dmaengine_dai_dma_data *capture_data = NULL;
+
+       if (playback) {
+               playback_data = &playback->dma_data;
+               playback_data->filter_data = (void *)playback->channel;
+               playback_data->chan_name = playback->ch_name;
+               playback_data->addr = playback->dma_addr;
+               playback_data->addr_width = playback->dma_size;
+       }
+       if (capture) {
+               capture_data = &capture->dma_data;
+               capture_data->filter_data = (void *)capture->channel;
+               capture_data->chan_name = capture->ch_name;
+               capture_data->addr = capture->dma_addr;
+               capture_data->addr_width = capture->dma_size;
+       }
+
+       snd_soc_dai_init_dma_data(dai, playback_data, capture_data);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
+
+int samsung_asoc_dma_platform_register(struct device *dev)
+{
+       return snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config,
+                                         SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
+                                         SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+                                         SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
+
+void samsung_asoc_dma_platform_unregister(struct device *dev)
+{
+       return snd_dmaengine_pcm_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
+
+MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_DESCRIPTION("Samsung dmaengine ASoC driver");
+MODULE_LICENSE("GPL");
index a5cbdb4f1655d8213a778159c34a0fb0321b2b77..92f64363427d44b741f2293fa84982c748a72d82 100644 (file)
@@ -702,6 +702,8 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        }
        writel(mod, i2s->addr + I2SMOD);
 
+       samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
+
        i2s->frmclk = params_rate(params);
 
        return 0;
@@ -946,8 +948,11 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
        struct i2s_dai *i2s = to_info(dai);
        struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
 
-       if (other && other->clk) /* If this is probe on secondary */
+       if (other && other->clk) { /* If this is probe on secondary */
+               samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
+                                          NULL);
                goto probe_exit;
+       }
 
        i2s->addr = ioremap(i2s->base, 0x100);
        if (i2s->addr == NULL) {
@@ -963,7 +968,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
        }
        clk_prepare_enable(i2s->clk);
 
-       snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
+       samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
 
        if (other) {
                other->addr = i2s->addr;
index e4f318fc2f82bb048f5047a6773f1a2c8be40902..3d5cf1530b6f754c4ff03c476777e2a61c3d45a1 100644 (file)
@@ -35,14 +35,6 @@ static const struct snd_pcm_hardware idma_hardware = {
                    SNDRV_PCM_INFO_MMAP_VALID |
                    SNDRV_PCM_INFO_PAUSE |
                    SNDRV_PCM_INFO_RESUME,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE |
-                   SNDRV_PCM_FMTBIT_U16_LE |
-                   SNDRV_PCM_FMTBIT_S24_LE |
-                   SNDRV_PCM_FMTBIT_U24_LE |
-                   SNDRV_PCM_FMTBIT_U8 |
-                   SNDRV_PCM_FMTBIT_S8,
-       .channels_min = 2,
-       .channels_max = 2,
        .buffer_bytes_max = MAX_IDMA_BUFFER,
        .period_bytes_min = 128,
        .period_bytes_max = MAX_IDMA_PERIOD,
index e54256fc4b2c6d35faa47f8c3a1d42ddb3f5c74e..6a5e4bf6ac96efaa1b3b3dba063390165eee724e 100644 (file)
@@ -275,7 +275,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-       struct s3c_dma_params *dma_data;
        void __iomem *regs = pcm->regs;
        struct clk *clk;
        int sclk_div, sync_div;
@@ -284,13 +283,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
 
        dev_dbg(pcm->dev, "Entered %s\n", __func__);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = pcm->dma_playback;
-       else
-               dma_data = pcm->dma_capture;
-
-       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
        /* Strictly check for sample size */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -461,10 +453,20 @@ static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
        .set_fmt        = s3c_pcm_set_fmt,
 };
 
+static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
+{
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, pcm->dma_playback, pcm->dma_capture);
+
+       return 0;
+}
+
 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
 
 #define S3C_PCM_DAI_DECLARE                    \
        .symmetric_rates = 1,                                   \
+       .probe = s3c_pcm_dai_probe,                             \
        .ops = &s3c_pcm_dai_ops,                                \
        .playback = {                                           \
                .channels_min   = 2,                            \
index c3878f7acb83fb33ac39d370ecd384e42bc4a473..a71be45bbffc87b6bb52c896ac29a13360494c80 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-ac97.h
- *
+/*
  * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
  *             http://www.simtec.co.uk/products/SWLINUX/
  *
@@ -10,8 +9,8 @@
  * S3C2440 AC97 Controller
 */
 
-#ifndef __ASM_ARCH_REGS_AC97_H
-#define __ASM_ARCH_REGS_AC97_H __FILE__
+#ifndef __SAMSUNG_REGS_AC97_H__
+#define __SAMSUNG_REGS_AC97_H__
 
 #define S3C_AC97_GLBCTRL                               (0x00)
 
@@ -64,4 +63,4 @@
 #define S3C_AC97_PCM_DATA                              (0x18)
 #define S3C_AC97_MIC_DATA                              (0x1C)
 
-#endif /* __ASM_ARCH_REGS_AC97_H */
+#endif /* __SAMSUNG_REGS_AC97_H__ */
index a18d35e7a735f156de8a8ee63ab9a546fc526220..dc6cbbe9c4f0eae35ef7e7074047e068b0b50f5f 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/plat-samsung/include/plat/regs-iis.h
- *
+/*
  * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
  *                   http://www.simtec.co.uk/products/SWLINUX/
  *
@@ -10,8 +9,8 @@
  * S3C2410 IIS register definition
 */
 
-#ifndef __ASM_ARCH_REGS_IIS_H
-#define __ASM_ARCH_REGS_IIS_H
+#ifndef __SAMSUNG_REGS_IIS_H__
+#define __SAMSUNG_REGS_IIS_H__
 
 #define S3C2410_IISCON                 (0x00)
 
@@ -67,4 +66,4 @@
 
 #define S3C2410_IISFIFO                        (0x10)
 
-#endif /* __ASM_ARCH_REGS_IIS_H */
+#endif /* __SAMSUNG_REGS_IIS_H__ */
index b33ca7cd085bf4b766dee1900a4101beffc9fa72..6101055aae1dc6fe4e0f7851bd17dde646624f79 100644 (file)
@@ -232,9 +232,9 @@ struct fsi_stream {
         * these are for DMAEngine
         */
        struct dma_chan         *chan;
-       struct sh_dmae_slave    slave; /* see fsi_handler_init() */
        struct work_struct      work;
        dma_addr_t              dma;
+       int                     dma_id;
        int                     loop_cnt;
        int                     additional_pos;
 };
@@ -1410,15 +1410,6 @@ static void fsi_dma_do_work(struct work_struct *work)
        }
 }
 
-static bool fsi_dma_filter(struct dma_chan *chan, void *param)
-{
-       struct sh_dmae_slave *slave = param;
-
-       chan->private = slave;
-
-       return true;
-}
-
 static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
 {
        schedule_work(&io->work);
@@ -1446,15 +1437,34 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
 {
        dma_cap_mask_t mask;
+       int is_play = fsi_stream_is_play(fsi, io);
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
+       io->chan = dma_request_slave_channel_compat(mask,
+                               shdma_chan_filter, (void *)io->dma_id,
+                               dev, is_play ? "tx" : "rx");
+       if (io->chan) {
+               struct dma_slave_config cfg;
+               int ret;
+
+               cfg.slave_id    = io->dma_id;
+               cfg.dst_addr    = 0; /* use default addr */
+               cfg.src_addr    = 0; /* use default addr */
+               cfg.direction   = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+
+               ret = dmaengine_slave_config(io->chan, &cfg);
+               if (ret < 0) {
+                       dma_release_channel(io->chan);
+                       io->chan = NULL;
+               }
+       }
+
        if (!io->chan) {
 
                /* switch to PIO handler */
-               if (fsi_stream_is_play(fsi, io))
+               if (is_play)
                        fsi->playback.handler   = &fsi_pio_push_handler;
                else
                        fsi->capture.handler    = &fsi_pio_pop_handler;
@@ -1960,7 +1970,7 @@ static void fsi_handler_init(struct fsi_priv *fsi,
        fsi->capture.priv       = fsi;
 
        if (info->tx_id) {
-               fsi->playback.slave.shdma_slave.slave_id = info->tx_id;
+               fsi->playback.dma_id  = info->tx_id;
                fsi->playback.handler = &fsi_dma_push_handler;
        }
 }
index 9430097979a580c972a989738bdeb9ada3557e5e..a53235c4d1b0dcc971d81ed04884e1636b80932a 100644 (file)
@@ -19,8 +19,8 @@
 struct rsnd_adg {
        struct clk *clk[CLKMAX];
 
-       int rate_of_441khz_div_6;
-       int rate_of_48khz_div_6;
+       int rbga_rate_for_441khz_div_6; /* RBGA */
+       int rbgb_rate_for_48khz_div_6;  /* RBGB */
        u32 ckr;
 };
 
@@ -30,41 +30,114 @@ struct rsnd_adg {
             i++, (pos) = adg->clk[i])
 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
 
-static enum rsnd_reg rsnd_adg_ssi_reg_get(int id)
+static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
+                                        struct rsnd_mod *mod,
+                                        unsigned int src_rate,
+                                        unsigned int dst_rate)
 {
-       enum rsnd_reg reg;
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int idx, sel, div, shift;
+       u32 mask, val;
+       int id = rsnd_mod_id(mod);
+       unsigned int sel_rate [] = {
+               clk_get_rate(adg->clk[CLKA]),   /* 000: CLKA */
+               clk_get_rate(adg->clk[CLKB]),   /* 001: CLKB */
+               clk_get_rate(adg->clk[CLKC]),   /* 010: CLKC */
+               0,                              /* 011: MLBCLK (not used) */
+               adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */
+               adg->rbgb_rate_for_48khz_div_6, /* 101: RBGB */
+       };
+
+       /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
+       for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
+               for (div  = 128,        idx = 0;
+                    div <= 2048;
+                    div *= 2,          idx++) {
+                       if (src_rate == sel_rate[sel] / div) {
+                               val = (idx << 4) | sel;
+                               goto find_rate;
+                       }
+               }
+       }
+       dev_err(dev, "can't find convert src clk\n");
+       return -EINVAL;
+
+find_rate:
+       shift   = (id % 4) * 8;
+       mask    = 0xFF << shift;
+       val     = val << shift;
+
+       dev_dbg(dev, "adg convert src clk = %02x\n", val);
+
+       switch (id / 4) {
+       case 0:
+               rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val);
+               break;
+       case 1:
+               rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val);
+               break;
+       case 2:
+               rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val);
+               break;
+       }
+
+       /*
+        * Gen1 doesn't need dst_rate settings,
+        * since it uses SSI WS pin.
+        * see also rsnd_src_set_route_if_gen1()
+        */
+
+       return 0;
+}
+
+int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
+                            struct rsnd_mod *mod,
+                            unsigned int src_rate,
+                            unsigned int dst_rate)
+{
+       if (rsnd_is_gen1(priv))
+               return rsnd_adg_set_convert_clk_gen1(priv, mod,
+                                                    src_rate, dst_rate);
+
+       return -EINVAL;
+}
+
+static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
+{
+       int id = rsnd_mod_id(mod);
+       int shift = (id % 4) * 8;
+       u32 mask = 0xFF << shift;
+
+       val = val << shift;
 
        /*
         * SSI 8 is not connected to ADG.
         * it works with SSI 7
         */
        if (id == 8)
-               return RSND_REG_MAX;
-
-       if (0 <= id && id <= 3)
-               reg = RSND_REG_AUDIO_CLK_SEL0;
-       else if (4 <= id && id <= 7)
-               reg = RSND_REG_AUDIO_CLK_SEL1;
-       else
-               reg = RSND_REG_AUDIO_CLK_SEL2;
-
-       return reg;
+               return;
+
+       switch (id / 4) {
+       case 0:
+               rsnd_mod_bset(mod, AUDIO_CLK_SEL0, mask, val);
+               break;
+       case 1:
+               rsnd_mod_bset(mod, AUDIO_CLK_SEL1, mask, val);
+               break;
+       case 2:
+               rsnd_mod_bset(mod, AUDIO_CLK_SEL2, mask, val);
+               break;
+       }
 }
 
 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       enum rsnd_reg reg;
-       int id;
-
        /*
         * "mod" = "ssi" here.
         * we can get "ssi id" from mod
         */
-       id  = rsnd_mod_id(mod);
-       reg = rsnd_adg_ssi_reg_get(id);
-
-       rsnd_write(priv, mod, reg, 0);
+       rsnd_adg_set_ssi_clk(mod, 0);
 
        return 0;
 }
@@ -75,8 +148,7 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct clk *clk;
-       enum rsnd_reg reg;
-       int id, shift, i;
+       int i;
        u32 data;
        int sel_table[] = {
                [CLKA] = 0x1,
@@ -102,12 +174,12 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
        /*
         * find 1/6 clock from BRGA/BRGB
         */
-       if (rate == adg->rate_of_441khz_div_6) {
+       if (rate == adg->rbga_rate_for_441khz_div_6) {
                data = 0x10;
                goto found_clock;
        }
 
-       if (rate == adg->rate_of_48khz_div_6) {
+       if (rate == adg->rbgb_rate_for_48khz_div_6) {
                data = 0x20;
                goto found_clock;
        }
@@ -125,19 +197,10 @@ found_clock:
         * This "mod" = "ssi" here.
         * we can get "ssi id" from mod
         */
-       id  = rsnd_mod_id(mod);
-       reg = rsnd_adg_ssi_reg_get(id);
-
-       dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate);
-
-       /*
-        * Enable SSIx clock
-        */
-       shift = (id % 4) * 8;
+       rsnd_adg_set_ssi_clk(mod, data);
 
-       rsnd_bset(priv, mod, reg,
-                  0xFF << shift,
-                  data << shift);
+       dev_dbg(dev, "ADG: ssi%d selects clk%d = %d",
+               rsnd_mod_id(mod), i, rate);
 
        return 0;
 }
@@ -166,8 +229,8 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
         *      rsnd_adg_ssi_clk_try_start()
         */
        ckr = 0;
-       adg->rate_of_441khz_div_6 = 0;
-       adg->rate_of_48khz_div_6  = 0;
+       adg->rbga_rate_for_441khz_div_6 = 0;
+       adg->rbgb_rate_for_48khz_div_6  = 0;
        for_each_rsnd_clk(clk, adg, i) {
                rate = clk_get_rate(clk);
 
@@ -175,14 +238,14 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
                        continue;
 
                /* RBGA */
-               if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) {
-                       adg->rate_of_441khz_div_6 = rate / 6;
+               if (!adg->rbga_rate_for_441khz_div_6 && (0 == rate % 44100)) {
+                       adg->rbga_rate_for_441khz_div_6 = rate / 6;
                        ckr |= brg_table[i] << 20;
                }
 
                /* RBGB */
-               if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) {
-                       adg->rate_of_48khz_div_6 = rate / 6;
+               if (!adg->rbgb_rate_for_48khz_div_6 && (0 == rate % 48000)) {
+                       adg->rbgb_rate_for_48khz_div_6 = rate / 6;
                        ckr |= brg_table[i] << 16;
                }
        }
index 61212ee97c28269a0cd245e424636c4f38efc4c7..add088bd4b2aa7163b98f5faab7bd84b52a77fff 100644 (file)
  */
 #include "rsnd.h"
 
-struct rsnd_gen_ops {
-       int (*probe)(struct platform_device *pdev,
-                    struct rcar_snd_info *info,
-                    struct rsnd_priv *priv);
-       void (*remove)(struct platform_device *pdev,
-                     struct rsnd_priv *priv);
-       int (*path_init)(struct rsnd_priv *priv,
-                        struct rsnd_dai *rdai,
-                        struct rsnd_dai_stream *io);
-       int (*path_exit)(struct rsnd_priv *priv,
-                        struct rsnd_dai *rdai,
-                        struct rsnd_dai_stream *io);
-};
-
 struct rsnd_gen {
        void __iomem *base[RSND_BASE_MAX];
 
@@ -86,12 +72,28 @@ static struct regmap_bus rsnd_regmap_bus = {
        .val_format_endian_default      = REGMAP_ENDIAN_NATIVE,
 };
 
+static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
+                                 struct rsnd_gen *gen, enum rsnd_reg reg)
+{
+       if (!gen->regs[reg]) {
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_err(dev, "unsupported register access %x\n", reg);
+               return 0;
+       }
+
+       return 1;
+}
+
 u32 rsnd_read(struct rsnd_priv *priv,
              struct rsnd_mod *mod, enum rsnd_reg reg)
 {
        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
        u32 val;
 
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return 0;
+
        regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
 
        return val;
@@ -103,6 +105,9 @@ void rsnd_write(struct rsnd_priv *priv,
 {
        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return;
+
        regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
 }
 
@@ -111,21 +116,48 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
 {
        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return;
+
        regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
                                  mask, data);
 }
 
-/*
- *             Gen2
- *             will be filled in the future
- */
+static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
+                               struct rsnd_gen  *gen,
+                               struct reg_field *regf)
+{
+       int i;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct regmap_config regc;
 
-/*
- *             Gen1
- */
-static int rsnd_gen1_path_init(struct rsnd_priv *priv,
-                              struct rsnd_dai *rdai,
-                              struct rsnd_dai_stream *io)
+       memset(&regc, 0, sizeof(regc));
+       regc.reg_bits = 32;
+       regc.val_bits = 32;
+
+       gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, &regc);
+       if (IS_ERR(gen->regmap)) {
+               dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap));
+               return PTR_ERR(gen->regmap);
+       }
+
+       for (i = 0; i < RSND_REG_MAX; i++) {
+               gen->regs[i] = NULL;
+               if (!regf[i].reg)
+                       continue;
+
+               gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]);
+               if (IS_ERR(gen->regs[i]))
+                       return PTR_ERR(gen->regs[i]);
+
+       }
+
+       return 0;
+}
+
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io)
 {
        struct rsnd_mod *mod;
        int ret;
@@ -163,9 +195,9 @@ static int rsnd_gen1_path_init(struct rsnd_priv *priv,
        return ret;
 }
 
-static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
-                              struct rsnd_dai *rdai,
-                              struct rsnd_dai_stream *io)
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io)
 {
        struct rsnd_mod *mod, *n;
        int ret = 0;
@@ -179,6 +211,94 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
        return ret;
 }
 
+/*
+ *             Gen2
+ */
+
+/* single address mapping */
+#define RSND_GEN2_S_REG(gen, reg, id, offset)                          \
+       RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10)
+
+/* multi address mapping */
+#define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset)              \
+       RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10)
+
+static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
+{
+       struct reg_field regf[RSND_REG_MAX] = {
+               RSND_GEN2_S_REG(gen, SSIU,      SSI_MODE0,      0x800),
+               RSND_GEN2_S_REG(gen, SSIU,      SSI_MODE1,      0x804),
+               /* FIXME: it needs SSI_MODE2/3 in the future */
+               RSND_GEN2_M_REG(gen, SSIU,      INT_ENABLE,     0x18,   0x80),
+
+               RSND_GEN2_S_REG(gen, ADG,       BRRA,           0x00),
+               RSND_GEN2_S_REG(gen, ADG,       BRRB,           0x04),
+               RSND_GEN2_S_REG(gen, ADG,       SSICKR,         0x08),
+               RSND_GEN2_S_REG(gen, ADG,       AUDIO_CLK_SEL0, 0x0c),
+               RSND_GEN2_S_REG(gen, ADG,       AUDIO_CLK_SEL1, 0x10),
+               RSND_GEN2_S_REG(gen, ADG,       AUDIO_CLK_SEL2, 0x14),
+
+               RSND_GEN2_M_REG(gen, SSI,       SSICR,          0x00,   0x40),
+               RSND_GEN2_M_REG(gen, SSI,       SSISR,          0x04,   0x40),
+               RSND_GEN2_M_REG(gen, SSI,       SSITDR,         0x08,   0x40),
+               RSND_GEN2_M_REG(gen, SSI,       SSIRDR,         0x0c,   0x40),
+               RSND_GEN2_M_REG(gen, SSI,       SSIWSR,         0x20,   0x40),
+       };
+
+       return rsnd_gen_regmap_init(priv, gen, regf);
+}
+
+static int rsnd_gen2_probe(struct platform_device *pdev,
+                          struct rcar_snd_info *info,
+                          struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       struct resource *scu_res;
+       struct resource *adg_res;
+       struct resource *ssiu_res;
+       struct resource *ssi_res;
+       int ret;
+
+       /*
+        * map address
+        */
+       scu_res  = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU);
+       adg_res  = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG);
+       ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU);
+       ssi_res  = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI);
+
+       gen->base[RSND_GEN2_SCU]  = devm_ioremap_resource(dev, scu_res);
+       gen->base[RSND_GEN2_ADG]  = devm_ioremap_resource(dev, adg_res);
+       gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res);
+       gen->base[RSND_GEN2_SSI]  = devm_ioremap_resource(dev, ssi_res);
+       if (IS_ERR(gen->base[RSND_GEN2_SCU])  ||
+           IS_ERR(gen->base[RSND_GEN2_ADG])  ||
+           IS_ERR(gen->base[RSND_GEN2_SSIU]) ||
+           IS_ERR(gen->base[RSND_GEN2_SSI]))
+               return -ENODEV;
+
+       ret = rsnd_gen2_regmap_init(priv, gen);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(dev, "Gen2 device probed\n");
+       dev_dbg(dev, "SRU  : %08x => %p\n", scu_res->start,
+               gen->base[RSND_GEN2_SCU]);
+       dev_dbg(dev, "ADG  : %08x => %p\n", adg_res->start,
+               gen->base[RSND_GEN2_ADG]);
+       dev_dbg(dev, "SSIU : %08x => %p\n", ssiu_res->start,
+               gen->base[RSND_GEN2_SSIU]);
+       dev_dbg(dev, "SSI  : %08x => %p\n", ssi_res->start,
+               gen->base[RSND_GEN2_SSI]);
+
+       return 0;
+}
+
+/*
+ *             Gen1
+ */
+
 /* single address mapping */
 #define RSND_GEN1_S_REG(gen, reg, id, offset)  \
        RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9)
@@ -189,19 +309,23 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
 
 static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
 {
-       int i;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct regmap_config regc;
        struct reg_field regf[RSND_REG_MAX] = {
                RSND_GEN1_S_REG(gen, SRU,       SRC_ROUTE_SEL,  0x00),
                RSND_GEN1_S_REG(gen, SRU,       SRC_TMG_SEL0,   0x08),
                RSND_GEN1_S_REG(gen, SRU,       SRC_TMG_SEL1,   0x0c),
                RSND_GEN1_S_REG(gen, SRU,       SRC_TMG_SEL2,   0x10),
-               RSND_GEN1_S_REG(gen, SRU,       SRC_CTRL,       0xc0),
+               RSND_GEN1_S_REG(gen, SRU,       SRC_ROUTE_CTRL, 0xc0),
                RSND_GEN1_S_REG(gen, SRU,       SSI_MODE0,      0xD0),
                RSND_GEN1_S_REG(gen, SRU,       SSI_MODE1,      0xD4),
                RSND_GEN1_M_REG(gen, SRU,       BUSIF_MODE,     0x20,   0x4),
-               RSND_GEN1_M_REG(gen, SRU,       BUSIF_ADINR,    0x214,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_ROUTE_MODE0,0x50,   0x8),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_SWRSR,      0x200,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_SRCIR,      0x204,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_ADINR,      0x214,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_IFSCR,      0x21c,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_IFSVR,      0x220,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_SRCCR,      0x224,  0x40),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_MNFSR,      0x228,  0x40),
 
                RSND_GEN1_S_REG(gen, ADG,       BRRA,           0x00),
                RSND_GEN1_S_REG(gen, ADG,       BRRB,           0x04),
@@ -219,24 +343,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
                RSND_GEN1_M_REG(gen, SSI,       SSIWSR,         0x20,   0x40),
        };
 
-       memset(&regc, 0, sizeof(regc));
-       regc.reg_bits = 32;
-       regc.val_bits = 32;
-
-       gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, &regc);
-       if (IS_ERR(gen->regmap)) {
-               dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap));
-               return PTR_ERR(gen->regmap);
-       }
-
-       for (i = 0; i < RSND_REG_MAX; i++) {
-               gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]);
-               if (IS_ERR(gen->regs[i]))
-                       return PTR_ERR(gen->regs[i]);
-
-       }
-
-       return 0;
+       return rsnd_gen_regmap_init(priv, gen, regf);
 }
 
 static int rsnd_gen1_probe(struct platform_device *pdev,
@@ -281,45 +388,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
 
 }
 
-static void rsnd_gen1_remove(struct platform_device *pdev,
-                            struct rsnd_priv *priv)
-{
-}
-
-static struct rsnd_gen_ops rsnd_gen1_ops = {
-       .probe          = rsnd_gen1_probe,
-       .remove         = rsnd_gen1_remove,
-       .path_init      = rsnd_gen1_path_init,
-       .path_exit      = rsnd_gen1_path_exit,
-};
-
 /*
  *             Gen
  */
-int rsnd_gen_path_init(struct rsnd_priv *priv,
-                      struct rsnd_dai *rdai,
-                      struct rsnd_dai_stream *io)
-{
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       return gen->ops->path_init(priv, rdai, io);
-}
-
-int rsnd_gen_path_exit(struct rsnd_priv *priv,
-                      struct rsnd_dai *rdai,
-                      struct rsnd_dai_stream *io)
-{
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       return gen->ops->path_exit(priv, rdai, io);
-}
-
 int rsnd_gen_probe(struct platform_device *pdev,
                   struct rcar_snd_info *info,
                   struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_gen *gen;
+       int ret;
 
        gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
        if (!gen) {
@@ -327,23 +405,21 @@ int rsnd_gen_probe(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       priv->gen = gen;
+
+       ret = -ENODEV;
        if (rsnd_is_gen1(priv))
-               gen->ops = &rsnd_gen1_ops;
+               ret = rsnd_gen1_probe(pdev, info, priv);
+       else if (rsnd_is_gen2(priv))
+               ret = rsnd_gen2_probe(pdev, info, priv);
 
-       if (!gen->ops) {
+       if (ret < 0)
                dev_err(dev, "unknown generation R-Car sound device\n");
-               return -ENODEV;
-       }
-
-       priv->gen = gen;
 
-       return gen->ops->probe(pdev, info, priv);
+       return ret;
 }
 
 void rsnd_gen_remove(struct platform_device *pdev,
                     struct rsnd_priv *priv)
 {
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       gen->ops->remove(pdev, priv);
 }
index 9e463e50e7e62b81fabeaeecf39f50de4206eeaf..4ca66cd899c87415e263219c400fea5ce4e51df0 100644 (file)
  * see gen1/gen2 for detail
  */
 enum rsnd_reg {
-       /* SRU/SCU */
-       RSND_REG_SRC_ROUTE_SEL,
-       RSND_REG_SRC_TMG_SEL0,
-       RSND_REG_SRC_TMG_SEL1,
-       RSND_REG_SRC_TMG_SEL2,
-       RSND_REG_SRC_CTRL,
+       /* SRU/SCU/SSIU */
+       RSND_REG_SRC_ROUTE_SEL,         /* for Gen1 */
+       RSND_REG_SRC_TMG_SEL0,          /* for Gen1 */
+       RSND_REG_SRC_TMG_SEL1,          /* for Gen1 */
+       RSND_REG_SRC_TMG_SEL2,          /* for Gen1 */
+       RSND_REG_SRC_ROUTE_CTRL,        /* for Gen1 */
        RSND_REG_SSI_MODE0,
        RSND_REG_SSI_MODE1,
        RSND_REG_BUSIF_MODE,
-       RSND_REG_BUSIF_ADINR,
+       RSND_REG_INT_ENABLE,            /* for Gen2 */
+       RSND_REG_SRC_ROUTE_MODE0,
+       RSND_REG_SRC_SWRSR,
+       RSND_REG_SRC_SRCIR,
+       RSND_REG_SRC_ADINR,
+       RSND_REG_SRC_IFSCR,
+       RSND_REG_SRC_IFSVR,
+       RSND_REG_SRC_SRCCR,
+       RSND_REG_SRC_MNFSR,
 
        /* ADG */
        RSND_REG_BRRA,
@@ -49,9 +57,9 @@ enum rsnd_reg {
        RSND_REG_AUDIO_CLK_SEL0,
        RSND_REG_AUDIO_CLK_SEL1,
        RSND_REG_AUDIO_CLK_SEL2,
-       RSND_REG_AUDIO_CLK_SEL3,
-       RSND_REG_AUDIO_CLK_SEL4,
-       RSND_REG_AUDIO_CLK_SEL5,
+       RSND_REG_AUDIO_CLK_SEL3,        /* for Gen1 */
+       RSND_REG_AUDIO_CLK_SEL4,        /* for Gen1 */
+       RSND_REG_AUDIO_CLK_SEL5,        /* for Gen1 */
 
        /* SSI */
        RSND_REG_SSICR,
@@ -174,11 +182,11 @@ struct rsnd_dai {
        struct rsnd_dai_stream playback;
        struct rsnd_dai_stream capture;
 
-       int clk_master:1;
-       int bit_clk_inv:1;
-       int frm_clk_inv:1;
-       int sys_delay:1;
-       int data_alignment:1;
+       unsigned int clk_master:1;
+       unsigned int bit_clk_inv:1;
+       unsigned int frm_clk_inv:1;
+       unsigned int sys_delay:1;
+       unsigned int data_alignment:1;
 };
 
 #define rsnd_dai_nr(priv) ((priv)->dai_nr)
@@ -229,6 +237,10 @@ int rsnd_adg_probe(struct platform_device *pdev,
                   struct rsnd_priv *priv);
 void rsnd_adg_remove(struct platform_device *pdev,
                   struct rsnd_priv *priv);
+int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
+                            struct rsnd_mod *mod,
+                            unsigned int src_rate,
+                            unsigned int dst_rate);
 
 /*
  *     R-Car sound priv
@@ -282,6 +294,10 @@ void rsnd_scu_remove(struct platform_device *pdev,
                     struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
 bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod);
+unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
+                                  struct rsnd_mod *ssi_mod,
+                                  struct snd_pcm_runtime *runtime);
+
 #define rsnd_scu_nr(priv) ((priv)->scu_nr)
 
 /*
index fa8fa15860b9bda89dc5d3af73c85a5c4f076f15..9bb08bb1d4553ba43cdc135b04c7c1b725a1af68 100644 (file)
 struct rsnd_scu {
        struct rsnd_scu_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
+       struct clk *clk;
 };
 
 #define rsnd_scu_mode_flags(p) ((p)->info->flags)
+#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate)
+
+#define RSND_SCU_NAME_SIZE 16
 
 /*
  * ADINR
@@ -26,6 +30,15 @@ struct rsnd_scu {
 #define OTBL_18                (6 << 16)
 #define OTBL_16                (8 << 16)
 
+/*
+ *             image of SRC (Sampling Rate Converter)
+ *
+ * 96kHz   <-> +-----+ 48kHz   +-----+  48kHz  +-------+
+ * 48kHz   <-> | SRC | <------>        | SSI | <-----> | codec |
+ * 44.1kHz <-> +-----+         +-----+         +-------+
+ * ...
+ *
+ */
 
 #define rsnd_mod_to_scu(_mod)  \
        container_of((_mod), struct rsnd_scu, mod)
@@ -36,7 +49,8 @@ struct rsnd_scu {
                     ((pos) = (struct rsnd_scu *)(priv)->scu + i);      \
             i++)
 
-static int rsnd_scu_set_route(struct rsnd_priv *priv,
+/* Gen1 only */
+static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv,
                              struct rsnd_mod *mod,
                              struct rsnd_dai *rdai,
                              struct rsnd_dai_stream *io)
@@ -55,7 +69,7 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
                { 0x3, 28, }, /* 7 */
                { 0x3, 30, }, /* 8 */
        };
-
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
        u32 mask;
        u32 val;
        int shift;
@@ -85,9 +99,18 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
         */
        shift   = (id % 4) * 8;
        mask    = 0x1F << shift;
-       if (8 == id) /* SRU8 is very special */
+
+       /*
+        * ADG is used as source clock if SRC was used,
+        * then, SSI WS is used as destination clock.
+        * SSI WS is used as source clock if SRC is not used
+        * (when playback, source/destination become reverse when capture)
+        */
+       if (rsnd_scu_convert_rate(scu)) /* use ADG */
+               val = 0;
+       else if (8 == id)               /* use SSI WS, but SRU8 is special */
                val = id << shift;
-       else
+       else                            /* use SSI WS */
                val = (id + 1) << shift;
 
        switch (id / 4) {
@@ -105,30 +128,45 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
        return 0;
 }
 
-static int rsnd_scu_set_mode(struct rsnd_priv *priv,
-                            struct rsnd_mod *mod,
-                            struct rsnd_dai *rdai,
-                            struct rsnd_dai_stream *io)
+unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
+                                  struct rsnd_mod *ssi_mod,
+                                  struct snd_pcm_runtime *runtime)
 {
-       int id = rsnd_mod_id(mod);
-       u32 val;
+       struct rsnd_scu *scu;
+       unsigned int rate;
 
-       if (rsnd_is_gen1(priv)) {
-               val = (1 << id);
-               rsnd_mod_bset(mod, SRC_CTRL, val, val);
-       }
+       /* this function is assuming SSI id = SCU id here */
+       scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
 
-       return 0;
+       /*
+        * return convert rate if SRC is used,
+        * otherwise, return runtime->rate as usual
+        */
+       rate = rsnd_scu_convert_rate(scu);
+       if (!rate)
+               rate = runtime->rate;
+
+       return rate;
 }
 
-static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
+static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv,
                              struct rsnd_mod *mod,
                              struct rsnd_dai *rdai,
                              struct rsnd_dai_stream *io)
 {
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+       u32 convert_rate = rsnd_scu_convert_rate(scu);
        u32 adinr = runtime->channels;
 
+       /* set/clear soft reset */
+       rsnd_mod_write(mod, SRC_SWRSR, 0);
+       rsnd_mod_write(mod, SRC_SWRSR, 1);
+
+       /* Initialize the operation of the SRC internal circuits */
+       rsnd_mod_write(mod, SRC_SRCIR, 1);
+
+       /* Set channel number and output bit length */
        switch (runtime->sample_bits) {
        case 16:
                adinr |= OTBL_16;
@@ -139,9 +177,81 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
        default:
                return -EIO;
        }
+       rsnd_mod_write(mod, SRC_ADINR, adinr);
+
+       if (convert_rate) {
+               u32 fsrate = 0x0400000 / convert_rate * runtime->rate;
+               int ret;
+
+               /* Enable the initial value of IFS */
+               rsnd_mod_write(mod, SRC_IFSCR, 1);
+
+               /* Set initial value of IFS */
+               rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+
+               /* Select SRC mode (fixed value) */
+               rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
+
+               /* Set the restriction value of the FS ratio (98%) */
+               rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98);
+
+               if (rsnd_is_gen1(priv)) {
+                       /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
+               }
 
+               /* set convert clock */
+               ret = rsnd_adg_set_convert_clk(priv, mod,
+                                              runtime->rate,
+                                              convert_rate);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Cancel the initialization and operate the SRC function */
+       rsnd_mod_write(mod, SRC_SRCIR, 0);
+
+       /* use DMA transfer */
        rsnd_mod_write(mod, BUSIF_MODE, 1);
-       rsnd_mod_write(mod, BUSIF_ADINR, adinr);
+
+       return 0;
+}
+
+static int rsnd_scu_transfer_start(struct rsnd_priv *priv,
+                                  struct rsnd_mod *mod,
+                                  struct rsnd_dai *rdai,
+                                  struct rsnd_dai_stream *io)
+{
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+       int id = rsnd_mod_id(mod);
+       u32 val;
+
+       if (rsnd_is_gen1(priv)) {
+               val = (1 << id);
+               rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val);
+       }
+
+       if (rsnd_scu_convert_rate(scu))
+               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+
+       return 0;
+}
+
+static int rsnd_scu_transfer_stop(struct rsnd_priv *priv,
+                                 struct rsnd_mod *mod,
+                                 struct rsnd_dai *rdai,
+                                 struct rsnd_dai_stream *io)
+{
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+       int id = rsnd_mod_id(mod);
+       u32 mask;
+
+       if (rsnd_is_gen1(priv)) {
+               mask = (1 << id);
+               rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0);
+       }
+
+       if (rsnd_scu_convert_rate(scu))
+               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
 
        return 0;
 }
@@ -159,6 +269,7 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
                          struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        int ret;
 
@@ -173,16 +284,19 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
                return 0;
        }
 
+       clk_enable(scu->clk);
+
        /* it use DMA transter */
-       ret = rsnd_scu_set_route(priv, mod, rdai, io);
+
+       ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_scu_set_mode(priv, mod, rdai, io);
+       ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_scu_set_hpbif(priv, mod, rdai, io);
+       ret = rsnd_scu_transfer_start(priv, mod, rdai, io);
        if (ret < 0)
                return ret;
 
@@ -191,9 +305,27 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_scu_stop(struct rsnd_mod *mod,
+                         struct rsnd_dai *rdai,
+                         struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+
+       if (!rsnd_scu_hpbif_is_enable(mod))
+               return 0;
+
+       rsnd_scu_transfer_stop(priv, mod, rdai, io);
+
+       clk_disable(scu->clk);
+
+       return 0;
+}
+
 static struct rsnd_mod_ops rsnd_scu_ops = {
        .name   = "scu",
        .start  = rsnd_scu_start,
+       .stop   = rsnd_scu_stop,
 };
 
 struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
@@ -210,6 +342,8 @@ int rsnd_scu_probe(struct platform_device *pdev,
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_scu *scu;
+       struct clk *clk;
+       char name[RSND_SCU_NAME_SIZE];
        int i, nr;
 
        /*
@@ -226,9 +360,16 @@ int rsnd_scu_probe(struct platform_device *pdev,
        priv->scu       = scu;
 
        for_each_rsnd_scu(scu, priv, i) {
+               snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+
                rsnd_mod_init(priv, &scu->mod,
                              &rsnd_scu_ops, i);
                scu->info = &info->scu_info[i];
+               scu->clk = clk;
 
                dev_dbg(dev, "SCU%d probed\n", i);
        }
index 5ac20cd5e00607efd0b8113fc85aec9ed97f57f4..4b8cf7ca9d19fb016b971cf9f0f1ddeb74fbb954 100644 (file)
@@ -187,9 +187,10 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
-                                    unsigned int rate)
+                                    struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int i, j, ret;
        int adg_clk_div_table[] = {
@@ -199,6 +200,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
                1, 2, 4, 8, 16, 6, 12,
        };
        unsigned int main_rate;
+       unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime);
 
        /*
         * Find best clock, and try to start ADG
@@ -209,7 +211,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
                        /*
                         * this driver is assuming that
                         * system word is 64fs (= 2 x 32bit)
-                        * see rsnd_ssi_start()
+                        * see rsnd_ssi_init()
                         */
                        main_rate = rate / adg_clk_div_table[i]
                                * 32 * 2 * ssi_clk_mul_table[j];
@@ -251,14 +253,10 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                clk_enable(ssi->clk);
 
                if (rsnd_rdai_is_clk_master(rdai)) {
-                       struct snd_pcm_runtime *runtime;
-
-                       runtime = rsnd_io_to_runtime(io);
-
                        if (rsnd_ssi_clk_from_parent(ssi))
                                rsnd_ssi_hw_start(ssi->parent, rdai, io);
                        else
-                               rsnd_ssi_master_clk_start(ssi, runtime->rate);
+                               rsnd_ssi_master_clk_start(ssi, io);
                }
        }
 
@@ -457,6 +455,10 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
        /* enable PIO IRQ */
        ssi->cr_etc = UIEN | OIEN | DIEN;
 
+       /* enable PIO interrupt if gen2 */
+       if (rsnd_is_gen2(priv))
+               rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000);
+
        rsnd_ssi_hw_start(ssi, rdai, io);
 
        dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
@@ -650,7 +652,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
 
                snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
 
-               clk = clk_get(dev, name);
+               clk = devm_clk_get(dev, name);
                if (IS_ERR(clk))
                        return PTR_ERR(clk);
 
@@ -711,7 +713,6 @@ void rsnd_ssi_remove(struct platform_device *pdev,
        int i;
 
        for_each_rsnd_ssi(ssi, priv, i) {
-               clk_put(ssi->clk);
                if (rsnd_ssi_dma_available(ssi))
                        rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
        }
index 21a8c954af1cd6dfedd65100cc331d54145f4746..4ab442a63d7ed55c411f1729995bd12efdce88db 100644 (file)
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 #include <sound/spear_spdif.h>
 #include "spdif_in_regs.h"
+#include "spear_pcm.h"
 
 struct spdif_in_params {
        u32 format;
@@ -37,6 +39,8 @@ struct spdif_in_dev {
        struct device *dev;
        void (*reset_perip)(void);
        int irq;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_pcm_config config;
 };
 
 static void spdif_in_configure(struct spdif_in_dev *host)
@@ -53,7 +57,8 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai)
 {
        struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
 
-       dai->capture_dma_data = &host->dma_params;
+       host->dma_params_rx.filter_data = &host->dma_params;
+       dai->capture_dma_data = &host->dma_params_rx;
 
        return 0;
 }
@@ -244,7 +249,6 @@ static int spdif_in_probe(struct platform_device *pdev)
        host->dma_params.addr = res_fifo->start;
        host->dma_params.max_burst = 16;
        host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       host->dma_params.filter = pdata->filter;
        host->reset_perip = pdata->reset_perip;
 
        host->dev = &pdev->dev;
@@ -257,8 +261,13 @@ static int spdif_in_probe(struct platform_device *pdev)
                return ret;
        }
 
-       return devm_snd_soc_register_component(&pdev->dev, &spdif_in_component,
-                                              &spdif_in_dai, 1);
+       ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component,
+                                             &spdif_in_dai, 1);
+       if (ret)
+               return ret;
+
+       return devm_spear_pcm_platform_register(&pdev->dev, &host->config,
+                                               pdata->filter);
 }
 
 static struct platform_driver spdif_in_driver = {
index b6ef6f78dc781ad8a45c18d594b1cdc4945647f1..fe99f461aff0bfd97337f663ba2f13eecd626bbb 100644 (file)
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 #include <sound/spear_spdif.h>
 #include "spdif_out_regs.h"
+#include "spear_pcm.h"
 
 struct spdif_out_params {
        u32 rate;
@@ -35,6 +37,8 @@ struct spdif_out_dev {
        struct spdif_out_params saved_params;
        u32 running;
        void __iomem *io_base;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+       struct snd_dmaengine_pcm_config config;
 };
 
 static void spdif_out_configure(struct spdif_out_dev *host)
@@ -244,7 +248,8 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai)
 {
        struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
 
-       dai->playback_dma_data = &host->dma_params;
+       host->dma_params_tx.filter_data = &host->dma_params;
+       dai->playback_dma_data = &host->dma_params_tx;
 
        return snd_soc_add_dai_controls(dai, spdif_out_controls,
                                ARRAY_SIZE(spdif_out_controls));
@@ -280,6 +285,7 @@ static int spdif_out_probe(struct platform_device *pdev)
        struct spdif_out_dev *host;
        struct spear_spdif_platform_data *pdata;
        struct resource *res;
+       int ret;
 
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
        if (!host) {
@@ -302,12 +308,16 @@ static int spdif_out_probe(struct platform_device *pdev)
        host->dma_params.addr = res->start + SPDIF_OUT_FIFO_DATA;
        host->dma_params.max_burst = 16;
        host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       host->dma_params.filter = pdata->filter;
 
        dev_set_drvdata(&pdev->dev, host);
 
-       return devm_snd_soc_register_component(&pdev->dev, &spdif_out_component,
-                                              &spdif_out_dai, 1);
+       ret = devm_snd_soc_register_component(&pdev->dev, &spdif_out_component,
+                                             &spdif_out_dai, 1);
+       if (ret)
+               return ret;
+
+       return devm_spear_pcm_platform_register(&pdev->dev, &host->config,
+                                               pdata->filter);
 }
 
 #ifdef CONFIG_PM
index 4707f2b862c3762502d622d1d799944ee0e401fc..0e5a8f35d0ad22da7925445a5d074fefb5478ab1 100644 (file)
@@ -18,6 +18,7 @@
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
+#include "spear_pcm.h"
 
 static const struct snd_pcm_hardware spear_pcm_hardware = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -31,49 +32,24 @@ static const struct snd_pcm_hardware spear_pcm_hardware = {
        .fifo_size = 0, /* fifo size in bytes */
 };
 
-static struct dma_chan *spear_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
-       struct snd_pcm_substream *substream)
-{
-       struct spear_dma_data *dma_data;
-
-       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       return snd_dmaengine_pcm_request_channel(dma_data->filter, dma_data);
-}
-
 static const struct snd_dmaengine_pcm_config spear_dmaengine_pcm_config = {
        .pcm_hardware = &spear_pcm_hardware,
-       .compat_request_channel = spear_pcm_request_chan,
        .prealloc_buffer_size = 16 * 1024,
 };
 
-static int spear_soc_platform_probe(struct platform_device *pdev)
+int devm_spear_pcm_platform_register(struct device *dev,
+                       struct snd_dmaengine_pcm_config *config,
+                       bool (*filter)(struct dma_chan *chan, void *slave))
 {
-       return snd_dmaengine_pcm_register(&pdev->dev,
-               &spear_dmaengine_pcm_config,
+       *config = spear_dmaengine_pcm_config;
+       config->compat_filter_fn = filter;
+
+       return snd_dmaengine_pcm_register(dev, config,
                SND_DMAENGINE_PCM_FLAG_NO_DT |
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
-
-static int spear_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_dmaengine_pcm_unregister(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver spear_pcm_driver = {
-       .driver = {
-               .name = "spear-pcm-audio",
-               .owner = THIS_MODULE,
-       },
-
-       .probe = spear_soc_platform_probe,
-       .remove = spear_soc_platform_remove,
-};
-
-module_platform_driver(spear_pcm_driver);
+EXPORT_SYMBOL_GPL(devm_spear_pcm_platform_register);
 
 MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
 MODULE_DESCRIPTION("SPEAr PCM DMA module");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:spear-pcm-audio");
diff --git a/sound/soc/spear/spear_pcm.h b/sound/soc/spear/spear_pcm.h
new file mode 100644 (file)
index 0000000..9b0ca62
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 __SPEAR_PCM_H__
+#define __SPEAR_PCM_H__
+
+int devm_spear_pcm_platform_register(struct device *dev,
+                       struct snd_dmaengine_pcm_config *config,
+                       bool (*filter)(struct dma_chan *chan, void *slave));
+
+#endif
index 8fc653ca3ab40b3ef04d1a58723a2466086ab8ff..65a85f542521563627be1fe02b4c22c6bfdea194 100644 (file)
@@ -116,3 +116,13 @@ config SND_SOC_TEGRA_ALC5632
        help
          Say Y or M here if you want to add support for SoC audio on the
          Toshiba AC100 netbook.
+
+config SND_SOC_TEGRA_MAX98090
+       tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+       select SND_SOC_MAX98090
+       help
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the MAX98090 codec, such as Venice2.
index 21d2550a08a4fc1e15e41f4c66cc0a84a290396f..5ae588cd96c4c39ff8060f98a6f1248f9e4855d9 100644 (file)
@@ -24,6 +24,7 @@ snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-wm9712-objs := tegra_wm9712.o
 snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
+snd-soc-tegra-max98090-objs := tegra_max98090.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
 obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
 obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
+obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
index ae27bcd586d25428458c305c16448395b9f74d88..088518d7694ae95d09ebf795d1dc7cdd33fc9a64 100644 (file)
@@ -404,7 +404,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
        if (ret) {
                dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
-               goto err_asoc_utils_fini;
+               goto err_clk_disable_unprepare;
        }
 
        ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
@@ -412,7 +412,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
-               goto err_asoc_utils_fini;
+               goto err_clk_disable_unprepare;
        }
 
        ret = tegra_pcm_platform_register(&pdev->dev);
@@ -428,6 +428,8 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 
 err_unregister_component:
        snd_soc_unregister_component(&pdev->dev);
+err_clk_disable_unprepare:
+       clk_disable_unprepare(ac97->clk_ac97);
 err_asoc_utils_fini:
        tegra_asoc_utils_fini(&ac97->util_data);
 err_clk_put:
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
new file mode 100644 (file)
index 0000000..0283cfb
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Tegra machine ASoC driver for boards using a MAX90809 CODEC.
+ *
+ * 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/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-max98090"
+
+struct tegra_max98090 {
+       struct tegra_asoc_utils_data util_data;
+       int gpio_hp_det;
+};
+
+static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       switch (srate) {
+       case 8000:
+       case 16000:
+       case 24000:
+       case 32000:
+       case 48000:
+       case 64000:
+       case 96000:
+               mclk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+               mclk = 11289600;
+               break;
+       default:
+               mclk = 12000000;
+               break;
+       }
+
+       err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_max98090_ops = {
+       .hw_params = tegra_max98090_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_max98090_hp_jack;
+
+static struct snd_soc_jack_pin tegra_max98090_hp_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = {
+       .name = "Headphone detection",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+       .invert = 1,
+};
+
+static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_max98090_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speakers"),
+};
+
+static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tegra_max98090 *machine = snd_soc_card_get_drvdata(codec->card);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
+                               &tegra_max98090_hp_jack);
+               snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
+                               ARRAY_SIZE(tegra_max98090_hp_jack_pins),
+                               tegra_max98090_hp_jack_pins);
+
+               tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
+               snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
+                                       1,
+                                       &tegra_max98090_hp_jack_gpio);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_max98090_dai = {
+       .name = "max98090",
+       .stream_name = "max98090 PCM",
+       .codec_dai_name = "HiFi",
+       .init = tegra_max98090_asoc_init,
+       .ops = &tegra_max98090_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_max98090 = {
+       .name = "tegra-max98090",
+       .owner = THIS_MODULE,
+       .dai_link = &tegra_max98090_dai,
+       .num_links = 1,
+       .controls = tegra_max98090_controls,
+       .num_controls = ARRAY_SIZE(tegra_max98090_controls),
+       .dapm_widgets = tegra_max98090_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_max98090_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int tegra_max98090_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &snd_soc_tegra_max98090;
+       struct tegra_max98090 *machine;
+       int ret;
+
+       machine = devm_kzalloc(&pdev->dev,
+                       sizeof(struct tegra_max98090), GFP_KERNEL);
+       if (!machine) {
+               dev_err(&pdev->dev, "Can't allocate tegra_max98090\n");
+               return -ENOMEM;
+       }
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (machine->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_max98090_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!tegra_max98090_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_max98090_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_max98090_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_max98090_dai.platform_of_node = tegra_max98090_dai.cpu_of_node;
+
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&machine->util_data);
+err:
+       return ret;
+}
+
+static int tegra_max98090_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
+                               &tegra_max98090_hp_jack_gpio);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_max98090_of_match[] = {
+       { .compatible = "nvidia,tegra-audio-max98090", },
+       {},
+};
+
+static struct platform_driver tegra_max98090_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_max98090_of_match,
+       },
+       .probe = tegra_max98090_probe,
+       .remove = tegra_max98090_remove,
+};
+module_platform_driver(tegra_max98090_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_max98090_of_match);
index 7b2d23ba69b3bf397ba3fb963feb2d3d2b5948af..c09ffd18791b9de9b13713dc068ee5cb4d75e42d 100644 (file)
@@ -42,9 +42,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
                                  SNDRV_PCM_INFO_INTERLEAVED,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .channels_min           = 2,
-       .channels_max           = 2,
        .period_bytes_min       = 1024,
        .period_bytes_max       = PAGE_SIZE,
        .periods_min            = 2,
index 5e119630b0e03fa677b49302e517499f8cb1df5f..45b57892b6a53564e60434262b56fb0ae16b91df 100644 (file)
@@ -55,7 +55,6 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link tegra_wm9712_dai = {
        .name = "AC97 HiFi",
        .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "tegra20-ac97",
        .codec_dai_name = "wm9712-hifi",
        .codec_name = "wm9712-codec",
        .init = tegra_wm9712_init,
index fbd077f4de729e24da0049e96924e6d27dababba..f0829de28708b20724fffddf831bec56818152d1 100644 (file)
@@ -40,11 +40,6 @@ static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
        .info             = SNDRV_PCM_INFO_INTERLEAVED |
                            SNDRV_PCM_INFO_BATCH |
                            SNDRV_PCM_INFO_PAUSE,
-#ifdef __BIG_ENDIAN
-       .formats          = SNDRV_PCM_FMTBIT_S16_BE,
-#else
-       .formats          = SNDRV_PCM_FMTBIT_S16_LE,
-#endif
        .period_bytes_min = 1024,
        .period_bytes_max = 8 * 1024,
        .periods_min      = 2,