Merge tag 'asoc-v3.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Fri, 28 Jun 2013 11:36:22 +0000 (13:36 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 28 Jun 2013 11:36:22 +0000 (13:36 +0200)
ASoC: More updates for v3.11

Some more fixes and enhancements, and also a bunch of refectoring for
AC'97 support which enables more than one AC'97 controller driver to be
built in.

299 files changed:
Documentation/devicetree/bindings/mfd/arizona.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mxs-saif.txt
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5640.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/sgtl5000.txt
Documentation/devicetree/bindings/sound/spdif-receiver.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/spdif-transmitter.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ssm2518.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wm8962.txt
Documentation/sound/alsa/HD-Audio-Models.txt
arch/blackfin/mach-bf527/boards/ad7160eval.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf609/boards/ezkit.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-i2c.c
drivers/mfd/arizona-spi.c
drivers/mfd/arizona.h
drivers/mfd/wm5102-tables.c
drivers/mfd/wm5110-tables.c
drivers/misc/atmel-ssc.c
include/linux/mfd/arizona/core.h
include/linux/mfd/arizona/pdata.h
include/linux/mfd/arizona/registers.h
include/linux/mfd/wm8994/pdata.h
include/linux/mfd/wm8994/registers.h
include/linux/platform_data/ssm2518.h [new file with mode: 0644]
include/sound/control.h
include/sound/core.h
include/sound/pcm.h
include/sound/rt5640.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/uapi/sound/asound.h
sound/arm/aaci.c
sound/arm/pxa2xx-ac97.c
sound/core/Kconfig
sound/core/init.c
sound/core/pcm_lib.c
sound/core/vmaster.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/ml403-ac97cr.c
sound/drivers/mpu401/mpu401.c
sound/drivers/mtpav.c
sound/drivers/pcsp/pcsp.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/drivers/vx/vx_core.c
sound/firewire/amdtp.h
sound/firewire/scs1x.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/ad1848/ad1848.c
sound/isa/adlib.c
sound/isa/cmi8328.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4236.c
sound/isa/es1688/es1688.c
sound/isa/es18xx.c
sound/isa/galaxy/galaxy.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/msnd/msnd_pinnacle.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/jazz16.c
sound/isa/sb/sb16.c
sound/isa/sb/sb8.c
sound/isa/sc6000.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/oss/kahlua.c
sound/parisc/harmony.c
sound/pci/ac97/ac97_codec.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpioctl.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/aw2/aw2-alsa.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/ppc/powermac.c
sound/sh/aica.c
sound/sh/sh_dac_audio.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/blackfin/Kconfig
sound/soc/blackfin/Makefile
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97-pcm.h [deleted file]
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.h
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.c
sound/soc/blackfin/bf5xx-sport.h
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c [deleted file]
sound/soc/blackfin/bf5xx-tdm-pcm.h [deleted file]
sound/soc/blackfin/bf5xx-tdm.c [deleted file]
sound/soc/blackfin/bf5xx-tdm.h [deleted file]
sound/soc/cirrus/Kconfig
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/cirrus/ep93xx-pcm.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ab8500-codec.h
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/bt-sco.c [moved from sound/soc/codecs/dfbmcs320.c with 53% similarity]
sound/soc/codecs/hdmi.c [moved from sound/soc/codecs/omap-hdmi.c with 69% similarity]
sound/soc/codecs/jz4740.c
sound/soc/codecs/max98090.c
sound/soc/codecs/rt5640.c [new file with mode: 0644]
sound/soc/codecs/rt5640.h [new file with mode: 0644]
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/sn95031.c
sound/soc/codecs/spdif_receiver.c
sound/soc/codecs/spdif_transmitter.c [moved from sound/soc/codecs/spdif_transciever.c with 88% similarity]
sound/soc/codecs/ssm2518.c [new file with mode: 0644]
sound/soc/codecs/ssm2518.h [new file with mode: 0644]
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm_adsp.c
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-sffsdr.c [deleted file]
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-pcm.c [deleted file]
sound/soc/fsl/imx-pcm.h
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h
sound/soc/fsl/imx-wm8962.c [new file with mode: 0644]
sound/soc/fsl/mx27vis-aic32x4.c
sound/soc/fsl/phycore-ac97.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/mxs/mxs-pcm.c
sound/soc/mxs/mxs-pcm.h
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-saif.h
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/omap-hdmi-card.c
sound/soc/omap/omap-mcbsp.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/mmp-pcm.c
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/saarb.c [deleted file]
sound/soc/pxa/tavorevb3.c [deleted file]
sound/soc/pxa/zylonite.c
sound/soc/samsung/Kconfig
sound/soc/samsung/bells.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/smdk_wm8580pcm.c
sound/soc/samsung/smdk_wm8994pcm.c
sound/soc/sh/fsi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-utils.c
sound/soc/spear/Kconfig [new file with mode: 0644]
sound/soc/spear/Makefile [new file with mode: 0644]
sound/soc/spear/spdif_in.c
sound/soc/spear/spdif_out.c
sound/soc/spear/spear_pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_rt5640.c [new file with mode: 0644]
sound/soc/ux500/mop500.c
sound/soc/ux500/mop500_ab8500.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_dai.h
sound/soc/ux500/ux500_msp_i2s.c
sound/soc/ux500/ux500_msp_i2s.h
sound/soc/ux500/ux500_pcm.c
sound/sparc/dbri.c
sound/spi/at73c213.c
sound/usb/6fire/chip.c
sound/usb/6fire/pcm.c
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/caiaq/audio.c
sound/usb/caiaq/device.c
sound/usb/card.h
sound/usb/clock.c
sound/usb/format.c
sound/usb/format.h
sound/usb/hiface/Makefile [new file with mode: 0644]
sound/usb/hiface/chip.c [new file with mode: 0644]
sound/usb/hiface/chip.h [new file with mode: 0644]
sound/usb/hiface/pcm.c [new file with mode: 0644]
sound/usb/hiface/pcm.h [new file with mode: 0644]
sound/usb/midi.c
sound/usb/misc/ua101.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/stream.c
sound/usb/usbaudio.h
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2yaudio.c

diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt
new file mode 100644 (file)
index 0000000..0e295c9
--- /dev/null
@@ -0,0 +1,62 @@
+Wolfson Arizona class audio SoCs
+
+These devices are audio SoCs with extensive digital capabilites and a range
+of analogue I/O.
+
+Required properties:
+
+  - compatible : one of the following chip-specific strings:
+       "wlf,wm5102"
+       "wlf,wm5110"
+  - reg : I2C slave address when connected using I2C, chip select number when
+    using SPI.
+
+  - interrupts : The interrupt line the /IRQ signal for the device is
+    connected to.
+  - interrupt-controller : Arizona class devices contain interrupt controllers
+    and may provide interrupt services to other devices.
+  - interrupt-parent : The parent interrupt controller.
+  - #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
+    The first cell is the IRQ number.
+    The second cell is the flags, encoded as the trigger masks from
+    Documentation/devicetree/bindings/interrupts.txt
+
+  - gpio-controller : Indicates this device is a GPIO controller.
+  - #gpio-cells : Must be 2. The first cell is the pin number and the
+    second cell is used to specify optional parameters (currently unused).
+
+  - AVDD1-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
+    SPKVDDL-supply, SPKVDDR-supply : power supplies for the device, as covered
+    in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Optional properties:
+
+  - wlf,reset : GPIO specifier for the GPIO controlling /RESET
+  - wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA
+
+  - wlf,gpio-defaults : A list of GPIO configuration register values. If
+    absent, no configuration of these registers is performed. If any
+    entry has a value that is out of range for a 16 bit register then
+    the chip default will be used.  If present exactly five values must
+    be specified.
+
+Example:
+
+codec: wm5102@1a {
+       compatible = "wlf,wm5102";
+       reg = <0x1a>;
+       interrupts = <347>;
+       #interrupt-cells = <2>;
+        interrupt-parent = <&gic>;
+
+       gpio-controller;
+       #gpio-cells = <2>;
+
+       wlf,gpio-defaults = <
+               0x00000000, /* AIF1TXLRCLK */
+               0xffffffff,
+               0xffffffff,
+               0xffffffff,
+               0xffffffff,
+       >;
+};
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
new file mode 100644 (file)
index 0000000..f49450a
--- /dev/null
@@ -0,0 +1,46 @@
+Freescale i.MX audio complex with WM8962 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-wm8962"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the WM8962 audio codec
+- audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names could be power
+  supplies, WM8962 pins, and the jacks on the board:
+
+  Power supplies:
+   * Mic Bias
+
+  Board connectors:
+   * Mic Jack
+   * Headphone Jack
+   * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+       compatible = "fsl,imx6q-sabresd-wm8962",
+                    "fsl,imx-audio-wm8962";
+       model = "wm8962-audio";
+       ssi-controller = <&ssi2>;
+       audio-codec = <&codec>;
+               audio-routing =
+               "Headphone Jack", "HPOUTL",
+               "Headphone Jack", "HPOUTR",
+               "Ext Spk", "SPKOUTL",
+               "Ext Spk", "SPKOUTR",
+               "MICBIAS", "AMIC",
+               "IN3R", "MICBIAS",
+               "DMIC", "MICBIAS",
+               "DMICDAT", "DMIC";
+       mux-int-port = <2>;
+       mux-ext-port = <3>;
+};
index c37ba61..7ba07a1 100644 (file)
@@ -3,8 +3,11 @@
 Required properties:
 - compatible: Should be "fsl,<chip>-saif"
 - reg: Should contain registers location and length
-- interrupts: Should contain ERROR and DMA interrupts
-- fsl,saif-dma-channel: APBX DMA channel for the SAIF
+- interrupts: Should contain ERROR interrupt number
+- dmas: DMA specifier, consisting of a phandle to DMA controller node
+  and SAIF DMA channel ID.
+  Refer to dma.txt and fsl-mxs-dma.txt for details.
+- dma-names: Must be "rx-tx".
 
 Optional properties:
 - fsl,saif-master: phandle to the master SAIF.  It's only required for
@@ -23,14 +26,16 @@ aliases {
 saif0: saif@80042000 {
        compatible = "fsl,imx28-saif";
        reg = <0x80042000 2000>;
-       interrupts = <59 80>;
-       fsl,saif-dma-channel = <4>;
+       interrupts = <59>;
+       dmas = <&dma_apbx 4>;
+       dma-names = "rx-tx";
 };
 
 saif1: saif@80046000 {
        compatible = "fsl,imx28-saif";
        reg = <0x80046000 2000>;
-       interrupts = <58 81>;
-       fsl,saif-dma-channel = <5>;
+       interrupts = <58>;
+       dmas = <&dma_apbx 5>;
+       dma-names = "rx-tx";
        fsl,saif-master = <&saif0>;
 };
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
new file mode 100644 (file)
index 0000000..d130818
--- /dev/null
@@ -0,0 +1,71 @@
+NVIDIA Tegra audio complex, with RT5640 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-rt5640"
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must include the following entries:
+  "pll_a" (The Tegra clock of that name),
+  "pll_a_out0" (The Tegra clock of that name),
+  "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 RT5640's pins, and the jacks on the board:
+
+  RT5640 pins:
+
+  * DMIC1
+  * DMIC2
+  * MICBIAS1
+  * IN1P
+  * IN1R
+  * IN2P
+  * IN2R
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * MONOP
+  * MONON
+  * SPOLP
+  * SPOLN
+  * SPORP
+  * SPORN
+
+  Board connectors:
+
+  * Headphones
+  * Speakers
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the RT5640 audio codec. This binding
+  assumes that AIF1 on the CODEC is connected to Tegra.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-rt5640-dalmore",
+                       "nvidia,tegra-audio-rt5640";
+       nvidia,model = "NVIDIA Tegra Dalmore";
+
+       nvidia,audio-routing =
+               "Headphones", "HPOR",
+               "Headphones", "HPOL",
+               "Speakers", "SPORP",
+               "Speakers", "SPORN",
+               "Speakers", "SPOLP",
+               "Speakers", "SPOLN";
+
+       nvidia,i2s-controller = <&tegra_i2s1>;
+       nvidia,audio-codec = <&rt5640>;
+
+       nvidia,hp-det-gpios = <&gpio 143 0>; /* GPIO PR7 */
+
+       clocks = <&tegra_car 216>, <&tegra_car 217>, <&tegra_car 120>;
+       clock-names = "pll_a", "pll_a_out0", "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt
new file mode 100644 (file)
index 0000000..005bcb2
--- /dev/null
@@ -0,0 +1,30 @@
+RT5640 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5640".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in2-differential
+  Boolean. Indicate MIC1/2 input are differential, rather than single-ended.
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+
+Example:
+
+rt5640 {
+       compatible = "realtek,rt5640";
+       reg = <0x1c>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+       realtek,ldo1-en-gpios =
+               <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
index 9cc4444..955df60 100644 (file)
@@ -5,9 +5,12 @@ Required properties:
 
 - reg : the I2C address of the device
 
+- clocks : the clock provider of SYS_MCLK
+
 Example:
 
 codec: sgtl5000@0a {
        compatible = "fsl,sgtl5000";
        reg = <0x0a>;
+       clocks = <&clks 150>;
 };
diff --git a/Documentation/devicetree/bindings/sound/spdif-receiver.txt b/Documentation/devicetree/bindings/sound/spdif-receiver.txt
new file mode 100644 (file)
index 0000000..80f807b
--- /dev/null
@@ -0,0 +1,10 @@
+Device-Tree bindings for dummy spdif receiver
+
+Required properties:
+       - compatible: should be "linux,spdif-dir".
+
+Example node:
+
+       codec: spdif-receiver {
+               compatible = "linux,spdif-dir";
+       };
diff --git a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt b/Documentation/devicetree/bindings/sound/spdif-transmitter.txt
new file mode 100644 (file)
index 0000000..55a8584
--- /dev/null
@@ -0,0 +1,10 @@
+Device-Tree bindings for dummy spdif transmitter
+
+Required properties:
+       - compatible: should be "linux,spdif-dit".
+
+Example node:
+
+       codec: spdif-transmitter {
+               compatible = "linux,spdif-dit";
+       };
diff --git a/Documentation/devicetree/bindings/sound/ssm2518.txt b/Documentation/devicetree/bindings/sound/ssm2518.txt
new file mode 100644 (file)
index 0000000..59381a7
--- /dev/null
@@ -0,0 +1,20 @@
+SSM2518 audio amplifier
+
+This device supports I2C only.
+
+Required properties:
+  - compatible : Must be "adi,ssm2518"
+  - reg : the I2C address of the device. This will either be 0x34 (ADDR pin low)
+       or 0x35 (ADDR pin high)
+
+Optional properties:
+  - gpios : GPIO connected to the nSD pin. If the property is not present it is
+               assumed that the nSD pin is hardwired to always on.
+
+Example:
+
+       ssm2518: ssm2518@34 {
+               compatible = "adi,ssm2518";
+               reg = <0x34>;
+               gpios = <&gpio 5 0>;
+       };
index dceb3b1..7f82b59 100644 (file)
@@ -8,9 +8,32 @@ Required properties:
 
   - reg : the I2C address of the device.
 
+Optional properties:
+  - spk-mono: This is a boolean property. If present, the SPK_MONO bit
+    of R51 (Class D Control 2) gets set, indicating that the speaker is
+    in mono mode.
+
+  - mic-cfg : Default register value for R48 (Additional Control 4).
+    If absent, the default should be the register default.
+
+  - gpio-cfg : A list of GPIO configuration register values. The list must
+    be 6 entries long. If absent, no configuration of these registers is
+    performed. And note that only the value within [0x0, 0xffff] is valid.
+    Any other value is regarded as setting the GPIO register by its reset
+    value 0x0.
+
 Example:
 
 codec: wm8962@1a {
        compatible = "wlf,wm8962";
        reg = <0x1a>;
+
+       gpio-cfg = <
+               0x0000 /* 0:Default */
+               0x0000 /* 1:Default */
+               0x0013 /* 2:FN_DMICCLK */
+               0x0000 /* 3:Default */
+               0x8014 /* 4:FN_DMICCDAT */
+               0x0000 /* 5:Default */
+       >;
 };
index 77d68e2..809d72b 100644 (file)
@@ -21,41 +21,41 @@ ALC267/268
 ==========
   inv-dmic     Inverted internal mic workaround
 
-ALC269/270/275/276/280/282
+ALC269/270/275/276/28x/29x
 ======
-  laptop-amic  Laptops with analog-mic input
-  laptop-dmic  Laptops with digital-mic input
-  alc269-dmic  Enable ALC269(VA) digital mic workaround
-  alc271-dmic  Enable ALC271X digital mic workaround
-  inv-dmic     Inverted internal mic workaround
-  lenovo-dock   Enables docking station I/O for some Lenovos
+  laptop-amic          Laptops with analog-mic input
+  laptop-dmic          Laptops with digital-mic input
+  alc269-dmic          Enable ALC269(VA) digital mic workaround
+  alc271-dmic          Enable ALC271X digital mic workaround
+  inv-dmic             Inverted internal mic workaround
+  lenovo-dock          Enables docking station I/O for some Lenovos
   dell-headset-multi   Headset jack, which can also be used as mic-in
   dell-headset-dock    Headset jack (without mic-in), and also dock I/O
 
-ALC662/663/272
+ALC66x/67x/892
 ==============
-  mario                Chromebook mario model fixup
-  asus-mode1   ASUS
-  asus-mode2   ASUS
-  asus-mode3   ASUS
-  asus-mode4   ASUS
-  asus-mode5   ASUS
-  asus-mode6   ASUS
-  asus-mode7   ASUS
-  asus-mode8   ASUS
-  inv-dmic     Inverted internal mic workaround
+  mario                        Chromebook mario model fixup
+  asus-mode1           ASUS
+  asus-mode2           ASUS
+  asus-mode3           ASUS
+  asus-mode4           ASUS
+  asus-mode5           ASUS
+  asus-mode6           ASUS
+  asus-mode7           ASUS
+  asus-mode8           ASUS
+  inv-dmic             Inverted internal mic workaround
   dell-headset-multi   Headset jack, which can also be used as mic-in
 
 ALC680
 ======
   N/A
 
-ALC882/883/885/888/889
+ALC88x/898/1150
 ======================
   acer-aspire-4930g    Acer Aspire 4930G/5930G/6530G/6930G/7730G
   acer-aspire-8930g    Acer Aspire 8330G/6935G
   acer-aspire          Acer Aspire others
-  inv-dmic     Inverted internal mic workaround
+  inv-dmic             Inverted internal mic workaround
   no-primary-hp                VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
 
 ALC861/660
index d58f50e..1e7be62 100644 (file)
@@ -283,14 +283,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
-};
-#endif
-
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -800,10 +792,6 @@ static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
-
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
 };
 
 static int __init ad7160eval_init(void)
index 29f16e5..d0a0c5e 100644 (file)
@@ -493,8 +493,7 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
 
 static const u16 bfin_snd_pin[][7] = {
        {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
@@ -549,13 +548,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -575,22 +567,10 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -1269,10 +1249,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s_pcm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -1281,10 +1257,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
        defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
        &bfin_ad1836_machine,
index 07811c2..90fb0d1 100644 (file)
@@ -450,14 +450,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -516,10 +508,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
index 6fca869..4a8c2e3 100644 (file)
@@ -542,8 +542,7 @@ static struct platform_device bfin_dpmc = {
 };
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) \
-       || defined(CONFIG_SND_BF5XX_AC97) || \
+       defined(CONFIG_SND_BF5XX_AC97) || \
        defined(CONFIG_SND_BF5XX_AC97_MODULE)
 
 #include <asm/bfin_sport.h>
@@ -603,13 +602,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -620,7 +612,7 @@ static struct platform_device bfin_ac97_pcm = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -675,20 +667,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
-       defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources =
-               ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
        defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
@@ -761,10 +739,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s_pcm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -792,11 +766,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
-       defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
        defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
index 6a3a14b..44fd1d4 100644 (file)
@@ -2570,7 +2570,6 @@ static struct platform_device bfin_dpmc = {
 };
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
        defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 
 #define SPORT_REQ(x) \
@@ -2628,13 +2627,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -2645,7 +2637,7 @@ static struct platform_device bfin_ac97_pcm = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -2699,18 +2691,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -2935,10 +2915,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s_pcm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -2961,10 +2937,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
 #endif
index c4d07f0..372eb54 100644 (file)
@@ -1393,7 +1393,6 @@ static struct platform_device bfin_dpmc = {
 };
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
        defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 
 #define SPORT_REQ(x) \
@@ -1461,13 +1460,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -1501,18 +1493,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -1646,9 +1626,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s_pcm,
 #endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
+
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -1661,10 +1639,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
index 551f866..92938e7 100644 (file)
@@ -523,14 +523,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -542,7 +534,7 @@ static struct platform_device bfin_ac97 = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -611,10 +603,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
index 97d7016..bba40ae 100644 (file)
@@ -821,7 +821,7 @@ static struct platform_device bfin_i2s = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.76",
 };
 static struct platform_device bfin_ad1836_machine = {
index 6ab0304..74b4481 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/mfd/core.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
 #include <linux/slab.h>
 
 #include <linux/mfd/arizona/core.h>
@@ -344,6 +348,17 @@ static int arizona_runtime_resume(struct device *dev)
 
        switch (arizona->type) {
        case WM5102:
+               if (arizona->external_dcvdd) {
+                       ret = regmap_update_bits(arizona->regmap,
+                                                ARIZONA_ISOLATION_CONTROL,
+                                                ARIZONA_ISOLATE_DCVDD1, 0);
+                       if (ret != 0) {
+                               dev_err(arizona->dev,
+                                       "Failed to connect DCVDD: %d\n", ret);
+                               goto err;
+                       }
+               }
+
                ret = wm5102_patch(arizona);
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to apply patch: %d\n",
@@ -365,6 +380,28 @@ static int arizona_runtime_resume(struct device *dev)
                        goto err;
                }
 
+               if (arizona->external_dcvdd) {
+                       ret = regmap_update_bits(arizona->regmap,
+                                                ARIZONA_ISOLATION_CONTROL,
+                                                ARIZONA_ISOLATE_DCVDD1, 0);
+                       if (ret != 0) {
+                               dev_err(arizona->dev,
+                                       "Failed to connect DCVDD: %d\n", ret);
+                               goto err;
+                       }
+               }
+               break;
+       }
+
+       switch (arizona->type) {
+       case WM5102:
+               ret = wm5102_patch(arizona);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to apply patch: %d\n",
+                               ret);
+                       goto err;
+               }
+       default:
                break;
        }
 
@@ -385,9 +422,22 @@ err:
 static int arizona_runtime_suspend(struct device *dev)
 {
        struct arizona *arizona = dev_get_drvdata(dev);
+       int ret;
 
        dev_dbg(arizona->dev, "Entering AoD mode\n");
 
+       if (arizona->external_dcvdd) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_ISOLATION_CONTROL,
+                                        ARIZONA_ISOLATE_DCVDD1,
+                                        ARIZONA_ISOLATE_DCVDD1);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
        regulator_disable(arizona->dcvdd);
        regcache_cache_only(arizona->regmap, true);
        regcache_mark_dirty(arizona->regmap);
@@ -397,6 +447,26 @@ static int arizona_runtime_suspend(struct device *dev)
 #endif
 
 #ifdef CONFIG_PM_SLEEP
+static int arizona_suspend(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Suspend, disabling IRQ\n");
+       disable_irq(arizona->irq);
+
+       return 0;
+}
+
+static int arizona_suspend_late(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n");
+       enable_irq(arizona->irq);
+
+       return 0;
+}
+
 static int arizona_resume_noirq(struct device *dev)
 {
        struct arizona *arizona = dev_get_drvdata(dev);
@@ -422,13 +492,78 @@ const struct dev_pm_ops arizona_pm_ops = {
        SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
                           arizona_runtime_resume,
                           NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
 #ifdef CONFIG_PM_SLEEP
+       .suspend_late = arizona_suspend_late,
        .resume_noirq = arizona_resume_noirq,
 #endif
 };
 EXPORT_SYMBOL_GPL(arizona_pm_ops);
 
+#ifdef CONFIG_OF
+int arizona_of_get_type(struct device *dev)
+{
+       const struct of_device_id *id = of_match_device(arizona_of_match, dev);
+
+       if (id)
+               return (int)id->data;
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_type);
+
+static int arizona_of_get_core_pdata(struct arizona *arizona)
+{
+       int ret, i;
+
+       arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
+                                                "wlf,reset", 0);
+       if (arizona->pdata.reset < 0)
+               arizona->pdata.reset = 0;
+
+       arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
+                                                 "wlf,ldoena", 0);
+       if (arizona->pdata.ldoena < 0)
+               arizona->pdata.ldoena = 0;
+
+       ret = of_property_read_u32_array(arizona->dev->of_node,
+                                        "wlf,gpio-defaults",
+                                        arizona->pdata.gpio_defaults,
+                                        ARRAY_SIZE(arizona->pdata.gpio_defaults));
+       if (ret >= 0) {
+               /*
+                * All values are literal except out of range values
+                * which are chip default, translate into platform
+                * data which uses 0 as chip default and out of range
+                * as zero.
+                */
+               for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+                       if (arizona->pdata.gpio_defaults[i] > 0xffff)
+                               arizona->pdata.gpio_defaults[i] = 0;
+                       if (arizona->pdata.gpio_defaults[i] == 0)
+                               arizona->pdata.gpio_defaults[i] = 0x10000;
+               }
+       } else {
+               dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
+                       ret);
+       }
+
+       return 0;
+}
+
+const struct of_device_id arizona_of_match[] = {
+       { .compatible = "wlf,wm5102", .data = (void *)WM5102 },
+       { .compatible = "wlf,wm5110", .data = (void *)WM5110 },
+       {},
+};
+EXPORT_SYMBOL_GPL(arizona_of_match);
+#else
+static inline int arizona_of_get_core_pdata(struct arizona *arizona)
+{
+       return 0;
+}
+#endif
+
 static struct mfd_cell early_devs[] = {
        { .name = "arizona-ldo1" },
 };
@@ -462,6 +597,8 @@ int arizona_dev_init(struct arizona *arizona)
        dev_set_drvdata(arizona->dev, arizona);
        mutex_init(&arizona->clk_lock);
 
+       arizona_of_get_core_pdata(arizona);
+
        if (dev_get_platdata(arizona->dev))
                memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
                       sizeof(arizona->pdata));
@@ -536,51 +673,22 @@ int arizona_dev_init(struct arizona *arizona)
 
        regcache_cache_only(arizona->regmap, false);
 
+       /* Verify that this is a chip we know about */
        ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
        if (ret != 0) {
                dev_err(dev, "Failed to read ID register: %d\n", ret);
                goto err_reset;
        }
 
-       ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
-                         &arizona->rev);
-       if (ret != 0) {
-               dev_err(dev, "Failed to read revision register: %d\n", ret);
-               goto err_reset;
-       }
-       arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
-
        switch (reg) {
-#ifdef CONFIG_MFD_WM5102
        case 0x5102:
-               type_name = "WM5102";
-               if (arizona->type != WM5102) {
-                       dev_err(arizona->dev, "WM5102 registered as %d\n",
-                               arizona->type);
-                       arizona->type = WM5102;
-               }
-               apply_patch = wm5102_patch;
-               arizona->rev &= 0x7;
-               break;
-#endif
-#ifdef CONFIG_MFD_WM5110
        case 0x5110:
-               type_name = "WM5110";
-               if (arizona->type != WM5110) {
-                       dev_err(arizona->dev, "WM5110 registered as %d\n",
-                               arizona->type);
-                       arizona->type = WM5110;
-               }
-               apply_patch = wm5110_patch;
                break;
-#endif
        default:
-               dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+               dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
                goto err_reset;
        }
 
-       dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
-
        /* If we have a /RESET GPIO we'll already be reset */
        if (!arizona->pdata.reset) {
                regcache_mark_dirty(arizona->regmap);
@@ -600,6 +708,7 @@ int arizona_dev_init(struct arizona *arizona)
                }
        }
 
+       /* Ensure device startup is complete */
        switch (arizona->type) {
        case WM5102:
                ret = regmap_read(arizona->regmap, 0x19, &val);
@@ -620,6 +729,52 @@ int arizona_dev_init(struct arizona *arizona)
                break;
        }
 
+       /* Read the device ID information & do device specific stuff */
+       ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read ID register: %d\n", ret);
+               goto err_reset;
+       }
+
+       ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
+                         &arizona->rev);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read revision register: %d\n", ret);
+               goto err_reset;
+       }
+       arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
+
+       switch (reg) {
+#ifdef CONFIG_MFD_WM5102
+       case 0x5102:
+               type_name = "WM5102";
+               if (arizona->type != WM5102) {
+                       dev_err(arizona->dev, "WM5102 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM5102;
+               }
+               apply_patch = wm5102_patch;
+               arizona->rev &= 0x7;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+       case 0x5110:
+               type_name = "WM5110";
+               if (arizona->type != WM5110) {
+                       dev_err(arizona->dev, "WM5110 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM5110;
+               }
+               apply_patch = wm5110_patch;
+               break;
+#endif
+       default:
+               dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+               goto err_reset;
+       }
+
+       dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
+
        if (apply_patch) {
                ret = apply_patch(arizona);
                if (ret != 0) {
@@ -651,6 +806,14 @@ int arizona_dev_init(struct arizona *arizona)
                             arizona->pdata.gpio_defaults[i]);
        }
 
+       /*
+        * LDO1 can only be used to supply DCVDD so if it has no
+        * consumers then DCVDD is supplied externally.
+        */
+       if (arizona->pdata.ldo1 &&
+           arizona->pdata.ldo1->num_consumer_supplies == 0)
+               arizona->external_dcvdd = true;
+
        pm_runtime_set_autosuspend_delay(arizona->dev, 100);
        pm_runtime_use_autosuspend(arizona->dev);
        pm_runtime_enable(arizona->dev);
@@ -697,7 +860,7 @@ int arizona_dev_init(struct arizona *arizona)
                if (arizona->pdata.micbias[i].discharge)
                        val |= ARIZONA_MICB1_DISCH;
 
-               if (arizona->pdata.micbias[i].fast_start)
+               if (arizona->pdata.micbias[i].soft_start)
                        val |= ARIZONA_MICB1_RATE;
 
                if (arizona->pdata.micbias[i].bypass)
@@ -809,6 +972,11 @@ int arizona_dev_exit(struct arizona *arizona)
        arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
        pm_runtime_disable(arizona->dev);
        arizona_irq_exit(arizona);
+       if (arizona->pdata.reset)
+               gpio_set_value_cansleep(arizona->pdata.reset, 0);
+       regulator_disable(arizona->dcvdd);
+       regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies),
+                              arizona->core_supplies);
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_dev_exit);
index 44a1bb9..deb267e 100644 (file)
@@ -27,9 +27,14 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
 {
        struct arizona *arizona;
        const struct regmap_config *regmap_config;
-       int ret;
+       int ret, type;
 
-       switch (id->driver_data) {
+       if (i2c->dev.of_node)
+               type = arizona_of_get_type(&i2c->dev);
+       else
+               type = id->driver_data;
+
+       switch (type) {
 #ifdef CONFIG_MFD_WM5102
        case WM5102:
                regmap_config = &wm5102_i2c_regmap;
@@ -84,6 +89,7 @@ static struct i2c_driver arizona_i2c_driver = {
                .name   = "arizona",
                .owner  = THIS_MODULE,
                .pm     = &arizona_pm_ops,
+               .of_match_table = of_match_ptr(arizona_of_match),
        },
        .probe          = arizona_i2c_probe,
        .remove         = arizona_i2c_remove,
index b57e642..47be7b3 100644 (file)
@@ -27,9 +27,14 @@ static int arizona_spi_probe(struct spi_device *spi)
        const struct spi_device_id *id = spi_get_device_id(spi);
        struct arizona *arizona;
        const struct regmap_config *regmap_config;
-       int ret;
+       int ret, type;
 
-       switch (id->driver_data) {
+       if (spi->dev.of_node)
+               type = arizona_of_get_type(&spi->dev);
+       else
+               type = id->driver_data;
+
+       switch (type) {
 #ifdef CONFIG_MFD_WM5102
        case WM5102:
                regmap_config = &wm5102_spi_regmap;
@@ -84,6 +89,7 @@ static struct spi_driver arizona_spi_driver = {
                .name   = "arizona",
                .owner  = THIS_MODULE,
                .pm     = &arizona_pm_ops,
+               .of_match_table = of_match_ptr(arizona_of_match),
        },
        .probe          = arizona_spi_probe,
        .remove         = arizona_spi_remove,
index 9798ae5..db55d98 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _WM5102_H
 #define _WM5102_H
 
+#include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/pm.h>
 
@@ -26,6 +27,8 @@ extern const struct regmap_config wm5110_spi_regmap;
 
 extern const struct dev_pm_ops arizona_pm_ops;
 
+extern const struct of_device_id arizona_of_match[];
+
 extern const struct regmap_irq_chip wm5102_aod;
 extern const struct regmap_irq_chip wm5102_irq;
 
@@ -37,4 +40,13 @@ int arizona_dev_exit(struct arizona *arizona);
 int arizona_irq_init(struct arizona *arizona);
 int arizona_irq_exit(struct arizona *arizona);
 
+#ifdef CONFIG_OF
+int arizona_of_get_type(struct device *dev);
+#else
+static inline int arizona_of_get_type(struct device *dev)
+{
+       return 0;
+}
+#endif
+
 #endif
index 155c4a1..802dd3c 100644 (file)
@@ -65,7 +65,8 @@ static const struct reg_default wm5102_revb_patch[] = {
        { 0x418, 0xa080 },
        { 0x420, 0xa080 },
        { 0x428, 0xe000 },
-       { 0x443, 0xDC1A },
+       { 0x442, 0x3F0A },
+       { 0x443, 0xDC1F },
        { 0x4B0, 0x0066 },
        { 0x458, 0x000b },
        { 0x212, 0x0000 },
@@ -424,6 +425,9 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */ 
        { 0x00000436, 0x0081 },   /* R1078  - DAC Volume Limit 5R */
        { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */
+       { 0x00000440, 0x8FFF },   /* R1088  - DRE Enable */
+       { 0x00000442, 0x3F0A },   /* R1090  - DRE Control 2 */
+       { 0x00000443, 0xDC1F },   /* R1090  - DRE Control 3 */
        { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */ 
        { 0x00000458, 0x000B },   /* R1112  - Noise Gate Control */
        { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */ 
@@ -1197,6 +1201,9 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DAC_DIGITAL_VOLUME_5R:
        case ARIZONA_DAC_VOLUME_LIMIT_5R:
        case ARIZONA_NOISE_GATE_SELECT_5R:
+       case ARIZONA_DRE_ENABLE:
+       case ARIZONA_DRE_CONTROL_2:
+       case ARIZONA_DRE_CONTROL_3:
        case ARIZONA_DAC_AEC_CONTROL_1:
        case ARIZONA_NOISE_GATE_CONTROL:
        case ARIZONA_PDM_SPK1_CTRL_1:
index c415998..2a79723 100644 (file)
@@ -2273,18 +2273,22 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_CLOCKING_1:
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_DSP1_STATUS_3:
        case ARIZONA_DSP2_CONTROL_1:
        case ARIZONA_DSP2_CLOCKING_1:
        case ARIZONA_DSP2_STATUS_1:
        case ARIZONA_DSP2_STATUS_2:
+       case ARIZONA_DSP2_STATUS_3:
        case ARIZONA_DSP3_CONTROL_1:
        case ARIZONA_DSP3_CLOCKING_1:
        case ARIZONA_DSP3_STATUS_1:
        case ARIZONA_DSP3_STATUS_2:
+       case ARIZONA_DSP3_STATUS_3:
        case ARIZONA_DSP4_CONTROL_1:
        case ARIZONA_DSP4_CLOCKING_1:
        case ARIZONA_DSP4_STATUS_1:
        case ARIZONA_DSP4_STATUS_2:
+       case ARIZONA_DSP4_STATUS_3:
                return true;
        default:
                return false;
@@ -2334,12 +2338,16 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_CLOCKING_1:
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_DSP1_STATUS_3:
        case ARIZONA_DSP2_STATUS_1:
        case ARIZONA_DSP2_STATUS_2:
+       case ARIZONA_DSP2_STATUS_3:
        case ARIZONA_DSP3_STATUS_1:
        case ARIZONA_DSP3_STATUS_2:
+       case ARIZONA_DSP3_STATUS_3:
        case ARIZONA_DSP4_STATUS_1:
        case ARIZONA_DSP4_STATUS_2:
+       case ARIZONA_DSP4_STATUS_3:
                return true;
        default:
                return false;
index 1abd5ad..f7b9066 100644 (file)
@@ -58,7 +58,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
        ssc->user++;
        spin_unlock(&user_lock);
 
-       clk_enable(ssc->clk);
+       clk_prepare_enable(ssc->clk);
 
        return ssc;
 }
@@ -69,7 +69,7 @@ void ssc_free(struct ssc_device *ssc)
        spin_lock(&user_lock);
        if (ssc->user) {
                ssc->user--;
-               clk_disable(ssc->clk);
+               clk_disable_unprepare(ssc->clk);
        } else {
                dev_dbg(&ssc->pdev->dev, "device already free\n");
        }
@@ -167,10 +167,10 @@ static int ssc_probe(struct platform_device *pdev)
        }
 
        /* disable all interrupts */
-       clk_enable(ssc->clk);
+       clk_prepare_enable(ssc->clk);
        ssc_writel(ssc->regs, IDR, -1);
        ssc_readl(ssc->regs, SR);
-       clk_disable(ssc->clk);
+       clk_disable_unprepare(ssc->clk);
 
        ssc->irq = platform_get_irq(pdev, 0);
        if (!ssc->irq) {
index cc28136..f797bb9 100644 (file)
@@ -95,6 +95,8 @@ struct arizona {
 
        struct arizona_pdata pdata;
 
+       unsigned int external_dcvdd:1;
+
        int irq;
        struct irq_domain *virq;
        struct regmap_irq_chip_data *aod_irq_chip;
index 80dead1..12a5c13 100644 (file)
@@ -77,7 +77,7 @@ struct arizona_micbias {
        int mV;                    /** Regulated voltage */
        unsigned int ext_cap:1;    /** External capacitor fitted */
        unsigned int discharge:1;  /** Actively discharge */
-       unsigned int fast_start:1; /** Enable aggressive startup ramp rate */
+       unsigned int soft_start:1; /** Disable aggressive startup ramp rate */
        unsigned int bypass:1;     /** Use bypass mode */
 };
 
index 715b6ba..4706d3d 100644 (file)
 #define ARIZONA_DAC_DIGITAL_VOLUME_6R            0x43D
 #define ARIZONA_DAC_VOLUME_LIMIT_6R              0x43E
 #define ARIZONA_NOISE_GATE_SELECT_6R             0x43F
+#define ARIZONA_DRE_ENABLE                       0x440
+#define ARIZONA_DRE_CONTROL_2                    0x442
+#define ARIZONA_DRE_CONTROL_3                    0x443
 #define ARIZONA_DAC_AEC_CONTROL_1                0x450
 #define ARIZONA_NOISE_GATE_CONTROL               0x458
 #define ARIZONA_PDM_SPK1_CTRL_1                  0x490
 #define ARIZONA_DSP2_CLOCKING_1                  0x1201
 #define ARIZONA_DSP2_STATUS_1                    0x1204
 #define ARIZONA_DSP2_STATUS_2                    0x1205
+#define ARIZONA_DSP2_STATUS_3                    0x1206
 #define ARIZONA_DSP2_SCRATCH_0                   0x1240
 #define ARIZONA_DSP2_SCRATCH_1                   0x1241
 #define ARIZONA_DSP2_SCRATCH_2                   0x1242
 #define ARIZONA_DSP3_CLOCKING_1                  0x1301
 #define ARIZONA_DSP3_STATUS_1                    0x1304
 #define ARIZONA_DSP3_STATUS_2                    0x1305
+#define ARIZONA_DSP3_STATUS_3                    0x1306
 #define ARIZONA_DSP3_SCRATCH_0                   0x1340
 #define ARIZONA_DSP3_SCRATCH_1                   0x1341
 #define ARIZONA_DSP3_SCRATCH_2                   0x1342
 #define ARIZONA_DSP4_CLOCKING_1                  0x1401
 #define ARIZONA_DSP4_STATUS_1                    0x1404
 #define ARIZONA_DSP4_STATUS_2                    0x1405
+#define ARIZONA_DSP4_STATUS_3                    0x1406
 #define ARIZONA_DSP4_SCRATCH_0                   0x1440
 #define ARIZONA_DSP4_SCRATCH_1                   0x1441
 #define ARIZONA_DSP4_SCRATCH_2                   0x1442
 #define ARIZONA_OUT6R_NGATE_SRC_SHIFT                 0  /* OUT6R_NGATE_SRC - [11:0] */
 #define ARIZONA_OUT6R_NGATE_SRC_WIDTH                12  /* OUT6R_NGATE_SRC - [11:0] */
 
+/*
+ * R1088 (0x440) - DRE Enable
+ */
+#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_DRE3L_ENA_WIDTH                       1  /* DRE3L_ENA */
+#define ARIZONA_DRE2R_ENA                        0x0008  /* DRE2R_ENA */
+#define ARIZONA_DRE2R_ENA_MASK                   0x0008  /* DRE2R_ENA */
+#define ARIZONA_DRE2R_ENA_SHIFT                       3  /* DRE2R_ENA */
+#define ARIZONA_DRE2R_ENA_WIDTH                       1  /* DRE2R_ENA */
+#define ARIZONA_DRE2L_ENA                        0x0004  /* DRE2L_ENA */
+#define ARIZONA_DRE2L_ENA_MASK                   0x0004  /* DRE2L_ENA */
+#define ARIZONA_DRE2L_ENA_SHIFT                       2  /* DRE2L_ENA */
+#define ARIZONA_DRE2L_ENA_WIDTH                       1  /* DRE2L_ENA */
+#define ARIZONA_DRE1R_ENA                        0x0002  /* DRE1R_ENA */
+#define ARIZONA_DRE1R_ENA_MASK                   0x0002  /* DRE1R_ENA */
+#define ARIZONA_DRE1R_ENA_SHIFT                       1  /* DRE1R_ENA */
+#define ARIZONA_DRE1R_ENA_WIDTH                       1  /* DRE1R_ENA */
+#define ARIZONA_DRE1L_ENA                        0x0001  /* DRE1L_ENA */
+#define ARIZONA_DRE1L_ENA_MASK                   0x0001  /* DRE1L_ENA */
+#define ARIZONA_DRE1L_ENA_SHIFT                       0  /* DRE1L_ENA */
+#define ARIZONA_DRE1L_ENA_WIDTH                       1  /* DRE1L_ENA */
+
+/*
+ * R1090 (0x442) - DRE Control 2
+ */
+#define ARIZONA_DRE_T_LOW_MASK                   0x3F00  /* DRE_T_LOW - [13:8] */
+#define ARIZONA_DRE_T_LOW_SHIFT                       8  /* DRE_T_LOW - [13:8] */
+#define ARIZONA_DRE_T_LOW_WIDTH                       6  /* DRE_T_LOW - [13:8] */
+
+/*
+ * R1091 (0x443) - DRE Control 3
+ */
+#define ARIZONA_DRE_GAIN_SHIFT_MASK              0xC000  /* DRE_GAIN_SHIFT - [15:14] */
+#define ARIZONA_DRE_GAIN_SHIFT_SHIFT                 14  /* DRE_GAIN_SHIFT - [15:14] */
+#define ARIZONA_DRE_GAIN_SHIFT_WIDTH                  2  /* DRE_GAIN_SHIFT - [15:14] */
+#define ARIZONA_DRE_LOW_LEVEL_ABS_MASK           0x000F  /* LOW_LEVEL_ABS - [3:0] */
+#define ARIZONA_DRE_LOW_LEVEL_ABS_SHIFT               0  /* LOW_LEVEL_ABS - [3:0] */
+#define ARIZONA_DRE_LOW_LEVEL_ABS_WIDTH               4  /* LOW_LEVEL_ABS - [3:0] */
+
 /*
  * R1104 (0x450) - DAC AEC Control 1
  */
index 68e7765..b5046f6 100644 (file)
@@ -182,6 +182,11 @@ struct wm8994_pdata {
         */
        int micdet_delay;
 
+       /* Delay between microphone detect completing and reporting on
+        * insert (specified in ms)
+        */
+       int mic_id_delay;
+
        /* IRQ for microphone detection if brought out directly as a
         * signal.
         */
index 0535489..db8cef3 100644 (file)
 /*
  * R772 (0x304) - AIF1ADC LRCLK
  */
+#define WM8958_AIF1_LRCLK_INV                   0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_MASK              0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_SHIFT                 12  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_WIDTH                  1  /* AIF1_LRCLK_INV */
 #define WM8994_AIF1ADC_LRCLK_DIR                0x0800  /* AIF1ADC_LRCLK_DIR */
 #define WM8994_AIF1ADC_LRCLK_DIR_MASK           0x0800  /* AIF1ADC_LRCLK_DIR */
 #define WM8994_AIF1ADC_LRCLK_DIR_SHIFT              11  /* AIF1ADC_LRCLK_DIR */
 /*
  * R773 (0x305) - AIF1DAC LRCLK
  */
+#define WM8958_AIF1_LRCLK_INV                   0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_MASK              0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_SHIFT                 12  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_WIDTH                  1  /* AIF1_LRCLK_INV */
 #define WM8994_AIF1DAC_LRCLK_DIR                0x0800  /* AIF1DAC_LRCLK_DIR */
 #define WM8994_AIF1DAC_LRCLK_DIR_MASK           0x0800  /* AIF1DAC_LRCLK_DIR */
 #define WM8994_AIF1DAC_LRCLK_DIR_SHIFT              11  /* AIF1DAC_LRCLK_DIR */
diff --git a/include/linux/platform_data/ssm2518.h b/include/linux/platform_data/ssm2518.h
new file mode 100644 (file)
index 0000000..9a8e3ea
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_SSM2518_H__
+#define __LINUX_PLATFORM_DATA_SSM2518_H__
+
+/**
+ * struct ssm2518_platform_data - Platform data for the ssm2518 driver
+ * @enable_gpio: GPIO connected to the nSD pin. Set to -1 if the nSD pin is
+ *            hardwired.
+ */
+struct ssm2518_platform_data {
+       int enable_gpio;
+};
+
+#endif
index 34bc93d..5358892 100644 (file)
@@ -233,7 +233,8 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
 int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,
                             void (*hook)(void *private_data, int),
                             void *private_data);
-void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kctl);
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);
+#define snd_ctl_sync_vmaster_hook(kctl)        snd_ctl_sync_vmaster(kctl, true)
 
 /*
  * Helper functions for jack-detection controls
index 5bfe513..c586617 100644 (file)
@@ -30,7 +30,7 @@
 
 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-#define SNDRV_CARDS 32
+#define SNDRV_CARDS CONFIG_SND_MAX_CARDS
 #else
 #define SNDRV_CARDS 8          /* don't change - minor numbers */
 #endif
index b48792f..84b10f9 100644 (file)
@@ -384,7 +384,7 @@ struct snd_pcm_substream {
        unsigned int dma_buf_id;
        size_t dma_max;
        /* -- hardware operations -- */
-       struct snd_pcm_ops *ops;
+       const struct snd_pcm_ops *ops;
        /* -- runtime information -- */
        struct snd_pcm_runtime *runtime;
         /* -- timer section -- */
@@ -871,7 +871,8 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
 snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian);
 
-void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, struct snd_pcm_ops *ops);
+void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
+                    const struct snd_pcm_ops *ops);
 void snd_pcm_set_sync(struct snd_pcm_substream *substream);
 int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
diff --git a/include/sound/rt5640.h b/include/sound/rt5640.h
new file mode 100644 (file)
index 0000000..27cc75e
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * linux/sound/rt5640.h -- Platform data for RT5640
+ *
+ * Copyright 2011 Realtek Microelectronics
+ *
+ * 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 __LINUX_SND_RT5640_H
+#define __LINUX_SND_RT5640_H
+
+struct rt5640_platform_data {
+       /* IN1 & IN2 can optionally be differential */
+       bool in1_diff;
+       bool in2_diff;
+
+       int ldo1_en; /* GPIO for LDO1_EN */
+};
+
+#endif
index 385c632..3e479f4 100644 (file)
@@ -311,6 +311,8 @@ struct device;
 #define SND_SOC_DAPM_POST_PMD  0x8             /* after widget power down */
 #define SND_SOC_DAPM_PRE_REG   0x10    /* before audio path setup */
 #define SND_SOC_DAPM_POST_REG  0x20    /* after audio path setup */
+#define SND_SOC_DAPM_WILL_PMU   0x40    /* called at start of sequence */
+#define SND_SOC_DAPM_WILL_PMD   0x80    /* called at start of sequence */
 #define SND_SOC_DAPM_PRE_POST_PMD \
                                (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
 
@@ -479,7 +481,6 @@ struct snd_soc_dapm_route {
 /* dapm audio path between two widgets */
 struct snd_soc_dapm_path {
        const char *name;
-       const char *long_name;
 
        /* source (input) and sink (output) widgets */
        struct snd_soc_dapm_widget *source;
index e3983d5..041203f 100644 (file)
@@ -817,6 +817,8 @@ typedef int __bitwise snd_ctl_elem_iface_t;
 #define SNDRV_CTL_POWER_D3hot          (SNDRV_CTL_POWER_D3|0x0000)     /* Off, with power */
 #define SNDRV_CTL_POWER_D3cold         (SNDRV_CTL_POWER_D3|0x0001)     /* Off, without power */
 
+#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN  44
+
 struct snd_ctl_elem_id {
        unsigned int numid;             /* numeric identifier, zero = invalid */
        snd_ctl_elem_iface_t iface;     /* interface identifier */
index aa5d803..1ca8dc2 100644 (file)
@@ -1076,8 +1076,6 @@ static int aaci_remove(struct amba_device *dev)
 {
        struct snd_card *card = amba_get_drvdata(dev);
 
-       amba_set_drvdata(dev, NULL);
-
        if (card) {
                struct aaci *aaci = card->private_data;
                writel(0, aaci->base + AACI_MAINCR);
index ec54be4..ce431e6 100644 (file)
@@ -230,7 +230,6 @@ static int pxa2xx_ac97_remove(struct platform_device *dev)
 
        if (card) {
                snd_card_free(card);
-               platform_set_drvdata(dev, NULL);
                pxa2xx_ac97_hw_remove(dev);
        }
 
index b413ed0..c0c2f57 100644 (file)
@@ -157,6 +157,15 @@ config SND_DYNAMIC_MINORS
 
          If you are unsure about this, say N here.
 
+config SND_MAX_CARDS
+       int "Max number of sound cards"
+       range 4 256
+       default 32
+       depends on SND_DYNAMIC_MINORS
+       help
+         Specify the max number of sound cards that can be assigned
+         on a single machine.
+
 config SND_SUPPORT_OLD_API
        bool "Support old ALSA API"
        default y
index 6ef0640..6b90871 100644 (file)
@@ -46,7 +46,8 @@ static LIST_HEAD(shutdown_files);
 
 static const struct file_operations snd_shutdown_f_ops;
 
-static unsigned int snd_cards_lock;    /* locked for registering/using */
+/* locked for registering/using */
+static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
 struct snd_card *snd_cards[SNDRV_CARDS];
 EXPORT_SYMBOL(snd_cards);
 
@@ -167,29 +168,35 @@ int snd_card_create(int idx, const char *xid,
        err = 0;
        mutex_lock(&snd_card_mutex);
        if (idx < 0) {
-               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
                        /* idx == -1 == 0xffff means: take any free slot */
-                       if (~snd_cards_lock & idx & 1<<idx2) {
+                       if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+                               continue;
+                       if (!test_bit(idx2, snd_cards_lock)) {
                                if (module_slot_match(module, idx2)) {
                                        idx = idx2;
                                        break;
                                }
                        }
+               }
        }
        if (idx < 0) {
-               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
                        /* idx == -1 == 0xffff means: take any free slot */
-                       if (~snd_cards_lock & idx & 1<<idx2) {
+                       if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+                               continue;
+                       if (!test_bit(idx2, snd_cards_lock)) {
                                if (!slots[idx2] || !*slots[idx2]) {
                                        idx = idx2;
                                        break;
                                }
                        }
+               }
        }
        if (idx < 0)
                err = -ENODEV;
        else if (idx < snd_ecards_limit) {
-               if (snd_cards_lock & (1 << idx))
+               if (test_bit(idx, snd_cards_lock))
                        err = -EBUSY;   /* invalid */
        } else if (idx >= SNDRV_CARDS)
                err = -ENODEV;
@@ -199,7 +206,7 @@ int snd_card_create(int idx, const char *xid,
                         idx, snd_ecards_limit - 1, err);
                goto __error;
        }
-       snd_cards_lock |= 1 << idx;             /* lock it */
+       set_bit(idx, snd_cards_lock);           /* lock it */
        if (idx >= snd_ecards_limit)
                snd_ecards_limit = idx + 1; /* increase the limit */
        mutex_unlock(&snd_card_mutex);
@@ -249,7 +256,7 @@ int snd_card_locked(int card)
        int locked;
 
        mutex_lock(&snd_card_mutex);
-       locked = snd_cards_lock & (1 << card);
+       locked = test_bit(card, snd_cards_lock);
        mutex_unlock(&snd_card_mutex);
        return locked;
 }
@@ -361,7 +368,7 @@ int snd_card_disconnect(struct snd_card *card)
        /* phase 1: disable fops (user space) operations for ALSA API */
        mutex_lock(&snd_card_mutex);
        snd_cards[card->number] = NULL;
-       snd_cards_lock &= ~(1 << card->number);
+       clear_bit(card->number, snd_cards_lock);
        mutex_unlock(&snd_card_mutex);
        
        /* phase 2: replace file->f_op with special dummy operations */
@@ -549,7 +556,6 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
                                    const char *nid)
 {
        int len, loops;
-       bool with_suffix;
        bool is_default = false;
        char *id;
        
@@ -565,26 +571,23 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
                is_default = true;
        }
 
-       with_suffix = false;
+       len = strlen(id);
        for (loops = 0; loops < SNDRV_CARDS; loops++) {
+               char *spos;
+               char sfxstr[5]; /* "_012" */
+               int sfxlen;
+
                if (card_id_ok(card, id))
                        return; /* OK */
 
-               len = strlen(id);
-               if (!with_suffix) {
-                       /* add the "_X" suffix */
-                       char *spos = id + len;
-                       if (len >  sizeof(card->id) - 3)
-                               spos = id + sizeof(card->id) - 3;
-                       strcpy(spos, "_1");
-                       with_suffix = true;
-               } else {
-                       /* modify the existing suffix */
-                       if (id[len - 1] != '9')
-                               id[len - 1]++;
-                       else
-                               id[len - 1] = 'A';
-               }
+               /* Add _XYZ suffix */
+               sprintf(sfxstr, "_%X", loops + 1);
+               sfxlen = strlen(sfxstr);
+               if (len + sfxlen >= sizeof(card->id))
+                       spos = id + sizeof(card->id) - sfxlen - 1;
+               else
+                       spos = id + len;
+               strcpy(spos, sfxstr);
        }
        /* fallback to the default id */
        if (!is_default) {
index 41b3dfe..82bb029 100644 (file)
@@ -568,7 +568,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
  *
  * Sets the given PCM operators to the pcm instance.
  */
-void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
+void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
+                    const struct snd_pcm_ops *ops)
 {
        struct snd_pcm_str *stream = &pcm->streams[direction];
        struct snd_pcm_substream *substream;
index 02f90b4..5df8dc2 100644 (file)
@@ -310,20 +310,10 @@ static int master_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int master_put(struct snd_kcontrol *kcontrol,
-                     struct snd_ctl_elem_value *ucontrol)
+static int sync_slaves(struct link_master *master, int old_val, int new_val)
 {
-       struct link_master *master = snd_kcontrol_chip(kcontrol);
        struct link_slave *slave;
        struct snd_ctl_elem_value *uval;
-       int err, old_val;
-
-       err = master_init(master);
-       if (err < 0)
-               return err;
-       old_val = master->val;
-       if (ucontrol->value.integer.value[0] == old_val)
-               return 0;
 
        uval = kmalloc(sizeof(*uval), GFP_KERNEL);
        if (!uval)
@@ -332,11 +322,33 @@ static int master_put(struct snd_kcontrol *kcontrol,
                master->val = old_val;
                uval->id = slave->slave.id;
                slave_get_val(slave, uval);
-               master->val = ucontrol->value.integer.value[0];
+               master->val = new_val;
                slave_put_val(slave, uval);
        }
        kfree(uval);
-       if (master->hook && !err)
+       return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct link_master *master = snd_kcontrol_chip(kcontrol);
+       int err, new_val, old_val;
+       bool first_init;
+
+       err = master_init(master);
+       if (err < 0)
+               return err;
+       first_init = err;
+       old_val = master->val;
+       new_val = ucontrol->value.integer.value[0];
+       if (new_val == old_val)
+               return 0;
+
+       err = sync_slaves(master, old_val, new_val);
+       if (err < 0)
+               return err;
+       if (master->hook && first_init)
                master->hook(master->hook_private_data, master->val);
        return 1;
 }
@@ -442,20 +454,33 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
 EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
 
 /**
- * snd_ctl_sync_vmaster_hook - Sync the vmaster hook
+ * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
  * @kcontrol: vmaster kctl element
+ * @hook_only: sync only the hook
  *
- * Call the hook function to synchronize with the current value of the given
- * vmaster element.  NOP when NULL is passed to @kcontrol or the hook doesn't
- * exist.
+ * Forcibly call the put callback of each slave and call the hook function
+ * to synchronize with the current value of the given vmaster element.
+ * NOP when NULL is passed to @kcontrol.
  */
-void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol)
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
 {
        struct link_master *master;
+       bool first_init = false;
+
        if (!kcontrol)
                return;
        master = snd_kcontrol_chip(kcontrol);
-       if (master->hook)
+       if (!hook_only) {
+               int err = master_init(master);
+               if (err < 0)
+                       return;
+               first_init = err;
+               err = sync_slaves(master, master->val, master->val);
+               if (err < 0)
+                       return;
+       }
+
+       if (master->hook && !first_init)
                master->hook(master->hook_private_data, master->val);
 }
-EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook);
+EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
index 6f78de9..f758992 100644 (file)
@@ -1183,7 +1183,6 @@ static int loopback_probe(struct platform_device *devptr)
 static int loopback_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index fd798f7..11048cc 100644 (file)
@@ -1129,7 +1129,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
 static int snd_dummy_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 8125a7e..95ea4a1 100644 (file)
@@ -1325,7 +1325,6 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
 static int snd_ml403_ac97cr_remove(struct platform_device *pfdev)
 {
        snd_card_free(platform_get_drvdata(pfdev));
-       platform_set_drvdata(pfdev, NULL);
        return 0;
 }
 
index da1a29b..90a3a7b 100644 (file)
@@ -129,7 +129,6 @@ static int snd_mpu401_probe(struct platform_device *devptr)
 static int snd_mpu401_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 9f1815b..e5ec7eb 100644 (file)
@@ -749,7 +749,6 @@ static int snd_mtpav_probe(struct platform_device *dev)
 static int snd_mtpav_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 7a5fdb9..1c19cd7 100644 (file)
@@ -189,7 +189,6 @@ static int pcsp_remove(struct platform_device *dev)
        struct snd_pcsp *chip = platform_get_drvdata(dev);
        alsa_card_pcsp_exit(chip);
        pcspkr_input_remove(chip->input_dev);
-       platform_set_drvdata(dev, NULL);
        return 0;
 }
 
index 7425dd8..e0bf5e7 100644 (file)
@@ -985,7 +985,6 @@ static int snd_serial_probe(struct platform_device *devptr)
 static int snd_serial_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index cc4be88..ace3879 100644 (file)
@@ -132,7 +132,6 @@ static int snd_virmidi_probe(struct platform_device *devptr)
 static int snd_virmidi_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index c39961c..8359689 100644 (file)
@@ -205,7 +205,7 @@ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
 
        if (size < 1)
                return 0;
-       if (snd_BUG_ON(size > SIZE_MAX_STATUS))
+       if (snd_BUG_ON(size >= SIZE_MAX_STATUS))
                return -EINVAL;
 
        for (i = 1; i <= size; i++) {
index b680c5e..f6103d6 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
-#include <linux/spinlock.h>
 #include "packets-buffer.h"
 
 /**
index 844a555..b252c21 100644 (file)
@@ -405,8 +405,10 @@ static int scs_probe(struct device *unit_dev)
        scs->output_idle = true;
 
        scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL);
-       if (!scs->buffer)
+       if (!scs->buffer) {
+               err = -ENOMEM;
                goto err_card;
+       }
 
        scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
        scs->hss_handler.address_callback = handle_hss;
index cef813d..ed726d1 100644 (file)
@@ -571,7 +571,7 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
        struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
        int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
        const char **input_names;
-       int  num_names, idx;
+       unsigned int num_names, idx;
 
        num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
        if (!num_names)
index c214ecf..e3f455b 100644 (file)
@@ -135,7 +135,6 @@ out:        snd_card_free(card);
 static int snd_ad1848_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index d265455..3565921 100644 (file)
@@ -101,7 +101,6 @@ out:        snd_card_free(card);
 static int snd_adlib_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index a7369fe..f84f073 100644 (file)
@@ -418,7 +418,6 @@ static int snd_cmi8328_remove(struct device *pdev, unsigned int dev)
        snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
        snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
        snd_card_free(card);
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index c707c52..270b965 100644 (file)
@@ -651,7 +651,6 @@ static int snd_cmi8330_isa_remove(struct device *devptr,
                                  unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index aa7a5d8..ba9a74e 100644 (file)
@@ -151,7 +151,6 @@ out:        snd_card_free(card);
 static int snd_cs4231_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 252e9fb..69614ac 100644 (file)
@@ -504,7 +504,6 @@ static int snd_cs423x_isa_remove(struct device *pdev,
                                 unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
@@ -600,7 +599,6 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
 static void snd_cs423x_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
-       pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
index 102874a..cdcfb57 100644 (file)
@@ -213,7 +213,6 @@ out:
 static int snd_es1688_isa_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 24380ef..12978b8 100644 (file)
@@ -2235,7 +2235,6 @@ static int snd_es18xx_isa_remove(struct device *devptr,
                                 unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
@@ -2305,7 +2304,6 @@ static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
 static void snd_audiodrive_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
-       pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
index 672184e..81244e7 100644 (file)
@@ -623,7 +623,6 @@ error:
 static int snd_galaxy_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 16bca4e..1adc1b9 100644 (file)
@@ -215,7 +215,6 @@ out:        snd_card_free(card);
 static int snd_gusclassic_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 0b9c242..38e1e32 100644 (file)
@@ -344,7 +344,6 @@ out:        snd_card_free(card);
 static int snd_gusextreme_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index c309a5d..652d5d8 100644 (file)
@@ -357,7 +357,6 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
 static int snd_gusmax_remove(struct device *devptr, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 78bc574..9942691 100644 (file)
@@ -849,7 +849,6 @@ static int snd_interwave_isa_probe(struct device *pdev,
 static int snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index ddabb40..81aeb93 100644 (file)
@@ -1064,7 +1064,6 @@ cfg_error:
 static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
 {
        snd_msnd_unload(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 075777a..cc01c41 100644 (file)
@@ -757,7 +757,6 @@ static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
 static void snd_opl3sa2_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
-       pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
@@ -900,7 +899,6 @@ static int snd_opl3sa2_isa_remove(struct device *devptr,
                                  unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index c3da1df..619753d 100644 (file)
@@ -1495,7 +1495,6 @@ static int snd_miro_isa_remove(struct device *devptr,
                               unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index b41ed86..103b333 100644 (file)
@@ -1035,7 +1035,6 @@ static int snd_opti9xx_isa_remove(struct device *devptr,
                                  unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 4961da4..356a630 100644 (file)
@@ -345,7 +345,6 @@ static int snd_jazz16_remove(struct device *devptr, unsigned int dev)
 {
        struct snd_card *card = dev_get_drvdata(devptr);
 
-       dev_set_drvdata(devptr, NULL);
        snd_card_free(card);
        return 0;
 }
index 50dbec4..a413099 100644 (file)
@@ -566,7 +566,6 @@ static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
 static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 237d964..a806ae9 100644 (file)
@@ -208,7 +208,6 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
 static int snd_sb8_remove(struct device *pdev, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 5376ebf..09d481b 100644 (file)
@@ -698,7 +698,6 @@ static int snd_sc6000_remove(struct device *devptr, unsigned int dev)
        release_region(port[dev], 0x10);
        release_region(mss_port[dev], 4);
 
-       dev_set_drvdata(devptr, NULL);
        snd_card_free(card);
        return 0;
 }
index 42a0097..57b3389 100644 (file)
@@ -1200,7 +1200,6 @@ _release_card:
 static int snd_sscape_remove(struct device *devptr, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index fe5dd98..82dd769 100644 (file)
@@ -581,7 +581,6 @@ static int snd_wavefront_isa_remove(struct device *devptr,
                                    unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 2a44cc1..12be1fb 100644 (file)
@@ -178,7 +178,6 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
 err_out_free:
-       pci_set_drvdata(pdev, NULL);
        kfree(hw_config);
        return 1;
 }
@@ -187,7 +186,6 @@ static void remove_one(struct pci_dev *pdev)
 {
        struct address_info *hw_config = pci_get_drvdata(pdev);
        sb_dsp_unload(hw_config, 0);
-       pci_set_drvdata(pdev, NULL);
        kfree(hw_config);
 }
 
index 0e66ba4..67f56a2 100644 (file)
@@ -902,8 +902,6 @@ snd_harmony_free(struct snd_harmony *h)
        if (h->iobase)
                iounmap(h->iobase);
 
-       parisc_set_drvdata(h->dev, NULL);
-
        kfree(h);
        return 0;
 }
@@ -1016,7 +1014,6 @@ static int
 snd_harmony_remove(struct parisc_device *padev)
 {
        snd_card_free(parisc_get_drvdata(padev));
-       parisc_set_drvdata(padev, NULL);
        return 0;
 }
 
index d37c683..445ca48 100644 (file)
@@ -1296,7 +1296,7 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
                                    struct snd_ac97 *ac97)
 {
        int err;
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        unsigned char lo_max, hi_max;
 
        if (! snd_ac97_valid_reg(ac97, reg))
index ad8a311..d2b9d61 100644 (file)
@@ -1046,7 +1046,6 @@ static void
 snd_ad1889_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
index 53754f5..3dfa12b 100644 (file)
@@ -2298,7 +2298,6 @@ static int snd_ali_probe(struct pci_dev *pci,
 static void snd_ali_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ali5451_driver = {
index 864c431..591efb6 100644 (file)
@@ -282,7 +282,6 @@ static void snd_als300_remove(struct pci_dev *pci)
 {
        snd_als300_dbgcallenter();
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
        snd_als300_dbgcallleave();
 }
 
index 61efda2..ffc821b 100644 (file)
@@ -984,7 +984,6 @@ out:
 static void snd_card_als4000_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index fbc1720..185d54a 100644 (file)
@@ -1278,7 +1278,7 @@ struct hpi_control {
        u16 dst_node_type;
        u16 dst_node_index;
        u16 band;
-       char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */
 };
 
 static const char * const asihpi_tuner_band_names[] = {
index ef5019f..7f02720 100644 (file)
@@ -445,7 +445,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
        if (pa->p_buffer)
                vfree(pa->p_buffer);
 
-       pci_set_drvdata(pci_dev, NULL);
        if (1)
                dev_info(&pci_dev->dev,
                         "remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n",
index 6e78c67..fe4c61b 100644 (file)
@@ -1714,7 +1714,6 @@ static int snd_atiixp_probe(struct pci_dev *pci,
 static void snd_atiixp_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver atiixp_driver = {
index d0bec7b..cf29b9a 100644 (file)
@@ -1334,7 +1334,6 @@ static int snd_atiixp_probe(struct pci_dev *pci,
 static void snd_atiixp_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver atiixp_modem_driver = {
index b157e1f..7059dd6 100644 (file)
@@ -371,7 +371,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_vortex_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 // pci_driver definition
index 08e9a47..2925220 100644 (file)
@@ -392,7 +392,6 @@ static int snd_aw2_probe(struct pci_dev *pci,
 static void snd_aw2_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /* open callback */
index 1204a0f..c8e1216 100644 (file)
@@ -2725,7 +2725,6 @@ snd_azf3328_remove(struct pci_dev *pci)
 {
        snd_azf3328_dbgcallenter();
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
        snd_azf3328_dbgcallleave();
 }
 
index 9febe55..1880203 100644 (file)
@@ -953,7 +953,6 @@ _error:
 static void snd_bt87x_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /* default entries for all Bt87x cards - it's not exported */
index 1610a57..f4db558 100644 (file)
@@ -1896,7 +1896,6 @@ static int snd_ca0106_probe(struct pci_dev *pci,
 static void snd_ca0106_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index c617435..2755ec5 100644 (file)
@@ -3317,7 +3317,6 @@ static int snd_cmipci_probe(struct pci_dev *pci,
 static void snd_cmipci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index 6a86950..1dc793e 100644 (file)
@@ -1312,7 +1312,7 @@ static int snd_cs4281_free(struct cs4281 *chip)
        /* Sound System Power Management - Turn Everything OFF */
        snd_cs4281_pokeBA0(chip, BA0_SSPM, 0);
        /* PCI interface - D3 state */
-       pci_set_power_state(chip->pci, 3);
+       pci_set_power_state(chip->pci, PCI_D3hot);
 
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
@@ -1971,7 +1971,6 @@ static int snd_cs4281_probe(struct pci_dev *pci,
 static void snd_cs4281_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /*
index 6b0d8b5..b034983 100644 (file)
@@ -158,7 +158,6 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
 static void snd_card_cs46xx_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver cs46xx_driver = {
index dace827..c6b82c8 100644 (file)
@@ -91,7 +91,6 @@ static int snd_cs5530_dev_free(struct snd_device *device)
 static void snd_cs5530_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
index 7e4b13e..902bebd 100644 (file)
@@ -391,7 +391,6 @@ static void snd_cs5535audio_remove(struct pci_dev *pci)
 {
        olpc_quirks_cleanup();
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver cs5535audio_driver = {
index d01ffcb..d464ad2 100644 (file)
@@ -122,7 +122,6 @@ error:
 static void ct_card_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 760cbff..05cfe55 100644 (file)
@@ -2323,7 +2323,6 @@ static void snd_echo_remove(struct pci_dev *pci)
        chip = pci_get_drvdata(pci);
        if (chip)
                snd_card_free(chip->card);
-       pci_set_drvdata(pci, NULL);
 }
 
 
index 8c5010f..9e1bd0c 100644 (file)
@@ -202,7 +202,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
 static void snd_card_emu10k1_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index cdff11d..56ad9d6 100644 (file)
@@ -1623,7 +1623,6 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
 static void snd_emu10k1x_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 // PCI IDs
index db2dc83..ca8929b 100644 (file)
@@ -1939,7 +1939,7 @@ static int snd_ensoniq_free(struct ensoniq *ensoniq)
 #endif
        if (ensoniq->irq >= 0)
                synchronize_irq(ensoniq->irq);
-       pci_set_power_state(ensoniq->pci, 3);
+       pci_set_power_state(ensoniq->pci, PCI_D3hot);
       __hw_end:
 #ifdef CHIP1370
        if (ensoniq->dma_bug.area)
@@ -2497,7 +2497,6 @@ static int snd_audiopci_probe(struct pci_dev *pci,
 static void snd_audiopci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ens137x_driver = {
index 8423403..9213fb3 100644 (file)
@@ -1881,7 +1881,6 @@ static int snd_es1938_probe(struct pci_dev *pci,
 static void snd_es1938_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver es1938_driver = {
index a1f32b5..5e2ec96 100644 (file)
@@ -564,6 +564,7 @@ struct es1968 {
 #ifdef CONFIG_SND_ES1968_RADIO
        struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
+       unsigned int tea575x_tuner;
 #endif
 };
 
@@ -2557,37 +2558,47 @@ static int snd_es1968_input_register(struct es1968 *chip)
                                bits 1=unmask write to given bit */
 #define IO_DIR         8      /* direction register offset from GPIO_DATA
                                bits 0/1=read/write direction */
-/* mask bits for GPIO lines */
-#define STR_DATA       0x0040 /* GPIO6 */
-#define STR_CLK                0x0080 /* GPIO7 */
-#define STR_WREN       0x0100 /* GPIO8 */
-#define STR_MOST       0x0200 /* GPIO9 */
+
+/* GPIO to TEA575x maps */
+struct snd_es1968_tea575x_gpio {
+       u8 data, clk, wren, most;
+       char *name;
+};
+
+static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = {
+       { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" },
+       { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" },
+};
+
+#define get_tea575x_gpio(chip) \
+       (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner])
+
 
 static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
        struct es1968 *chip = tea->private_data;
-       unsigned long io = chip->io_port + GPIO_DATA;
+       struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
        u16 val = 0;
 
-       val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
-       val |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
-       val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+       val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
+       val |= (pins & TEA575X_CLK)  ? (1 << gpio.clk)  : 0;
+       val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;
 
-       outw(val, io);
+       outw(val, chip->io_port + GPIO_DATA);
 }
 
 static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
 {
        struct es1968 *chip = tea->private_data;
-       unsigned long io = chip->io_port + GPIO_DATA;
-       u16 val = inw(io);
-       u8 ret;
+       struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
+       u16 val = inw(chip->io_port + GPIO_DATA);
+       u8 ret = 0;
 
-       ret = 0;
-       if (val & STR_DATA)
+       if (val & (1 << gpio.data))
                ret |= TEA575X_DATA;
-       if (val & STR_MOST)
+       if (val & (1 << gpio.most))
                ret |= TEA575X_MOST;
+
        return ret;
 }
 
@@ -2596,13 +2607,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
        struct es1968 *chip = tea->private_data;
        unsigned long io = chip->io_port + GPIO_DATA;
        u16 odir = inw(io + IO_DIR);
+       struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
 
        if (output) {
-               outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
-               outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+               outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)),
+                       io + IO_MASK);
+               outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren),
+                       io + IO_DIR);
        } else {
-               outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
-               outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+               outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)),
+                       io + IO_MASK);
+               outw((odir & ~((1 << gpio.data) | (1 << gpio.most)))
+                       | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR);
        }
 }
 
@@ -2772,6 +2788,9 @@ static int snd_es1968_create(struct snd_card *card,
        snd_card_set_dev(card, &pci->dev);
 
 #ifdef CONFIG_SND_ES1968_RADIO
+       /* don't play with GPIOs on laptops */
+       if (chip->pci->subsystem_vendor != 0x125d)
+               goto no_radio;
        err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
        if (err < 0) {
                snd_es1968_free(chip);
@@ -2781,10 +2800,18 @@ static int snd_es1968_create(struct snd_card *card,
        chip->tea.private_data = chip;
        chip->tea.radio_nr = radio_nr;
        chip->tea.ops = &snd_es1968_tea_ops;
-       strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
        sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
-       if (!snd_tea575x_init(&chip->tea, THIS_MODULE))
-               printk(KERN_INFO "es1968: detected TEA575x radio\n");
+       for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) {
+               chip->tea575x_tuner = i;
+               if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
+                       snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n",
+                                  get_tea575x_gpio(chip)->name);
+                       strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
+                               sizeof(chip->tea.card));
+                       break;
+               }
+       }
+no_radio:
 #endif
 
        *chip_ret = chip;
@@ -2909,7 +2936,6 @@ static int snd_es1968_probe(struct pci_dev *pci,
 static void snd_es1968_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver es1968_driver = {
index 4f07fda..706c5b6 100644 (file)
@@ -1370,7 +1370,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
 static void snd_card_fm801_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 80a7d44..0c5371a 100644 (file)
@@ -140,7 +140,6 @@ config SND_HDA_CODEC_VIA
 
 config SND_HDA_CODEC_HDMI
        bool "Build HDMI/DisplayPort HD-audio codec support"
-       select SND_DYNAMIC_MINORS
        default y
        help
          Say Y here to include HDMI and DisplayPort HD-audio codec
index 55108b5..35090b3 100644 (file)
@@ -185,20 +185,19 @@ EXPORT_SYMBOL_HDA(snd_hda_get_jack_type);
  * Compose a 32bit command word to be sent to the HD-audio controller
  */
 static inline unsigned int
-make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
               unsigned int verb, unsigned int parm)
 {
        u32 val;
 
-       if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
+       if ((codec->addr & ~0xf) || (nid & ~0x7f) ||
            (verb & ~0xfff) || (parm & ~0xffff)) {
-               printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
-                      codec->addr, direct, nid, verb, parm);
+               printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x\n",
+                      codec->addr, nid, verb, parm);
                return ~0;
        }
 
        val = (u32)codec->addr << 28;
-       val |= (u32)direct << 27;
        val |= (u32)nid << 20;
        val |= verb << 8;
        val |= parm;
@@ -209,7 +208,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
  * Send and receive a verb
  */
 static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
-                          unsigned int *res)
+                          int flags, unsigned int *res)
 {
        struct hda_bus *bus = codec->bus;
        int err;
@@ -222,6 +221,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  again:
        snd_hda_power_up(codec);
        mutex_lock(&bus->cmd_mutex);
+       if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
+               bus->no_response_fallback = 1;
        for (;;) {
                trace_hda_send_cmd(codec, cmd);
                err = bus->ops.command(bus, cmd);
@@ -234,6 +235,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
                *res = bus->ops.get_response(bus, codec->addr);
                trace_hda_get_response(codec, *res);
        }
+       bus->no_response_fallback = 0;
        mutex_unlock(&bus->cmd_mutex);
        snd_hda_power_down(codec);
        if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
@@ -255,7 +257,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  * snd_hda_codec_read - send a command and get the response
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -264,12 +266,12 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  * Returns the obtained response value, or -1 for an error.
  */
 unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
-                               int direct,
+                               int flags,
                                unsigned int verb, unsigned int parm)
 {
-       unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+       unsigned cmd = make_codec_cmd(codec, nid, flags, verb, parm);
        unsigned int res;
-       if (codec_exec_verb(codec, cmd, &res))
+       if (codec_exec_verb(codec, cmd, flags, &res))
                return -1;
        return res;
 }
@@ -279,7 +281,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
  * snd_hda_codec_write - send a single command without waiting for response
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -287,12 +289,12 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
-                        unsigned int verb, unsigned int parm)
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
+                       unsigned int verb, unsigned int parm)
 {
-       unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+       unsigned int cmd = make_codec_cmd(codec, nid, flags, verb, parm);
        unsigned int res;
-       return codec_exec_verb(codec, cmd,
+       return codec_exec_verb(codec, cmd, flags,
                               codec->bus->sync_write ? &res : NULL);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write);
@@ -3582,7 +3584,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
  * snd_hda_codec_write_cache - send a single command with caching
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -3591,7 +3593,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
-                             int direct, unsigned int verb, unsigned int parm)
+                             int flags, unsigned int verb, unsigned int parm)
 {
        int err;
        struct hda_cache_head *c;
@@ -3600,7 +3602,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 
        cache_only = codec->cached_write;
        if (!cache_only) {
-               err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+               err = snd_hda_codec_write(codec, nid, flags, verb, parm);
                if (err < 0)
                        return err;
        }
@@ -3624,7 +3626,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
  * snd_hda_codec_update_cache - check cache and write the cmd only when needed
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -3635,7 +3637,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
-                              int direct, unsigned int verb, unsigned int parm)
+                              int flags, unsigned int verb, unsigned int parm)
 {
        struct hda_cache_head *c;
        u32 key;
@@ -3651,7 +3653,7 @@ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
                return 0;
        }
        mutex_unlock(&codec->bus->cmd_mutex);
-       return snd_hda_codec_write_cache(codec, nid, direct, verb, parm);
+       return snd_hda_codec_write_cache(codec, nid, flags, verb, parm);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
 
@@ -3806,11 +3808,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
        hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
        int count;
        unsigned int state;
+       int flags = 0;
 
        /* this delay seems necessary to avoid click noise at power-down */
        if (power_state == AC_PWRST_D3) {
                /* transition time less than 10ms for power down */
                msleep(codec->epss ? 10 : 100);
+               flags = HDA_RW_NO_RESPONSE_FALLBACK;
        }
 
        /* repeat power states setting at most 10 times*/
@@ -3819,7 +3823,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
                        codec->patch_ops.set_power_state(codec, fg,
                                                         power_state);
                else {
-                       snd_hda_codec_read(codec, fg, 0,
+                       snd_hda_codec_read(codec, fg, flags,
                                           AC_VERB_SET_POWER_STATE,
                                           power_state);
                        snd_hda_codec_set_power_to_all(codec, fg, power_state);
@@ -4461,12 +4465,13 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
 
 /*
  * get the empty PCM device number to assign
- *
- * note the max device number is limited by HDA_MAX_PCMS, currently 10
  */
-static int get_empty_pcm_device(struct hda_bus *bus, int type)
+static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
 {
        /* audio device indices; not linear to keep compatibility */
+       /* assigned to static slots up to dev#10; if more needed, assign
+        * the later slot dynamically (when CONFIG_SND_DYNAMIC_MINORS=y)
+        */
        static int audio_idx[HDA_PCM_NTYPES][5] = {
                [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 },
                [HDA_PCM_TYPE_SPDIF] = { 1, -1 },
@@ -4480,18 +4485,28 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                return -EINVAL;
        }
 
-       for (i = 0; audio_idx[type][i] >= 0 ; i++)
+       for (i = 0; audio_idx[type][i] >= 0; i++) {
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+               if (audio_idx[type][i] >= 8)
+                       break;
+#endif
                if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
                        return audio_idx[type][i];
+       }
 
+#ifdef CONFIG_SND_DYNAMIC_MINORS
        /* non-fixed slots starting from 10 */
        for (i = 10; i < 32; i++) {
                if (!test_and_set_bit(i, bus->pcm_dev_bits))
                        return i;
        }
+#endif
 
        snd_printk(KERN_WARNING "Too many %s devices\n",
                snd_hda_pcm_type_name[type]);
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+       snd_printk(KERN_WARNING "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
+#endif
        return -EAGAIN;
 }
 
index c93f902..701c2e0 100644 (file)
@@ -679,6 +679,7 @@ struct hda_bus {
        unsigned int response_reset:1;  /* controller was reset */
        unsigned int in_reset:1;        /* during reset operation */
        unsigned int power_keep_link_on:1; /* don't power off HDA link */
+       unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
 
        int primary_dig_out_type;       /* primary digital out PCM type */
 };
@@ -930,6 +931,8 @@ enum {
        HDA_INPUT, HDA_OUTPUT
 };
 
+/* snd_hda_codec_read/write optional flags */
+#define HDA_RW_NO_RESPONSE_FALLBACK    (1 << 0)
 
 /*
  * constructors
@@ -945,9 +948,9 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec);
  * low level functions
  */
 unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
-                               int direct,
+                               int flags,
                                unsigned int verb, unsigned int parm);
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
                        unsigned int verb, unsigned int parm);
 #define snd_hda_param_read(codec, nid, param) \
        snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param)
@@ -986,11 +989,11 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
 
 /* cached write */
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
-                             int direct, unsigned int verb, unsigned int parm);
+                             int flags, unsigned int verb, unsigned int parm);
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
                                  const struct hda_verb *seq);
 int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
-                             int direct, unsigned int verb, unsigned int parm);
+                             int flags, unsigned int verb, unsigned int parm);
 void snd_hda_codec_resume_cache(struct hda_codec *codec);
 /* both for cmd & amp caches */
 void snd_hda_codec_flush_cache(struct hda_codec *codec);
index 4b1524a..8e77cbb 100644 (file)
@@ -133,6 +133,9 @@ static void parse_user_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
        if (val >= 0)
                spec->line_in_auto_switch = !!val;
+       val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
+       if (val >= 0)
+               spec->auto_mute_via_amp = !!val;
        val = snd_hda_get_bool_hint(codec, "need_dac_fix");
        if (val >= 0)
                spec->need_dac_fix = !!val;
@@ -808,6 +811,9 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
  * Helper functions for creating mixer ctl elements
  */
 
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol);
+
 enum {
        HDA_CTL_WIDGET_VOL,
        HDA_CTL_WIDGET_MUTE,
@@ -815,7 +821,15 @@ enum {
 };
 static const struct snd_kcontrol_new control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
-       HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       /* only the put callback is replaced for handling the special mute */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = hda_gen_mixer_mute_put, /* replaced */
+               .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
+       },
        HDA_BIND_MUTE(NULL, 0, 0, 0),
 };
 
@@ -840,7 +854,7 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
                                const char *pfx, const char *dir,
                                const char *sfx, int cidx, unsigned long val)
 {
-       char name[32];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
        if (!add_control(spec, type, name, cidx, val))
                return -ENOMEM;
@@ -922,6 +936,23 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
        return add_sw_ctl(codec, pfx, cidx, chs, path);
 }
 
+/* playback mute control with the software mute bit check */
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->auto_mute_via_amp) {
+               hda_nid_t nid = get_amp_nid(kcontrol);
+               bool enabled = !((spec->mute_bits >> nid) & 1);
+               ucontrol->value.integer.value[0] &= enabled;
+               ucontrol->value.integer.value[1] &= enabled;
+       }
+
+       return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+}
+
 /* any ctl assigned to the path with the given index? */
 static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
 {
@@ -1900,7 +1931,7 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins,
 
        for (i = 0; i < num_pins; i++) {
                const char *name;
-               char tmp[44];
+               char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
                int err, idx = 0;
 
                if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
@@ -2453,7 +2484,7 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
                }
                if (get_out_jack_num_items(codec, pin) > 1) {
                        struct snd_kcontrol_new *knew;
-                       char name[44];
+                       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
                        get_jack_mode_name(codec, pin, name, sizeof(name));
                        knew = snd_hda_gen_add_kctl(spec, name,
                                                    &out_jack_mode_enum);
@@ -2585,7 +2616,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct snd_kcontrol_new *knew;
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        unsigned int defcfg;
 
        if (pin == spec->hp_mic_pin)
@@ -3285,7 +3316,7 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
                              bool inv_dmic)
 {
        struct hda_gen_spec *spec = codec->spec;
-       char tmpname[44];
+       char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
        const char *sfx = is_switch ? "Switch" : "Volume";
        unsigned int chs = inv_dmic ? 1 : 3;
@@ -3547,7 +3578,7 @@ static int parse_mic_boost(struct hda_codec *codec)
                struct nid_path *path;
                unsigned int val;
                int idx;
-               char boost_label[44];
+               char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 
                idx = imux->items[i].index;
                if (idx >= imux->num_items)
@@ -3719,6 +3750,16 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
                unsigned int val, oldval;
                if (!nid)
                        break;
+
+               if (spec->auto_mute_via_amp) {
+                       if (mute)
+                               spec->mute_bits |= (1ULL << nid);
+                       else
+                               spec->mute_bits &= ~(1ULL << nid);
+                       set_pin_eapd(codec, nid, !mute);
+                       continue;
+               }
+
                oldval = snd_hda_codec_get_pin_target(codec, nid);
                if (oldval & PIN_IN)
                        continue; /* no mute for inputs */
@@ -3786,6 +3827,10 @@ static void call_update_outputs(struct hda_codec *codec)
                spec->automute_hook(codec);
        else
                snd_hda_gen_update_outputs(codec);
+
+       /* sync the whole vmaster slaves to reflect the new auto-mute status */
+       if (spec->auto_mute_via_amp && !codec->bus->shutdown)
+               snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
 }
 
 /* standard HP-automute helper */
index 7620031..e199a85 100644 (file)
@@ -209,6 +209,7 @@ struct hda_gen_spec {
        unsigned int master_mute:1;     /* master mute over all */
        unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
        unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
+       unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */
 
        /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
        unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
@@ -237,6 +238,9 @@ struct hda_gen_spec {
        unsigned int have_aamix_ctl:1;
        unsigned int hp_mic_jack_modes:1;
 
+       /* additional mute flags (only effective with auto_mute_via_amp=1) */
+       u64 mute_bits;
+
        /* badness tables for output path evaluations */
        const struct badness_table *main_out_badness;
        const struct badness_table *extra_out_badness;
index de18722..f39de90 100644 (file)
@@ -942,6 +942,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
+       if (!bus->no_response_fallback)
+               return -1;
+
        if (!chip->polling_mode && chip->poll_count < 2) {
                snd_printdd(SFX "%s: azx_get_response timeout, "
                           "polling the codec once: last cmd=0x%08x\n",
@@ -1117,37 +1120,52 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
                                 struct snd_dma_buffer *dmab);
 #endif
 
-/* reset codec link */
-static int azx_reset(struct azx *chip, int full_reset)
+/* enter link reset */
+static void azx_enter_link_reset(struct azx *chip)
 {
        unsigned long timeout;
 
-       if (!full_reset)
-               goto __skip;
-
-       /* clear STATESTS */
-       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
-
        /* reset controller */
        azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
 
        timeout = jiffies + msecs_to_jiffies(100);
-       while (azx_readb(chip, GCTL) &&
+       while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
                        time_before(jiffies, timeout))
                usleep_range(500, 1000);
+}
 
-       /* delay for >= 100us for codec PLL to settle per spec
-        * Rev 0.9 section 5.5.1
-        */
-       usleep_range(500, 1000);
+/* exit link reset */
+static void azx_exit_link_reset(struct azx *chip)
+{
+       unsigned long timeout;
 
-       /* Bring controller out of reset */
        azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
 
        timeout = jiffies + msecs_to_jiffies(100);
        while (!azx_readb(chip, GCTL) &&
                        time_before(jiffies, timeout))
                usleep_range(500, 1000);
+}
+
+/* reset codec link */
+static int azx_reset(struct azx *chip, int full_reset)
+{
+       if (!full_reset)
+               goto __skip;
+
+       /* clear STATESTS */
+       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
+       /* reset controller */
+       azx_enter_link_reset(chip);
+
+       /* delay for >= 100us for codec PLL to settle per spec
+        * Rev 0.9 section 5.5.1
+        */
+       usleep_range(500, 1000);
+
+       /* Bring controller out of reset */
+       azx_exit_link_reset(chip);
 
        /* Brent Chartrand said to wait >= 540us for codecs to initialize */
        usleep_range(1000, 1200);
@@ -2891,6 +2909,7 @@ static int azx_suspend(struct device *dev)
        if (chip->initialized)
                snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
+       azx_enter_link_reset(chip);
        if (chip->irq >= 0) {
                free_irq(chip->irq, chip);
                chip->irq = -1;
@@ -2943,6 +2962,7 @@ static int azx_runtime_suspend(struct device *dev)
        struct azx *chip = card->private_data;
 
        azx_stop_chip(chip);
+       azx_enter_link_reset(chip);
        azx_clear_irq_pending(chip);
        return 0;
 }
@@ -3764,7 +3784,6 @@ static int azx_probe(struct pci_dev *pci,
 
 out_free:
        snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
        return err;
 }
 
@@ -3834,7 +3853,6 @@ static void azx_remove(struct pci_dev *pci)
 
        if (card)
                snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
 }
 
 /* PCI IDs */
@@ -3878,6 +3896,9 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* Oaktrail */
        { PCI_DEVICE(0x8086, 0x080a),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       /* BayTrail */
+       { PCI_DEVICE(0x8086, 0x0f04),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* ICH */
        { PCI_DEVICE(0x8086, 0x2668),
          .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
index 9e0a952..3fd2973 100644 (file)
@@ -398,7 +398,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
                         const char *base_name)
 {
        unsigned int def_conf, conn;
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int idx, err;
        bool phantom_jack;
 
index e0bf753..2e7493e 100644 (file)
@@ -562,6 +562,14 @@ static inline unsigned int get_wcaps_channels(u32 wcaps)
        return chans;
 }
 
+static inline void snd_hda_override_wcaps(struct hda_codec *codec,
+                                         hda_nid_t nid, u32 val)
+{
+       if (nid >= codec->start_nid &&
+           nid < codec->start_nid + codec->num_nodes)
+               codec->wcaps[nid - codec->start_nid] = val;
+}
+
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
@@ -667,7 +675,7 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
        if (state & AC_PWRST_ERROR)
                return true;
        state = (state >> 4) & 0x0f;
-       return (state != target_state);
+       return (state == target_state);
 }
 
 unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
index 0fee8fa..9760f00 100644 (file)
@@ -504,6 +504,8 @@ static void print_conn_list(struct snd_info_buffer *buffer,
                            int conn_len)
 {
        int c, curr = -1;
+       const hda_nid_t *list;
+       int cache_len;
 
        if (conn_len > 1 &&
            wid_type != AC_WID_AUD_MIX &&
@@ -521,6 +523,19 @@ static void print_conn_list(struct snd_info_buffer *buffer,
                }
                snd_iprintf(buffer, "\n");
        }
+
+       /* Get Cache connections info */
+       cache_len = snd_hda_get_conn_list(codec, nid, &list);
+       if (cache_len != conn_len
+                       || memcmp(list, conn, conn_len)) {
+               snd_iprintf(buffer, "  In-driver Connection: %d\n", cache_len);
+               if (cache_len > 0) {
+                       snd_iprintf(buffer, "    ");
+                       for (c = 0; c < cache_len; c++)
+                               snd_iprintf(buffer, " 0x%02x", list[c]);
+                       snd_iprintf(buffer, "\n");
+               }
+       }
 }
 
 static void print_gpio(struct snd_info_buffer *buffer,
index 90ff7a3..6e9876f 100644 (file)
@@ -139,7 +139,7 @@ enum {
 #define DSP_SPEAKER_OUT_LATENCY         7
 
 struct ct_effect {
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        hda_nid_t nid;
        int mid; /*effect module ID*/
        int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/
@@ -270,7 +270,7 @@ enum {
 };
 
 struct ct_tuning_ctl {
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        hda_nid_t parent_nid;
        hda_nid_t nid;
        int mid; /*effect module ID*/
@@ -3103,7 +3103,7 @@ static int add_tuning_control(struct hda_codec *codec,
                                hda_nid_t pnid, hda_nid_t nid,
                                const char *name, int dir)
 {
-       char namestr[44];
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
@@ -3935,7 +3935,7 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
                         const char *pfx, int dir)
 {
-       char namestr[44];
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type);
index b314d3e..de00ce1 100644 (file)
@@ -2947,7 +2947,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
-       SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
        {}
@@ -3318,6 +3317,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
index e12f7a0..540bdef 100644 (file)
@@ -1018,13 +1018,18 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
                hdmi_non_intrinsic_event(codec, res);
 }
 
-static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid)
+static void haswell_verify_pin_D0(struct hda_codec *codec,
+               hda_nid_t cvt_nid, hda_nid_t nid)
 {
        int pwr, lamp, ramp;
 
-       pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
-       pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
-       if (pwr != AC_PWRST_D0) {
+       /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+        * thus pins could only choose converter 0 for use. Make sure the
+        * converters are in correct power state */
+       if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
+               snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
                                    AC_PWRST_D0);
                msleep(40);
@@ -1068,7 +1073,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        int new_pinctl = 0;
 
        if (codec->vendor_id == 0x80862807)
-               haswell_verify_pin_D0(codec, pin_nid);
+               haswell_verify_pin_D0(codec, cvt_nid, pin_nid);
 
        if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
                pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -1101,26 +1106,15 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        return 0;
 }
 
-/*
- * HDA PCM callbacks
- */
-static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
-                        struct hda_codec *codec,
-                        struct snd_pcm_substream *substream)
+static int hdmi_choose_cvt(struct hda_codec *codec,
+                       int pin_idx, int *cvt_id, int *mux_id)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int pin_idx, cvt_idx, mux_idx = 0;
        struct hdmi_spec_per_pin *per_pin;
-       struct hdmi_eld *eld;
        struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int cvt_idx, mux_idx = 0;
 
-       /* Validate hinfo */
-       pin_idx = hinfo_to_pin_index(spec, hinfo);
-       if (snd_BUG_ON(pin_idx < 0))
-               return -EINVAL;
        per_pin = get_pin(spec, pin_idx);
-       eld = &per_pin->sink_eld;
 
        /* Dynamically assign converter to stream */
        for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
@@ -1138,17 +1132,89 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                        continue;
                break;
        }
+
        /* No free converters */
        if (cvt_idx == spec->num_cvts)
                return -ENODEV;
 
+       if (cvt_id)
+               *cvt_id = cvt_idx;
+       if (mux_id)
+               *mux_id = mux_idx;
+
+       return 0;
+}
+
+static void haswell_config_cvts(struct hda_codec *codec,
+                       int pin_id, int mux_id)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin;
+       int pin_idx, mux_idx;
+       int curr;
+       int err;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               per_pin = get_pin(spec, pin_idx);
+
+               if (pin_idx == pin_id)
+                       continue;
+
+               curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+
+               /* Choose another unused converter */
+               if (curr == mux_id) {
+                       err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx);
+                       if (err < 0)
+                               return;
+                       snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx);
+                       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           mux_idx);
+               }
+       }
+}
+
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+                        struct hda_codec *codec,
+                        struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int pin_idx, cvt_idx, mux_idx = 0;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
+       struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int err;
+
+       /* Validate hinfo */
+       pin_idx = hinfo_to_pin_index(spec, hinfo);
+       if (snd_BUG_ON(pin_idx < 0))
+               return -EINVAL;
+       per_pin = get_pin(spec, pin_idx);
+       eld = &per_pin->sink_eld;
+
+       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
+       if (err < 0)
+               return err;
+
+       per_cvt = get_cvt(spec, cvt_idx);
        /* Claim converter */
        per_cvt->assigned = 1;
        hinfo->nid = per_cvt->cvt_nid;
 
-       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
                            AC_VERB_SET_CONNECT_SEL,
                            mux_idx);
+
+       /* configure unused pins to choose other converters */
+       if (codec->vendor_id == 0x80862807)
+               haswell_config_cvts(codec, pin_idx, mux_idx);
+
        snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
 
        /* Initially set the converter's capabilities */
@@ -1798,12 +1864,33 @@ static void generic_hdmi_free(struct hda_codec *codec)
        kfree(spec);
 }
 
+#ifdef CONFIG_PM
+static int generic_hdmi_resume(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       generic_hdmi_init(codec);
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               hdmi_present_sense(per_pin, 1);
+       }
+       return 0;
+}
+#endif
+
 static const struct hda_codec_ops generic_hdmi_patch_ops = {
        .init                   = generic_hdmi_init,
        .free                   = generic_hdmi_free,
        .build_pcms             = generic_hdmi_build_pcms,
        .build_controls         = generic_hdmi_build_controls,
        .unsol_event            = hdmi_unsol_event,
+#ifdef CONFIG_PM
+       .resume                 = generic_hdmi_resume,
+#endif
 };
 
 
@@ -1821,7 +1908,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
 
        /* override pins connection list */
        snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
-       nconns = max(spec->num_cvts, 4);
        snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
 }
 
index 403010c..7d6a9f5 100644 (file)
@@ -115,6 +115,7 @@ struct alc_spec {
 
        int init_amp;
        int codec_variant;      /* flag for other variants */
+       bool has_alc5505_dsp;
 
        /* for PLL fix */
        hda_nid_t pll_nid;
@@ -2580,7 +2581,96 @@ static void alc269_shutup(struct hda_codec *codec)
        }
 }
 
+static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
+                            unsigned int val)
+{
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */
+}
+
+static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg)
+{
+       unsigned int val;
+
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+       val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+               & 0xffff;
+       val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+               << 16;
+       return val;
+}
+
+static void alc5505_dsp_halt(struct hda_codec *codec)
+{
+       unsigned int val;
+
+       alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */
+       alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */
+       alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */
+       alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */
+       alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */
+       alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */
+       alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */
+       val = alc5505_coef_get(codec, 0x6220);
+       alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */
+}
+
+static void alc5505_dsp_back_from_halt(struct hda_codec *codec)
+{
+       alc5505_coef_set(codec, 0x61b8, 0x04133302);
+       alc5505_coef_set(codec, 0x61b0, 0x00005b16);
+       alc5505_coef_set(codec, 0x61b4, 0x040a2b02);
+       alc5505_coef_set(codec, 0x6230, 0xf80d4011);
+       alc5505_coef_set(codec, 0x6220, 0x2002010f);
+       alc5505_coef_set(codec, 0x880c, 0x00000004);
+}
+
+static void alc5505_dsp_init(struct hda_codec *codec)
+{
+       unsigned int val;
+
+       alc5505_dsp_halt(codec);
+       alc5505_dsp_back_from_halt(codec);
+       alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */
+       alc5505_coef_set(codec, 0x61b0, 0x5b16);
+       alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */
+       alc5505_coef_set(codec, 0x61b4, 0x04132b02);
+       alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/
+       alc5505_coef_set(codec, 0x61b8, 0x041f3302);
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */
+       alc5505_coef_set(codec, 0x61b8, 0x041b3302);
+       alc5505_coef_set(codec, 0x61b8, 0x04173302);
+       alc5505_coef_set(codec, 0x61b8, 0x04163302);
+       alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */
+       alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */
+       alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */
+
+       val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */
+       if (val <= 3)
+               alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */
+       else
+               alc5505_coef_set(codec, 0x6220, 0x6002018f);
+
+       alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/
+       alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */
+       alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */
+       alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */
+       alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
+       alc5505_coef_set(codec, 0x880c, 0x00000003);
+       alc5505_coef_set(codec, 0x880c, 0x00000010);
+}
+
 #ifdef CONFIG_PM
+static int alc269_suspend(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->has_alc5505_dsp)
+               alc5505_dsp_halt(codec);
+       return alc_suspend(codec);
+}
+
 static int alc269_resume(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -2603,7 +2693,10 @@ static int alc269_resume(struct hda_codec *codec)
 
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
+       alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
+       if (spec->has_alc5505_dsp)
+               alc5505_dsp_back_from_halt(codec);
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -3225,6 +3318,7 @@ enum {
        ALC271_FIXUP_HP_GATE_MIC_JACK,
        ALC269_FIXUP_ACER_AC700,
        ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+       ALC269VB_FIXUP_ORDISSIMO_EVE2,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -3467,6 +3561,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_limit_int_mic_boost,
        },
+       [ALC269VB_FIXUP_ORDISSIMO_EVE2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x18, 0x03a11d20 }, /* mic */
+                       { 0x19, 0x411111f0 }, /* Unused bogus pin */
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3495,9 +3598,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
        SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -3539,6 +3645,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+       SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
 
 #if 0
        /* Below is a quirk table taken from the old code.
@@ -3718,6 +3825,11 @@ static int patch_alc269(struct hda_codec *codec)
                break;
        }
 
+       if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
+               spec->has_alc5505_dsp = true;
+               spec->init_hook = alc5505_dsp_init;
+       }
+
        /* automatic parse from the BIOS config */
        err = alc269_parse_auto_config(codec);
        if (err < 0)
@@ -3728,6 +3840,7 @@ static int patch_alc269(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
+       codec->patch_ops.suspend = alc269_suspend;
        codec->patch_ops.resume = alc269_resume;
 #endif
        spec->shutup = alc269_shutup;
index 1d9d642..e2f8359 100644 (file)
@@ -2233,6 +2233,10 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
                          "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900,
                          "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
@@ -3707,14 +3711,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 #endif
 
 #ifdef CONFIG_PM
-static int stac_resume(struct hda_codec *codec)
-{
-       codec->patch_ops.init(codec);
-       snd_hda_codec_resume_amp(codec);
-       snd_hda_codec_resume_cache(codec);
-       return 0;
-}
-
 static int stac_suspend(struct hda_codec *codec)
 {
        stac_shutup(codec);
@@ -3743,7 +3739,6 @@ static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 }
 #else
 #define stac_suspend           NULL
-#define stac_resume            NULL
 #define stac_set_power_state   NULL
 #endif /* CONFIG_PM */
 
@@ -3755,7 +3750,6 @@ static const struct hda_codec_ops stac_patch_ops = {
        .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .suspend = stac_suspend,
-       .resume = stac_resume,
 #endif
        .reboot_notify = stac_shutup,
 };
index e524554..e2481ba 100644 (file)
@@ -480,14 +480,9 @@ static int via_suspend(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
        vt1708_stop_hp_work(codec);
 
-       if (spec->codec_type == VT1802) {
-               /* Fix pop noise on headphones */
-               int i;
-               for (i = 0; i < spec->gen.autocfg.hp_outs; i++)
-                       snd_hda_codec_write(codec, spec->gen.autocfg.hp_pins[i],
-                                           0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           0x00);
-       }
+       /* Fix pop noise on headphones */
+       if (spec->codec_type == VT1802)
+               snd_hda_shutup_pins(codec);
 
        return 0;
 }
@@ -746,6 +741,8 @@ static int patch_vt1708(struct hda_codec *codec)
        /* don't support the input jack switching due to lack of unsol event */
        /* (it may work with polling, though, but it needs testing) */
        spec->gen.suppress_auto_mic = 1;
+       /* Some machines show the broken speaker mute */
+       spec->gen.auto_mute_via_amp = 1;
 
        /* Add HP and CD pin config connect bit re-config action */
        vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
@@ -910,6 +907,8 @@ static const struct hda_verb vt1708S_init_verbs[] = {
 static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
                               int offset, int num_steps, int step_size)
 {
+       snd_hda_override_wcaps(codec, pin,
+                              get_wcaps(codec, pin) | AC_WCAP_IN_AMP);
        snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
                                  (offset << AC_AMPCAP_OFFSET_SHIFT) |
                                  (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
index 806407a..28ec872 100644 (file)
@@ -2807,7 +2807,6 @@ static void snd_ice1712_remove(struct pci_dev *pci)
        if (ice->card_info && ice->card_info->chip_exit)
                ice->card_info->chip_exit(ice);
        snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ice1712_driver = {
index ce70e7f..5004717 100644 (file)
@@ -2800,7 +2800,6 @@ static void snd_vt1724_remove(struct pci_dev *pci)
        if (ice->card_info && ice->card_info->chip_exit)
                ice->card_info->chip_exit(ice);
        snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index b8fe405..59c8aae 100644 (file)
@@ -3364,7 +3364,6 @@ static int snd_intel8x0_probe(struct pci_dev *pci,
 static void snd_intel8x0_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver intel8x0_driver = {
index fea09e8..3573c11 100644 (file)
@@ -1328,7 +1328,6 @@ static int snd_intel8x0m_probe(struct pci_dev *pci,
 static void snd_intel8x0m_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver intel8x0m_driver = {
index 43b4228..9cf9829 100644 (file)
@@ -2473,7 +2473,6 @@ snd_korg1212_probe(struct pci_dev *pci,
 static void snd_korg1212_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver korg1212_driver = {
index 322b638..7307d97 100644 (file)
@@ -759,7 +759,6 @@ out_free:
 static void lola_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /* PCI IDs */
index 298bc9b..3230e57 100644 (file)
@@ -1139,7 +1139,6 @@ out_free:
 static void snd_lx6464es_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index c76ac14..d541736 100644 (file)
@@ -2775,7 +2775,6 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_m3_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver m3_driver = {
index 934dec9..1e0f6ee 100644 (file)
@@ -1377,7 +1377,6 @@ static int snd_mixart_probe(struct pci_dev *pci,
 static void snd_mixart_remove(struct pci_dev *pci)
 {
        snd_mixart_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver mixart_driver = {
index 6febedb..fe79fff 100644 (file)
@@ -1746,7 +1746,6 @@ static int snd_nm256_probe(struct pci_dev *pci,
 static void snd_nm256_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index 9562dc6..b0cb48a 100644 (file)
@@ -722,7 +722,6 @@ EXPORT_SYMBOL(oxygen_pci_probe);
 void oxygen_pci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 EXPORT_SYMBOL(oxygen_pci_remove);
 
index b97384a..d379b28 100644 (file)
@@ -1691,7 +1691,6 @@ static int pcxhr_probe(struct pci_dev *pci,
 static void pcxhr_remove(struct pci_dev *pci)
 {
        pcxhr_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver pcxhr_driver = {
index 63c1c80..56cc891 100644 (file)
@@ -2066,7 +2066,6 @@ static void snd_riptide_joystick_remove(struct pci_dev *pci)
        if (gameport) {
                release_region(gameport->io, 8);
                gameport_unregister_port(gameport);
-               pci_set_drvdata(pci, NULL);
        }
 }
 #endif
@@ -2179,7 +2178,6 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_card_riptide_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver driver = {
index 0ecd410..cc26346 100644 (file)
@@ -1981,7 +1981,6 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_rme32_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver rme32_driver = {
index 5fb88ac..2a8ad9d 100644 (file)
@@ -2390,7 +2390,6 @@ snd_rme96_probe(struct pci_dev *pci,
 static void snd_rme96_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver rme96_driver = {
index 94084cd..4f255df 100644 (file)
@@ -5412,7 +5412,6 @@ static int snd_hdsp_probe(struct pci_dev *pci,
 static void snd_hdsp_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver hdsp_driver = {
index 9ea05e9..bd50193 100644 (file)
@@ -400,8 +400,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 #define HDSPM_wc_freq0 (1<<5)  /* input freq detected via autosync  */
 #define HDSPM_wc_freq1 (1<<6)  /* 001=32, 010==44.1, 011=48, */
-#define HDSPM_wc_freq2 (1<<7)  /* 100=64, 101=88.2, 110=96, */
-/* missing Bit   for               111=128, 1000=176.4, 1001=192 */
+#define HDSPM_wc_freq2 (1<<7)  /* 100=64, 101=88.2, 110=96, 111=128 */
+#define HDSPM_wc_freq3 0x800   /* 1000=176.4, 1001=192 */
 
 #define HDSPM_SyncRef0 0x10000  /* Sync Reference */
 #define HDSPM_SyncRef1 0x20000
@@ -412,13 +412,17 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync)
 
-#define HDSPM_wcFreqMask  (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreqMask  (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\
+                           HDSPM_wc_freq3)
 #define HDSPM_wcFreq32    (HDSPM_wc_freq0)
 #define HDSPM_wcFreq44_1  (HDSPM_wc_freq1)
 #define HDSPM_wcFreq48    (HDSPM_wc_freq0|HDSPM_wc_freq1)
 #define HDSPM_wcFreq64    (HDSPM_wc_freq2)
 #define HDSPM_wcFreq88_2  (HDSPM_wc_freq0|HDSPM_wc_freq2)
 #define HDSPM_wcFreq96    (HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq128   (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3)
+#define HDSPM_wcFreq192   (HDSPM_wc_freq0|HDSPM_wc_freq3)
 
 #define HDSPM_status1_F_0 0x0400000
 #define HDSPM_status1_F_1 0x0800000
@@ -1087,6 +1091,26 @@ static int hdspm_round_frequency(int rate)
                return 48000;
 }
 
+/* QS and DS rates normally can not be detected
+ * automatically by the card. Only exception is MADI
+ * in 96k frame mode.
+ *
+ * So if we read SS values (32 .. 48k), check for
+ * user-provided DS/QS bits in the control register
+ * and multiply the base frequency accordingly.
+ */
+static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
+{
+       if (rate <= 48000) {
+               if (hdspm->control_register & HDSPM_QuadSpeed)
+                       return rate * 4;
+               else if (hdspm->control_register &
+                               HDSPM_DoubleSpeed)
+                       return rate * 2;
+       };
+       return rate;
+}
+
 static int hdspm_tco_sync_check(struct hdspm *hdspm);
 static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
 
@@ -1181,6 +1205,15 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                        case HDSPM_wcFreq96:
                                rate = 96000;
                                break;
+                       case HDSPM_wcFreq128:
+                               rate = 128000;
+                               break;
+                       case HDSPM_wcFreq176_4:
+                               rate = 176400;
+                               break;
+                       case HDSPM_wcFreq192:
+                               rate = 192000;
+                               break;
                        default:
                                rate = 0;
                                break;
@@ -1192,7 +1225,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                 */
                if (rate != 0 &&
                (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
-                       return rate;
+                       return hdspm_rate_multiplier(hdspm, rate);
 
                /* maybe a madi input (which is taken if sel sync is madi) */
                if (status & HDSPM_madiLock) {
@@ -1255,21 +1288,8 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                        }
                }
 
-               /* QS and DS rates normally can not be detected
-                * automatically by the card. Only exception is MADI
-                * in 96k frame mode.
-                *
-                * So if we read SS values (32 .. 48k), check for
-                * user-provided DS/QS bits in the control register
-                * and multiply the base frequency accordingly.
-                */
-               if (rate <= 48000) {
-                       if (hdspm->control_register & HDSPM_QuadSpeed)
-                               rate *= 4;
-                       else if (hdspm->control_register &
-                                       HDSPM_DoubleSpeed)
-                               rate *= 2;
-               }
+               rate = hdspm_rate_multiplier(hdspm, rate);
+
                break;
        }
 
@@ -6737,7 +6757,6 @@ static int snd_hdspm_probe(struct pci_dev *pci,
 static void snd_hdspm_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver hdspm_driver = {
index 773a67f..b96d9e1 100644 (file)
@@ -2628,7 +2628,6 @@ static int snd_rme9652_probe(struct pci_dev *pci,
 static void snd_rme9652_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver rme9652_driver = {
index 748e82d..e413b4e 100644 (file)
@@ -1482,7 +1482,6 @@ error_out:
 static void snd_sis7019_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver sis7019_driver = {
index a2e7686..2a46bf9 100644 (file)
@@ -1528,7 +1528,6 @@ static int snd_sonic_probe(struct pci_dev *pci,
 static void snd_sonic_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver sonicvibes_driver = {
index 1aefd62..b3b588b 100644 (file)
@@ -169,7 +169,6 @@ static int snd_trident_probe(struct pci_dev *pci,
 static void snd_trident_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver trident_driver = {
index d756a35..3c511d0 100644 (file)
@@ -2646,7 +2646,6 @@ static int snd_via82xx_probe(struct pci_dev *pci,
 static void snd_via82xx_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver via82xx_driver = {
index 4f5fd80..ca19028 100644 (file)
@@ -1227,7 +1227,6 @@ static int snd_via82xx_probe(struct pci_dev *pci,
 static void snd_via82xx_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver via82xx_modem_driver = {
index e2f1ab3..ab8a9b1 100644 (file)
@@ -254,7 +254,6 @@ static int snd_vx222_probe(struct pci_dev *pci,
 static void snd_vx222_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 01c4965..e8932b2 100644 (file)
@@ -347,7 +347,6 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
 static void snd_card_ymfpci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ymfpci_driver = {
index 22056c5..d591c15 100644 (file)
@@ -2258,7 +2258,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
        /* FIXME: temporarily disabled, otherwise we cannot fire up
         * the chip again unless reboot.  ACPI bug?
         */
-       pci_set_power_state(chip->pci, 3);
+       pci_set_power_state(chip->pci, PCI_D3hot);
 #endif
 
 #ifdef CONFIG_PM_SLEEP
index 09fc848..8abb521 100644 (file)
@@ -139,7 +139,6 @@ __error:
 static int snd_pmac_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index e59a73a..78a3697 100644 (file)
@@ -598,7 +598,6 @@ static int snd_aica_remove(struct platform_device *devptr)
                return -ENODEV;
        snd_card_free(dreamcastcard->card);
        kfree(dreamcastcard);
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index e68c4fc..7c9422c 100644 (file)
@@ -290,8 +290,6 @@ static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
 static int snd_sh_dac_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
-
        return 0;
 }
 
index 9e675c7..45eeaa9 100644 (file)
@@ -51,6 +51,7 @@ source "sound/soc/pxa/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/spear/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
index 197b6ae..bc02614 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_SND_SOC) += pxa/
 obj-$(CONFIG_SND_SOC)  += samsung/
 obj-$(CONFIG_SND_SOC)  += s6000/
 obj-$(CONFIG_SND_SOC)  += sh/
+obj-$(CONFIG_SND_SOC)  += spear/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += ux500/
index 2d6fbd0..802717e 100644 (file)
@@ -38,8 +38,6 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 
-#include <linux/pinctrl/consumer.h>
-
 #include <linux/atmel-ssc.h>
 
 #include <sound/core.h>
@@ -203,15 +201,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        struct device_node *codec_np, *cpu_np;
        struct clk *pllb;
        struct snd_soc_card *card = &snd_soc_at91sam9g20ek;
-       struct pinctrl *pinctrl;
        int ret;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(&pdev->dev, "Failed to request pinctrl for mck\n");
-               return PTR_ERR(pinctrl);
-       }
-
        if (!np) {
                if (!(machine_is_at91sam9g20ek() ||
                        machine_is_at91sam9g20ek_2mmc()))
index 16b88f5..54f74f8 100644 (file)
@@ -56,6 +56,23 @@ config SND_SOC_BFIN_EVAL_ADAV80X
          Note: This driver assumes that the ADAV80X digital record and playback
          interfaces are connected to the first SPORT port on the BF5XX board.
 
+config SND_BF5XX_SOC_AD1836
+       tristate "SoC AD1836 Audio support for BF5xx"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_AD1836
+       help
+         Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
+
+config SND_BF5XX_SOC_AD193X
+       tristate "SoC AD193X Audio support for Blackfin"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_AD193X
+       help
+         Say Y if you want to add support for AD193X codec on Blackfin.
+         This driver supports AD1936, AD1937, AD1938 and AD1939.
+
 config SND_BF5XX_SOC_AD73311
        tristate "SoC AD73311 Audio support for Blackfin"
        depends on SND_BF5XX_I2S
@@ -72,33 +89,6 @@ config SND_BFIN_AD73311_SE
          Enter the GPIO used to control AD73311's SE pin. Acceptable
          values are 0 to 7
 
-config SND_BF5XX_TDM
-       tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
-       depends on (BLACKFIN && SND_SOC)
-       select SND_BF5XX_SOC_SPORT
-       help
-         Say Y or M if you want to add support for codecs attached to
-         the Blackfin SPORT (synchronous serial ports) interface in TDM
-         mode.
-         You will also need to select the audio interfaces to support below.
-
-config SND_BF5XX_SOC_AD1836
-       tristate "SoC AD1836 Audio support for BF5xx"
-       depends on SND_BF5XX_TDM
-       select SND_BF5XX_SOC_TDM
-       select SND_SOC_AD1836
-       help
-         Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
-
-config SND_BF5XX_SOC_AD193X
-       tristate "SoC AD193X Audio support for Blackfin"
-       depends on SND_BF5XX_TDM
-       select SND_BF5XX_SOC_TDM
-       select SND_SOC_AD193X
-       help
-         Say Y if you want to add support for AD193X codec on Blackfin.
-         This driver supports AD1936, AD1937, AD1938 and AD1939.
-
 config SND_BF5XX_AC97
        tristate "SoC AC97 Audio for the ADI BF5xx chip"
        depends on BLACKFIN
@@ -174,9 +164,6 @@ config SND_BF5XX_SOC_I2S
 config SND_BF6XX_SOC_I2S
        tristate
 
-config SND_BF5XX_SOC_TDM
-       tristate
-
 config SND_BF5XX_SOC_AC97
        tristate
 
index 6fea1f4..ad0a6e9 100644 (file)
@@ -1,23 +1,19 @@
 # Blackfin Platform Support
 snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
 snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
-snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
 snd-soc-bf5xx-sport-objs := bf5xx-sport.o
 snd-soc-bf6xx-sport-objs := bf6xx-sport.o
 snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
 snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
 snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
-snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
 
 obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
 obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
-obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
 obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
 obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
 obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
 obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
 obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
-obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
 
 # Blackfin Machine Support
 snd-ad1836-objs := bf5xx-ad1836.o
index 7e2f360..53f8408 100644 (file)
@@ -39,7 +39,6 @@
 
 #include <asm/dma.h>
 
-#include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 #include "bf5xx-sport.h"
 
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
deleted file mode 100644 (file)
index d324d58..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/sound/arm/bf5xx-ac97-pcm.h -- ALSA PCM interface for the Blackfin
- *
- * Copyright 2007 Analog Device 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 _BF5XX_AC97_PCM_H
-#define _BF5XX_AC97_PCM_H
-
-struct bf5xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-};
-
-struct bf5xx_gpio {
-       u32 sys;
-       u32 rx;
-       u32 tx;
-       u32 clk;
-       u32 frm;
-};
-
-#endif
index c5af677..efb1dae 100644 (file)
@@ -230,9 +230,9 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
                return 0;
 
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-       ret = sport_set_multichannel(sport, 16, 0x3FF, 1);
+       ret = sport_set_multichannel(sport, 16, 0x3FF, 0x3FF, 1);
 #else
-       ret = sport_set_multichannel(sport, 16, 0x1F, 1);
+       ret = sport_set_multichannel(sport, 16, 0x1F, 0x1F, 1);
 #endif
        if (ret) {
                pr_err("SPORT is busy!\n");
@@ -311,9 +311,9 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 
        /*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-       ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
+       ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 0x3FF, 1);
 #else
-       ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+       ret = sport_set_multichannel(sport_handle, 16, 0x1F, 0x1F, 1);
 #endif
        if (ret) {
                pr_err("SPORT is busy!\n");
index d23f4b0..8fcfc4e 100644 (file)
 
 #include "../codecs/ad1836.h"
 
-#include "bf5xx-tdm-pcm.h"
-#include "bf5xx-tdm.h"
-
 static struct snd_soc_card bf5xx_ad1836;
 
-static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+static int bf5xx_ad1836_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
        int ret = 0;
@@ -49,13 +44,13 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
-static struct snd_soc_ops bf5xx_ad1836_ops = {
-       .hw_params = bf5xx_ad1836_hw_params,
-};
-
 #define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
                                SND_SOC_DAIFMT_CBM_CFM)
 
@@ -63,9 +58,9 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai = {
        .name = "ad1836",
        .stream_name = "AD1836",
        .codec_dai_name = "ad1836-hifi",
-       .platform_name = "bfin-tdm-pcm-audio",
-       .ops = &bf5xx_ad1836_ops,
+       .platform_name = "bfin-i2s-pcm-audio",
        .dai_fmt = BF5XX_AD1836_DAIFMT,
+       .init = bf5xx_ad1836_init,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
index 0e55e9f..603ad1f 100644 (file)
 
 #include "../codecs/ad193x.h"
 
-#include "bf5xx-tdm-pcm.h"
-#include "bf5xx-tdm.h"
-
 static struct snd_soc_card bf5xx_ad193x;
 
-static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+static int bf5xx_ad193x_link_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       unsigned int clk = 0;
-       unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
-       int ret = 0;
-
-       switch (params_rate(params)) {
-       case 48000:
-               clk = 24576000;
-               break;
-       }
+       int ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
-               SND_SOC_CLOCK_IN);
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
@@ -71,9 +57,7 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       /* set cpu DAI channel mapping */
-       ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
-               channel_map, ARRAY_SIZE(channel_map), channel_map);
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
        if (ret < 0)
                return ret;
 
@@ -83,30 +67,26 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 #define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
                                SND_SOC_DAIFMT_CBM_CFM)
 
-static struct snd_soc_ops bf5xx_ad193x_ops = {
-       .hw_params = bf5xx_ad193x_hw_params,
-};
-
 static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
        {
                .name = "ad193x",
                .stream_name = "AD193X",
-               .cpu_dai_name = "bfin-tdm.0",
+               .cpu_dai_name = "bfin-i2s.0",
                .codec_dai_name ="ad193x-hifi",
-               .platform_name = "bfin-tdm-pcm-audio",
+               .platform_name = "bfin-i2s-pcm-audio",
                .codec_name = "spi0.5",
-               .ops = &bf5xx_ad193x_ops,
                .dai_fmt = BF5XX_AD193X_DAIFMT,
+               .init = bf5xx_ad193x_link_init,
        },
        {
                .name = "ad193x",
                .stream_name = "AD193X",
-               .cpu_dai_name = "bfin-tdm.1",
+               .cpu_dai_name = "bfin-i2s.1",
                .codec_dai_name ="ad193x-hifi",
-               .platform_name = "bfin-tdm-pcm-audio",
+               .platform_name = "bfin-i2s-pcm-audio",
                .codec_name = "spi0.5",
-               .ops = &bf5xx_ad193x_ops,
                .dai_fmt = BF5XX_AD193X_DAIFMT,
+               .init = bf5xx_ad193x_link_init,
        },
 };
 
index b30f88b..3450e8f 100644 (file)
@@ -48,7 +48,6 @@
 
 #include "../codecs/ad1980.h"
 
-#include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
 static struct snd_soc_card bf5xx_board;
index 61cc91d..786bbdd 100644 (file)
@@ -45,7 +45,6 @@
 
 #include "../codecs/ad73311.h"
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s-pcm.h"
 
 #if CONFIG_SND_BF5XX_SPORT_NUM == 0
 #define bfin_write_SPORT_TCR1  bfin_write_SPORT0_TCR1
index 262c1de..9cb4a80 100644 (file)
@@ -39,8 +39,8 @@
 
 #include <asm/dma.h>
 
-#include "bf5xx-i2s-pcm.h"
 #include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
 
 static void bf5xx_dma_irq(void *data)
 {
@@ -50,7 +50,6 @@ static void bf5xx_dma_irq(void *data)
 
 static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
-                                  SNDRV_PCM_INFO_MMAP |
                                   SNDRV_PCM_INFO_MMAP_VALID |
                                   SNDRV_PCM_INFO_BLOCK_TRANSFER,
        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
@@ -67,10 +66,16 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
 static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
-       snd_pcm_lib_malloc_pages(substream, size);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned int buffer_size = params_buffer_bytes(params);
+       struct bf5xx_i2s_pcm_data *dma_data;
 
-       return 0;
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode)
+               buffer_size = buffer_size / params_channels(params) * 8;
+
+       return snd_pcm_lib_malloc_pages(substream, buffer_size);
 }
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
@@ -82,9 +87,16 @@ static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct sport_device *sport = runtime->private_data;
        int period_bytes = frames_to_bytes(runtime, runtime->period_size);
+       struct bf5xx_i2s_pcm_data *dma_data;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode)
+               period_bytes = period_bytes / runtime->channels * 8;
 
        pr_debug("%s enter\n", __func__);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -131,10 +143,15 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
 static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct sport_device *sport = runtime->private_data;
        unsigned int diff;
        snd_pcm_uframes_t frames;
+       struct bf5xx_i2s_pcm_data *dma_data;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
        pr_debug("%s enter\n", __func__);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                diff = sport_curr_offset_tx(sport);
@@ -151,6 +168,8 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
                diff = 0;
 
        frames = bytes_to_frames(substream->runtime, diff);
+       if (dma_data->tdm_mode)
+               frames = frames * runtime->channels / 8;
 
        return frames;
 }
@@ -162,11 +181,18 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_dma_buffer *buf = &substream->dma_buffer;
+       struct bf5xx_i2s_pcm_data *dma_data;
        int ret;
 
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
        pr_debug("%s enter\n", __func__);
 
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+       if (dma_data->tdm_mode)
+               runtime->hw.buffer_bytes_max /= 4;
+       else
+               runtime->hw.info |= SNDRV_PCM_INFO_MMAP;
 
        ret = snd_pcm_hw_constraint_integer(runtime,
                        SNDRV_PCM_HW_PARAM_PERIODS);
@@ -202,6 +228,88 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
        return 0 ;
 }
 
+static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+       snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int sample_size = runtime->sample_bits / 8;
+       struct bf5xx_i2s_pcm_data *dma_data;
+       unsigned int i;
+       void *src, *dst;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       src = buf;
+                       dst = runtime->dma_area;
+                       dst += pos * sample_size * 8;
+
+                       while (count--) {
+                               for (i = 0; i < runtime->channels; i++) {
+                                       memcpy(dst + dma_data->map[i] *
+                                               sample_size, src, sample_size);
+                                       src += sample_size;
+                               }
+                               dst += 8 * sample_size;
+                       }
+               } else {
+                       src = runtime->dma_area;
+                       src += pos * sample_size * 8;
+                       dst = buf;
+
+                       while (count--) {
+                               for (i = 0; i < runtime->channels; i++) {
+                                       memcpy(dst, src + dma_data->map[i] *
+                                               sample_size, sample_size);
+                                       dst += sample_size;
+                               }
+                               src += 8 * sample_size;
+                       }
+               }
+       } else {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       src = buf;
+                       dst = runtime->dma_area;
+                       dst += frames_to_bytes(runtime, pos);
+               } else {
+                       src = runtime->dma_area;
+                       src += frames_to_bytes(runtime, pos);
+                       dst = buf;
+               }
+
+               memcpy(dst, src, frames_to_bytes(runtime, count));
+       }
+
+       return 0;
+}
+
+static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
+       int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int sample_size = runtime->sample_bits / 8;
+       void *buf = runtime->dma_area;
+       struct bf5xx_i2s_pcm_data *dma_data;
+       unsigned int offset, size;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode) {
+               offset = pos * 8 * sample_size;
+               size = count * 8 * sample_size;
+       } else {
+               offset = frames_to_bytes(runtime, pos);
+               size = frames_to_bytes(runtime, count);
+       }
+
+       snd_pcm_format_set_silence(runtime->format, buf + offset, size);
+
+       return 0;
+}
+
 static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
        .open           = bf5xx_pcm_open,
        .ioctl          = snd_pcm_lib_ioctl,
@@ -211,57 +319,16 @@ static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
        .trigger        = bf5xx_pcm_trigger,
        .pointer        = bf5xx_pcm_pointer,
        .mmap           = bf5xx_pcm_mmap,
+       .copy           = bf5xx_pcm_copy,
+       .silence        = bf5xx_pcm_silence,
 };
 
-static int bf5xx_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 = bf5xx_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_coherent(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       if (!buf->area) {
-               pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
-               return -ENOMEM;
-       }
-       buf->bytes = size;
-
-       pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
-               buf->area, buf->bytes);
-
-       return 0;
-}
-
-static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_coherent(NULL, buf->bytes, buf->area, 0);
-               buf->area = NULL;
-       }
-}
-
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 
 static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
 
        pr_debug("%s enter\n", __func__);
        if (!card->dev->dma_mask)
@@ -269,27 +336,13 @@ static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
+       return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+                               SNDRV_DMA_TYPE_DEV, card->dev, size, size);
 }
 
 static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
        .ops            = &bf5xx_pcm_i2s_ops,
        .pcm_new        = bf5xx_pcm_i2s_new,
-       .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
 
 static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
index 0c2c5a6..1f04352 100644 (file)
@@ -1,26 +1,17 @@
 /*
- * linux/sound/arm/bf5xx-i2s-pcm.h -- ALSA PCM interface for the Blackfin
- *
- * Copyright 2007 Analog Device 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 _BF5XX_I2S_PCM_H
-#define _BF5XX_I2S_PCM_H
+#ifndef _BF5XX_TDM_PCM_H
+#define _BF5XX_TDM_PCM_H
 
-struct bf5xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-};
+#define BFIN_TDM_DAI_MAX_SLOTS 8
 
-struct bf5xx_gpio {
-       u32 sys;
-       u32 rx;
-       u32 tx;
-       u32 clk;
-       u32 frm;
+struct bf5xx_i2s_pcm_data {
+       unsigned int map[BFIN_TDM_DAI_MAX_SLOTS];
+       bool tdm_mode;
 };
 
 #endif
index dd0c2a4..9a174fc 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/gpio.h>
 
 #include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
 
 struct bf5xx_i2s_port {
        u16 tcr1;
@@ -49,6 +50,13 @@ struct bf5xx_i2s_port {
        u16 tcr2;
        u16 rcr2;
        int configured;
+
+       unsigned int slots;
+       unsigned int tx_mask;
+       unsigned int rx_mask;
+
+       struct bf5xx_i2s_pcm_data tx_dma_data;
+       struct bf5xx_i2s_pcm_data rx_dma_data;
 };
 
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -74,7 +82,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                ret = -EINVAL;
                break;
        default:
-               printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
+               dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
+                       __func__);
                ret = -EINVAL;
                break;
        }
@@ -88,7 +97,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                ret = -EINVAL;
                break;
        default:
-               printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
+               dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
+                       __func__);
                ret = -EINVAL;
                break;
        }
@@ -141,14 +151,14 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
                                      bf5xx_i2s->rcr2, 0, 0);
                if (ret) {
-                       pr_err("SPORT is busy!\n");
+                       dev_err(dai->dev, "SPORT is busy!\n");
                        return -EBUSY;
                }
 
                ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
                                      bf5xx_i2s->tcr2, 0, 0);
                if (ret) {
-                       pr_err("SPORT is busy!\n");
+                       dev_err(dai->dev, "SPORT is busy!\n");
                        return -EBUSY;
                }
        }
@@ -162,18 +172,76 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
        struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
        struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 
-       pr_debug("%s enter\n", __func__);
+       dev_dbg(dai->dev, "%s enter\n", __func__);
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
                bf5xx_i2s->configured = 0;
 }
 
+static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
+               unsigned int tx_num, unsigned int *tx_slot,
+               unsigned int rx_num, unsigned int *rx_slot)
+{
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+       unsigned int tx_mapped = 0, rx_mapped = 0;
+       unsigned int slot;
+       int i;
+
+       if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
+                       (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
+               return -EINVAL;
+
+       for (i = 0; i < tx_num; i++) {
+               slot = tx_slot[i];
+               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+                               (!(tx_mapped & (1 << slot)))) {
+                       bf5xx_i2s->tx_dma_data.map[i] = slot;
+                       tx_mapped |= 1 << slot;
+               } else
+                       return -EINVAL;
+       }
+       for (i = 0; i < rx_num; i++) {
+               slot = rx_slot[i];
+               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+                               (!(rx_mapped & (1 << slot)))) {
+                       bf5xx_i2s->rx_dma_data.map[i] = slot;
+                       rx_mapped |= 1 << slot;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+       unsigned int rx_mask, int slots, int width)
+{
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
+       if (slots % 8 != 0 || slots > 8)
+               return -EINVAL;
+
+       if (width != 32)
+               return -EINVAL;
+
+       bf5xx_i2s->slots = slots;
+       bf5xx_i2s->tx_mask = tx_mask;
+       bf5xx_i2s->rx_mask = rx_mask;
+
+       bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
+       bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
+
+       return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
+}
+
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
        struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
-       pr_debug("%s : sport %d\n", __func__, dai->id);
+       dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
 
        if (dai->capture_active)
                sport_rx_stop(sport_handle);
@@ -188,23 +256,24 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
        struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret;
 
-       pr_debug("%s : sport %d\n", __func__, dai->id);
+       dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
 
        ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
                                      bf5xx_i2s->rcr2, 0, 0);
        if (ret) {
-               pr_err("SPORT is busy!\n");
+               dev_err(dai->dev, "SPORT is busy!\n");
                return -EBUSY;
        }
 
        ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
                                      bf5xx_i2s->tcr2, 0, 0);
        if (ret) {
-               pr_err("SPORT is busy!\n");
+               dev_err(dai->dev, "SPORT is busy!\n");
                return -EBUSY;
        }
 
-       return 0;
+       return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
+                       bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
 }
 
 #else
@@ -212,6 +281,23 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 #define bf5xx_i2s_resume       NULL
 #endif
 
+static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+       unsigned int i;
+
+       for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
+               bf5xx_i2s->tx_dma_data.map[i] = i;
+               bf5xx_i2s->rx_dma_data.map[i] = i;
+       }
+
+       dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
+       dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
+
+       return 0;
+}
+
 #define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
@@ -224,22 +310,25 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
         SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
-       .shutdown       = bf5xx_i2s_shutdown,
-       .hw_params      = bf5xx_i2s_hw_params,
-       .set_fmt        = bf5xx_i2s_set_dai_fmt,
+       .shutdown        = bf5xx_i2s_shutdown,
+       .hw_params       = bf5xx_i2s_hw_params,
+       .set_fmt         = bf5xx_i2s_set_dai_fmt,
+       .set_tdm_slot    = bf5xx_i2s_set_tdm_slot,
+       .set_channel_map = bf5xx_i2s_set_channel_map,
 };
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
+       .probe = bf5xx_i2s_dai_probe,
        .suspend = bf5xx_i2s_suspend,
        .resume = bf5xx_i2s_resume,
        .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
+               .channels_min = 2,
+               .channels_max = 8,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
        .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
+               .channels_min = 2,
+               .channels_max = 8,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
        .ops = &bf5xx_i2s_dai_ops,
@@ -255,7 +344,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
        int ret;
 
        /* configure SPORT for I2S */
-       sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
                sizeof(struct bf5xx_i2s_port));
        if (!sport_handle)
                return -ENODEV;
@@ -264,7 +353,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
        ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
                                         &bf5xx_i2s_dai, 1);
        if (ret) {
-               pr_err("Failed to register DAI: %d\n", ret);
+               dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
                sport_done(sport_handle);
                return ret;
        }
@@ -276,7 +365,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
 {
        struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-       pr_debug("%s enter\n", __func__);
+       dev_dbg(&pdev->dev, "%s enter\n", __func__);
 
        snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
index 2fd9f2a..6953512 100644 (file)
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
-               int tdm_count, u32 mask, int packed)
+               int tdm_count, u32 tx_mask, u32 rx_mask, int packed)
 {
-       pr_debug("%s tdm_count=%d mask:0x%08x packed=%d\n", __func__,
-                       tdm_count, mask, packed);
+       pr_debug("%s tdm_count=%d tx_mask:0x%08x rx_mask:0x%08x packed=%d\n",
+                       __func__, tdm_count, tx_mask, rx_mask, packed);
 
        if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
                return -EBUSY;
@@ -65,8 +65,8 @@ int sport_set_multichannel(struct sport_device *sport,
                sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \
                                (packed ? (MCDTXPE|MCDRXPE) : 0);
 
-               sport->regs->mtcs0 = mask;
-               sport->regs->mrcs0 = mask;
+               sport->regs->mtcs0 = tx_mask;
+               sport->regs->mrcs0 = rx_mask;
                sport->regs->mtcs1 = 0;
                sport->regs->mrcs1 = 0;
                sport->regs->mtcs2 = 0;
index 5ab60bd..9fc2192 100644 (file)
@@ -128,7 +128,7 @@ void sport_done(struct sport_device *sport);
 /* note: multichannel is in units of 8 channels, tdm_count is number of channels
  *  NOT / 8 ! all channels are enabled by default */
 int sport_set_multichannel(struct sport_device *sport, int tdm_count,
-               u32 mask, int packed);
+               u32 tx_mask, u32 rx_mask, int packed);
 
 int sport_config_rx(struct sport_device *sport,
                unsigned int rcr1, unsigned int rcr2,
index 7dbeef1..9c19ccc 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/gpio.h>
 #include "../codecs/ssm2602.h"
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s-pcm.h"
 
 static struct snd_soc_card bf5xx_ssm2602;
 
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
deleted file mode 100644 (file)
index 0e6b888..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * File:         sound/soc/blackfin/bf5xx-tdm-pcm.c
- * Author:       Barry Song <Barry.Song@analog.com>
- *
- * Created:      Tue June 06 2009
- * Description:  DMA driver for tdm codec
- *
- * Modified:
- *               Copyright 2009 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gfp.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-
-#include "bf5xx-tdm-pcm.h"
-#include "bf5xx-tdm.h"
-#include "bf5xx-sport.h"
-
-#define PCM_BUFFER_MAX  0x8000
-#define FRAGMENT_SIZE_MIN  (4*1024)
-#define FRAGMENTS_MIN  2
-#define FRAGMENTS_MAX  32
-
-static void bf5xx_dma_irq(void *data)
-{
-       struct snd_pcm_substream *pcm = data;
-       snd_pcm_period_elapsed(pcm);
-}
-
-static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_RESUME),
-       .formats =          SNDRV_PCM_FMTBIT_S32_LE,
-       .rates =            SNDRV_PCM_RATE_48000,
-       .channels_min =     2,
-       .channels_max =     8,
-       .buffer_bytes_max = PCM_BUFFER_MAX,
-       .period_bytes_min = FRAGMENT_SIZE_MIN,
-       .period_bytes_max = PCM_BUFFER_MAX/2,
-       .periods_min =      FRAGMENTS_MIN,
-       .periods_max =      FRAGMENTS_MAX,
-};
-
-static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
-       snd_pcm_lib_malloc_pages(substream, size * 4);
-
-       return 0;
-}
-
-static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_lib_free_pages(substream);
-
-       return 0;
-}
-
-static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size);
-
-       fragsize_bytes /= runtime->channels;
-       /* inflate the fragsize to match the dma width of SPORT */
-       fragsize_bytes *= 8;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
-               sport_config_tx_dma(sport, runtime->dma_area,
-                       runtime->periods, fragsize_bytes);
-       } else {
-               sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
-               sport_config_rx_dma(sport, runtime->dma_area,
-                       runtime->periods, fragsize_bytes);
-       }
-
-       return 0;
-}
-
-static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sport_tx_start(sport);
-               else
-                       sport_rx_start(sport);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sport_tx_stop(sport);
-               else
-                       sport_rx_stop(sport);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       unsigned int diff;
-       snd_pcm_uframes_t frames;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               diff = sport_curr_offset_tx(sport);
-               frames = diff / (8*4); /* 32 bytes per frame */
-       } else {
-               diff = sport_curr_offset_rx(sport);
-               frames = diff / (8*4);
-       }
-       return frames;
-}
-
-static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-
-       int ret = 0;
-
-       snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
-
-       ret = snd_pcm_hw_constraint_integer(runtime,
-               SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               goto out;
-
-       if (sport_handle != NULL) {
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sport_handle->tx_buf = buf->area;
-               else
-                       sport_handle->rx_buf = buf->area;
-
-               runtime->private_data = sport_handle;
-       } else {
-               pr_err("sport_handle is NULL\n");
-               ret = -ENODEV;
-       }
-out:
-       return ret;
-}
-
-static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
-       snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       struct bf5xx_tdm_port *tdm_port = sport->private_data;
-       unsigned int *src;
-       unsigned int *dst;
-       int i;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               src = buf;
-               dst = (unsigned int *)substream->runtime->dma_area;
-
-               dst += pos * 8;
-               while (count--) {
-                       for (i = 0; i < substream->runtime->channels; i++)
-                               *(dst + tdm_port->tx_map[i]) = *src++;
-                       dst += 8;
-               }
-       } else {
-               src = (unsigned int *)substream->runtime->dma_area;
-               dst = buf;
-
-               src += pos * 8;
-               while (count--) {
-                       for (i = 0; i < substream->runtime->channels; i++)
-                               *dst++ = *(src + tdm_port->rx_map[i]);
-                       src += 8;
-               }
-       }
-
-       return 0;
-}
-
-static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
-       int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
-{
-       unsigned char *buf = substream->runtime->dma_area;
-       buf += pos * 8 * 4;
-       memset(buf, '\0', count * 8 * 4);
-
-       return 0;
-}
-
-
-struct snd_pcm_ops bf5xx_pcm_tdm_ops = {
-       .open           = bf5xx_pcm_open,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = bf5xx_pcm_hw_params,
-       .hw_free        = bf5xx_pcm_hw_free,
-       .prepare        = bf5xx_pcm_prepare,
-       .trigger        = bf5xx_pcm_trigger,
-       .pointer        = bf5xx_pcm_pointer,
-       .copy           = bf5xx_pcm_copy,
-       .silence        = bf5xx_pcm_silence,
-};
-
-static int bf5xx_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 = bf5xx_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_coherent(pcm->card->dev, size * 4,
-               &buf->addr, GFP_KERNEL);
-       if (!buf->area) {
-               pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
-               return -ENOMEM;
-       }
-       buf->bytes = size;
-
-       return 0;
-}
-
-static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_coherent(NULL, buf->bytes, buf->area, 0);
-               buf->area = NULL;
-       }
-}
-
-static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &bf5xx_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
-out:
-       return ret;
-}
-
-static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
-       .ops        = &bf5xx_pcm_tdm_ops,
-       .pcm_new        = bf5xx_pcm_tdm_new,
-       .pcm_free       = bf5xx_pcm_free_dma_buffers,
-};
-
-static int bf5xx_soc_platform_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
-}
-
-static int bf5xx_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver bfin_tdm_driver = {
-       .driver = {
-                       .name = "bfin-tdm-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = bf5xx_soc_platform_probe,
-       .remove = bf5xx_soc_platform_remove,
-};
-
-module_platform_driver(bfin_tdm_driver);
-
-MODULE_AUTHOR("Barry Song");
-MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
deleted file mode 100644 (file)
index 7f8cc01..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin
- *
- * Copyright 2009 Analog Device 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 _BF5XX_TDM_PCM_H
-#define _BF5XX_TDM_PCM_H
-
-struct bf5xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-};
-
-#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
deleted file mode 100644 (file)
index 69e9a3e..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * File:         sound/soc/blackfin/bf5xx-tdm.c
- * Author:       Barry Song <Barry.Song@analog.com>
- *
- * Created:      Thurs June 04 2009
- * Description:  Blackfin I2S(TDM) CPU DAI driver
- *              Even though TDM mode can be as part of I2S DAI, but there
- *              are so much difference in configuration and data flow,
- *              it's very ugly to integrate I2S and TDM into a module
- *
- * Modified:
- *               Copyright 2009 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <asm/irq.h>
-#include <asm/portmux.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-
-#include "bf5xx-sport.h"
-#include "bf5xx-tdm.h"
-
-static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-       unsigned int fmt)
-{
-       int ret = 0;
-
-       /* interface format:support TDM,slave mode */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               break;
-       default:
-               printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
-               ret = -EINVAL;
-               break;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_CBM_CFS:
-       case SND_SOC_DAIFMT_CBS_CFM:
-               ret = -EINVAL;
-               break;
-       default:
-               printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params,
-       struct snd_soc_dai *dai)
-{
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
-       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
-       int ret = 0;
-
-       bf5xx_tdm->tcr2 &= ~0x1f;
-       bf5xx_tdm->rcr2 &= ~0x1f;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_tdm->tcr2 |= 31;
-               bf5xx_tdm->rcr2 |= 31;
-               sport_handle->wdsize = 4;
-               break;
-               /* at present, we only support 32bit transfer */
-       default:
-               pr_err("not supported PCM format yet\n");
-               return -EINVAL;
-               break;
-       }
-
-       if (!bf5xx_tdm->configured) {
-               /*
-                * TX and RX are not independent,they are enabled at the
-                * same time, even if only one side is running. So, we
-                * need to configure both of them at the time when the first
-                * stream is opened.
-                *
-                * CPU DAI:slave mode.
-                */
-               ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
-                       bf5xx_tdm->rcr2, 0, 0);
-               if (ret) {
-                       pr_err("SPORT is busy!\n");
-                       return -EBUSY;
-               }
-
-               ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
-                       bf5xx_tdm->tcr2, 0, 0);
-               if (ret) {
-                       pr_err("SPORT is busy!\n");
-                       return -EBUSY;
-               }
-
-               bf5xx_tdm->configured = 1;
-       }
-
-       return 0;
-}
-
-static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
-       struct snd_soc_dai *dai)
-{
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
-       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
-
-       /* No active stream, SPORT is allowed to be configured again. */
-       if (!dai->active)
-               bf5xx_tdm->configured = 0;
-}
-
-static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
-               unsigned int tx_num, unsigned int *tx_slot,
-               unsigned int rx_num, unsigned int *rx_slot)
-{
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
-       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
-       int i;
-       unsigned int slot;
-       unsigned int tx_mapped = 0, rx_mapped = 0;
-
-       if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
-                       (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
-               return -EINVAL;
-
-       for (i = 0; i < tx_num; i++) {
-               slot = tx_slot[i];
-               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
-                               (!(tx_mapped & (1 << slot)))) {
-                       bf5xx_tdm->tx_map[i] = slot;
-                       tx_mapped |= 1 << slot;
-               } else
-                       return -EINVAL;
-       }
-       for (i = 0; i < rx_num; i++) {
-               slot = rx_slot[i];
-               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
-                               (!(rx_mapped & (1 << slot)))) {
-                       bf5xx_tdm->rx_map[i] = slot;
-                       rx_mapped |= 1 << slot;
-               } else
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
-{
-       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
-
-       if (dai->playback_active)
-               sport_tx_stop(sport);
-       if (dai->capture_active)
-               sport_rx_stop(sport);
-
-       /* isolate sync/clock pins from codec while sports resume */
-       peripheral_free_list(sport->pin_req);
-
-       return 0;
-}
-
-static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
-{
-       int ret;
-       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
-
-       ret = sport_set_multichannel(sport, 8, 0xFF, 1);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-       }
-
-       ret = sport_config_rx(sport, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-       }
-
-       ret = sport_config_tx(sport, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-       }
-
-       peripheral_request_list(sport->pin_req, "soc-audio");
-
-       return 0;
-}
-
-#else
-#define bf5xx_tdm_suspend      NULL
-#define bf5xx_tdm_resume       NULL
-#endif
-
-static const struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
-       .hw_params      = bf5xx_tdm_hw_params,
-       .set_fmt        = bf5xx_tdm_set_dai_fmt,
-       .shutdown       = bf5xx_tdm_shutdown,
-       .set_channel_map   = bf5xx_tdm_set_channel_map,
-};
-
-static struct snd_soc_dai_driver bf5xx_tdm_dai = {
-       .suspend = bf5xx_tdm_suspend,
-       .resume = bf5xx_tdm_resume,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
-       .ops = &bf5xx_tdm_dai_ops,
-};
-
-static const struct snd_soc_component_driver bf5xx_tdm_component = {
-       .name           = "bf5xx-tdm",
-};
-
-static int bfin_tdm_probe(struct platform_device *pdev)
-{
-       struct sport_device *sport_handle;
-       int ret;
-
-       /* configure SPORT for TDM */
-       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
-               sizeof(struct bf5xx_tdm_port));
-       if (!sport_handle)
-               return -ENODEV;
-
-       /* SPORT works in TDM mode */
-       ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-               goto sport_config_err;
-       }
-
-       ret = sport_config_rx(sport_handle, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-               goto sport_config_err;
-       }
-
-       ret = sport_config_tx(sport_handle, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-               goto sport_config_err;
-       }
-
-       ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
-                                        &bf5xx_tdm_dai, 1);
-       if (ret) {
-               pr_err("Failed to register DAI: %d\n", ret);
-               goto sport_config_err;
-       }
-
-       return 0;
-
-sport_config_err:
-       sport_done(sport_handle);
-       return ret;
-}
-
-static int bfin_tdm_remove(struct platform_device *pdev)
-{
-       struct sport_device *sport_handle = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_component(&pdev->dev);
-       sport_done(sport_handle);
-
-       return 0;
-}
-
-static struct platform_driver bfin_tdm_driver = {
-       .probe  = bfin_tdm_probe,
-       .remove = bfin_tdm_remove,
-       .driver = {
-               .name   = "bfin-tdm",
-               .owner  = THIS_MODULE,
-       },
-};
-
-module_platform_driver(bfin_tdm_driver);
-
-/* Module information */
-MODULE_AUTHOR("Barry Song");
-MODULE_DESCRIPTION("TDM driver for ADI Blackfin");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
deleted file mode 100644 (file)
index e986a3e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-tdm.h
- *
- * 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 _BF5XX_TDM_H
-#define _BF5XX_TDM_H
-
-#define BFIN_TDM_DAI_MAX_SLOTS 8
-struct bf5xx_tdm_port {
-       u16 tcr1;
-       u16 rcr1;
-       u16 tcr2;
-       u16 rcr2;
-       unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS];
-       unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS];
-       int configured;
-};
-
-#endif
index 88143db..2c20f01 100644 (file)
@@ -1,7 +1,7 @@
 config SND_EP93XX_SOC
        tristate "SoC Audio support for the Cirrus Logic EP93xx series"
        depends on ARCH_EP93XX && SND_SOC
-       select SND_SOC_DMAENGINE_PCM
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
          the EP93xx I2S or AC97 interfaces.
index 4bc9490..ac73c60 100644 (file)
@@ -313,22 +313,15 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
+static int ep93xx_ac97_dai_probe(struct snd_soc_dai *dai)
 {
-       struct ep93xx_dma_data *dma_data;
+       dai->playback_dma_data = &ep93xx_ac97_pcm_out;
+       dai->capture_dma_data = &ep93xx_ac97_pcm_in;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = &ep93xx_ac97_pcm_out;
-       else
-               dma_data = &ep93xx_ac97_pcm_in;
-
-       snd_soc_dai_set_dma_data(dai, substream, dma_data);
        return 0;
 }
 
 static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
-       .startup        = ep93xx_ac97_startup,
        .trigger        = ep93xx_ac97_trigger,
 };
 
@@ -336,6 +329,7 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
        .name           = "ep93xx-ac97",
        .id             = 0,
        .ac97_control   = 1,
+       .probe          = ep93xx_ac97_dai_probe,
        .playback       = {
                .stream_name    = "AC97 Playback",
                .channels_min   = 2,
@@ -406,7 +400,6 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
        return 0;
 
 fail:
-       platform_set_drvdata(pdev, NULL);
        ep93xx_ac97_info = NULL;
        snd_soc_set_ac97_ops(NULL);
        return ret;
@@ -421,7 +414,6 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
        /* disable the AC97 controller */
        ep93xx_ac97_write_reg(info, AC97GCR, 0);
 
-       platform_set_drvdata(pdev, NULL);
        ep93xx_ac97_info = NULL;
 
        snd_soc_set_ac97_ops(NULL);
index 5c1102e..17ad70b 100644 (file)
@@ -60,11 +60,10 @@ struct ep93xx_i2s_info {
        struct clk                      *mclk;
        struct clk                      *sclk;
        struct clk                      *lrclk;
-       struct ep93xx_dma_data          *dma_data;
        void __iomem                    *regs;
 };
 
-struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
+static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
        [SNDRV_PCM_STREAM_PLAYBACK] = {
                .name           = "i2s-pcm-out",
                .port           = EP93XX_DMA_I2S1,
@@ -139,15 +138,11 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
        }
 }
 
-static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
-                             struct snd_soc_dai *dai)
+static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
-       struct snd_soc_dai *cpu_dai = rtd->cpu_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];
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream,
-                                &info->dma_data[substream->stream]);
        return 0;
 }
 
@@ -338,7 +333,6 @@ static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
 #endif
 
 static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
-       .startup        = ep93xx_i2s_startup,
        .shutdown       = ep93xx_i2s_shutdown,
        .hw_params      = ep93xx_i2s_hw_params,
        .set_sysclk     = ep93xx_i2s_set_sysclk,
@@ -349,6 +343,7 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
 
 static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .symmetric_rates= 1,
+       .probe          = ep93xx_i2s_dai_probe,
        .suspend        = ep93xx_i2s_suspend,
        .resume         = ep93xx_i2s_resume,
        .playback       = {
@@ -407,7 +402,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
        }
 
        dev_set_drvdata(&pdev->dev, info);
-       info->dma_data = ep93xx_i2s_dma_data;
 
        err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component,
                                         &ep93xx_i2s_dai, 1);
index 4880326..0e9f56e 100644 (file)
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
+#include <linux/platform_device.h>
 #include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
-#include <mach/hardware.h>
-#include <mach/ep93xx-regs.h>
 
 static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
        .info                   = (SNDRV_PCM_INFO_MMAP          |
@@ -63,134 +57,24 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
        return false;
 }
 
-static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
-
-       return snd_dmaengine_pcm_open_request_chan(substream,
-                       ep93xx_pcm_dma_filter,
-                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
-}
-
-static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-       return 0;
-}
-
-static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       return 0;
-}
-
-static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
-                          struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops ep93xx_pcm_ops = {
-       .open           = ep93xx_pcm_open,
-       .close          = snd_dmaengine_pcm_close_release_chan,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = ep93xx_pcm_hw_params,
-       .hw_free        = ep93xx_pcm_hw_free,
-       .trigger        = snd_dmaengine_pcm_trigger,
-       .pointer        = snd_dmaengine_pcm_pointer_no_residue,
-       .mmap           = ep93xx_pcm_mmap,
-};
-
-static int ep93xx_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 = ep93xx_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_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-       buf->bytes = size;
-
-       return (buf->area == NULL) ? -ENOMEM : 0;
-}
-
-static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {                
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-               
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
-                                     buf->addr);
-               buf->area = NULL;
-       }
-}
-
-static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &ep93xx_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
-                                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       return ret;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
-                                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver ep93xx_soc_platform = {
-       .ops            = &ep93xx_pcm_ops,
-       .pcm_new        = &ep93xx_pcm_new,
-       .pcm_free       = &ep93xx_pcm_free_dma_buffers,
+static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
+       .pcm_hardware = &ep93xx_pcm_hardware,
+       .compat_filter_fn = ep93xx_pcm_dma_filter,
+       .prealloc_buffer_size = 131072,
 };
 
 static int ep93xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
+       return snd_dmaengine_pcm_register(&pdev->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_soc_unregister_platform(&pdev->dev);
+       snd_dmaengine_pcm_unregister(&pdev->dev);
        return 0;
 }
 
index e2bd3dd..8af0434 100644 (file)
@@ -1442,7 +1442,7 @@ static int pm860x_codec_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
                if (!res) {
                        dev_err(&pdev->dev, "Failed to get IRQ resources\n");
-                       goto out;
+                       return -EINVAL;
                }
                pm860x->irq[i] = res->start + chip->irq_base;
                strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
@@ -1452,19 +1452,14 @@ static int pm860x_codec_probe(struct platform_device *pdev)
                                     pm860x_dai, ARRAY_SIZE(pm860x_dai));
        if (ret) {
                dev_err(&pdev->dev, "Failed to register codec\n");
-               goto out;
+               return -EINVAL;
        }
        return ret;
-
-out:
-       platform_set_drvdata(pdev, NULL);
-       return -EINVAL;
 }
 
 static int pm860x_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 2f45f00..badb6fb 100644 (file)
@@ -19,7 +19,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
        select SND_SOC_AD73311
        select SND_SOC_ADAU1373 if I2C
-       select SND_SOC_ADAV80X
+       select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
@@ -40,7 +40,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_DA7213 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
-       select SND_SOC_DFBMCS320
+       select SND_SOC_BT_SCO
        select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
@@ -53,13 +53,15 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_MC13783 if MFD_MC13XXX
        select SND_SOC_ML26124 if I2C
-       select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
+       select SND_SOC_HDMI_CODEC
        select SND_SOC_PCM3008
        select SND_SOC_RT5631 if I2C
+       select SND_SOC_RT5640 if I2C
        select SND_SOC_SGTL5000 if I2C
        select SND_SOC_SI476X if MFD_SI476X_CORE
        select SND_SOC_SN95031 if INTEL_SCU_IPC
        select SND_SOC_SPDIF
+       select SND_SOC_SSM2518 if I2C
        select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
        select SND_SOC_STA32X if I2C
        select SND_SOC_STA529 if I2C
@@ -263,7 +265,7 @@ config SND_SOC_DA732X
 config SND_SOC_DA9055
        tristate
 
-config SND_SOC_DFBMCS320
+config SND_SOC_BT_SCO
        tristate
 
 config SND_SOC_DMIC
@@ -287,7 +289,7 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX9850
        tristate
 
-config SND_SOC_OMAP_HDMI_CODEC
+config SND_SOC_HDMI_CODEC
        tristate
 
 config SND_SOC_PCM3008
@@ -296,6 +298,9 @@ config SND_SOC_PCM3008
 config SND_SOC_RT5631
        tristate
 
+config SND_SOC_RT5640
+       tristate
+
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
        tristate
@@ -313,6 +318,9 @@ config SND_SOC_SN95031
 config SND_SOC_SPDIF
        tristate
 
+config SND_SOC_SSM2518
+       tristate
+
 config SND_SOC_SSM2602
        tristate
 
index b9e41c9..70fd806 100644 (file)
@@ -27,7 +27,7 @@ snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
 snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
-snd-soc-dfbmcs320-objs := dfbmcs320.o
+snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
@@ -41,17 +41,19 @@ snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
-snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
+snd-soc-hdmi-codec-objs := hdmi.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
+snd-soc-rt5640-objs := rt5640.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
 snd-soc-sigmadsp-objs := sigmadsp.o
 snd-soc-si476x-objs := si476x.o
 snd-soc-sn95031-objs := sn95031.o
-snd-soc-spdif-tx-objs := spdif_transciever.o
+snd-soc-spdif-tx-objs := spdif_transmitter.o
 snd-soc-spdif-rx-objs := spdif_receiver.o
+snd-soc-ssm2518-objs := ssm2518.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta529-objs := sta529.o
@@ -154,7 +156,7 @@ obj-$(CONFIG_SND_SOC_DA7210)        += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)   += snd-soc-da7213.o
 obj-$(CONFIG_SND_SOC_DA732X)   += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
-obj-$(CONFIG_SND_SOC_DFBMCS320)        += snd-soc-dfbmcs320.o
+obj-$(CONFIG_SND_SOC_BT_SCO)   += snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
@@ -168,14 +170,16 @@ obj-$(CONFIG_SND_SOC_MAX98095)    += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
-obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
+obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SI476X)   += snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SN95031)  +=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
+obj-$(CONFIG_SND_SOC_SSM2518)  += snd-soc-ssm2518.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
index a153b16..b8ba0ad 100644 (file)
@@ -1496,6 +1496,12 @@ static const char * const enum_ad_to_slot_map[] = {"AD_OUT1",
                                        "AD_OUT7",
                                        "AD_OUT8",
                                        "zeroes",
+                                       "zeroes",
+                                       "zeroes",
+                                       "zeroes",
+                                       "tristate",
+                                       "tristate",
+                                       "tristate",
                                        "tristate"};
 static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map,
                        AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT,
@@ -2230,7 +2236,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
                int slots, int slot_width)
 {
        struct snd_soc_codec *codec = dai->codec;
-       unsigned int val, mask, slots_active;
+       unsigned int val, mask, slot, slots_active;
 
        mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
                BIT(AB8500_DIGIFCONF2_IF0WL1);
@@ -2286,27 +2292,34 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
 
        /* Setup TDM DA according to active tx slots */
+
+       if (tx_mask & ~0xff)
+               return -EINVAL;
+
        mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
+       tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
        slots_active = hweight32(tx_mask);
+
        dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
                slots_active);
+
        switch (slots_active) {
        case 0:
                break;
        case 1:
-               /* Slot 9 -> DA_IN1 & DA_IN3 */
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
+               slot = find_first_bit((unsigned long *)&tx_mask, 32);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
                break;
        case 2:
-               /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
-
+               slot = find_first_bit((unsigned long *)&tx_mask, 32);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
+               slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
                break;
        case 8:
                dev_dbg(dai->codec->dev,
@@ -2321,25 +2334,36 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        }
 
        /* Setup TDM AD according to active RX-slots */
+
+       if (rx_mask & ~0xff)
+               return -EINVAL;
+
+       rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
        slots_active = hweight32(rx_mask);
+
        dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
                slots_active);
+
        switch (slots_active) {
        case 0:
                break;
        case 1:
-               /* AD_OUT3 -> slot 0 & 1 */
-               snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL,
-                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
-                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD);
+               slot = find_first_bit((unsigned long *)&rx_mask, 32);
+               snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot),
+                               AB8500_MASK_SLOT(slot),
+                               AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
                break;
        case 2:
-               /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */
+               slot = find_first_bit((unsigned long *)&rx_mask, 32);
                snd_soc_update_bits(codec,
-                               AB8500_ADSLOTSEL1,
-                               AB8500_MASK_ALL,
-                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
-                               AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD);
+                               AB8500_ADSLOTSEL(slot),
+                               AB8500_MASK_SLOT(slot),
+                               AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
+               slot = find_next_bit((unsigned long *)&rx_mask, 32, slot + 1);
+               snd_soc_update_bits(codec,
+                               AB8500_ADSLOTSEL(slot),
+                               AB8500_MASK_SLOT(slot),
+                               AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
                break;
        case 8:
                dev_dbg(dai->codec->dev,
@@ -2356,6 +2380,11 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        return 0;
 }
 
+static const struct snd_soc_dai_ops ab8500_codec_ops = {
+       .set_fmt = ab8500_codec_set_dai_fmt,
+       .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+};
+
 static struct snd_soc_dai_driver ab8500_codec_dai[] = {
        {
                .name = "ab8500-codec-dai.0",
@@ -2367,12 +2396,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
                        .rates = AB8500_SUPPORTED_RATE,
                        .formats = AB8500_SUPPORTED_FMT,
                },
-               .ops = (struct snd_soc_dai_ops[]) {
-                       {
-                               .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
-                               .set_fmt = ab8500_codec_set_dai_fmt,
-                       }
-               },
+               .ops = &ab8500_codec_ops,
                .symmetric_rates = 1
        },
        {
@@ -2385,12 +2409,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
                        .rates = AB8500_SUPPORTED_RATE,
                        .formats = AB8500_SUPPORTED_FMT,
                },
-               .ops = (struct snd_soc_dai_ops[]) {
-                       {
-                               .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
-                               .set_fmt = ab8500_codec_set_dai_fmt,
-                       }
-               },
+               .ops = &ab8500_codec_ops,
                .symmetric_rates = 1
        }
 };
index 306d0bc..e2e5442 100644 (file)
 #define AB8500_SUPPORTED_RATE                  (SNDRV_PCM_RATE_48000)
 #define AB8500_SUPPORTED_FMT                   (SNDRV_PCM_FMTBIT_S16_LE)
 
+/* AB8500 interface slot offset definitions */
+
+#define AB8500_AD_DATA0_OFFSET 0
+#define AB8500_DA_DATA0_OFFSET 8
+#define AB8500_AD_DATA1_OFFSET 16
+#define AB8500_DA_DATA1_OFFSET 24
+
 /* AB8500 audio bank (0x0d) register definitions */
 
 #define AB8500_POWERUP                         0x00
@@ -73,6 +80,7 @@
 #define AB8500_ADSLOTSEL14                     0x2C
 #define AB8500_ADSLOTSEL15                     0x2D
 #define AB8500_ADSLOTSEL16                     0x2E
+#define AB8500_ADSLOTSEL(slot)                 (AB8500_ADSLOTSEL1 + (slot >> 1))
 #define AB8500_ADSLOTHIZCTRL1                  0x2F
 #define AB8500_ADSLOTHIZCTRL2                  0x30
 #define AB8500_ADSLOTHIZCTRL3                  0x31
 #define AB8500_CACHEREGNUM                     (AB8500_LAST_REG + 1)
 
 #define AB8500_MASK_ALL                                0xFF
+#define AB8500_MASK_SLOT(slot)                 ((slot & 1) ? 0xF0 : 0x0F)
 #define AB8500_MASK_NONE                       0x00
 
 /* AB8500_POWERUP */
 #define AB8500_DIGIFCONF4_IF1WL0               0
 
 /* AB8500_ADSLOTSELX */
-#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD  0x00
-#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD  0x10
-#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD  0x20
-#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD  0x30
-#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD  0x40
-#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD  0x50
-#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD  0x60
-#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD  0x70
-#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD   0x80
-#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0xF0
-#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00
-#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x01
-#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x02
-#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x03
-#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x04
-#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x05
-#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x06
-#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x07
-#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN  0x08
-#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN        0x0F
+#define AB8500_AD_OUT1 0x0
+#define AB8500_AD_OUT2 0x1
+#define AB8500_AD_OUT3 0x2
+#define AB8500_AD_OUT4 0x3
+#define AB8500_AD_OUT5 0x4
+#define AB8500_AD_OUT6 0x5
+#define AB8500_AD_OUT7 0x6
+#define AB8500_AD_OUT8 0x7
+#define AB8500_ZEROES  0x8
+#define AB8500_TRISTATE        0xF
 #define AB8500_ADSLOTSELX_EVEN_SHIFT           0
 #define AB8500_ADSLOTSELX_ODD_SHIFT            4
+#define AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(out, slot)    \
+       ((out) << (((slot) & 1) ? \
+        AB8500_ADSLOTSELX_ODD_SHIFT : AB8500_ADSLOTSELX_EVEN_SHIFT))
 
 /* AB8500_ADSLOTHIZCTRL1 */
 /* AB8500_ADSLOTHIZCTRL2 */
index 389f232..de62581 100644 (file)
@@ -1198,6 +1198,13 @@ const struct snd_soc_dai_ops arizona_dai_ops = {
 };
 EXPORT_SYMBOL_GPL(arizona_dai_ops);
 
+const struct snd_soc_dai_ops arizona_simple_dai_ops = {
+       .startup = arizona_startup,
+       .hw_params = arizona_hw_params_rate,
+       .set_sysclk = arizona_dai_set_sysclk,
+};
+EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
+
 int arizona_init_dai(struct arizona_priv *priv, int id)
 {
        struct arizona_dai_priv *dai_priv = &priv->dai[id];
index af39f10..b60b08c 100644 (file)
@@ -57,7 +57,7 @@
 #define ARIZONA_CLK_98MHZ  5
 #define ARIZONA_CLK_147MHZ 6
 
-#define ARIZONA_MAX_DAI  4
+#define ARIZONA_MAX_DAI  6
 #define ARIZONA_MAX_ADSP 4
 
 struct arizona;
@@ -213,6 +213,7 @@ extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                              int source, unsigned int freq, int dir);
 
 extern const struct snd_soc_dai_ops arizona_dai_ops;
+extern const struct snd_soc_dai_ops arizona_simple_dai_ops;
 
 #define ARIZONA_FLL_NAME_LEN 20
 
similarity index 53%
rename from sound/soc/codecs/dfbmcs320.c
rename to sound/soc/codecs/bt-sco.c
index 4f4f7f4..a081d9f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Driver for the DFBM-CS320 bluetooth module
+ * Driver for generic Bluetooth SCO link
  * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -15,8 +15,8 @@
 
 #include <sound/soc.h>
 
-static struct snd_soc_dai_driver dfbmcs320_dai = {
-       .name = "dfbmcs320-pcm",
+static struct snd_soc_dai_driver bt_sco_dai = {
+       .name = "bt-sco-pcm",
        .playback = {
                .channels_min = 1,
                .channels_max = 1,
@@ -31,32 +31,41 @@ static struct snd_soc_dai_driver dfbmcs320_dai = {
        },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_dfbmcs320;
+static struct snd_soc_codec_driver soc_codec_dev_bt_sco;
 
-static int dfbmcs320_probe(struct platform_device *pdev)
+static int bt_sco_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_dfbmcs320,
-                       &dfbmcs320_dai, 1);
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
+                       &bt_sco_dai, 1);
 }
 
-static int dfbmcs320_remove(struct platform_device *pdev)
+static int bt_sco_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
 
        return 0;
 }
 
-static struct platform_driver dfmcs320_driver = {
+static struct platform_device_id bt_sco_driver_ids[] = {
+       {
+               .name           = "dfbmcs320",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
+
+static struct platform_driver bt_sco_driver = {
        .driver = {
-               .name = "dfbmcs320",
+               .name = "bt-sco",
                .owner = THIS_MODULE,
        },
-       .probe = dfbmcs320_probe,
-       .remove = dfbmcs320_remove,
+       .probe = bt_sco_probe,
+       .remove = bt_sco_remove,
+       .id_table = bt_sco_driver_ids,
 };
 
-module_platform_driver(dfmcs320_driver);
+module_platform_driver(bt_sco_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("ASoC DFBM-CS320 bluethooth module driver");
+MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver");
 MODULE_LICENSE("GPL");
similarity index 69%
rename from sound/soc/codecs/omap-hdmi.c
rename to sound/soc/codecs/hdmi.c
index 529d064..2bcae2b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ALSA SoC codec driver for HDMI audio on OMAP processors.
+ * ALSA SoC codec driver for HDMI audio codecs.
  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
  * Author: Ricardo Neri <ricardo.neri@ti.com>
  *
 
 #define DRV_NAME "hdmi-audio-codec"
 
-static struct snd_soc_codec_driver omap_hdmi_codec;
+static struct snd_soc_codec_driver hdmi_codec;
 
-static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
-       .name = "omap-hdmi-hifi",
+static struct snd_soc_dai_driver hdmi_codec_dai = {
+       .name = "hdmi-hifi",
        .playback = {
                .channels_min = 2,
                .channels_max = 8,
@@ -39,31 +39,31 @@ static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
        },
 };
 
-static int omap_hdmi_codec_probe(struct platform_device *pdev)
+static int hdmi_codec_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec,
-                       &omap_hdmi_codec_dai, 1);
+       return snd_soc_register_codec(&pdev->dev, &hdmi_codec,
+                       &hdmi_codec_dai, 1);
 }
 
-static int omap_hdmi_codec_remove(struct platform_device *pdev)
+static int hdmi_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
-static struct platform_driver omap_hdmi_codec_driver = {
+static struct platform_driver hdmi_codec_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
 
-       .probe          = omap_hdmi_codec_probe,
-       .remove         = omap_hdmi_codec_remove,
+       .probe          = hdmi_codec_probe,
+       .remove         = hdmi_codec_remove,
 };
 
-module_platform_driver(omap_hdmi_codec_driver);
+module_platform_driver(hdmi_codec_driver);
 
 MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver");
+MODULE_DESCRIPTION("ASoC generic HDMI codec driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
index 5f607b3..bcebd1a 100644 (file)
@@ -384,8 +384,6 @@ static int jz4740_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 8d14a76..ad5313f 100644 (file)
@@ -857,6 +857,14 @@ static const struct soc_enum mic2_mux_enum =
 static const struct snd_kcontrol_new max98090_mic2_mux =
        SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
 
+static const char *dmic_mux_text[] = { "ADC", "DMIC" };
+
+static const struct soc_enum dmic_mux_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text);
+
+static const struct snd_kcontrol_new max98090_dmic_mux =
+       SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum);
+
 static const char *max98090_micpre_text[] = { "Off", "On" };
 
 static const struct soc_enum max98090_pa1en_enum =
@@ -1144,6 +1152,9 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,
                0, 0, &max98090_mic2_mux),
 
+       SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM,
+               0, 0, &max98090_dmic_mux),
+
        SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
                M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
                SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1336,11 +1347,14 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
        {"ADCL", NULL, "SHDN"},
        {"ADCR", NULL, "SHDN"},
 
-       {"LBENL Mux", "Normal", "ADCL"},
-       {"LBENL Mux", "Normal", "DMICL"},
+       {"DMIC Mux", "ADC", "ADCL"},
+       {"DMIC Mux", "ADC", "ADCR"},
+       {"DMIC Mux", "DMIC", "DMICL"},
+       {"DMIC Mux", "DMIC", "DMICR"},
+
+       {"LBENL Mux", "Normal", "DMIC Mux"},
        {"LBENL Mux", "Loopback", "LTENL Mux"},
-       {"LBENR Mux", "Normal", "ADCR"},
-       {"LBENR Mux", "Normal", "DMICR"},
+       {"LBENR Mux", "Normal", "DMIC Mux"},
        {"LBENR Mux", "Loopback", "LTENR Mux"},
 
        {"AIFOUTL", NULL, "LBENL Mux"},
@@ -2336,6 +2350,7 @@ static int max98090_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
 static int max98090_runtime_resume(struct device *dev)
 {
        struct max98090_priv *max98090 = dev_get_drvdata(dev);
@@ -2355,6 +2370,7 @@ static int max98090_runtime_suspend(struct device *dev)
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops max98090_pm = {
        SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
new file mode 100644 (file)
index 0000000..ce585e3
--- /dev/null
@@ -0,0 +1,2128 @@
+/*
+ * rt5640.c  --  RT5640 ALSA SoC audio codec driver
+ *
+ * Copyright 2011 Realtek Semiconductor Corp.
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5640.h"
+
+#define RT5640_DEVICE_ID 0x6231
+
+#define RT5640_PR_RANGE_BASE (0xff + 1)
+#define RT5640_PR_SPACING 0x100
+
+#define RT5640_PR_BASE (RT5640_PR_RANGE_BASE + (0 * RT5640_PR_SPACING))
+
+static const struct regmap_range_cfg rt5640_ranges[] = {
+       { .name = "PR", .range_min = RT5640_PR_BASE,
+         .range_max = RT5640_PR_BASE + 0xb4,
+         .selector_reg = RT5640_PRIV_INDEX,
+         .selector_mask = 0xff,
+         .selector_shift = 0x0,
+         .window_start = RT5640_PRIV_DATA,
+         .window_len = 0x1, },
+};
+
+static struct reg_default init_list[] = {
+       {RT5640_PR_BASE + 0x3d, 0x3600},
+       {RT5640_PR_BASE + 0x1c, 0x0D21},
+       {RT5640_PR_BASE + 0x1b, 0x0000},
+       {RT5640_PR_BASE + 0x12, 0x0aa8},
+       {RT5640_PR_BASE + 0x14, 0x0aaa},
+       {RT5640_PR_BASE + 0x20, 0x6110},
+       {RT5640_PR_BASE + 0x21, 0xe0e0},
+       {RT5640_PR_BASE + 0x23, 0x1804},
+};
+#define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
+       { 0x00, 0x000e },
+       { 0x01, 0xc8c8 },
+       { 0x02, 0xc8c8 },
+       { 0x03, 0xc8c8 },
+       { 0x04, 0x8000 },
+       { 0x0d, 0x0000 },
+       { 0x0e, 0x0000 },
+       { 0x0f, 0x0808 },
+       { 0x19, 0xafaf },
+       { 0x1a, 0xafaf },
+       { 0x1b, 0x0000 },
+       { 0x1c, 0x2f2f },
+       { 0x1d, 0x2f2f },
+       { 0x1e, 0x0000 },
+       { 0x27, 0x7060 },
+       { 0x28, 0x7070 },
+       { 0x29, 0x8080 },
+       { 0x2a, 0x5454 },
+       { 0x2b, 0x5454 },
+       { 0x2c, 0xaa00 },
+       { 0x2d, 0x0000 },
+       { 0x2e, 0xa000 },
+       { 0x2f, 0x0000 },
+       { 0x3b, 0x0000 },
+       { 0x3c, 0x007f },
+       { 0x3d, 0x0000 },
+       { 0x3e, 0x007f },
+       { 0x45, 0xe000 },
+       { 0x46, 0x003e },
+       { 0x47, 0x003e },
+       { 0x48, 0xf800 },
+       { 0x49, 0x3800 },
+       { 0x4a, 0x0004 },
+       { 0x4c, 0xfc00 },
+       { 0x4d, 0x0000 },
+       { 0x4f, 0x01ff },
+       { 0x50, 0x0000 },
+       { 0x51, 0x0000 },
+       { 0x52, 0x01ff },
+       { 0x53, 0xf000 },
+       { 0x61, 0x0000 },
+       { 0x62, 0x0000 },
+       { 0x63, 0x00c0 },
+       { 0x64, 0x0000 },
+       { 0x65, 0x0000 },
+       { 0x66, 0x0000 },
+       { 0x6a, 0x0000 },
+       { 0x6c, 0x0000 },
+       { 0x70, 0x8000 },
+       { 0x71, 0x8000 },
+       { 0x72, 0x8000 },
+       { 0x73, 0x1114 },
+       { 0x74, 0x0c00 },
+       { 0x75, 0x1d00 },
+       { 0x80, 0x0000 },
+       { 0x81, 0x0000 },
+       { 0x82, 0x0000 },
+       { 0x83, 0x0000 },
+       { 0x84, 0x0000 },
+       { 0x85, 0x0008 },
+       { 0x89, 0x0000 },
+       { 0x8a, 0x0000 },
+       { 0x8b, 0x0600 },
+       { 0x8c, 0x0228 },
+       { 0x8d, 0xa000 },
+       { 0x8e, 0x0004 },
+       { 0x8f, 0x1100 },
+       { 0x90, 0x0646 },
+       { 0x91, 0x0c00 },
+       { 0x92, 0x0000 },
+       { 0x93, 0x3000 },
+       { 0xb0, 0x2080 },
+       { 0xb1, 0x0000 },
+       { 0xb4, 0x2206 },
+       { 0xb5, 0x1f00 },
+       { 0xb6, 0x0000 },
+       { 0xb8, 0x034b },
+       { 0xb9, 0x0066 },
+       { 0xba, 0x000b },
+       { 0xbb, 0x0000 },
+       { 0xbc, 0x0000 },
+       { 0xbd, 0x0000 },
+       { 0xbe, 0x0000 },
+       { 0xbf, 0x0000 },
+       { 0xc0, 0x0400 },
+       { 0xc2, 0x0000 },
+       { 0xc4, 0x0000 },
+       { 0xc5, 0x0000 },
+       { 0xc6, 0x2000 },
+       { 0xc8, 0x0000 },
+       { 0xc9, 0x0000 },
+       { 0xca, 0x0000 },
+       { 0xcb, 0x0000 },
+       { 0xcc, 0x0000 },
+       { 0xcf, 0x0013 },
+       { 0xd0, 0x0680 },
+       { 0xd1, 0x1c17 },
+       { 0xd2, 0x8c00 },
+       { 0xd3, 0xaa20 },
+       { 0xd6, 0x0400 },
+       { 0xd9, 0x0809 },
+       { 0xfe, 0x10ec },
+       { 0xff, 0x6231 },
+};
+
+static int rt5640_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, RT5640_RESET, 0);
+}
+
+static bool rt5640_volatile_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5640_ranges); i++)
+               if ((reg >= rt5640_ranges[i].window_start &&
+                    reg <= rt5640_ranges[i].window_start +
+                    rt5640_ranges[i].window_len) ||
+                   (reg >= rt5640_ranges[i].range_min &&
+                    reg <= rt5640_ranges[i].range_max))
+                       return true;
+
+       switch (reg) {
+       case RT5640_RESET:
+       case RT5640_ASRC_5:
+       case RT5640_EQ_CTRL1:
+       case RT5640_DRC_AGC_1:
+       case RT5640_ANC_CTRL1:
+       case RT5640_IRQ_CTRL2:
+       case RT5640_INT_IRQ_ST:
+       case RT5640_DSP_CTRL2:
+       case RT5640_DSP_CTRL3:
+       case RT5640_PRIV_INDEX:
+       case RT5640_PRIV_DATA:
+       case RT5640_PGM_REG_ARR1:
+       case RT5640_PGM_REG_ARR3:
+       case RT5640_VENDOR_ID:
+       case RT5640_VENDOR_ID1:
+       case RT5640_VENDOR_ID2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5640_readable_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5640_ranges); i++)
+               if ((reg >= rt5640_ranges[i].window_start &&
+                    reg <= rt5640_ranges[i].window_start +
+                    rt5640_ranges[i].window_len) ||
+                   (reg >= rt5640_ranges[i].range_min &&
+                    reg <= rt5640_ranges[i].range_max))
+                       return true;
+
+       switch (reg) {
+       case RT5640_RESET:
+       case RT5640_SPK_VOL:
+       case RT5640_HP_VOL:
+       case RT5640_OUTPUT:
+       case RT5640_MONO_OUT:
+       case RT5640_IN1_IN2:
+       case RT5640_IN3_IN4:
+       case RT5640_INL_INR_VOL:
+       case RT5640_DAC1_DIG_VOL:
+       case RT5640_DAC2_DIG_VOL:
+       case RT5640_DAC2_CTRL:
+       case RT5640_ADC_DIG_VOL:
+       case RT5640_ADC_DATA:
+       case RT5640_ADC_BST_VOL:
+       case RT5640_STO_ADC_MIXER:
+       case RT5640_MONO_ADC_MIXER:
+       case RT5640_AD_DA_MIXER:
+       case RT5640_STO_DAC_MIXER:
+       case RT5640_MONO_DAC_MIXER:
+       case RT5640_DIG_MIXER:
+       case RT5640_DSP_PATH1:
+       case RT5640_DSP_PATH2:
+       case RT5640_DIG_INF_DATA:
+       case RT5640_REC_L1_MIXER:
+       case RT5640_REC_L2_MIXER:
+       case RT5640_REC_R1_MIXER:
+       case RT5640_REC_R2_MIXER:
+       case RT5640_HPO_MIXER:
+       case RT5640_SPK_L_MIXER:
+       case RT5640_SPK_R_MIXER:
+       case RT5640_SPO_L_MIXER:
+       case RT5640_SPO_R_MIXER:
+       case RT5640_SPO_CLSD_RATIO:
+       case RT5640_MONO_MIXER:
+       case RT5640_OUT_L1_MIXER:
+       case RT5640_OUT_L2_MIXER:
+       case RT5640_OUT_L3_MIXER:
+       case RT5640_OUT_R1_MIXER:
+       case RT5640_OUT_R2_MIXER:
+       case RT5640_OUT_R3_MIXER:
+       case RT5640_LOUT_MIXER:
+       case RT5640_PWR_DIG1:
+       case RT5640_PWR_DIG2:
+       case RT5640_PWR_ANLG1:
+       case RT5640_PWR_ANLG2:
+       case RT5640_PWR_MIXER:
+       case RT5640_PWR_VOL:
+       case RT5640_PRIV_INDEX:
+       case RT5640_PRIV_DATA:
+       case RT5640_I2S1_SDP:
+       case RT5640_I2S2_SDP:
+       case RT5640_ADDA_CLK1:
+       case RT5640_ADDA_CLK2:
+       case RT5640_DMIC:
+       case RT5640_GLB_CLK:
+       case RT5640_PLL_CTRL1:
+       case RT5640_PLL_CTRL2:
+       case RT5640_ASRC_1:
+       case RT5640_ASRC_2:
+       case RT5640_ASRC_3:
+       case RT5640_ASRC_4:
+       case RT5640_ASRC_5:
+       case RT5640_HP_OVCD:
+       case RT5640_CLS_D_OVCD:
+       case RT5640_CLS_D_OUT:
+       case RT5640_DEPOP_M1:
+       case RT5640_DEPOP_M2:
+       case RT5640_DEPOP_M3:
+       case RT5640_CHARGE_PUMP:
+       case RT5640_PV_DET_SPK_G:
+       case RT5640_MICBIAS:
+       case RT5640_EQ_CTRL1:
+       case RT5640_EQ_CTRL2:
+       case RT5640_WIND_FILTER:
+       case RT5640_DRC_AGC_1:
+       case RT5640_DRC_AGC_2:
+       case RT5640_DRC_AGC_3:
+       case RT5640_SVOL_ZC:
+       case RT5640_ANC_CTRL1:
+       case RT5640_ANC_CTRL2:
+       case RT5640_ANC_CTRL3:
+       case RT5640_JD_CTRL:
+       case RT5640_ANC_JD:
+       case RT5640_IRQ_CTRL1:
+       case RT5640_IRQ_CTRL2:
+       case RT5640_INT_IRQ_ST:
+       case RT5640_GPIO_CTRL1:
+       case RT5640_GPIO_CTRL2:
+       case RT5640_GPIO_CTRL3:
+       case RT5640_DSP_CTRL1:
+       case RT5640_DSP_CTRL2:
+       case RT5640_DSP_CTRL3:
+       case RT5640_DSP_CTRL4:
+       case RT5640_PGM_REG_ARR1:
+       case RT5640_PGM_REG_ARR2:
+       case RT5640_PGM_REG_ARR3:
+       case RT5640_PGM_REG_ARR4:
+       case RT5640_PGM_REG_ARR5:
+       case RT5640_SCB_FUNC:
+       case RT5640_SCB_CTRL:
+       case RT5640_BASE_BACK:
+       case RT5640_MP3_PLUS1:
+       case RT5640_MP3_PLUS2:
+       case RT5640_3D_HP:
+       case RT5640_ADJ_HPF:
+       case RT5640_HP_CALIB_AMP_DET:
+       case RT5640_HP_CALIB2:
+       case RT5640_SV_ZCD1:
+       case RT5640_SV_ZCD2:
+       case RT5640_DUMMY1:
+       case RT5640_DUMMY2:
+       case RT5640_DUMMY3:
+       case RT5640_VENDOR_ID:
+       case RT5640_VENDOR_ID1:
+       case RT5640_VENDOR_ID2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+       6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+       8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+};
+
+/* Interface data select */
+static const char * const rt5640_data_select[] = {
+       "Normal", "left copy to right", "right copy to left", "Swap"};
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF1_ADC_SEL_SFT, rt5640_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF2_DAC_SEL_SFT, rt5640_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);
+
+/* Class D speaker gain ratio */
+static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x",
+       "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
+       RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
+
+static const struct snd_kcontrol_new rt5640_snd_controls[] = {
+       /* Speaker Output Volume */
+       SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
+               RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* Headphone Output Volume */
+       SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
+               RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* OUTPUT Control */
+       SOC_DOUBLE("OUT Playback Switch", RT5640_OUTPUT,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("OUT Channel Switch", RT5640_OUTPUT,
+               RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* MONO Output Control */
+       SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT,
+                               RT5640_L_MUTE_SFT, 1, 1),
+       /* DAC Digital Volume */
+       SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,
+               RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       /* IN1/IN2 Control */
+       SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,
+               RT5640_BST_SFT1, 8, 0, bst_tlv),
+       SOC_SINGLE_TLV("IN2 Boost", RT5640_IN3_IN4,
+               RT5640_BST_SFT2, 8, 0, bst_tlv),
+       /* INL/INR Volume Control */
+       SOC_DOUBLE_TLV("IN Capture Volume", RT5640_INL_INR_VOL,
+                       RT5640_INL_VOL_SFT, RT5640_INR_VOL_SFT,
+                       31, 1, in_vol_tlv),
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("ADC Capture Switch", RT5640_ADC_DIG_VOL,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+       SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("ADC Boost Gain", RT5640_ADC_BST_VOL,
+                       RT5640_ADC_L_BST_SFT, RT5640_ADC_R_BST_SFT,
+                       3, 0, adc_bst_tlv),
+       /* Class D speaker gain ratio */
+       SOC_ENUM("Class D SPK Ratio Control", rt5640_clsd_spk_ratio_enum),
+
+       SOC_ENUM("ADC IF1 Data Switch", rt5640_if1_adc_enum),
+       SOC_ENUM("DAC IF1 Data Switch", rt5640_if1_dac_enum),
+       SOC_ENUM("ADC IF2 Data Switch", rt5640_if2_adc_enum),
+       SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       int div[] = {2, 3, 4, 6, 8, 12};
+       int idx = -EINVAL, i;
+       int rate, red, bound, temp;
+
+       rate = rt5640->sysclk;
+       red = 3000000 * 12;
+       for (i = 0; i < ARRAY_SIZE(div); i++) {
+               bound = div[i] * 3000000;
+               if (rate > bound)
+                       continue;
+               temp = bound - rate;
+               if (temp < red) {
+                       red = temp;
+                       idx = i;
+               }
+       }
+       if (idx < 0)
+               dev_err(codec->dev, "Failed to set DMIC clock\n");
+       else
+               snd_soc_update_bits(codec, RT5640_DMIC, RT5640_DMIC_CLK_MASK,
+                                       idx << RT5640_DMIC_CLK_SFT);
+       return idx;
+}
+
+static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+
+       val = snd_soc_read(source->codec, RT5640_GLB_CLK);
+       val &= RT5640_SCLK_SRC_MASK;
+       if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T)
+               return 1;
+       else
+               return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_L2_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ANC Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_ANC_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_R2_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ANC Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_ANC_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_L1_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_L2_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_R1_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_R2_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_L2_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dig_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_STO_L_DAC_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_DAC_L2_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dig_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_STO_R_DAC_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_DAC_R2_DAC_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5640_rec_l_mix[] = {
+       SOC_DAPM_SINGLE("HPOL Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_HP_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_IN_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_BST4_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_BST1_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXL Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_rec_r_mix[] = {
+       SOC_DAPM_SINGLE("HPOR Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_HP_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_IN_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_BST4_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_BST1_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXR Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+static const struct snd_kcontrol_new rt5640_spk_l_mix[] = {
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_RM_L_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_IN_L_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_DAC_L1_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_DAC_L2_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXL Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_OM_L_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spk_r_mix[] = {
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_RM_R_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_IN_R_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_DAC_R1_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_DAC_R2_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXR Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_OM_R_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_out_l_mix[] = {
+       SOC_DAPM_SINGLE("SPK MIXL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_SM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_IN_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_RM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_R2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_L2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_out_r_mix[] = {
+       SOC_DAPM_SINGLE("SPK MIXR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_SM_L_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_BST4_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_BST1_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_IN_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_RM_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_L2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_R2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_DAC_R1_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_DAC_L1_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("SPKVOL R Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_SV_R_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("SPKVOL L Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_SV_L_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_BST1_SPM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spo_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_R_MIXER,
+                       RT5640_M_DAC_R1_SPM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("SPKVOL R Switch", RT5640_SPO_R_MIXER,
+                       RT5640_M_SV_R_SPM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_SPO_R_MIXER,
+                       RT5640_M_BST1_SPM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_hpo_mix[] = {
+       SOC_DAPM_SINGLE("HPO MIX DAC2 Switch", RT5640_HPO_MIXER,
+                       RT5640_M_DAC2_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER,
+                       RT5640_M_DAC1_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER,
+                       RT5640_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_lout_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_DAC_L1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_DAC_R1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_OV_L_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_MIXER,
+                       RT5640_M_DAC_R2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_MIXER,
+                       RT5640_M_DAC_L2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5640_MONO_MIXER,
+                       RT5640_M_OV_R_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5640_MONO_MIXER,
+                       RT5640_M_OV_L_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_MONO_MIXER,
+                       RT5640_M_BST1_MM_SFT, 1, 1),
+};
+
+/* INL/R source */
+static const char * const rt5640_inl_src[] = {
+       "IN2P", "MONOP"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_inl_enum, RT5640_INL_INR_VOL,
+       RT5640_INL_SEL_SFT, rt5640_inl_src);
+
+static const struct snd_kcontrol_new rt5640_inl_mux =
+       SOC_DAPM_ENUM("INL source", rt5640_inl_enum);
+
+static const char * const rt5640_inr_src[] = {
+       "IN2N", "MONON"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_inr_enum, RT5640_INL_INR_VOL,
+       RT5640_INR_SEL_SFT, rt5640_inr_src);
+
+static const struct snd_kcontrol_new rt5640_inr_mux =
+       SOC_DAPM_ENUM("INR source", rt5640_inr_enum);
+
+/* Stereo ADC source */
+static const char * const rt5640_stereo_adc1_src[] = {
+       "DIG MIX", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER,
+       RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5640_sto_adc_1_mux =
+       SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum);
+
+static const char * const rt5640_stereo_adc2_src[] = {
+       "DMIC1", "DMIC2", "DIG MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER,
+       RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5640_sto_adc_2_mux =
+       SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum);
+
+/* Mono ADC source */
+static const char * const rt5640_mono_adc_l1_src[] = {
+       "Mono DAC MIXL", "ADCL"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =
+       SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum);
+
+static const char * const rt5640_mono_adc_l2_src[] = {
+       "DMIC L1", "DMIC L2", "Mono DAC MIXL"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux =
+       SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum);
+
+static const char * const rt5640_mono_adc_r1_src[] = {
+       "Mono DAC MIXR", "ADCR"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =
+       SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum);
+
+static const char * const rt5640_mono_adc_r2_src[] = {
+       "DMIC R1", "DMIC R2", "Mono DAC MIXR"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux =
+       SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum);
+
+/* DAC2 channel source */
+static const char * const rt5640_dac_l2_src[] = {
+       "IF2", "Base L/R"
+};
+
+static int rt5640_dac_l2_values[] = {
+       0,
+       3,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT,
+       0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
+
+static const struct snd_kcontrol_new rt5640_dac_l2_mux =
+       SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
+
+static const char * const rt5640_dac_r2_src[] = {
+       "IF2",
+};
+
+static int rt5640_dac_r2_values[] = {
+       0,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT,
+       0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);
+
+static const struct snd_kcontrol_new rt5640_dac_r2_mux =
+       SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum);
+
+/* digital interface and iis interface map */
+static const char * const rt5640_dai_iis_map[] = {
+       "1:1|2:2", "1:2|2:1", "1:1|2:1", "1:2|2:2"
+};
+
+static int rt5640_dai_iis_map_values[] = {
+       0,
+       5,
+       6,
+       7,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT,
+       0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values);
+
+static const struct snd_kcontrol_new rt5640_dai_mux =
+       SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum);
+
+/* SDI select */
+static const char * const rt5640_sdi_sel[] = {
+       "IF1", "IF2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
+       RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);
+
+static const struct snd_kcontrol_new rt5640_sdi_mux =
+       SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
+
+static int spk_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
+                                       0x0001, 0x0001);
+               regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
+                                       0xf000, 0xf000);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
+                                       0xf000, 0x0000);
+               regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
+                                       0x0001, 0x0000);
+               break;
+
+       default:
+               return 0;
+       }
+       return 0;
+}
+
+static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK,
+                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK |
+                       RT5640_DMIC_1_DP_MASK,
+                       RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING |
+                       RT5640_DMIC_1_DP_IN1P);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK,
+                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK |
+                       RT5640_DMIC_2_DP_MASK,
+                       RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING |
+                       RT5640_DMIC_2_DP_IN1N);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
+                       RT5640_PWR_PLL_BIT, 0, NULL, 0),
+       /* Input Side */
+       /* micbias */
+       SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
+                       RT5640_PWR_LDO2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5640_PWR_ANLG2,
+                       RT5640_PWR_MB1_BIT, 0, NULL, 0),
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("DMIC1"),
+       SND_SOC_DAPM_INPUT("DMIC2"),
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN1N"),
+       SND_SOC_DAPM_INPUT("IN2P"),
+       SND_SOC_DAPM_INPUT("IN2N"),
+       SND_SOC_DAPM_PGA("DMIC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC R2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+               set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC,
+               RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event,
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC,
+               RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event,
+               SND_SOC_DAPM_PRE_PMU),
+       /* Boost */
+       SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,
+               RT5640_PWR_BST1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST2", RT5640_PWR_ANLG2,
+               RT5640_PWR_BST4_BIT, 0, NULL, 0),
+       /* Input Volume */
+       SND_SOC_DAPM_PGA("INL VOL", RT5640_PWR_VOL,
+               RT5640_PWR_IN_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL,
+               RT5640_PWR_IN_R_BIT, 0, NULL, 0),
+       /* IN Mux */
+       SND_SOC_DAPM_MUX("INL Mux", SND_SOC_NOPM, 0, 0, &rt5640_inl_mux),
+       SND_SOC_DAPM_MUX("INR Mux", SND_SOC_NOPM, 0, 0, &rt5640_inr_mux),
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0,
+                       rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIXR", RT5640_PWR_MIXER, RT5640_PWR_RM_R_BIT, 0,
+                       rt5640_rec_r_mix, ARRAY_SIZE(rt5640_rec_r_mix)),
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC L", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_ADC_L_BIT, 0),
+       SND_SOC_DAPM_ADC("ADC R", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_ADC_R_BIT, 0),
+       /* ADC Mux */
+       SND_SOC_DAPM_MUX("Stereo ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_2_mux),
+       SND_SOC_DAPM_MUX("Stereo ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_2_mux),
+       SND_SOC_DAPM_MUX("Stereo ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_1_mux),
+       SND_SOC_DAPM_MUX("Stereo ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_l2_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_l1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_r1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_r2_mux),
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("Stereo Filter", RT5640_PWR_DIG2,
+               RT5640_PWR_ADC_SF_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo ADC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_adc_l_mix, ARRAY_SIZE(rt5640_sto_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo ADC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_adc_r_mix, ARRAY_SIZE(rt5640_sto_adc_r_mix)),
+       SND_SOC_DAPM_SUPPLY("Mono Left Filter", RT5640_PWR_DIG2,
+               RT5640_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_adc_l_mix, ARRAY_SIZE(rt5640_mono_adc_l_mix)),
+       SND_SOC_DAPM_SUPPLY("Mono Right Filter", RT5640_PWR_DIG2,
+               RT5640_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_adc_r_mix, ARRAY_SIZE(rt5640_mono_adc_r_mix)),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1", RT5640_PWR_DIG1,
+               RT5640_PWR_I2S1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2", RT5640_PWR_DIG1,
+               RT5640_PWR_I2S2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* Digital Interface Select */
+       SND_SOC_DAPM_MUX("DAI1 RX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI1 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI1 IF1 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI1 IF2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("SDI1 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_sdi_mux),
+       SND_SOC_DAPM_MUX("DAI2 RX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI2 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI2 IF1 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI2 IF2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("SDI2 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_sdi_mux),
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+       /* Audio DSP */
+       SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* ANC */
+       SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)),
+       /* DAC2 channel Mux */
+       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_dac_r2_mux),
+       /* DAC Mixer */
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_dac_r_mix, ARRAY_SIZE(rt5640_mono_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("DIG MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_dig_l_mix, ARRAY_SIZE(rt5640_dig_l_mix)),
+       SND_SOC_DAPM_MIXER("DIG MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_dig_r_mix, ARRAY_SIZE(rt5640_dig_r_mix)),
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_L1_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_L2_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_R1_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_R2_BIT, 0),
+       /* SPK/OUT Mixer */
+       SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,
+               0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
+       SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,
+               0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+               0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+               0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
+       /* Ouput Volume */
+       SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,
+               RT5640_PWR_SV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPKVOL R", RT5640_PWR_VOL,
+               RT5640_PWR_SV_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("OUTVOL L", RT5640_PWR_VOL,
+               RT5640_PWR_OV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("OUTVOL R", RT5640_PWR_VOL,
+               RT5640_PWR_OV_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL L", RT5640_PWR_VOL,
+               RT5640_PWR_HV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL R", RT5640_PWR_VOL,
+               RT5640_PWR_HV_R_BIT, 0, NULL, 0),
+       /* SPO/HPO/LOUT/Mono Mixer */
+       SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0,
+               0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
+       SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
+               0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
+       SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+       SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+       SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,
+               rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)),
+       SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
+               rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
+       SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
+               RT5640_PWR_MA_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Improve HP Amp Drv", RT5640_PWR_ANLG1,
+               SND_SOC_NOPM, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
+               RT5640_PWR_HP_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
+               RT5640_PWR_HP_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
+               SND_SOC_NOPM, 0, spk_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("SPOLP"),
+       SND_SOC_DAPM_OUTPUT("SPOLN"),
+       SND_SOC_DAPM_OUTPUT("SPORP"),
+       SND_SOC_DAPM_OUTPUT("SPORN"),
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+       SND_SOC_DAPM_OUTPUT("MONOP"),
+       SND_SOC_DAPM_OUTPUT("MONON"),
+};
+
+static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
+       {"IN1P", NULL, "LDO2"},
+       {"IN2P", NULL, "LDO2"},
+
+       {"DMIC L1", NULL, "DMIC1"},
+       {"DMIC R1", NULL, "DMIC1"},
+       {"DMIC L2", NULL, "DMIC2"},
+       {"DMIC R2", NULL, "DMIC2"},
+
+       {"BST1", NULL, "IN1P"},
+       {"BST1", NULL, "IN1N"},
+       {"BST2", NULL, "IN2P"},
+       {"BST2", NULL, "IN2N"},
+
+       {"INL VOL", NULL, "IN2P"},
+       {"INR VOL", NULL, "IN2N"},
+
+       {"RECMIXL", "HPOL Switch", "HPOL"},
+       {"RECMIXL", "INL Switch", "INL VOL"},
+       {"RECMIXL", "BST2 Switch", "BST2"},
+       {"RECMIXL", "BST1 Switch", "BST1"},
+       {"RECMIXL", "OUT MIXL Switch", "OUT MIXL"},
+
+       {"RECMIXR", "HPOR Switch", "HPOR"},
+       {"RECMIXR", "INR Switch", "INR VOL"},
+       {"RECMIXR", "BST2 Switch", "BST2"},
+       {"RECMIXR", "BST1 Switch", "BST1"},
+       {"RECMIXR", "OUT MIXR Switch", "OUT MIXR"},
+
+       {"ADC L", NULL, "RECMIXL"},
+       {"ADC R", NULL, "RECMIXR"},
+
+       {"DMIC L1", NULL, "DMIC CLK"},
+       {"DMIC L1", NULL, "DMIC1 Power"},
+       {"DMIC R1", NULL, "DMIC CLK"},
+       {"DMIC R1", NULL, "DMIC1 Power"},
+       {"DMIC L2", NULL, "DMIC CLK"},
+       {"DMIC L2", NULL, "DMIC2 Power"},
+       {"DMIC R2", NULL, "DMIC CLK"},
+       {"DMIC R2", NULL, "DMIC2 Power"},
+
+       {"Stereo ADC L2 Mux", "DMIC1", "DMIC L1"},
+       {"Stereo ADC L2 Mux", "DMIC2", "DMIC L2"},
+       {"Stereo ADC L2 Mux", "DIG MIX", "DIG MIXL"},
+       {"Stereo ADC L1 Mux", "ADC", "ADC L"},
+       {"Stereo ADC L1 Mux", "DIG MIX", "DIG MIXL"},
+
+       {"Stereo ADC R1 Mux", "ADC", "ADC R"},
+       {"Stereo ADC R1 Mux", "DIG MIX", "DIG MIXR"},
+       {"Stereo ADC R2 Mux", "DMIC1", "DMIC R1"},
+       {"Stereo ADC R2 Mux", "DMIC2", "DMIC R2"},
+       {"Stereo ADC R2 Mux", "DIG MIX", "DIG MIXR"},
+
+       {"Mono ADC L2 Mux", "DMIC L1", "DMIC L1"},
+       {"Mono ADC L2 Mux", "DMIC L2", "DMIC L2"},
+       {"Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL"},
+       {"Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL"},
+       {"Mono ADC L1 Mux", "ADCL", "ADC L"},
+
+       {"Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR"},
+       {"Mono ADC R1 Mux", "ADCR", "ADC R"},
+       {"Mono ADC R2 Mux", "DMIC R1", "DMIC R1"},
+       {"Mono ADC R2 Mux", "DMIC R2", "DMIC R2"},
+       {"Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR"},
+
+       {"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
+       {"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
+       {"Stereo ADC MIXL", NULL, "Stereo Filter"},
+       {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
+       {"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
+       {"Stereo ADC MIXR", NULL, "Stereo Filter"},
+       {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
+       {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
+       {"Mono ADC MIXL", NULL, "Mono Left Filter"},
+       {"Mono Left Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
+       {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
+       {"Mono ADC MIXR", NULL, "Mono Right Filter"},
+       {"Mono Right Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"IF2 ADC L", NULL, "Mono ADC MIXL"},
+       {"IF2 ADC R", NULL, "Mono ADC MIXR"},
+       {"IF1 ADC L", NULL, "Stereo ADC MIXL"},
+       {"IF1 ADC R", NULL, "Stereo ADC MIXR"},
+
+       {"IF1 ADC", NULL, "I2S1"},
+       {"IF1 ADC", NULL, "IF1 ADC L"},
+       {"IF1 ADC", NULL, "IF1 ADC R"},
+       {"IF2 ADC", NULL, "I2S2"},
+       {"IF2 ADC", NULL, "IF2 ADC L"},
+       {"IF2 ADC", NULL, "IF2 ADC R"},
+
+       {"DAI1 TX Mux", "1:1|2:2", "IF1 ADC"},
+       {"DAI1 TX Mux", "1:2|2:1", "IF2 ADC"},
+       {"DAI1 IF1 Mux", "1:1|2:1", "IF1 ADC"},
+       {"DAI1 IF2 Mux", "1:1|2:1", "IF2 ADC"},
+       {"SDI1 TX Mux", "IF1", "DAI1 IF1 Mux"},
+       {"SDI1 TX Mux", "IF2", "DAI1 IF2 Mux"},
+
+       {"DAI2 TX Mux", "1:2|2:1", "IF1 ADC"},
+       {"DAI2 TX Mux", "1:1|2:2", "IF2 ADC"},
+       {"DAI2 IF1 Mux", "1:2|2:2", "IF1 ADC"},
+       {"DAI2 IF2 Mux", "1:2|2:2", "IF2 ADC"},
+       {"SDI2 TX Mux", "IF1", "DAI2 IF1 Mux"},
+       {"SDI2 TX Mux", "IF2", "DAI2 IF2 Mux"},
+
+       {"AIF1TX", NULL, "DAI1 TX Mux"},
+       {"AIF1TX", NULL, "SDI1 TX Mux"},
+       {"AIF2TX", NULL, "DAI2 TX Mux"},
+       {"AIF2TX", NULL, "SDI2 TX Mux"},
+
+       {"DAI1 RX Mux", "1:1|2:2", "AIF1RX"},
+       {"DAI1 RX Mux", "1:1|2:1", "AIF1RX"},
+       {"DAI1 RX Mux", "1:2|2:1", "AIF2RX"},
+       {"DAI1 RX Mux", "1:2|2:2", "AIF2RX"},
+
+       {"DAI2 RX Mux", "1:2|2:1", "AIF1RX"},
+       {"DAI2 RX Mux", "1:1|2:1", "AIF1RX"},
+       {"DAI2 RX Mux", "1:1|2:2", "AIF2RX"},
+       {"DAI2 RX Mux", "1:2|2:2", "AIF2RX"},
+
+       {"IF1 DAC", NULL, "I2S1"},
+       {"IF1 DAC", NULL, "DAI1 RX Mux"},
+       {"IF2 DAC", NULL, "I2S2"},
+       {"IF2 DAC", NULL, "DAI2 RX Mux"},
+
+       {"IF1 DAC L", NULL, "IF1 DAC"},
+       {"IF1 DAC R", NULL, "IF1 DAC"},
+       {"IF2 DAC L", NULL, "IF2 DAC"},
+       {"IF2 DAC R", NULL, "IF2 DAC"},
+
+       {"DAC MIXL", "Stereo ADC Switch", "Stereo ADC MIXL"},
+       {"DAC MIXL", "INF1 Switch", "IF1 DAC L"},
+       {"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},
+       {"DAC MIXR", "INF1 Switch", "IF1 DAC R"},
+
+       {"ANC", NULL, "Stereo ADC MIXL"},
+       {"ANC", NULL, "Stereo ADC MIXR"},
+
+       {"Audio DSP", NULL, "DAC MIXL"},
+       {"Audio DSP", NULL, "DAC MIXR"},
+
+       {"DAC L2 Mux", "IF2", "IF2 DAC L"},
+       {"DAC L2 Mux", "Base L/R", "Audio DSP"},
+
+       {"DAC R2 Mux", "IF2", "IF2 DAC R"},
+
+       {"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Stereo DAC MIXL", "ANC Switch", "ANC"},
+       {"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Stereo DAC MIXR", "ANC Switch", "ANC"},
+
+       {"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+
+       {"DIG MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+
+       {"DAC L1", NULL, "Stereo DAC MIXL"},
+       {"DAC L1", NULL, "PLL1", check_sysclk1_source},
+       {"DAC R1", NULL, "Stereo DAC MIXR"},
+       {"DAC R1", NULL, "PLL1", check_sysclk1_source},
+       {"DAC L2", NULL, "Mono DAC MIXL"},
+       {"DAC L2", NULL, "PLL1", check_sysclk1_source},
+       {"DAC R2", NULL, "Mono DAC MIXR"},
+       {"DAC R2", NULL, "PLL1", check_sysclk1_source},
+
+       {"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
+       {"SPK MIXL", "INL Switch", "INL VOL"},
+       {"SPK MIXL", "DAC L1 Switch", "DAC L1"},
+       {"SPK MIXL", "DAC L2 Switch", "DAC L2"},
+       {"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},
+       {"SPK MIXR", "REC MIXR Switch", "RECMIXR"},
+       {"SPK MIXR", "INR Switch", "INR VOL"},
+       {"SPK MIXR", "DAC R1 Switch", "DAC R1"},
+       {"SPK MIXR", "DAC R2 Switch", "DAC R2"},
+       {"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"},
+
+       {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
+       {"OUT MIXL", "BST1 Switch", "BST1"},
+       {"OUT MIXL", "INL Switch", "INL VOL"},
+       {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+       {"OUT MIXL", "DAC R2 Switch", "DAC R2"},
+       {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+       {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+       {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
+       {"OUT MIXR", "BST2 Switch", "BST2"},
+       {"OUT MIXR", "BST1 Switch", "BST1"},
+       {"OUT MIXR", "INR Switch", "INR VOL"},
+       {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+       {"OUT MIXR", "DAC L2 Switch", "DAC L2"},
+       {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+       {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+       {"SPKVOL L", NULL, "SPK MIXL"},
+       {"SPKVOL R", NULL, "SPK MIXR"},
+       {"HPOVOL L", NULL, "OUT MIXL"},
+       {"HPOVOL R", NULL, "OUT MIXR"},
+       {"OUTVOL L", NULL, "OUT MIXL"},
+       {"OUTVOL R", NULL, "OUT MIXR"},
+
+       {"SPOL MIX", "DAC R1 Switch", "DAC R1"},
+       {"SPOL MIX", "DAC L1 Switch", "DAC L1"},
+       {"SPOL MIX", "SPKVOL R Switch", "SPKVOL R"},
+       {"SPOL MIX", "SPKVOL L Switch", "SPKVOL L"},
+       {"SPOL MIX", "BST1 Switch", "BST1"},
+       {"SPOR MIX", "DAC R1 Switch", "DAC R1"},
+       {"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},
+       {"SPOR MIX", "BST1 Switch", "BST1"},
+
+       {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
+       {"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
+       {"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
+       {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
+       {"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
+       {"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
+
+       {"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+       {"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+       {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+       {"Mono MIX", "DAC R2 Switch", "DAC R2"},
+       {"Mono MIX", "DAC L2 Switch", "DAC L2"},
+       {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
+       {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"Mono MIX", "BST1 Switch", "BST1"},
+
+       {"HP L Amp", NULL, "HPO MIX L"},
+       {"HP R Amp", NULL, "HPO MIX R"},
+
+       {"SPOLP", NULL, "SPOL MIX"},
+       {"SPOLN", NULL, "SPOL MIX"},
+       {"SPORP", NULL, "SPOR MIX"},
+       {"SPORN", NULL, "SPOR MIX"},
+
+       {"SPOLP", NULL, "Improve SPK Amp Drv"},
+       {"SPOLN", NULL, "Improve SPK Amp Drv"},
+       {"SPORP", NULL, "Improve SPK Amp Drv"},
+       {"SPORN", NULL, "Improve SPK Amp Drv"},
+
+       {"HPOL", NULL, "Improve HP Amp Drv"},
+       {"HPOR", NULL, "Improve HP Amp Drv"},
+
+       {"HPOL", NULL, "HP L Amp"},
+       {"HPOR", NULL, "HP R Amp"},
+       {"LOUTL", NULL, "LOUT MIX"},
+       {"LOUTR", NULL, "LOUT MIX"},
+       {"MONOP", NULL, "Mono MIX"},
+       {"MONON", NULL, "Mono MIX"},
+       {"MONOP", NULL, "Improve MONO Amp Drv"},
+};
+
+static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
+{
+       int ret = 0, val;
+
+       if (codec == NULL)
+               return -EINVAL;
+
+       val = snd_soc_read(codec, RT5640_I2S1_SDP);
+       val = (val & RT5640_I2S_IF_MASK) >> RT5640_I2S_IF_SFT;
+       switch (dai_id) {
+       case RT5640_AIF1:
+               switch (val) {
+               case RT5640_IF_123:
+               case RT5640_IF_132:
+                       ret |= RT5640_U_IF1;
+                       break;
+               case RT5640_IF_113:
+                       ret |= RT5640_U_IF1;
+               case RT5640_IF_312:
+               case RT5640_IF_213:
+                       ret |= RT5640_U_IF2;
+                       break;
+               }
+               break;
+
+       case RT5640_AIF2:
+               switch (val) {
+               case RT5640_IF_231:
+               case RT5640_IF_213:
+                       ret |= RT5640_U_IF1;
+                       break;
+               case RT5640_IF_223:
+                       ret |= RT5640_U_IF1;
+               case RT5640_IF_123:
+               case RT5640_IF_321:
+                       ret |= RT5640_U_IF2;
+                       break;
+               }
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int get_clk_info(int sclk, int rate)
+{
+       int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+       if (sclk <= 0 || rate <= 0)
+               return -EINVAL;
+
+       rate = rate << 8;
+       for (i = 0; i < ARRAY_SIZE(pd); i++)
+               if (sclk == rate * pd[i])
+                       return i;
+
+       return -EINVAL;
+}
+
+static int rt5640_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_codec *codec = rtd->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0, val_clk, mask_clk, dai_sel;
+       int pre_div, bclk_ms, frame_size;
+
+       rt5640->lrck[dai->id] = params_rate(params);
+       pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
+       if (pre_div < 0) {
+               dev_err(codec->dev, "Unsupported clock setting\n");
+               return -EINVAL;
+       }
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               return frame_size;
+       }
+       if (frame_size > 32)
+               bclk_ms = 1;
+       else
+               bclk_ms = 0;
+       rt5640->bclk[dai->id] = rt5640->lrck[dai->id] * (32 << bclk_ms);
+
+       dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+               rt5640->bclk[dai->id], rt5640->lrck[dai->id]);
+       dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+                               bclk_ms, pre_div, dai->id);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val_len |= RT5640_I2S_DL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val_len |= RT5640_I2S_DL_24;
+               break;
+       case SNDRV_PCM_FORMAT_S8:
+               val_len |= RT5640_I2S_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dai_sel = get_sdp_info(codec, dai->id);
+       if (dai_sel < 0) {
+               dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+               return -EINVAL;
+       }
+       if (dai_sel & RT5640_U_IF1) {
+               mask_clk = RT5640_I2S_BCLK_MS1_MASK | RT5640_I2S_PD1_MASK;
+               val_clk = bclk_ms << RT5640_I2S_BCLK_MS1_SFT |
+                       pre_div << RT5640_I2S_PD1_SFT;
+               snd_soc_update_bits(codec, RT5640_I2S1_SDP,
+                       RT5640_I2S_DL_MASK, val_len);
+               snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
+       }
+       if (dai_sel & RT5640_U_IF2) {
+               mask_clk = RT5640_I2S_BCLK_MS2_MASK | RT5640_I2S_PD2_MASK;
+               val_clk = bclk_ms << RT5640_I2S_BCLK_MS2_SFT |
+                       pre_div << RT5640_I2S_PD2_SFT;
+               snd_soc_update_bits(codec, RT5640_I2S2_SDP,
+                       RT5640_I2S_DL_MASK, val_len);
+               snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
+       }
+
+       return 0;
+}
+
+static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0, dai_sel;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5640->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg_val |= RT5640_I2S_MS_S;
+               rt5640->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5640_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5640_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5640_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val  |= RT5640_I2S_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dai_sel = get_sdp_info(codec, dai->id);
+       if (dai_sel < 0) {
+               dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+               return -EINVAL;
+       }
+       if (dai_sel & RT5640_U_IF1) {
+               snd_soc_update_bits(codec, RT5640_I2S1_SDP,
+                       RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
+                       RT5640_I2S_DF_MASK, reg_val);
+       }
+       if (dai_sel & RT5640_U_IF2) {
+               snd_soc_update_bits(codec, RT5640_I2S2_SDP,
+                       RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
+                       RT5640_I2S_DF_MASK, reg_val);
+       }
+
+       return 0;
+}
+
+static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5640_SCLK_S_MCLK:
+               reg_val |= RT5640_SCLK_SRC_MCLK;
+               break;
+       case RT5640_SCLK_S_PLL1:
+               reg_val |= RT5640_SCLK_SRC_PLL1;
+               break;
+       case RT5640_SCLK_S_PLL1_TK:
+               reg_val |= RT5640_SCLK_SRC_PLL1T;
+               break;
+       case RT5640_SCLK_S_RCCLK:
+               reg_val |= RT5640_SCLK_SRC_RCCLK;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+               RT5640_SCLK_SRC_MASK, reg_val);
+       rt5640->sysclk = freq;
+       rt5640->sysclk_src = clk_id;
+
+       dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+       return 0;
+}
+
+/**
+ * rt5640_pll_calc - Calculate PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ *
+ * Calculate M/N/K code to configure PLL for codec. And K is assigned to 2
+ * which make calculation more efficiently.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5640_pll_calc(const unsigned int freq_in,
+       const unsigned int freq_out, struct rt5640_pll_code *pll_code)
+{
+       int max_n = RT5640_PLL_N_MAX, max_m = RT5640_PLL_M_MAX;
+       int n = 0, m = 0, red, n_t, m_t, in_t, out_t;
+       int red_t = abs(freq_out - freq_in);
+       bool bypass = false;
+
+       if (RT5640_PLL_INP_MAX < freq_in || RT5640_PLL_INP_MIN > freq_in)
+               return -EINVAL;
+
+       for (n_t = 0; n_t <= max_n; n_t++) {
+               in_t = (freq_in >> 1) + (freq_in >> 2) * n_t;
+               if (in_t < 0)
+                       continue;
+               if (in_t == freq_out) {
+                       bypass = true;
+                       n = n_t;
+                       goto code_find;
+               }
+               for (m_t = 0; m_t <= max_m; m_t++) {
+                       out_t = in_t / (m_t + 2);
+                       red = abs(out_t - freq_out);
+                       if (red < red_t) {
+                               n = n_t;
+                               m = m_t;
+                               if (red == 0)
+                                       goto code_find;
+                               red_t = red;
+                       }
+               }
+       }
+       pr_debug("Only get approximation about PLL\n");
+
+code_find:
+       pll_code->m_bp = bypass;
+       pll_code->m_code = m;
+       pll_code->n_code = n;
+       pll_code->k_code = 2;
+       return 0;
+}
+
+static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+                       unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       struct rt5640_pll_code *pll_code = &rt5640->pll_code;
+       int ret, dai_sel;
+
+       if (source == rt5640->pll_src && freq_in == rt5640->pll_in &&
+           freq_out == rt5640->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(codec->dev, "PLL disabled\n");
+
+               rt5640->pll_in = 0;
+               rt5640->pll_out = 0;
+               snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                       RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (source) {
+       case RT5640_PLL1_S_MCLK:
+               snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                       RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_MCLK);
+               break;
+       case RT5640_PLL1_S_BCLK1:
+       case RT5640_PLL1_S_BCLK2:
+               dai_sel = get_sdp_info(codec, dai->id);
+               if (dai_sel < 0) {
+                       dev_err(codec->dev,
+                               "Failed to get sdp info: %d\n", dai_sel);
+                       return -EINVAL;
+               }
+               if (dai_sel & RT5640_U_IF1) {
+                       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                               RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK1);
+               }
+               if (dai_sel & RT5640_U_IF2) {
+                       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                               RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK2);
+               }
+               break;
+       default:
+               dev_err(codec->dev, "Unknown PLL source %d\n", source);
+               return -EINVAL;
+       }
+
+       ret = rt5640_pll_calc(freq_in, freq_out, pll_code);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp,
+               (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code);
+
+       snd_soc_write(codec, RT5640_PLL_CTRL1,
+               pll_code->n_code << RT5640_PLL_N_SFT | pll_code->k_code);
+       snd_soc_write(codec, RT5640_PLL_CTRL2,
+               (pll_code->m_bp ? 0 : pll_code->m_code) << RT5640_PLL_M_SFT |
+               pll_code->m_bp << RT5640_PLL_M_BP_SFT);
+
+       rt5640->pll_in = freq_in;
+       rt5640->pll_out = freq_out;
+       rt5640->pll_src = source;
+
+       return 0;
+}
+
+static int rt5640_set_bias_level(struct snd_soc_codec *codec,
+                       enum snd_soc_bias_level level)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+                       regcache_cache_only(rt5640->regmap, false);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_VREF1 | RT5640_PWR_MB |
+                               RT5640_PWR_BG | RT5640_PWR_VREF2,
+                               RT5640_PWR_VREF1 | RT5640_PWR_MB |
+                               RT5640_PWR_BG | RT5640_PWR_VREF2);
+                       mdelay(10);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2);
+                       regcache_sync(rt5640->regmap);
+                       snd_soc_update_bits(codec, RT5640_DUMMY1,
+                                               0x0301, 0x0301);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                                               0x001d, 0x0019);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M2,
+                                               0x2000, 0x2000);
+                       snd_soc_update_bits(codec, RT5640_MICBIAS,
+                                               0x0030, 0x0030);
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, RT5640_DEPOP_M1, 0x0004);
+               snd_soc_write(codec, RT5640_DEPOP_M2, 0x1100);
+               snd_soc_update_bits(codec, RT5640_DUMMY1, 0x1, 0);
+               snd_soc_write(codec, RT5640_PWR_DIG1, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_DIG2, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_VOL, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_MIXER, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_ANLG1, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_ANLG2, 0x0000);
+               break;
+
+       default:
+               break;
+       }
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int rt5640_probe(struct snd_soc_codec *codec)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       rt5640->codec = codec;
+       codec->control_data = rt5640->regmap;
+
+       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;
+       }
+
+       codec->dapm.idle_bias_off = 1;
+       rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
+       snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
+       snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
+
+       return 0;
+}
+
+static int rt5640_remove(struct snd_soc_codec *codec)
+{
+       rt5640_reset(codec);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5640_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       rt5640_reset(codec);
+       regcache_cache_only(rt5640->regmap, true);
+       regcache_mark_dirty(rt5640->regmap);
+
+       return 0;
+}
+
+static int rt5640_resume(struct snd_soc_codec *codec)
+{
+       rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define rt5640_suspend NULL
+#define rt5640_resume NULL
+#endif
+
+#define RT5640_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5640_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5640_aif_dai_ops = {
+       .hw_params = rt5640_hw_params,
+       .set_fmt = rt5640_set_dai_fmt,
+       .set_sysclk = rt5640_set_dai_sysclk,
+       .set_pll = rt5640_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5640_dai[] = {
+       {
+               .name = "rt5640-aif1",
+               .id = RT5640_AIF1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .ops = &rt5640_aif_dai_ops,
+       },
+       {
+               .name = "rt5640-aif2",
+               .id = RT5640_AIF2,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .ops = &rt5640_aif_dai_ops,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
+       .probe = rt5640_probe,
+       .remove = rt5640_remove,
+       .suspend = rt5640_suspend,
+       .resume = rt5640_resume,
+       .set_bias_level = rt5640_set_bias_level,
+       .controls = rt5640_snd_controls,
+       .num_controls = ARRAY_SIZE(rt5640_snd_controls),
+       .dapm_widgets = rt5640_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets),
+       .dapm_routes = rt5640_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes),
+};
+
+static const struct regmap_config rt5640_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) *
+                                              RT5640_PR_SPACING),
+       .volatile_reg = rt5640_volatile_register,
+       .readable_reg = rt5640_readable_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5640_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5640_reg),
+       .ranges = rt5640_ranges,
+       .num_ranges = ARRAY_SIZE(rt5640_ranges),
+};
+
+static const struct i2c_device_id rt5640_i2c_id[] = {
+       { "rt5640", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
+
+static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
+{
+       rt5640->pdata.in1_diff = of_property_read_bool(np,
+                                       "realtek,in1-differential");
+       rt5640->pdata.in2_diff = of_property_read_bool(np,
+                                       "realtek,in2-differential");
+
+       rt5640->pdata.ldo1_en = of_get_named_gpio(np,
+                                       "realtek,ldo1-en-gpios", 0);
+       /*
+        * LDO1_EN is optional (it may be statically tied on the board).
+        * -ENOENT means that the property doesn't exist, i.e. there is no
+        * GPIO, so is not an error. Any other error code means the property
+        * exists, but could not be parsed.
+        */
+       if (!gpio_is_valid(rt5640->pdata.ldo1_en) &&
+                       (rt5640->pdata.ldo1_en != -ENOENT))
+               return rt5640->pdata.ldo1_en;
+
+       return 0;
+}
+
+static int rt5640_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       struct rt5640_priv *rt5640;
+       int ret;
+       unsigned int val;
+
+       rt5640 = devm_kzalloc(&i2c->dev,
+                               sizeof(struct rt5640_priv),
+                               GFP_KERNEL);
+       if (NULL == rt5640)
+               return -ENOMEM;
+       i2c_set_clientdata(i2c, rt5640);
+
+       if (pdata) {
+               rt5640->pdata = *pdata;
+               /*
+                * Translate zero'd out (default) pdata value to an invalid
+                * GPIO ID. This makes the pdata and DT paths consistent in
+                * terms of the value left in this field when no GPIO is
+                * specified, but means we can't actually use GPIO 0.
+                */
+               if (!rt5640->pdata.ldo1_en)
+                       rt5640->pdata.ldo1_en = -EINVAL;
+       } else if (i2c->dev.of_node) {
+               ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
+               if (ret)
+                       return ret;
+       } else
+               rt5640->pdata.ldo1_en = -EINVAL;
+
+       rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
+       if (IS_ERR(rt5640->regmap)) {
+               ret = PTR_ERR(rt5640->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
+               ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "RT5640 LDO1_EN");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
+                               rt5640->pdata.ldo1_en, ret);
+                       return ret;
+               }
+               msleep(400);
+       }
+
+       regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
+       if ((val != RT5640_DEVICE_ID)) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %x is not rt5640/39\n", val);
+               return -ENODEV;
+       }
+
+       regmap_write(rt5640->regmap, RT5640_RESET, 0);
+
+       ret = regmap_register_patch(rt5640->regmap, init_list,
+                                   ARRAY_SIZE(init_list));
+       if (ret != 0)
+               dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+       if (rt5640->pdata.in1_diff)
+               regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
+                                       RT5640_IN_DF1, RT5640_IN_DF1);
+
+       if (rt5640->pdata.in2_diff)
+               regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
+                                       RT5640_IN_DF2, RT5640_IN_DF2);
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
+                       rt5640_dai, ARRAY_SIZE(rt5640_dai));
+       if (ret < 0)
+               goto err;
+
+       return 0;
+err:
+       return ret;
+}
+
+static int rt5640_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static struct i2c_driver rt5640_i2c_driver = {
+       .driver = {
+               .name = "rt5640",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5640_i2c_probe,
+       .remove   = rt5640_i2c_remove,
+       .id_table = rt5640_i2c_id,
+};
+module_i2c_driver(rt5640_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5640 driver");
+MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
new file mode 100644 (file)
index 0000000..c48286d
--- /dev/null
@@ -0,0 +1,2092 @@
+/*
+ * rt5640.h  --  RT5640 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _RT5640_H
+#define _RT5640_H
+
+#include <sound/rt5640.h>
+
+/* Info */
+#define RT5640_RESET                           0x00
+#define RT5640_VENDOR_ID                       0xfd
+#define RT5640_VENDOR_ID1                      0xfe
+#define RT5640_VENDOR_ID2                      0xff
+/*  I/O - Output */
+#define RT5640_SPK_VOL                         0x01
+#define RT5640_HP_VOL                          0x02
+#define RT5640_OUTPUT                          0x03
+#define RT5640_MONO_OUT                                0x04
+/* I/O - Input */
+#define RT5640_IN1_IN2                         0x0d
+#define RT5640_IN3_IN4                         0x0e
+#define RT5640_INL_INR_VOL                     0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5640_DAC1_DIG_VOL                    0x19
+#define RT5640_DAC2_DIG_VOL                    0x1a
+#define RT5640_DAC2_CTRL                       0x1b
+#define RT5640_ADC_DIG_VOL                     0x1c
+#define RT5640_ADC_DATA                                0x1d
+#define RT5640_ADC_BST_VOL                     0x1e
+/* Mixer - D-D */
+#define RT5640_STO_ADC_MIXER                   0x27
+#define RT5640_MONO_ADC_MIXER                  0x28
+#define RT5640_AD_DA_MIXER                     0x29
+#define RT5640_STO_DAC_MIXER                   0x2a
+#define RT5640_MONO_DAC_MIXER                  0x2b
+#define RT5640_DIG_MIXER                       0x2c
+#define RT5640_DSP_PATH1                       0x2d
+#define RT5640_DSP_PATH2                       0x2e
+#define RT5640_DIG_INF_DATA                    0x2f
+/* Mixer - ADC */
+#define RT5640_REC_L1_MIXER                    0x3b
+#define RT5640_REC_L2_MIXER                    0x3c
+#define RT5640_REC_R1_MIXER                    0x3d
+#define RT5640_REC_R2_MIXER                    0x3e
+/* Mixer - DAC */
+#define RT5640_HPO_MIXER                       0x45
+#define RT5640_SPK_L_MIXER                     0x46
+#define RT5640_SPK_R_MIXER                     0x47
+#define RT5640_SPO_L_MIXER                     0x48
+#define RT5640_SPO_R_MIXER                     0x49
+#define RT5640_SPO_CLSD_RATIO                  0x4a
+#define RT5640_MONO_MIXER                      0x4c
+#define RT5640_OUT_L1_MIXER                    0x4d
+#define RT5640_OUT_L2_MIXER                    0x4e
+#define RT5640_OUT_L3_MIXER                    0x4f
+#define RT5640_OUT_R1_MIXER                    0x50
+#define RT5640_OUT_R2_MIXER                    0x51
+#define RT5640_OUT_R3_MIXER                    0x52
+#define RT5640_LOUT_MIXER                      0x53
+/* Power */
+#define RT5640_PWR_DIG1                                0x61
+#define RT5640_PWR_DIG2                                0x62
+#define RT5640_PWR_ANLG1                       0x63
+#define RT5640_PWR_ANLG2                       0x64
+#define RT5640_PWR_MIXER                       0x65
+#define RT5640_PWR_VOL                         0x66
+/* Private Register Control */
+#define RT5640_PRIV_INDEX                      0x6a
+#define RT5640_PRIV_DATA                       0x6c
+/* Format - ADC/DAC */
+#define RT5640_I2S1_SDP                                0x70
+#define RT5640_I2S2_SDP                                0x71
+#define RT5640_ADDA_CLK1                       0x73
+#define RT5640_ADDA_CLK2                       0x74
+#define RT5640_DMIC                            0x75
+/* Function - Analog */
+#define RT5640_GLB_CLK                         0x80
+#define RT5640_PLL_CTRL1                       0x81
+#define RT5640_PLL_CTRL2                       0x82
+#define RT5640_ASRC_1                          0x83
+#define RT5640_ASRC_2                          0x84
+#define RT5640_ASRC_3                          0x85
+#define RT5640_ASRC_4                          0x89
+#define RT5640_ASRC_5                          0x8a
+#define RT5640_HP_OVCD                         0x8b
+#define RT5640_CLS_D_OVCD                      0x8c
+#define RT5640_CLS_D_OUT                       0x8d
+#define RT5640_DEPOP_M1                                0x8e
+#define RT5640_DEPOP_M2                                0x8f
+#define RT5640_DEPOP_M3                                0x90
+#define RT5640_CHARGE_PUMP                     0x91
+#define RT5640_PV_DET_SPK_G                    0x92
+#define RT5640_MICBIAS                         0x93
+/* Function - Digital */
+#define RT5640_EQ_CTRL1                                0xb0
+#define RT5640_EQ_CTRL2                                0xb1
+#define RT5640_WIND_FILTER                     0xb2
+#define RT5640_DRC_AGC_1                       0xb4
+#define RT5640_DRC_AGC_2                       0xb5
+#define RT5640_DRC_AGC_3                       0xb6
+#define RT5640_SVOL_ZC                         0xb7
+#define RT5640_ANC_CTRL1                       0xb8
+#define RT5640_ANC_CTRL2                       0xb9
+#define RT5640_ANC_CTRL3                       0xba
+#define RT5640_JD_CTRL                         0xbb
+#define RT5640_ANC_JD                          0xbc
+#define RT5640_IRQ_CTRL1                       0xbd
+#define RT5640_IRQ_CTRL2                       0xbe
+#define RT5640_INT_IRQ_ST                      0xbf
+#define RT5640_GPIO_CTRL1                      0xc0
+#define RT5640_GPIO_CTRL2                      0xc1
+#define RT5640_GPIO_CTRL3                      0xc2
+#define RT5640_DSP_CTRL1                       0xc4
+#define RT5640_DSP_CTRL2                       0xc5
+#define RT5640_DSP_CTRL3                       0xc6
+#define RT5640_DSP_CTRL4                       0xc7
+#define RT5640_PGM_REG_ARR1                    0xc8
+#define RT5640_PGM_REG_ARR2                    0xc9
+#define RT5640_PGM_REG_ARR3                    0xca
+#define RT5640_PGM_REG_ARR4                    0xcb
+#define RT5640_PGM_REG_ARR5                    0xcc
+#define RT5640_SCB_FUNC                                0xcd
+#define RT5640_SCB_CTRL                                0xce
+#define RT5640_BASE_BACK                       0xcf
+#define RT5640_MP3_PLUS1                       0xd0
+#define RT5640_MP3_PLUS2                       0xd1
+#define RT5640_3D_HP                           0xd2
+#define RT5640_ADJ_HPF                         0xd3
+#define RT5640_HP_CALIB_AMP_DET                        0xd6
+#define RT5640_HP_CALIB2                       0xd7
+#define RT5640_SV_ZCD1                         0xd9
+#define RT5640_SV_ZCD2                         0xda
+/* Dummy Register */
+#define RT5640_DUMMY1                          0xfa
+#define RT5640_DUMMY2                          0xfb
+#define RT5640_DUMMY3                          0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5640_3D_SPK                          0x63
+#define RT5640_WND_1                           0x6c
+#define RT5640_WND_2                           0x6d
+#define RT5640_WND_3                           0x6e
+#define RT5640_WND_4                           0x6f
+#define RT5640_WND_5                           0x70
+#define RT5640_WND_8                           0x73
+#define RT5640_DIP_SPK_INF                     0x75
+#define RT5640_EQ_BW_LOP                       0xa0
+#define RT5640_EQ_GN_LOP                       0xa1
+#define RT5640_EQ_FC_BP1                       0xa2
+#define RT5640_EQ_BW_BP1                       0xa3
+#define RT5640_EQ_GN_BP1                       0xa4
+#define RT5640_EQ_FC_BP2                       0xa5
+#define RT5640_EQ_BW_BP2                       0xa6
+#define RT5640_EQ_GN_BP2                       0xa7
+#define RT5640_EQ_FC_BP3                       0xa8
+#define RT5640_EQ_BW_BP3                       0xa9
+#define RT5640_EQ_GN_BP3                       0xaa
+#define RT5640_EQ_FC_BP4                       0xab
+#define RT5640_EQ_BW_BP4                       0xac
+#define RT5640_EQ_GN_BP4                       0xad
+#define RT5640_EQ_FC_HIP1                      0xae
+#define RT5640_EQ_GN_HIP1                      0xaf
+#define RT5640_EQ_FC_HIP2                      0xb0
+#define RT5640_EQ_BW_HIP2                      0xb1
+#define RT5640_EQ_GN_HIP2                      0xb2
+#define RT5640_EQ_PRE_VOL                      0xb3
+#define RT5640_EQ_PST_VOL                      0xb4
+
+/* global definition */
+#define RT5640_L_MUTE                          (0x1 << 15)
+#define RT5640_L_MUTE_SFT                      15
+#define RT5640_VOL_L_MUTE                      (0x1 << 14)
+#define RT5640_VOL_L_SFT                       14
+#define RT5640_R_MUTE                          (0x1 << 7)
+#define RT5640_R_MUTE_SFT                      7
+#define RT5640_VOL_R_MUTE                      (0x1 << 6)
+#define RT5640_VOL_R_SFT                       6
+#define RT5640_L_VOL_MASK                      (0x3f << 8)
+#define RT5640_L_VOL_SFT                       8
+#define RT5640_R_VOL_MASK                      (0x3f)
+#define RT5640_R_VOL_SFT                       0
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5640_BST_SFT1                                12
+#define RT5640_BST_SFT2                                8
+#define RT5640_IN_DF1                          (0x1 << 7)
+#define RT5640_IN_SFT1                         7
+#define RT5640_IN_DF2                          (0x1 << 6)
+#define RT5640_IN_SFT2                         6
+
+/* INL and INR Volume Control (0x0f) */
+#define RT5640_INL_SEL_MASK                    (0x1 << 15)
+#define RT5640_INL_SEL_SFT                     15
+#define RT5640_INL_SEL_IN4P                    (0x0 << 15)
+#define RT5640_INL_SEL_MONOP                   (0x1 << 15)
+#define RT5640_INL_VOL_MASK                    (0x1f << 8)
+#define RT5640_INL_VOL_SFT                     8
+#define RT5640_INR_SEL_MASK                    (0x1 << 7)
+#define RT5640_INR_SEL_SFT                     7
+#define RT5640_INR_SEL_IN4N                    (0x0 << 7)
+#define RT5640_INR_SEL_MONON                   (0x1 << 7)
+#define RT5640_INR_VOL_MASK                    (0x1f)
+#define RT5640_INR_VOL_SFT                     0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5640_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5640_DAC_L1_VOL_SFT                  8
+#define RT5640_DAC_R1_VOL_MASK                 (0xff)
+#define RT5640_DAC_R1_VOL_SFT                  0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5640_DAC_L2_VOL_MASK                 (0xff << 8)
+#define RT5640_DAC_L2_VOL_SFT                  8
+#define RT5640_DAC_R2_VOL_MASK                 (0xff)
+#define RT5640_DAC_R2_VOL_SFT                  0
+
+/* DAC2 Control (0x1b) */
+#define RT5640_M_DAC_L2_VOL                    (0x1 << 13)
+#define RT5640_M_DAC_L2_VOL_SFT                        13
+#define RT5640_M_DAC_R2_VOL                    (0x1 << 12)
+#define RT5640_M_DAC_R2_VOL_SFT                        12
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5640_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5640_ADC_L_VOL_SFT                   8
+#define RT5640_ADC_R_VOL_MASK                  (0x7f)
+#define RT5640_ADC_R_VOL_SFT                   0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5640_MONO_ADC_L_VOL_MASK             (0x7f << 8)
+#define RT5640_MONO_ADC_L_VOL_SFT              8
+#define RT5640_MONO_ADC_R_VOL_MASK             (0x7f)
+#define RT5640_MONO_ADC_R_VOL_SFT              0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5640_ADC_L_BST_MASK                  (0x3 << 14)
+#define RT5640_ADC_L_BST_SFT                   14
+#define RT5640_ADC_R_BST_MASK                  (0x3 << 12)
+#define RT5640_ADC_R_BST_SFT                   12
+#define RT5640_ADC_COMP_MASK                   (0x3 << 10)
+#define RT5640_ADC_COMP_SFT                    10
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5640_M_ADC_L1                                (0x1 << 14)
+#define RT5640_M_ADC_L1_SFT                    14
+#define RT5640_M_ADC_L2                                (0x1 << 13)
+#define RT5640_M_ADC_L2_SFT                    13
+#define RT5640_ADC_1_SRC_MASK                  (0x1 << 12)
+#define RT5640_ADC_1_SRC_SFT                   12
+#define RT5640_ADC_1_SRC_ADC                   (0x1 << 12)
+#define RT5640_ADC_1_SRC_DACMIX                        (0x0 << 12)
+#define RT5640_ADC_2_SRC_MASK                  (0x3 << 10)
+#define RT5640_ADC_2_SRC_SFT                   10
+#define RT5640_ADC_2_SRC_DMIC1                 (0x0 << 10)
+#define RT5640_ADC_2_SRC_DMIC2                 (0x1 << 10)
+#define RT5640_ADC_2_SRC_DACMIX                        (0x2 << 10)
+#define RT5640_M_ADC_R1                                (0x1 << 6)
+#define RT5640_M_ADC_R1_SFT                    6
+#define RT5640_M_ADC_R2                                (0x1 << 5)
+#define RT5640_M_ADC_R2_SFT                    5
+
+/* Mono ADC Mixer Control (0x28) */
+#define RT5640_M_MONO_ADC_L1                   (0x1 << 14)
+#define RT5640_M_MONO_ADC_L1_SFT               14
+#define RT5640_M_MONO_ADC_L2                   (0x1 << 13)
+#define RT5640_M_MONO_ADC_L2_SFT               13
+#define RT5640_MONO_ADC_L1_SRC_MASK            (0x1 << 12)
+#define RT5640_MONO_ADC_L1_SRC_SFT             12
+#define RT5640_MONO_ADC_L1_SRC_DACMIXL         (0x0 << 12)
+#define RT5640_MONO_ADC_L1_SRC_ADCL            (0x1 << 12)
+#define RT5640_MONO_ADC_L2_SRC_MASK            (0x3 << 10)
+#define RT5640_MONO_ADC_L2_SRC_SFT             10
+#define RT5640_MONO_ADC_L2_SRC_DMIC_L1         (0x0 << 10)
+#define RT5640_MONO_ADC_L2_SRC_DMIC_L2         (0x1 << 10)
+#define RT5640_MONO_ADC_L2_SRC_DACMIXL         (0x2 << 10)
+#define RT5640_M_MONO_ADC_R1                   (0x1 << 6)
+#define RT5640_M_MONO_ADC_R1_SFT               6
+#define RT5640_M_MONO_ADC_R2                   (0x1 << 5)
+#define RT5640_M_MONO_ADC_R2_SFT               5
+#define RT5640_MONO_ADC_R1_SRC_MASK            (0x1 << 4)
+#define RT5640_MONO_ADC_R1_SRC_SFT             4
+#define RT5640_MONO_ADC_R1_SRC_ADCR            (0x1 << 4)
+#define RT5640_MONO_ADC_R1_SRC_DACMIXR         (0x0 << 4)
+#define RT5640_MONO_ADC_R2_SRC_MASK            (0x3 << 2)
+#define RT5640_MONO_ADC_R2_SRC_SFT             2
+#define RT5640_MONO_ADC_R2_SRC_DMIC_R1         (0x0 << 2)
+#define RT5640_MONO_ADC_R2_SRC_DMIC_R2         (0x1 << 2)
+#define RT5640_MONO_ADC_R2_SRC_DACMIXR         (0x2 << 2)
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5640_M_ADCMIX_L                      (0x1 << 15)
+#define RT5640_M_ADCMIX_L_SFT                  15
+#define RT5640_M_IF1_DAC_L                     (0x1 << 14)
+#define RT5640_M_IF1_DAC_L_SFT                 14
+#define RT5640_M_ADCMIX_R                      (0x1 << 7)
+#define RT5640_M_ADCMIX_R_SFT                  7
+#define RT5640_M_IF1_DAC_R                     (0x1 << 6)
+#define RT5640_M_IF1_DAC_R_SFT                 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5640_M_DAC_L1                                (0x1 << 14)
+#define RT5640_M_DAC_L1_SFT                    14
+#define RT5640_DAC_L1_STO_L_VOL_MASK           (0x1 << 13)
+#define RT5640_DAC_L1_STO_L_VOL_SFT            13
+#define RT5640_M_DAC_L2                                (0x1 << 12)
+#define RT5640_M_DAC_L2_SFT                    12
+#define RT5640_DAC_L2_STO_L_VOL_MASK           (0x1 << 11)
+#define RT5640_DAC_L2_STO_L_VOL_SFT            11
+#define RT5640_M_ANC_DAC_L                     (0x1 << 10)
+#define RT5640_M_ANC_DAC_L_SFT                 10
+#define RT5640_M_DAC_R1                                (0x1 << 6)
+#define RT5640_M_DAC_R1_SFT                    6
+#define RT5640_DAC_R1_STO_R_VOL_MASK           (0x1 << 5)
+#define RT5640_DAC_R1_STO_R_VOL_SFT            5
+#define RT5640_M_DAC_R2                                (0x1 << 4)
+#define RT5640_M_DAC_R2_SFT                    4
+#define RT5640_DAC_R2_STO_R_VOL_MASK           (0x1 << 3)
+#define RT5640_DAC_R2_STO_R_VOL_SFT            3
+#define RT5640_M_ANC_DAC_R                     (0x1 << 2)
+#define RT5640_M_ANC_DAC_R_SFT         2
+
+/* Mono DAC Mixer Control (0x2b) */
+#define RT5640_M_DAC_L1_MONO_L                 (0x1 << 14)
+#define RT5640_M_DAC_L1_MONO_L_SFT             14
+#define RT5640_DAC_L1_MONO_L_VOL_MASK          (0x1 << 13)
+#define RT5640_DAC_L1_MONO_L_VOL_SFT           13
+#define RT5640_M_DAC_L2_MONO_L                 (0x1 << 12)
+#define RT5640_M_DAC_L2_MONO_L_SFT             12
+#define RT5640_DAC_L2_MONO_L_VOL_MASK          (0x1 << 11)
+#define RT5640_DAC_L2_MONO_L_VOL_SFT           11
+#define RT5640_M_DAC_R2_MONO_L                 (0x1 << 10)
+#define RT5640_M_DAC_R2_MONO_L_SFT             10
+#define RT5640_DAC_R2_MONO_L_VOL_MASK          (0x1 << 9)
+#define RT5640_DAC_R2_MONO_L_VOL_SFT           9
+#define RT5640_M_DAC_R1_MONO_R                 (0x1 << 6)
+#define RT5640_M_DAC_R1_MONO_R_SFT             6
+#define RT5640_DAC_R1_MONO_R_VOL_MASK          (0x1 << 5)
+#define RT5640_DAC_R1_MONO_R_VOL_SFT           5
+#define RT5640_M_DAC_R2_MONO_R                 (0x1 << 4)
+#define RT5640_M_DAC_R2_MONO_R_SFT             4
+#define RT5640_DAC_R2_MONO_R_VOL_MASK          (0x1 << 3)
+#define RT5640_DAC_R2_MONO_R_VOL_SFT           3
+#define RT5640_M_DAC_L2_MONO_R                 (0x1 << 2)
+#define RT5640_M_DAC_L2_MONO_R_SFT             2
+#define RT5640_DAC_L2_MONO_R_VOL_MASK          (0x1 << 1)
+#define RT5640_DAC_L2_MONO_R_VOL_SFT           1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5640_M_STO_L_DAC_L                   (0x1 << 15)
+#define RT5640_M_STO_L_DAC_L_SFT               15
+#define RT5640_STO_L_DAC_L_VOL_MASK            (0x1 << 14)
+#define RT5640_STO_L_DAC_L_VOL_SFT             14
+#define RT5640_M_DAC_L2_DAC_L                  (0x1 << 13)
+#define RT5640_M_DAC_L2_DAC_L_SFT              13
+#define RT5640_DAC_L2_DAC_L_VOL_MASK           (0x1 << 12)
+#define RT5640_DAC_L2_DAC_L_VOL_SFT            12
+#define RT5640_M_STO_R_DAC_R                   (0x1 << 11)
+#define RT5640_M_STO_R_DAC_R_SFT               11
+#define RT5640_STO_R_DAC_R_VOL_MASK            (0x1 << 10)
+#define RT5640_STO_R_DAC_R_VOL_SFT             10
+#define RT5640_M_DAC_R2_DAC_R                  (0x1 << 9)
+#define RT5640_M_DAC_R2_DAC_R_SFT              9
+#define RT5640_DAC_R2_DAC_R_VOL_MASK           (0x1 << 8)
+#define RT5640_DAC_R2_DAC_R_VOL_SFT            8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5640_RXDP_SRC_MASK                   (0x1 << 15)
+#define RT5640_RXDP_SRC_SFT                    15
+#define RT5640_RXDP_SRC_NOR                    (0x0 << 15)
+#define RT5640_RXDP_SRC_DIV3                   (0x1 << 15)
+#define RT5640_TXDP_SRC_MASK                   (0x1 << 14)
+#define RT5640_TXDP_SRC_SFT                    14
+#define RT5640_TXDP_SRC_NOR                    (0x0 << 14)
+#define RT5640_TXDP_SRC_DIV3                   (0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5640_DAC_L2_SEL_MASK                 (0x3 << 14)
+#define RT5640_DAC_L2_SEL_SFT                  14
+#define RT5640_DAC_L2_SEL_IF2                  (0x0 << 14)
+#define RT5640_DAC_L2_SEL_IF3                  (0x1 << 14)
+#define RT5640_DAC_L2_SEL_TXDC                 (0x2 << 14)
+#define RT5640_DAC_L2_SEL_BASS                 (0x3 << 14)
+#define RT5640_DAC_R2_SEL_MASK                 (0x3 << 12)
+#define RT5640_DAC_R2_SEL_SFT                  12
+#define RT5640_DAC_R2_SEL_IF2                  (0x0 << 12)
+#define RT5640_DAC_R2_SEL_IF3                  (0x1 << 12)
+#define RT5640_DAC_R2_SEL_TXDC                 (0x2 << 12)
+#define RT5640_IF2_ADC_L_SEL_MASK              (0x1 << 11)
+#define RT5640_IF2_ADC_L_SEL_SFT               11
+#define RT5640_IF2_ADC_L_SEL_TXDP              (0x0 << 11)
+#define RT5640_IF2_ADC_L_SEL_PASS              (0x1 << 11)
+#define RT5640_IF2_ADC_R_SEL_MASK              (0x1 << 10)
+#define RT5640_IF2_ADC_R_SEL_SFT               10
+#define RT5640_IF2_ADC_R_SEL_TXDP              (0x0 << 10)
+#define RT5640_IF2_ADC_R_SEL_PASS              (0x1 << 10)
+#define RT5640_RXDC_SEL_MASK                   (0x3 << 8)
+#define RT5640_RXDC_SEL_SFT                    8
+#define RT5640_RXDC_SEL_NOR                    (0x0 << 8)
+#define RT5640_RXDC_SEL_L2R                    (0x1 << 8)
+#define RT5640_RXDC_SEL_R2L                    (0x2 << 8)
+#define RT5640_RXDC_SEL_SWAP                   (0x3 << 8)
+#define RT5640_RXDP_SEL_MASK                   (0x3 << 6)
+#define RT5640_RXDP_SEL_SFT                    6
+#define RT5640_RXDP_SEL_NOR                    (0x0 << 6)
+#define RT5640_RXDP_SEL_L2R                    (0x1 << 6)
+#define RT5640_RXDP_SEL_R2L                    (0x2 << 6)
+#define RT5640_RXDP_SEL_SWAP                   (0x3 << 6)
+#define RT5640_TXDC_SEL_MASK                   (0x3 << 4)
+#define RT5640_TXDC_SEL_SFT                    4
+#define RT5640_TXDC_SEL_NOR                    (0x0 << 4)
+#define RT5640_TXDC_SEL_L2R                    (0x1 << 4)
+#define RT5640_TXDC_SEL_R2L                    (0x2 << 4)
+#define RT5640_TXDC_SEL_SWAP                   (0x3 << 4)
+#define RT5640_TXDP_SEL_MASK                   (0x3 << 2)
+#define RT5640_TXDP_SEL_SFT                    2
+#define RT5640_TXDP_SEL_NOR                    (0x0 << 2)
+#define RT5640_TXDP_SEL_L2R                    (0x1 << 2)
+#define RT5640_TXDP_SEL_R2L                    (0x2 << 2)
+#define RT5640_TRXDP_SEL_SWAP                  (0x3 << 2)
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5640_IF1_DAC_SEL_MASK                        (0x3 << 14)
+#define RT5640_IF1_DAC_SEL_SFT                 14
+#define RT5640_IF1_DAC_SEL_NOR                 (0x0 << 14)
+#define RT5640_IF1_DAC_SEL_L2R                 (0x1 << 14)
+#define RT5640_IF1_DAC_SEL_R2L                 (0x2 << 14)
+#define RT5640_IF1_DAC_SEL_SWAP                        (0x3 << 14)
+#define RT5640_IF1_ADC_SEL_MASK                        (0x3 << 12)
+#define RT5640_IF1_ADC_SEL_SFT                 12
+#define RT5640_IF1_ADC_SEL_NOR                 (0x0 << 12)
+#define RT5640_IF1_ADC_SEL_L2R                 (0x1 << 12)
+#define RT5640_IF1_ADC_SEL_R2L                 (0x2 << 12)
+#define RT5640_IF1_ADC_SEL_SWAP                        (0x3 << 12)
+#define RT5640_IF2_DAC_SEL_MASK                        (0x3 << 10)
+#define RT5640_IF2_DAC_SEL_SFT                 10
+#define RT5640_IF2_DAC_SEL_NOR                 (0x0 << 10)
+#define RT5640_IF2_DAC_SEL_L2R                 (0x1 << 10)
+#define RT5640_IF2_DAC_SEL_R2L                 (0x2 << 10)
+#define RT5640_IF2_DAC_SEL_SWAP                        (0x3 << 10)
+#define RT5640_IF2_ADC_SEL_MASK                        (0x3 << 8)
+#define RT5640_IF2_ADC_SEL_SFT                 8
+#define RT5640_IF2_ADC_SEL_NOR                 (0x0 << 8)
+#define RT5640_IF2_ADC_SEL_L2R                 (0x1 << 8)
+#define RT5640_IF2_ADC_SEL_R2L                 (0x2 << 8)
+#define RT5640_IF2_ADC_SEL_SWAP                        (0x3 << 8)
+#define RT5640_IF3_DAC_SEL_MASK                        (0x3 << 6)
+#define RT5640_IF3_DAC_SEL_SFT                 6
+#define RT5640_IF3_DAC_SEL_NOR                 (0x0 << 6)
+#define RT5640_IF3_DAC_SEL_L2R                 (0x1 << 6)
+#define RT5640_IF3_DAC_SEL_R2L                 (0x2 << 6)
+#define RT5640_IF3_DAC_SEL_SWAP                        (0x3 << 6)
+#define RT5640_IF3_ADC_SEL_MASK                        (0x3 << 4)
+#define RT5640_IF3_ADC_SEL_SFT                 4
+#define RT5640_IF3_ADC_SEL_NOR                 (0x0 << 4)
+#define RT5640_IF3_ADC_SEL_L2R                 (0x1 << 4)
+#define RT5640_IF3_ADC_SEL_R2L                 (0x2 << 4)
+#define RT5640_IF3_ADC_SEL_SWAP                        (0x3 << 4)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5640_G_HP_L_RM_L_MASK                        (0x7 << 13)
+#define RT5640_G_HP_L_RM_L_SFT                 13
+#define RT5640_G_IN_L_RM_L_MASK                        (0x7 << 10)
+#define RT5640_G_IN_L_RM_L_SFT                 10
+#define RT5640_G_BST4_RM_L_MASK                        (0x7 << 7)
+#define RT5640_G_BST4_RM_L_SFT                 7
+#define RT5640_G_BST3_RM_L_MASK                        (0x7 << 4)
+#define RT5640_G_BST3_RM_L_SFT                 4
+#define RT5640_G_BST2_RM_L_MASK                        (0x7 << 1)
+#define RT5640_G_BST2_RM_L_SFT                 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5640_G_BST1_RM_L_MASK                        (0x7 << 13)
+#define RT5640_G_BST1_RM_L_SFT                 13
+#define RT5640_G_OM_L_RM_L_MASK                        (0x7 << 10)
+#define RT5640_G_OM_L_RM_L_SFT                 10
+#define RT5640_M_HP_L_RM_L                     (0x1 << 6)
+#define RT5640_M_HP_L_RM_L_SFT                 6
+#define RT5640_M_IN_L_RM_L                     (0x1 << 5)
+#define RT5640_M_IN_L_RM_L_SFT                 5
+#define RT5640_M_BST4_RM_L                     (0x1 << 4)
+#define RT5640_M_BST4_RM_L_SFT                 4
+#define RT5640_M_BST3_RM_L                     (0x1 << 3)
+#define RT5640_M_BST3_RM_L_SFT                 3
+#define RT5640_M_BST2_RM_L                     (0x1 << 2)
+#define RT5640_M_BST2_RM_L_SFT                 2
+#define RT5640_M_BST1_RM_L                     (0x1 << 1)
+#define RT5640_M_BST1_RM_L_SFT                 1
+#define RT5640_M_OM_L_RM_L                     (0x1)
+#define RT5640_M_OM_L_RM_L_SFT                 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5640_G_HP_R_RM_R_MASK                        (0x7 << 13)
+#define RT5640_G_HP_R_RM_R_SFT                 13
+#define RT5640_G_IN_R_RM_R_MASK                        (0x7 << 10)
+#define RT5640_G_IN_R_RM_R_SFT                 10
+#define RT5640_G_BST4_RM_R_MASK                        (0x7 << 7)
+#define RT5640_G_BST4_RM_R_SFT                 7
+#define RT5640_G_BST3_RM_R_MASK                        (0x7 << 4)
+#define RT5640_G_BST3_RM_R_SFT                 4
+#define RT5640_G_BST2_RM_R_MASK                        (0x7 << 1)
+#define RT5640_G_BST2_RM_R_SFT                 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5640_G_BST1_RM_R_MASK                        (0x7 << 13)
+#define RT5640_G_BST1_RM_R_SFT                 13
+#define RT5640_G_OM_R_RM_R_MASK                        (0x7 << 10)
+#define RT5640_G_OM_R_RM_R_SFT                 10
+#define RT5640_M_HP_R_RM_R                     (0x1 << 6)
+#define RT5640_M_HP_R_RM_R_SFT                 6
+#define RT5640_M_IN_R_RM_R                     (0x1 << 5)
+#define RT5640_M_IN_R_RM_R_SFT                 5
+#define RT5640_M_BST4_RM_R                     (0x1 << 4)
+#define RT5640_M_BST4_RM_R_SFT                 4
+#define RT5640_M_BST3_RM_R                     (0x1 << 3)
+#define RT5640_M_BST3_RM_R_SFT                 3
+#define RT5640_M_BST2_RM_R                     (0x1 << 2)
+#define RT5640_M_BST2_RM_R_SFT                 2
+#define RT5640_M_BST1_RM_R                     (0x1 << 1)
+#define RT5640_M_BST1_RM_R_SFT                 1
+#define RT5640_M_OM_R_RM_R                     (0x1)
+#define RT5640_M_OM_R_RM_R_SFT                 0
+
+/* HPMIX Control (0x45) */
+#define RT5640_M_DAC2_HM                       (0x1 << 15)
+#define RT5640_M_DAC2_HM_SFT                   15
+#define RT5640_M_DAC1_HM                       (0x1 << 14)
+#define RT5640_M_DAC1_HM_SFT                   14
+#define RT5640_M_HPVOL_HM                      (0x1 << 13)
+#define RT5640_M_HPVOL_HM_SFT                  13
+#define RT5640_G_HPOMIX_MASK                   (0x1 << 12)
+#define RT5640_G_HPOMIX_SFT                    12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5640_G_RM_L_SM_L_MASK                        (0x3 << 14)
+#define RT5640_G_RM_L_SM_L_SFT                 14
+#define RT5640_G_IN_L_SM_L_MASK                        (0x3 << 12)
+#define RT5640_G_IN_L_SM_L_SFT                 12
+#define RT5640_G_DAC_L1_SM_L_MASK              (0x3 << 10)
+#define RT5640_G_DAC_L1_SM_L_SFT               10
+#define RT5640_G_DAC_L2_SM_L_MASK              (0x3 << 8)
+#define RT5640_G_DAC_L2_SM_L_SFT               8
+#define RT5640_G_OM_L_SM_L_MASK                        (0x3 << 6)
+#define RT5640_G_OM_L_SM_L_SFT                 6
+#define RT5640_M_RM_L_SM_L                     (0x1 << 5)
+#define RT5640_M_RM_L_SM_L_SFT                 5
+#define RT5640_M_IN_L_SM_L                     (0x1 << 4)
+#define RT5640_M_IN_L_SM_L_SFT                 4
+#define RT5640_M_DAC_L1_SM_L                   (0x1 << 3)
+#define RT5640_M_DAC_L1_SM_L_SFT               3
+#define RT5640_M_DAC_L2_SM_L                   (0x1 << 2)
+#define RT5640_M_DAC_L2_SM_L_SFT               2
+#define RT5640_M_OM_L_SM_L                     (0x1 << 1)
+#define RT5640_M_OM_L_SM_L_SFT         1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5640_G_RM_R_SM_R_MASK                        (0x3 << 14)
+#define RT5640_G_RM_R_SM_R_SFT                 14
+#define RT5640_G_IN_R_SM_R_MASK                        (0x3 << 12)
+#define RT5640_G_IN_R_SM_R_SFT                 12
+#define RT5640_G_DAC_R1_SM_R_MASK              (0x3 << 10)
+#define RT5640_G_DAC_R1_SM_R_SFT               10
+#define RT5640_G_DAC_R2_SM_R_MASK              (0x3 << 8)
+#define RT5640_G_DAC_R2_SM_R_SFT               8
+#define RT5640_G_OM_R_SM_R_MASK                        (0x3 << 6)
+#define RT5640_G_OM_R_SM_R_SFT                 6
+#define RT5640_M_RM_R_SM_R                     (0x1 << 5)
+#define RT5640_M_RM_R_SM_R_SFT                 5
+#define RT5640_M_IN_R_SM_R                     (0x1 << 4)
+#define RT5640_M_IN_R_SM_R_SFT                 4
+#define RT5640_M_DAC_R1_SM_R                   (0x1 << 3)
+#define RT5640_M_DAC_R1_SM_R_SFT               3
+#define RT5640_M_DAC_R2_SM_R                   (0x1 << 2)
+#define RT5640_M_DAC_R2_SM_R_SFT               2
+#define RT5640_M_OM_R_SM_R                     (0x1 << 1)
+#define RT5640_M_OM_R_SM_R_SFT                 1
+
+/* SPOLMIX Control (0x48) */
+#define RT5640_M_DAC_R1_SPM_L                  (0x1 << 15)
+#define RT5640_M_DAC_R1_SPM_L_SFT              15
+#define RT5640_M_DAC_L1_SPM_L                  (0x1 << 14)
+#define RT5640_M_DAC_L1_SPM_L_SFT              14
+#define RT5640_M_SV_R_SPM_L                    (0x1 << 13)
+#define RT5640_M_SV_R_SPM_L_SFT                        13
+#define RT5640_M_SV_L_SPM_L                    (0x1 << 12)
+#define RT5640_M_SV_L_SPM_L_SFT                        12
+#define RT5640_M_BST1_SPM_L                    (0x1 << 11)
+#define RT5640_M_BST1_SPM_L_SFT                        11
+
+/* SPORMIX Control (0x49) */
+#define RT5640_M_DAC_R1_SPM_R                  (0x1 << 13)
+#define RT5640_M_DAC_R1_SPM_R_SFT              13
+#define RT5640_M_SV_R_SPM_R                    (0x1 << 12)
+#define RT5640_M_SV_R_SPM_R_SFT                        12
+#define RT5640_M_BST1_SPM_R                    (0x1 << 11)
+#define RT5640_M_BST1_SPM_R_SFT                        11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5640_SPO_CLSD_RATIO_MASK             (0x7)
+#define RT5640_SPO_CLSD_RATIO_SFT              0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5640_M_DAC_R2_MM                     (0x1 << 15)
+#define RT5640_M_DAC_R2_MM_SFT                 15
+#define RT5640_M_DAC_L2_MM                     (0x1 << 14)
+#define RT5640_M_DAC_L2_MM_SFT                 14
+#define RT5640_M_OV_R_MM                       (0x1 << 13)
+#define RT5640_M_OV_R_MM_SFT                   13
+#define RT5640_M_OV_L_MM                       (0x1 << 12)
+#define RT5640_M_OV_L_MM_SFT                   12
+#define RT5640_M_BST1_MM                       (0x1 << 11)
+#define RT5640_M_BST1_MM_SFT                   11
+#define RT5640_G_MONOMIX_MASK                  (0x1 << 10)
+#define RT5640_G_MONOMIX_SFT                   10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5640_G_BST3_OM_L_MASK                        (0x7 << 13)
+#define RT5640_G_BST3_OM_L_SFT                 13
+#define RT5640_G_BST2_OM_L_MASK                        (0x7 << 10)
+#define RT5640_G_BST2_OM_L_SFT                 10
+#define RT5640_G_BST1_OM_L_MASK                        (0x7 << 7)
+#define RT5640_G_BST1_OM_L_SFT                 7
+#define RT5640_G_IN_L_OM_L_MASK                        (0x7 << 4)
+#define RT5640_G_IN_L_OM_L_SFT                 4
+#define RT5640_G_RM_L_OM_L_MASK                        (0x7 << 1)
+#define RT5640_G_RM_L_OM_L_SFT                 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5640_G_DAC_R2_OM_L_MASK              (0x7 << 13)
+#define RT5640_G_DAC_R2_OM_L_SFT               13
+#define RT5640_G_DAC_L2_OM_L_MASK              (0x7 << 10)
+#define RT5640_G_DAC_L2_OM_L_SFT               10
+#define RT5640_G_DAC_L1_OM_L_MASK              (0x7 << 7)
+#define RT5640_G_DAC_L1_OM_L_SFT               7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5640_M_SM_L_OM_L                     (0x1 << 8)
+#define RT5640_M_SM_L_OM_L_SFT                 8
+#define RT5640_M_BST3_OM_L                     (0x1 << 7)
+#define RT5640_M_BST3_OM_L_SFT                 7
+#define RT5640_M_BST2_OM_L                     (0x1 << 6)
+#define RT5640_M_BST2_OM_L_SFT                 6
+#define RT5640_M_BST1_OM_L                     (0x1 << 5)
+#define RT5640_M_BST1_OM_L_SFT                 5
+#define RT5640_M_IN_L_OM_L                     (0x1 << 4)
+#define RT5640_M_IN_L_OM_L_SFT                 4
+#define RT5640_M_RM_L_OM_L                     (0x1 << 3)
+#define RT5640_M_RM_L_OM_L_SFT                 3
+#define RT5640_M_DAC_R2_OM_L                   (0x1 << 2)
+#define RT5640_M_DAC_R2_OM_L_SFT               2
+#define RT5640_M_DAC_L2_OM_L                   (0x1 << 1)
+#define RT5640_M_DAC_L2_OM_L_SFT               1
+#define RT5640_M_DAC_L1_OM_L                   (0x1)
+#define RT5640_M_DAC_L1_OM_L_SFT               0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5640_G_BST4_OM_R_MASK                        (0x7 << 13)
+#define RT5640_G_BST4_OM_R_SFT                 13
+#define RT5640_G_BST2_OM_R_MASK                        (0x7 << 10)
+#define RT5640_G_BST2_OM_R_SFT                 10
+#define RT5640_G_BST1_OM_R_MASK                        (0x7 << 7)
+#define RT5640_G_BST1_OM_R_SFT                 7
+#define RT5640_G_IN_R_OM_R_MASK                        (0x7 << 4)
+#define RT5640_G_IN_R_OM_R_SFT                 4
+#define RT5640_G_RM_R_OM_R_MASK                        (0x7 << 1)
+#define RT5640_G_RM_R_OM_R_SFT                 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5640_G_DAC_L2_OM_R_MASK              (0x7 << 13)
+#define RT5640_G_DAC_L2_OM_R_SFT               13
+#define RT5640_G_DAC_R2_OM_R_MASK              (0x7 << 10)
+#define RT5640_G_DAC_R2_OM_R_SFT               10
+#define RT5640_G_DAC_R1_OM_R_MASK              (0x7 << 7)
+#define RT5640_G_DAC_R1_OM_R_SFT               7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5640_M_SM_L_OM_R                     (0x1 << 8)
+#define RT5640_M_SM_L_OM_R_SFT                 8
+#define RT5640_M_BST4_OM_R                     (0x1 << 7)
+#define RT5640_M_BST4_OM_R_SFT                 7
+#define RT5640_M_BST2_OM_R                     (0x1 << 6)
+#define RT5640_M_BST2_OM_R_SFT                 6
+#define RT5640_M_BST1_OM_R                     (0x1 << 5)
+#define RT5640_M_BST1_OM_R_SFT                 5
+#define RT5640_M_IN_R_OM_R                     (0x1 << 4)
+#define RT5640_M_IN_R_OM_R_SFT                 4
+#define RT5640_M_RM_R_OM_R                     (0x1 << 3)
+#define RT5640_M_RM_R_OM_R_SFT                 3
+#define RT5640_M_DAC_L2_OM_R                   (0x1 << 2)
+#define RT5640_M_DAC_L2_OM_R_SFT               2
+#define RT5640_M_DAC_R2_OM_R                   (0x1 << 1)
+#define RT5640_M_DAC_R2_OM_R_SFT               1
+#define RT5640_M_DAC_R1_OM_R                   (0x1)
+#define RT5640_M_DAC_R1_OM_R_SFT               0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5640_M_DAC_L1_LM                     (0x1 << 15)
+#define RT5640_M_DAC_L1_LM_SFT                 15
+#define RT5640_M_DAC_R1_LM                     (0x1 << 14)
+#define RT5640_M_DAC_R1_LM_SFT                 14
+#define RT5640_M_OV_L_LM                       (0x1 << 13)
+#define RT5640_M_OV_L_LM_SFT                   13
+#define RT5640_M_OV_R_LM                       (0x1 << 12)
+#define RT5640_M_OV_R_LM_SFT                   12
+#define RT5640_G_LOUTMIX_MASK                  (0x1 << 11)
+#define RT5640_G_LOUTMIX_SFT                   11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5640_PWR_I2S1                                (0x1 << 15)
+#define RT5640_PWR_I2S1_BIT                    15
+#define RT5640_PWR_I2S2                                (0x1 << 14)
+#define RT5640_PWR_I2S2_BIT                    14
+#define RT5640_PWR_DAC_L1                      (0x1 << 12)
+#define RT5640_PWR_DAC_L1_BIT                  12
+#define RT5640_PWR_DAC_R1                      (0x1 << 11)
+#define RT5640_PWR_DAC_R1_BIT                  11
+#define RT5640_PWR_DAC_L2                      (0x1 << 7)
+#define RT5640_PWR_DAC_L2_BIT                  7
+#define RT5640_PWR_DAC_R2                      (0x1 << 6)
+#define RT5640_PWR_DAC_R2_BIT                  6
+#define RT5640_PWR_ADC_L                       (0x1 << 2)
+#define RT5640_PWR_ADC_L_BIT                   2
+#define RT5640_PWR_ADC_R                       (0x1 << 1)
+#define RT5640_PWR_ADC_R_BIT                   1
+#define RT5640_PWR_CLS_D                       (0x1)
+#define RT5640_PWR_CLS_D_BIT                   0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5640_PWR_ADC_SF                      (0x1 << 15)
+#define RT5640_PWR_ADC_SF_BIT                  15
+#define RT5640_PWR_ADC_MF_L                    (0x1 << 14)
+#define RT5640_PWR_ADC_MF_L_BIT                        14
+#define RT5640_PWR_ADC_MF_R                    (0x1 << 13)
+#define RT5640_PWR_ADC_MF_R_BIT                        13
+#define RT5640_PWR_I2S_DSP                     (0x1 << 12)
+#define RT5640_PWR_I2S_DSP_BIT                 12
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5640_PWR_VREF1                       (0x1 << 15)
+#define RT5640_PWR_VREF1_BIT                   15
+#define RT5640_PWR_FV1                         (0x1 << 14)
+#define RT5640_PWR_FV1_BIT                     14
+#define RT5640_PWR_MB                          (0x1 << 13)
+#define RT5640_PWR_MB_BIT                      13
+#define RT5640_PWR_LM                          (0x1 << 12)
+#define RT5640_PWR_LM_BIT                      12
+#define RT5640_PWR_BG                          (0x1 << 11)
+#define RT5640_PWR_BG_BIT                      11
+#define RT5640_PWR_MM                          (0x1 << 10)
+#define RT5640_PWR_MM_BIT                      10
+#define RT5640_PWR_MA                          (0x1 << 8)
+#define RT5640_PWR_MA_BIT                      8
+#define RT5640_PWR_HP_L                                (0x1 << 7)
+#define RT5640_PWR_HP_L_BIT                    7
+#define RT5640_PWR_HP_R                                (0x1 << 6)
+#define RT5640_PWR_HP_R_BIT                    6
+#define RT5640_PWR_HA                          (0x1 << 5)
+#define RT5640_PWR_HA_BIT                      5
+#define RT5640_PWR_VREF2                       (0x1 << 4)
+#define RT5640_PWR_VREF2_BIT                   4
+#define RT5640_PWR_FV2                         (0x1 << 3)
+#define RT5640_PWR_FV2_BIT                     3
+#define RT5640_PWR_LDO2                                (0x1 << 2)
+#define RT5640_PWR_LDO2_BIT                    2
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5640_PWR_BST1                                (0x1 << 15)
+#define RT5640_PWR_BST1_BIT                    15
+#define RT5640_PWR_BST2                                (0x1 << 14)
+#define RT5640_PWR_BST2_BIT                    14
+#define RT5640_PWR_BST3                                (0x1 << 13)
+#define RT5640_PWR_BST3_BIT                    13
+#define RT5640_PWR_BST4                                (0x1 << 12)
+#define RT5640_PWR_BST4_BIT                    12
+#define RT5640_PWR_MB1                         (0x1 << 11)
+#define RT5640_PWR_MB1_BIT                     11
+#define RT5640_PWR_PLL                         (0x1 << 9)
+#define RT5640_PWR_PLL_BIT                     9
+
+/* Power Management for Mixer (0x65) */
+#define RT5640_PWR_OM_L                                (0x1 << 15)
+#define RT5640_PWR_OM_L_BIT                    15
+#define RT5640_PWR_OM_R                                (0x1 << 14)
+#define RT5640_PWR_OM_R_BIT                    14
+#define RT5640_PWR_SM_L                                (0x1 << 13)
+#define RT5640_PWR_SM_L_BIT                    13
+#define RT5640_PWR_SM_R                                (0x1 << 12)
+#define RT5640_PWR_SM_R_BIT                    12
+#define RT5640_PWR_RM_L                                (0x1 << 11)
+#define RT5640_PWR_RM_L_BIT                    11
+#define RT5640_PWR_RM_R                                (0x1 << 10)
+#define RT5640_PWR_RM_R_BIT                    10
+
+/* Power Management for Volume (0x66) */
+#define RT5640_PWR_SV_L                                (0x1 << 15)
+#define RT5640_PWR_SV_L_BIT                    15
+#define RT5640_PWR_SV_R                                (0x1 << 14)
+#define RT5640_PWR_SV_R_BIT                    14
+#define RT5640_PWR_OV_L                                (0x1 << 13)
+#define RT5640_PWR_OV_L_BIT                    13
+#define RT5640_PWR_OV_R                                (0x1 << 12)
+#define RT5640_PWR_OV_R_BIT                    12
+#define RT5640_PWR_HV_L                                (0x1 << 11)
+#define RT5640_PWR_HV_L_BIT                    11
+#define RT5640_PWR_HV_R                                (0x1 << 10)
+#define RT5640_PWR_HV_R_BIT                    10
+#define RT5640_PWR_IN_L                                (0x1 << 9)
+#define RT5640_PWR_IN_L_BIT                    9
+#define RT5640_PWR_IN_R                                (0x1 << 8)
+#define RT5640_PWR_IN_R_BIT                    8
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71 0x72) */
+#define RT5640_I2S_MS_MASK                     (0x1 << 15)
+#define RT5640_I2S_MS_SFT                      15
+#define RT5640_I2S_MS_M                                (0x0 << 15)
+#define RT5640_I2S_MS_S                                (0x1 << 15)
+#define RT5640_I2S_IF_MASK                     (0x7 << 12)
+#define RT5640_I2S_IF_SFT                      12
+#define RT5640_I2S_O_CP_MASK                   (0x3 << 10)
+#define RT5640_I2S_O_CP_SFT                    10
+#define RT5640_I2S_O_CP_OFF                    (0x0 << 10)
+#define RT5640_I2S_O_CP_U_LAW                  (0x1 << 10)
+#define RT5640_I2S_O_CP_A_LAW                  (0x2 << 10)
+#define RT5640_I2S_I_CP_MASK                   (0x3 << 8)
+#define RT5640_I2S_I_CP_SFT                    8
+#define RT5640_I2S_I_CP_OFF                    (0x0 << 8)
+#define RT5640_I2S_I_CP_U_LAW                  (0x1 << 8)
+#define RT5640_I2S_I_CP_A_LAW                  (0x2 << 8)
+#define RT5640_I2S_BP_MASK                     (0x1 << 7)
+#define RT5640_I2S_BP_SFT                      7
+#define RT5640_I2S_BP_NOR                      (0x0 << 7)
+#define RT5640_I2S_BP_INV                      (0x1 << 7)
+#define RT5640_I2S_DL_MASK                     (0x3 << 2)
+#define RT5640_I2S_DL_SFT                      2
+#define RT5640_I2S_DL_16                       (0x0 << 2)
+#define RT5640_I2S_DL_20                       (0x1 << 2)
+#define RT5640_I2S_DL_24                       (0x2 << 2)
+#define RT5640_I2S_DL_8                                (0x3 << 2)
+#define RT5640_I2S_DF_MASK                     (0x3)
+#define RT5640_I2S_DF_SFT                      0
+#define RT5640_I2S_DF_I2S                      (0x0)
+#define RT5640_I2S_DF_LEFT                     (0x1)
+#define RT5640_I2S_DF_PCM_A                    (0x2)
+#define RT5640_I2S_DF_PCM_B                    (0x3)
+
+/* I2S2 Audio Serial Data Port Control (0x71) */
+#define RT5640_I2S2_SDI_MASK                   (0x1 << 6)
+#define RT5640_I2S2_SDI_SFT                    6
+#define RT5640_I2S2_SDI_I2S1                   (0x0 << 6)
+#define RT5640_I2S2_SDI_I2S2                   (0x1 << 6)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5640_I2S_BCLK_MS1_MASK               (0x1 << 15)
+#define RT5640_I2S_BCLK_MS1_SFT                        15
+#define RT5640_I2S_BCLK_MS1_32                 (0x0 << 15)
+#define RT5640_I2S_BCLK_MS1_64                 (0x1 << 15)
+#define RT5640_I2S_PD1_MASK                    (0x7 << 12)
+#define RT5640_I2S_PD1_SFT                     12
+#define RT5640_I2S_PD1_1                       (0x0 << 12)
+#define RT5640_I2S_PD1_2                       (0x1 << 12)
+#define RT5640_I2S_PD1_3                       (0x2 << 12)
+#define RT5640_I2S_PD1_4                       (0x3 << 12)
+#define RT5640_I2S_PD1_6                       (0x4 << 12)
+#define RT5640_I2S_PD1_8                       (0x5 << 12)
+#define RT5640_I2S_PD1_12                      (0x6 << 12)
+#define RT5640_I2S_PD1_16                      (0x7 << 12)
+#define RT5640_I2S_BCLK_MS2_MASK               (0x1 << 11)
+#define RT5640_I2S_BCLK_MS2_SFT                        11
+#define RT5640_I2S_BCLK_MS2_32                 (0x0 << 11)
+#define RT5640_I2S_BCLK_MS2_64                 (0x1 << 11)
+#define RT5640_I2S_PD2_MASK                    (0x7 << 8)
+#define RT5640_I2S_PD2_SFT                     8
+#define RT5640_I2S_PD2_1                       (0x0 << 8)
+#define RT5640_I2S_PD2_2                       (0x1 << 8)
+#define RT5640_I2S_PD2_3                       (0x2 << 8)
+#define RT5640_I2S_PD2_4                       (0x3 << 8)
+#define RT5640_I2S_PD2_6                       (0x4 << 8)
+#define RT5640_I2S_PD2_8                       (0x5 << 8)
+#define RT5640_I2S_PD2_12                      (0x6 << 8)
+#define RT5640_I2S_PD2_16                      (0x7 << 8)
+#define RT5640_I2S_BCLK_MS3_MASK               (0x1 << 7)
+#define RT5640_I2S_BCLK_MS3_SFT                        7
+#define RT5640_I2S_BCLK_MS3_32                 (0x0 << 7)
+#define RT5640_I2S_BCLK_MS3_64                 (0x1 << 7)
+#define RT5640_I2S_PD3_MASK                    (0x7 << 4)
+#define RT5640_I2S_PD3_SFT                     4
+#define RT5640_I2S_PD3_1                       (0x0 << 4)
+#define RT5640_I2S_PD3_2                       (0x1 << 4)
+#define RT5640_I2S_PD3_3                       (0x2 << 4)
+#define RT5640_I2S_PD3_4                       (0x3 << 4)
+#define RT5640_I2S_PD3_6                       (0x4 << 4)
+#define RT5640_I2S_PD3_8                       (0x5 << 4)
+#define RT5640_I2S_PD3_12                      (0x6 << 4)
+#define RT5640_I2S_PD3_16                      (0x7 << 4)
+#define RT5640_DAC_OSR_MASK                    (0x3 << 2)
+#define RT5640_DAC_OSR_SFT                     2
+#define RT5640_DAC_OSR_128                     (0x0 << 2)
+#define RT5640_DAC_OSR_64                      (0x1 << 2)
+#define RT5640_DAC_OSR_32                      (0x2 << 2)
+#define RT5640_DAC_OSR_16                      (0x3 << 2)
+#define RT5640_ADC_OSR_MASK                    (0x3)
+#define RT5640_ADC_OSR_SFT                     0
+#define RT5640_ADC_OSR_128                     (0x0)
+#define RT5640_ADC_OSR_64                      (0x1)
+#define RT5640_ADC_OSR_32                      (0x2)
+#define RT5640_ADC_OSR_16                      (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5640_DAC_L_OSR_MASK                  (0x3 << 14)
+#define RT5640_DAC_L_OSR_SFT                   14
+#define RT5640_DAC_L_OSR_128                   (0x0 << 14)
+#define RT5640_DAC_L_OSR_64                    (0x1 << 14)
+#define RT5640_DAC_L_OSR_32                    (0x2 << 14)
+#define RT5640_DAC_L_OSR_16                    (0x3 << 14)
+#define RT5640_ADC_R_OSR_MASK                  (0x3 << 12)
+#define RT5640_ADC_R_OSR_SFT                   12
+#define RT5640_ADC_R_OSR_128                   (0x0 << 12)
+#define RT5640_ADC_R_OSR_64                    (0x1 << 12)
+#define RT5640_ADC_R_OSR_32                    (0x2 << 12)
+#define RT5640_ADC_R_OSR_16                    (0x3 << 12)
+#define RT5640_DAHPF_EN                                (0x1 << 11)
+#define RT5640_DAHPF_EN_SFT                    11
+#define RT5640_ADHPF_EN                                (0x1 << 10)
+#define RT5640_ADHPF_EN_SFT                    10
+
+/* Digital Microphone Control (0x75) */
+#define RT5640_DMIC_1_EN_MASK                  (0x1 << 15)
+#define RT5640_DMIC_1_EN_SFT                   15
+#define RT5640_DMIC_1_DIS                      (0x0 << 15)
+#define RT5640_DMIC_1_EN                       (0x1 << 15)
+#define RT5640_DMIC_2_EN_MASK                  (0x1 << 14)
+#define RT5640_DMIC_2_EN_SFT                   14
+#define RT5640_DMIC_2_DIS                      (0x0 << 14)
+#define RT5640_DMIC_2_EN                       (0x1 << 14)
+#define RT5640_DMIC_1L_LH_MASK                 (0x1 << 13)
+#define RT5640_DMIC_1L_LH_SFT                  13
+#define RT5640_DMIC_1L_LH_FALLING              (0x0 << 13)
+#define RT5640_DMIC_1L_LH_RISING               (0x1 << 13)
+#define RT5640_DMIC_1R_LH_MASK                 (0x1 << 12)
+#define RT5640_DMIC_1R_LH_SFT                  12
+#define RT5640_DMIC_1R_LH_FALLING              (0x0 << 12)
+#define RT5640_DMIC_1R_LH_RISING               (0x1 << 12)
+#define RT5640_DMIC_1_DP_MASK                  (0x1 << 11)
+#define RT5640_DMIC_1_DP_SFT                   11
+#define RT5640_DMIC_1_DP_GPIO3                 (0x0 << 11)
+#define RT5640_DMIC_1_DP_IN1P                  (0x1 << 11)
+#define RT5640_DMIC_2_DP_MASK                  (0x1 << 10)
+#define RT5640_DMIC_2_DP_SFT                   10
+#define RT5640_DMIC_2_DP_GPIO4                 (0x0 << 10)
+#define RT5640_DMIC_2_DP_IN1N                  (0x1 << 10)
+#define RT5640_DMIC_2L_LH_MASK                 (0x1 << 9)
+#define RT5640_DMIC_2L_LH_SFT                  9
+#define RT5640_DMIC_2L_LH_FALLING              (0x0 << 9)
+#define RT5640_DMIC_2L_LH_RISING               (0x1 << 9)
+#define RT5640_DMIC_2R_LH_MASK                 (0x1 << 8)
+#define RT5640_DMIC_2R_LH_SFT                  8
+#define RT5640_DMIC_2R_LH_FALLING              (0x0 << 8)
+#define RT5640_DMIC_2R_LH_RISING               (0x1 << 8)
+#define RT5640_DMIC_CLK_MASK                   (0x7 << 5)
+#define RT5640_DMIC_CLK_SFT                    5
+
+/* Global Clock Control (0x80) */
+#define RT5640_SCLK_SRC_MASK                   (0x3 << 14)
+#define RT5640_SCLK_SRC_SFT                    14
+#define RT5640_SCLK_SRC_MCLK                   (0x0 << 14)
+#define RT5640_SCLK_SRC_PLL1                   (0x1 << 14)
+#define RT5640_SCLK_SRC_PLL1T                  (0x2 << 14)
+#define RT5640_SCLK_SRC_RCCLK                  (0x3 << 14) /* 15MHz */
+#define RT5640_PLL1_SRC_MASK                   (0x3 << 12)
+#define RT5640_PLL1_SRC_SFT                    12
+#define RT5640_PLL1_SRC_MCLK                   (0x0 << 12)
+#define RT5640_PLL1_SRC_BCLK1                  (0x1 << 12)
+#define RT5640_PLL1_SRC_BCLK2                  (0x2 << 12)
+#define RT5640_PLL1_SRC_BCLK3                  (0x3 << 12)
+#define RT5640_PLL1_PD_MASK                    (0x1 << 3)
+#define RT5640_PLL1_PD_SFT                     3
+#define RT5640_PLL1_PD_1                       (0x0 << 3)
+#define RT5640_PLL1_PD_2                       (0x1 << 3)
+
+#define RT5640_PLL_INP_MAX                     40000000
+#define RT5640_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5640_PLL_N_MAX                       0x1ff
+#define RT5640_PLL_N_MASK                      (RT5640_PLL_N_MAX << 7)
+#define RT5640_PLL_N_SFT                       7
+#define RT5640_PLL_K_MAX                       0x1f
+#define RT5640_PLL_K_MASK                      (RT5640_PLL_K_MAX)
+#define RT5640_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5640_PLL_M_MAX                       0xf
+#define RT5640_PLL_M_MASK                      (RT5640_PLL_M_MAX << 12)
+#define RT5640_PLL_M_SFT                       12
+#define RT5640_PLL_M_BP                                (0x1 << 11)
+#define RT5640_PLL_M_BP_SFT                    11
+
+/* ASRC Control 1 (0x83) */
+#define RT5640_STO_T_MASK                      (0x1 << 15)
+#define RT5640_STO_T_SFT                       15
+#define RT5640_STO_T_SCLK                      (0x0 << 15)
+#define RT5640_STO_T_LRCK1                     (0x1 << 15)
+#define RT5640_M1_T_MASK                       (0x1 << 14)
+#define RT5640_M1_T_SFT                                14
+#define RT5640_M1_T_I2S2                       (0x0 << 14)
+#define RT5640_M1_T_I2S2_D3                    (0x1 << 14)
+#define RT5640_I2S2_F_MASK                     (0x1 << 12)
+#define RT5640_I2S2_F_SFT                      12
+#define RT5640_I2S2_F_I2S2_D2                  (0x0 << 12)
+#define RT5640_I2S2_F_I2S1_TCLK                        (0x1 << 12)
+#define RT5640_DMIC_1_M_MASK                   (0x1 << 9)
+#define RT5640_DMIC_1_M_SFT                    9
+#define RT5640_DMIC_1_M_NOR                    (0x0 << 9)
+#define RT5640_DMIC_1_M_ASYN                   (0x1 << 9)
+#define RT5640_DMIC_2_M_MASK                   (0x1 << 8)
+#define RT5640_DMIC_2_M_SFT                    8
+#define RT5640_DMIC_2_M_NOR                    (0x0 << 8)
+#define RT5640_DMIC_2_M_ASYN                   (0x1 << 8)
+
+/* ASRC Control 2 (0x84) */
+#define RT5640_MDA_L_M_MASK                    (0x1 << 15)
+#define RT5640_MDA_L_M_SFT                     15
+#define RT5640_MDA_L_M_NOR                     (0x0 << 15)
+#define RT5640_MDA_L_M_ASYN                    (0x1 << 15)
+#define RT5640_MDA_R_M_MASK                    (0x1 << 14)
+#define RT5640_MDA_R_M_SFT                     14
+#define RT5640_MDA_R_M_NOR                     (0x0 << 14)
+#define RT5640_MDA_R_M_ASYN                    (0x1 << 14)
+#define RT5640_MAD_L_M_MASK                    (0x1 << 13)
+#define RT5640_MAD_L_M_SFT                     13
+#define RT5640_MAD_L_M_NOR                     (0x0 << 13)
+#define RT5640_MAD_L_M_ASYN                    (0x1 << 13)
+#define RT5640_MAD_R_M_MASK                    (0x1 << 12)
+#define RT5640_MAD_R_M_SFT                     12
+#define RT5640_MAD_R_M_NOR                     (0x0 << 12)
+#define RT5640_MAD_R_M_ASYN                    (0x1 << 12)
+#define RT5640_ADC_M_MASK                      (0x1 << 11)
+#define RT5640_ADC_M_SFT                       11
+#define RT5640_ADC_M_NOR                       (0x0 << 11)
+#define RT5640_ADC_M_ASYN                      (0x1 << 11)
+#define RT5640_STO_DAC_M_MASK                  (0x1 << 5)
+#define RT5640_STO_DAC_M_SFT                   5
+#define RT5640_STO_DAC_M_NOR                   (0x0 << 5)
+#define RT5640_STO_DAC_M_ASYN                  (0x1 << 5)
+#define RT5640_I2S1_R_D_MASK                   (0x1 << 4)
+#define RT5640_I2S1_R_D_SFT                    4
+#define RT5640_I2S1_R_D_DIS                    (0x0 << 4)
+#define RT5640_I2S1_R_D_EN                     (0x1 << 4)
+#define RT5640_I2S2_R_D_MASK                   (0x1 << 3)
+#define RT5640_I2S2_R_D_SFT                    3
+#define RT5640_I2S2_R_D_DIS                    (0x0 << 3)
+#define RT5640_I2S2_R_D_EN                     (0x1 << 3)
+#define RT5640_PRE_SCLK_MASK                   (0x3)
+#define RT5640_PRE_SCLK_SFT                    0
+#define RT5640_PRE_SCLK_512                    (0x0)
+#define RT5640_PRE_SCLK_1024                   (0x1)
+#define RT5640_PRE_SCLK_2048                   (0x2)
+
+/* ASRC Control 3 (0x85) */
+#define RT5640_I2S1_RATE_MASK                  (0xf << 12)
+#define RT5640_I2S1_RATE_SFT                   12
+#define RT5640_I2S2_RATE_MASK                  (0xf << 8)
+#define RT5640_I2S2_RATE_SFT                   8
+
+/* ASRC Control 4 (0x89) */
+#define RT5640_I2S1_PD_MASK                    (0x7 << 12)
+#define RT5640_I2S1_PD_SFT                     12
+#define RT5640_I2S2_PD_MASK                    (0x7 << 8)
+#define RT5640_I2S2_PD_SFT                     8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5640_HP_OVCD_MASK                    (0x1 << 10)
+#define RT5640_HP_OVCD_SFT                     10
+#define RT5640_HP_OVCD_DIS                     (0x0 << 10)
+#define RT5640_HP_OVCD_EN                      (0x1 << 10)
+#define RT5640_HP_OC_TH_MASK                   (0x3 << 8)
+#define RT5640_HP_OC_TH_SFT                    8
+#define RT5640_HP_OC_TH_90                     (0x0 << 8)
+#define RT5640_HP_OC_TH_105                    (0x1 << 8)
+#define RT5640_HP_OC_TH_120                    (0x2 << 8)
+#define RT5640_HP_OC_TH_135                    (0x3 << 8)
+
+/* Class D Over Current Control (0x8c) */
+#define RT5640_CLSD_OC_MASK                    (0x1 << 9)
+#define RT5640_CLSD_OC_SFT                     9
+#define RT5640_CLSD_OC_PU                      (0x0 << 9)
+#define RT5640_CLSD_OC_PD                      (0x1 << 9)
+#define RT5640_AUTO_PD_MASK                    (0x1 << 8)
+#define RT5640_AUTO_PD_SFT                     8
+#define RT5640_AUTO_PD_DIS                     (0x0 << 8)
+#define RT5640_AUTO_PD_EN                      (0x1 << 8)
+#define RT5640_CLSD_OC_TH_MASK                 (0x3f)
+#define RT5640_CLSD_OC_TH_SFT                  0
+
+/* Class D Output Control (0x8d) */
+#define RT5640_CLSD_RATIO_MASK                 (0xf << 12)
+#define RT5640_CLSD_RATIO_SFT                  12
+#define RT5640_CLSD_OM_MASK                    (0x1 << 11)
+#define RT5640_CLSD_OM_SFT                     11
+#define RT5640_CLSD_OM_MONO                    (0x0 << 11)
+#define RT5640_CLSD_OM_STO                     (0x1 << 11)
+#define RT5640_CLSD_SCH_MASK                   (0x1 << 10)
+#define RT5640_CLSD_SCH_SFT                    10
+#define RT5640_CLSD_SCH_L                      (0x0 << 10)
+#define RT5640_CLSD_SCH_S                      (0x1 << 10)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5640_SMT_TRIG_MASK                   (0x1 << 15)
+#define RT5640_SMT_TRIG_SFT                    15
+#define RT5640_SMT_TRIG_DIS                    (0x0 << 15)
+#define RT5640_SMT_TRIG_EN                     (0x1 << 15)
+#define RT5640_HP_L_SMT_MASK                   (0x1 << 9)
+#define RT5640_HP_L_SMT_SFT                    9
+#define RT5640_HP_L_SMT_DIS                    (0x0 << 9)
+#define RT5640_HP_L_SMT_EN                     (0x1 << 9)
+#define RT5640_HP_R_SMT_MASK                   (0x1 << 8)
+#define RT5640_HP_R_SMT_SFT                    8
+#define RT5640_HP_R_SMT_DIS                    (0x0 << 8)
+#define RT5640_HP_R_SMT_EN                     (0x1 << 8)
+#define RT5640_HP_CD_PD_MASK                   (0x1 << 7)
+#define RT5640_HP_CD_PD_SFT                    7
+#define RT5640_HP_CD_PD_DIS                    (0x0 << 7)
+#define RT5640_HP_CD_PD_EN                     (0x1 << 7)
+#define RT5640_RSTN_MASK                       (0x1 << 6)
+#define RT5640_RSTN_SFT                                6
+#define RT5640_RSTN_DIS                                (0x0 << 6)
+#define RT5640_RSTN_EN                         (0x1 << 6)
+#define RT5640_RSTP_MASK                       (0x1 << 5)
+#define RT5640_RSTP_SFT                                5
+#define RT5640_RSTP_DIS                                (0x0 << 5)
+#define RT5640_RSTP_EN                         (0x1 << 5)
+#define RT5640_HP_CO_MASK                      (0x1 << 4)
+#define RT5640_HP_CO_SFT                       4
+#define RT5640_HP_CO_DIS                       (0x0 << 4)
+#define RT5640_HP_CO_EN                                (0x1 << 4)
+#define RT5640_HP_CP_MASK                      (0x1 << 3)
+#define RT5640_HP_CP_SFT                       3
+#define RT5640_HP_CP_PD                                (0x0 << 3)
+#define RT5640_HP_CP_PU                                (0x1 << 3)
+#define RT5640_HP_SG_MASK                      (0x1 << 2)
+#define RT5640_HP_SG_SFT                       2
+#define RT5640_HP_SG_DIS                       (0x0 << 2)
+#define RT5640_HP_SG_EN                                (0x1 << 2)
+#define RT5640_HP_DP_MASK                      (0x1 << 1)
+#define RT5640_HP_DP_SFT                       1
+#define RT5640_HP_DP_PD                                (0x0 << 1)
+#define RT5640_HP_DP_PU                                (0x1 << 1)
+#define RT5640_HP_CB_MASK                      (0x1)
+#define RT5640_HP_CB_SFT                       0
+#define RT5640_HP_CB_PD                                (0x0)
+#define RT5640_HP_CB_PU                                (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5640_DEPOP_MASK                      (0x1 << 13)
+#define RT5640_DEPOP_SFT                       13
+#define RT5640_DEPOP_AUTO                      (0x0 << 13)
+#define RT5640_DEPOP_MAN                       (0x1 << 13)
+#define RT5640_RAMP_MASK                       (0x1 << 12)
+#define RT5640_RAMP_SFT                                12
+#define RT5640_RAMP_DIS                                (0x0 << 12)
+#define RT5640_RAMP_EN                         (0x1 << 12)
+#define RT5640_BPS_MASK                                (0x1 << 11)
+#define RT5640_BPS_SFT                         11
+#define RT5640_BPS_DIS                         (0x0 << 11)
+#define RT5640_BPS_EN                          (0x1 << 11)
+#define RT5640_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5640_FAST_UPDN_SFT                   10
+#define RT5640_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5640_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5640_MRES_MASK                       (0x3 << 8)
+#define RT5640_MRES_SFT                                8
+#define RT5640_MRES_15MO                       (0x0 << 8)
+#define RT5640_MRES_25MO                       (0x1 << 8)
+#define RT5640_MRES_35MO                       (0x2 << 8)
+#define RT5640_MRES_45MO                       (0x3 << 8)
+#define RT5640_VLO_MASK                                (0x1 << 7)
+#define RT5640_VLO_SFT                         7
+#define RT5640_VLO_3V                          (0x0 << 7)
+#define RT5640_VLO_32V                         (0x1 << 7)
+#define RT5640_DIG_DP_MASK                     (0x1 << 6)
+#define RT5640_DIG_DP_SFT                      6
+#define RT5640_DIG_DP_DIS                      (0x0 << 6)
+#define RT5640_DIG_DP_EN                       (0x1 << 6)
+#define RT5640_DP_TH_MASK                      (0x3 << 4)
+#define RT5640_DP_TH_SFT                       4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5640_CP_SYS_MASK                     (0x7 << 12)
+#define RT5640_CP_SYS_SFT                      12
+#define RT5640_CP_FQ1_MASK                     (0x7 << 8)
+#define RT5640_CP_FQ1_SFT                      8
+#define RT5640_CP_FQ2_MASK                     (0x7 << 4)
+#define RT5640_CP_FQ2_SFT                      4
+#define RT5640_CP_FQ3_MASK                     (0x7)
+#define RT5640_CP_FQ3_SFT                      0
+
+/* HPOUT charge pump (0x91) */
+#define RT5640_OSW_L_MASK                      (0x1 << 11)
+#define RT5640_OSW_L_SFT                       11
+#define RT5640_OSW_L_DIS                       (0x0 << 11)
+#define RT5640_OSW_L_EN                                (0x1 << 11)
+#define RT5640_OSW_R_MASK                      (0x1 << 10)
+#define RT5640_OSW_R_SFT                       10
+#define RT5640_OSW_R_DIS                       (0x0 << 10)
+#define RT5640_OSW_R_EN                                (0x1 << 10)
+#define RT5640_PM_HP_MASK                      (0x3 << 8)
+#define RT5640_PM_HP_SFT                       8
+#define RT5640_PM_HP_LV                                (0x0 << 8)
+#define RT5640_PM_HP_MV                                (0x1 << 8)
+#define RT5640_PM_HP_HV                                (0x2 << 8)
+#define RT5640_IB_HP_MASK                      (0x3 << 6)
+#define RT5640_IB_HP_SFT                       6
+#define RT5640_IB_HP_125IL                     (0x0 << 6)
+#define RT5640_IB_HP_25IL                      (0x1 << 6)
+#define RT5640_IB_HP_5IL                       (0x2 << 6)
+#define RT5640_IB_HP_1IL                       (0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5640_PVDD_DET_MASK                   (0x1 << 15)
+#define RT5640_PVDD_DET_SFT                    15
+#define RT5640_PVDD_DET_DIS                    (0x0 << 15)
+#define RT5640_PVDD_DET_EN                     (0x1 << 15)
+#define RT5640_SPK_AG_MASK                     (0x1 << 14)
+#define RT5640_SPK_AG_SFT                      14
+#define RT5640_SPK_AG_DIS                      (0x0 << 14)
+#define RT5640_SPK_AG_EN                       (0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5640_MIC1_BS_MASK                    (0x1 << 15)
+#define RT5640_MIC1_BS_SFT                     15
+#define RT5640_MIC1_BS_9AV                     (0x0 << 15)
+#define RT5640_MIC1_BS_75AV                    (0x1 << 15)
+#define RT5640_MIC2_BS_MASK                    (0x1 << 14)
+#define RT5640_MIC2_BS_SFT                     14
+#define RT5640_MIC2_BS_9AV                     (0x0 << 14)
+#define RT5640_MIC2_BS_75AV                    (0x1 << 14)
+#define RT5640_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5640_MIC1_CLK_SFT                    13
+#define RT5640_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5640_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5640_MIC2_CLK_MASK                   (0x1 << 12)
+#define RT5640_MIC2_CLK_SFT                    12
+#define RT5640_MIC2_CLK_DIS                    (0x0 << 12)
+#define RT5640_MIC2_CLK_EN                     (0x1 << 12)
+#define RT5640_MIC1_OVCD_MASK                  (0x1 << 11)
+#define RT5640_MIC1_OVCD_SFT                   11
+#define RT5640_MIC1_OVCD_DIS                   (0x0 << 11)
+#define RT5640_MIC1_OVCD_EN                    (0x1 << 11)
+#define RT5640_MIC1_OVTH_MASK                  (0x3 << 9)
+#define RT5640_MIC1_OVTH_SFT                   9
+#define RT5640_MIC1_OVTH_600UA                 (0x0 << 9)
+#define RT5640_MIC1_OVTH_1500UA                        (0x1 << 9)
+#define RT5640_MIC1_OVTH_2000UA                        (0x2 << 9)
+#define RT5640_MIC2_OVCD_MASK                  (0x1 << 8)
+#define RT5640_MIC2_OVCD_SFT                   8
+#define RT5640_MIC2_OVCD_DIS                   (0x0 << 8)
+#define RT5640_MIC2_OVCD_EN                    (0x1 << 8)
+#define RT5640_MIC2_OVTH_MASK                  (0x3 << 6)
+#define RT5640_MIC2_OVTH_SFT                   6
+#define RT5640_MIC2_OVTH_600UA                 (0x0 << 6)
+#define RT5640_MIC2_OVTH_1500UA                        (0x1 << 6)
+#define RT5640_MIC2_OVTH_2000UA                        (0x2 << 6)
+#define RT5640_PWR_MB_MASK                     (0x1 << 5)
+#define RT5640_PWR_MB_SFT                      5
+#define RT5640_PWR_MB_PD                       (0x0 << 5)
+#define RT5640_PWR_MB_PU                       (0x1 << 5)
+#define RT5640_PWR_CLK25M_MASK                 (0x1 << 4)
+#define RT5640_PWR_CLK25M_SFT                  4
+#define RT5640_PWR_CLK25M_PD                   (0x0 << 4)
+#define RT5640_PWR_CLK25M_PU                   (0x1 << 4)
+
+/* EQ Control 1 (0xb0) */
+#define RT5640_EQ_SRC_MASK                     (0x1 << 15)
+#define RT5640_EQ_SRC_SFT                      15
+#define RT5640_EQ_SRC_DAC                      (0x0 << 15)
+#define RT5640_EQ_SRC_ADC                      (0x1 << 15)
+#define RT5640_EQ_UPD                          (0x1 << 14)
+#define RT5640_EQ_UPD_BIT                      14
+#define RT5640_EQ_CD_MASK                      (0x1 << 13)
+#define RT5640_EQ_CD_SFT                       13
+#define RT5640_EQ_CD_DIS                       (0x0 << 13)
+#define RT5640_EQ_CD_EN                                (0x1 << 13)
+#define RT5640_EQ_DITH_MASK                    (0x3 << 8)
+#define RT5640_EQ_DITH_SFT                     8
+#define RT5640_EQ_DITH_NOR                     (0x0 << 8)
+#define RT5640_EQ_DITH_LSB                     (0x1 << 8)
+#define RT5640_EQ_DITH_LSB_1                   (0x2 << 8)
+#define RT5640_EQ_DITH_LSB_2                   (0x3 << 8)
+
+/* EQ Control 2 (0xb1) */
+#define RT5640_EQ_HPF1_M_MASK                  (0x1 << 8)
+#define RT5640_EQ_HPF1_M_SFT                   8
+#define RT5640_EQ_HPF1_M_HI                    (0x0 << 8)
+#define RT5640_EQ_HPF1_M_1ST                   (0x1 << 8)
+#define RT5640_EQ_LPF1_M_MASK                  (0x1 << 7)
+#define RT5640_EQ_LPF1_M_SFT                   7
+#define RT5640_EQ_LPF1_M_LO                    (0x0 << 7)
+#define RT5640_EQ_LPF1_M_1ST                   (0x1 << 7)
+#define RT5640_EQ_HPF2_MASK                    (0x1 << 6)
+#define RT5640_EQ_HPF2_SFT                     6
+#define RT5640_EQ_HPF2_DIS                     (0x0 << 6)
+#define RT5640_EQ_HPF2_EN                      (0x1 << 6)
+#define RT5640_EQ_HPF1_MASK                    (0x1 << 5)
+#define RT5640_EQ_HPF1_SFT                     5
+#define RT5640_EQ_HPF1_DIS                     (0x0 << 5)
+#define RT5640_EQ_HPF1_EN                      (0x1 << 5)
+#define RT5640_EQ_BPF4_MASK                    (0x1 << 4)
+#define RT5640_EQ_BPF4_SFT                     4
+#define RT5640_EQ_BPF4_DIS                     (0x0 << 4)
+#define RT5640_EQ_BPF4_EN                      (0x1 << 4)
+#define RT5640_EQ_BPF3_MASK                    (0x1 << 3)
+#define RT5640_EQ_BPF3_SFT                     3
+#define RT5640_EQ_BPF3_DIS                     (0x0 << 3)
+#define RT5640_EQ_BPF3_EN                      (0x1 << 3)
+#define RT5640_EQ_BPF2_MASK                    (0x1 << 2)
+#define RT5640_EQ_BPF2_SFT                     2
+#define RT5640_EQ_BPF2_DIS                     (0x0 << 2)
+#define RT5640_EQ_BPF2_EN                      (0x1 << 2)
+#define RT5640_EQ_BPF1_MASK                    (0x1 << 1)
+#define RT5640_EQ_BPF1_SFT                     1
+#define RT5640_EQ_BPF1_DIS                     (0x0 << 1)
+#define RT5640_EQ_BPF1_EN                      (0x1 << 1)
+#define RT5640_EQ_LPF_MASK                     (0x1)
+#define RT5640_EQ_LPF_SFT                      0
+#define RT5640_EQ_LPF_DIS                      (0x0)
+#define RT5640_EQ_LPF_EN                       (0x1)
+
+/* Memory Test (0xb2) */
+#define RT5640_MT_MASK                         (0x1 << 15)
+#define RT5640_MT_SFT                          15
+#define RT5640_MT_DIS                          (0x0 << 15)
+#define RT5640_MT_EN                           (0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5640_DRC_AGC_P_MASK                  (0x1 << 15)
+#define RT5640_DRC_AGC_P_SFT                   15
+#define RT5640_DRC_AGC_P_DAC                   (0x0 << 15)
+#define RT5640_DRC_AGC_P_ADC                   (0x1 << 15)
+#define RT5640_DRC_AGC_MASK                    (0x1 << 14)
+#define RT5640_DRC_AGC_SFT                     14
+#define RT5640_DRC_AGC_DIS                     (0x0 << 14)
+#define RT5640_DRC_AGC_EN                      (0x1 << 14)
+#define RT5640_DRC_AGC_UPD                     (0x1 << 13)
+#define RT5640_DRC_AGC_UPD_BIT                 13
+#define RT5640_DRC_AGC_AR_MASK                 (0x1f << 8)
+#define RT5640_DRC_AGC_AR_SFT                  8
+#define RT5640_DRC_AGC_R_MASK                  (0x7 << 5)
+#define RT5640_DRC_AGC_R_SFT                   5
+#define RT5640_DRC_AGC_R_48K                   (0x1 << 5)
+#define RT5640_DRC_AGC_R_96K                   (0x2 << 5)
+#define RT5640_DRC_AGC_R_192K                  (0x3 << 5)
+#define RT5640_DRC_AGC_R_441K                  (0x5 << 5)
+#define RT5640_DRC_AGC_R_882K                  (0x6 << 5)
+#define RT5640_DRC_AGC_R_1764K                 (0x7 << 5)
+#define RT5640_DRC_AGC_RC_MASK                 (0x1f)
+#define RT5640_DRC_AGC_RC_SFT                  0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5640_DRC_AGC_POB_MASK                        (0x3f << 8)
+#define RT5640_DRC_AGC_POB_SFT                 8
+#define RT5640_DRC_AGC_CP_MASK                 (0x1 << 7)
+#define RT5640_DRC_AGC_CP_SFT                  7
+#define RT5640_DRC_AGC_CP_DIS                  (0x0 << 7)
+#define RT5640_DRC_AGC_CP_EN                   (0x1 << 7)
+#define RT5640_DRC_AGC_CPR_MASK                        (0x3 << 5)
+#define RT5640_DRC_AGC_CPR_SFT                 5
+#define RT5640_DRC_AGC_CPR_1_1                 (0x0 << 5)
+#define RT5640_DRC_AGC_CPR_1_2                 (0x1 << 5)
+#define RT5640_DRC_AGC_CPR_1_3                 (0x2 << 5)
+#define RT5640_DRC_AGC_CPR_1_4                 (0x3 << 5)
+#define RT5640_DRC_AGC_PRB_MASK                        (0x1f)
+#define RT5640_DRC_AGC_PRB_SFT                 0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5640_DRC_AGC_NGB_MASK                        (0xf << 12)
+#define RT5640_DRC_AGC_NGB_SFT                 12
+#define RT5640_DRC_AGC_TAR_MASK                        (0x1f << 7)
+#define RT5640_DRC_AGC_TAR_SFT                 7
+#define RT5640_DRC_AGC_NG_MASK                 (0x1 << 6)
+#define RT5640_DRC_AGC_NG_SFT                  6
+#define RT5640_DRC_AGC_NG_DIS                  (0x0 << 6)
+#define RT5640_DRC_AGC_NG_EN                   (0x1 << 6)
+#define RT5640_DRC_AGC_NGH_MASK                        (0x1 << 5)
+#define RT5640_DRC_AGC_NGH_SFT                 5
+#define RT5640_DRC_AGC_NGH_DIS                 (0x0 << 5)
+#define RT5640_DRC_AGC_NGH_EN                  (0x1 << 5)
+#define RT5640_DRC_AGC_NGT_MASK                        (0x1f)
+#define RT5640_DRC_AGC_NGT_SFT                 0
+
+/* ANC Control 1 (0xb8) */
+#define RT5640_ANC_M_MASK                      (0x1 << 15)
+#define RT5640_ANC_M_SFT                       15
+#define RT5640_ANC_M_NOR                       (0x0 << 15)
+#define RT5640_ANC_M_REV                       (0x1 << 15)
+#define RT5640_ANC_MASK                                (0x1 << 14)
+#define RT5640_ANC_SFT                         14
+#define RT5640_ANC_DIS                         (0x0 << 14)
+#define RT5640_ANC_EN                          (0x1 << 14)
+#define RT5640_ANC_MD_MASK                     (0x3 << 12)
+#define RT5640_ANC_MD_SFT                      12
+#define RT5640_ANC_MD_DIS                      (0x0 << 12)
+#define RT5640_ANC_MD_67MS                     (0x1 << 12)
+#define RT5640_ANC_MD_267MS                    (0x2 << 12)
+#define RT5640_ANC_MD_1067MS                   (0x3 << 12)
+#define RT5640_ANC_SN_MASK                     (0x1 << 11)
+#define RT5640_ANC_SN_SFT                      11
+#define RT5640_ANC_SN_DIS                      (0x0 << 11)
+#define RT5640_ANC_SN_EN                       (0x1 << 11)
+#define RT5640_ANC_CLK_MASK                    (0x1 << 10)
+#define RT5640_ANC_CLK_SFT                     10
+#define RT5640_ANC_CLK_ANC                     (0x0 << 10)
+#define RT5640_ANC_CLK_REG                     (0x1 << 10)
+#define RT5640_ANC_ZCD_MASK                    (0x3 << 8)
+#define RT5640_ANC_ZCD_SFT                     8
+#define RT5640_ANC_ZCD_DIS                     (0x0 << 8)
+#define RT5640_ANC_ZCD_T1                      (0x1 << 8)
+#define RT5640_ANC_ZCD_T2                      (0x2 << 8)
+#define RT5640_ANC_ZCD_WT                      (0x3 << 8)
+#define RT5640_ANC_CS_MASK                     (0x1 << 7)
+#define RT5640_ANC_CS_SFT                      7
+#define RT5640_ANC_CS_DIS                      (0x0 << 7)
+#define RT5640_ANC_CS_EN                       (0x1 << 7)
+#define RT5640_ANC_SW_MASK                     (0x1 << 6)
+#define RT5640_ANC_SW_SFT                      6
+#define RT5640_ANC_SW_NOR                      (0x0 << 6)
+#define RT5640_ANC_SW_AUTO                     (0x1 << 6)
+#define RT5640_ANC_CO_L_MASK                   (0x3f)
+#define RT5640_ANC_CO_L_SFT                    0
+
+/* ANC Control 2 (0xb6) */
+#define RT5640_ANC_FG_R_MASK                   (0xf << 12)
+#define RT5640_ANC_FG_R_SFT                    12
+#define RT5640_ANC_FG_L_MASK                   (0xf << 8)
+#define RT5640_ANC_FG_L_SFT                    8
+#define RT5640_ANC_CG_R_MASK                   (0xf << 4)
+#define RT5640_ANC_CG_R_SFT                    4
+#define RT5640_ANC_CG_L_MASK                   (0xf)
+#define RT5640_ANC_CG_L_SFT                    0
+
+/* ANC Control 3 (0xb6) */
+#define RT5640_ANC_CD_MASK                     (0x1 << 6)
+#define RT5640_ANC_CD_SFT                      6
+#define RT5640_ANC_CD_BOTH                     (0x0 << 6)
+#define RT5640_ANC_CD_IND                      (0x1 << 6)
+#define RT5640_ANC_CO_R_MASK                   (0x3f)
+#define RT5640_ANC_CO_R_SFT                    0
+
+/* Jack Detect Control (0xbb) */
+#define RT5640_JD_MASK                         (0x7 << 13)
+#define RT5640_JD_SFT                          13
+#define RT5640_JD_DIS                          (0x0 << 13)
+#define RT5640_JD_GPIO1                                (0x1 << 13)
+#define RT5640_JD_JD1_IN4P                     (0x2 << 13)
+#define RT5640_JD_JD2_IN4N                     (0x3 << 13)
+#define RT5640_JD_GPIO2                                (0x4 << 13)
+#define RT5640_JD_GPIO3                                (0x5 << 13)
+#define RT5640_JD_GPIO4                                (0x6 << 13)
+#define RT5640_JD_HP_MASK                      (0x1 << 11)
+#define RT5640_JD_HP_SFT                       11
+#define RT5640_JD_HP_DIS                       (0x0 << 11)
+#define RT5640_JD_HP_EN                                (0x1 << 11)
+#define RT5640_JD_HP_TRG_MASK                  (0x1 << 10)
+#define RT5640_JD_HP_TRG_SFT                   10
+#define RT5640_JD_HP_TRG_LO                    (0x0 << 10)
+#define RT5640_JD_HP_TRG_HI                    (0x1 << 10)
+#define RT5640_JD_SPL_MASK                     (0x1 << 9)
+#define RT5640_JD_SPL_SFT                      9
+#define RT5640_JD_SPL_DIS                      (0x0 << 9)
+#define RT5640_JD_SPL_EN                       (0x1 << 9)
+#define RT5640_JD_SPL_TRG_MASK                 (0x1 << 8)
+#define RT5640_JD_SPL_TRG_SFT                  8
+#define RT5640_JD_SPL_TRG_LO                   (0x0 << 8)
+#define RT5640_JD_SPL_TRG_HI                   (0x1 << 8)
+#define RT5640_JD_SPR_MASK                     (0x1 << 7)
+#define RT5640_JD_SPR_SFT                      7
+#define RT5640_JD_SPR_DIS                      (0x0 << 7)
+#define RT5640_JD_SPR_EN                       (0x1 << 7)
+#define RT5640_JD_SPR_TRG_MASK                 (0x1 << 6)
+#define RT5640_JD_SPR_TRG_SFT                  6
+#define RT5640_JD_SPR_TRG_LO                   (0x0 << 6)
+#define RT5640_JD_SPR_TRG_HI                   (0x1 << 6)
+#define RT5640_JD_MO_MASK                      (0x1 << 5)
+#define RT5640_JD_MO_SFT                       5
+#define RT5640_JD_MO_DIS                       (0x0 << 5)
+#define RT5640_JD_MO_EN                                (0x1 << 5)
+#define RT5640_JD_MO_TRG_MASK                  (0x1 << 4)
+#define RT5640_JD_MO_TRG_SFT                   4
+#define RT5640_JD_MO_TRG_LO                    (0x0 << 4)
+#define RT5640_JD_MO_TRG_HI                    (0x1 << 4)
+#define RT5640_JD_LO_MASK                      (0x1 << 3)
+#define RT5640_JD_LO_SFT                       3
+#define RT5640_JD_LO_DIS                       (0x0 << 3)
+#define RT5640_JD_LO_EN                                (0x1 << 3)
+#define RT5640_JD_LO_TRG_MASK                  (0x1 << 2)
+#define RT5640_JD_LO_TRG_SFT                   2
+#define RT5640_JD_LO_TRG_LO                    (0x0 << 2)
+#define RT5640_JD_LO_TRG_HI                    (0x1 << 2)
+#define RT5640_JD1_IN4P_MASK                   (0x1 << 1)
+#define RT5640_JD1_IN4P_SFT                    1
+#define RT5640_JD1_IN4P_DIS                    (0x0 << 1)
+#define RT5640_JD1_IN4P_EN                     (0x1 << 1)
+#define RT5640_JD2_IN4N_MASK                   (0x1)
+#define RT5640_JD2_IN4N_SFT                    0
+#define RT5640_JD2_IN4N_DIS                    (0x0)
+#define RT5640_JD2_IN4N_EN                     (0x1)
+
+/* Jack detect for ANC (0xbc) */
+#define RT5640_ANC_DET_MASK                    (0x3 << 4)
+#define RT5640_ANC_DET_SFT                     4
+#define RT5640_ANC_DET_DIS                     (0x0 << 4)
+#define RT5640_ANC_DET_MB1                     (0x1 << 4)
+#define RT5640_ANC_DET_MB2                     (0x2 << 4)
+#define RT5640_ANC_DET_JD                      (0x3 << 4)
+#define RT5640_AD_TRG_MASK                     (0x1 << 3)
+#define RT5640_AD_TRG_SFT                      3
+#define RT5640_AD_TRG_LO                       (0x0 << 3)
+#define RT5640_AD_TRG_HI                       (0x1 << 3)
+#define RT5640_ANCM_DET_MASK                   (0x3 << 4)
+#define RT5640_ANCM_DET_SFT                    4
+#define RT5640_ANCM_DET_DIS                    (0x0 << 4)
+#define RT5640_ANCM_DET_MB1                    (0x1 << 4)
+#define RT5640_ANCM_DET_MB2                    (0x2 << 4)
+#define RT5640_ANCM_DET_JD                     (0x3 << 4)
+#define RT5640_AMD_TRG_MASK                    (0x1 << 3)
+#define RT5640_AMD_TRG_SFT                     3
+#define RT5640_AMD_TRG_LO                      (0x0 << 3)
+#define RT5640_AMD_TRG_HI                      (0x1 << 3)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5640_IRQ_JD_MASK                     (0x1 << 15)
+#define RT5640_IRQ_JD_SFT                      15
+#define RT5640_IRQ_JD_BP                       (0x0 << 15)
+#define RT5640_IRQ_JD_NOR                      (0x1 << 15)
+#define RT5640_IRQ_OT_MASK                     (0x1 << 14)
+#define RT5640_IRQ_OT_SFT                      14
+#define RT5640_IRQ_OT_BP                       (0x0 << 14)
+#define RT5640_IRQ_OT_NOR                      (0x1 << 14)
+#define RT5640_JD_STKY_MASK                    (0x1 << 13)
+#define RT5640_JD_STKY_SFT                     13
+#define RT5640_JD_STKY_DIS                     (0x0 << 13)
+#define RT5640_JD_STKY_EN                      (0x1 << 13)
+#define RT5640_OT_STKY_MASK                    (0x1 << 12)
+#define RT5640_OT_STKY_SFT                     12
+#define RT5640_OT_STKY_DIS                     (0x0 << 12)
+#define RT5640_OT_STKY_EN                      (0x1 << 12)
+#define RT5640_JD_P_MASK                       (0x1 << 11)
+#define RT5640_JD_P_SFT                                11
+#define RT5640_JD_P_NOR                                (0x0 << 11)
+#define RT5640_JD_P_INV                                (0x1 << 11)
+#define RT5640_OT_P_MASK                       (0x1 << 10)
+#define RT5640_OT_P_SFT                                10
+#define RT5640_OT_P_NOR                                (0x0 << 10)
+#define RT5640_OT_P_INV                                (0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5640_IRQ_MB1_OC_MASK                 (0x1 << 15)
+#define RT5640_IRQ_MB1_OC_SFT                  15
+#define RT5640_IRQ_MB1_OC_BP                   (0x0 << 15)
+#define RT5640_IRQ_MB1_OC_NOR                  (0x1 << 15)
+#define RT5640_IRQ_MB2_OC_MASK                 (0x1 << 14)
+#define RT5640_IRQ_MB2_OC_SFT                  14
+#define RT5640_IRQ_MB2_OC_BP                   (0x0 << 14)
+#define RT5640_IRQ_MB2_OC_NOR                  (0x1 << 14)
+#define RT5640_MB1_OC_STKY_MASK                        (0x1 << 11)
+#define RT5640_MB1_OC_STKY_SFT                 11
+#define RT5640_MB1_OC_STKY_DIS                 (0x0 << 11)
+#define RT5640_MB1_OC_STKY_EN                  (0x1 << 11)
+#define RT5640_MB2_OC_STKY_MASK                        (0x1 << 10)
+#define RT5640_MB2_OC_STKY_SFT                 10
+#define RT5640_MB2_OC_STKY_DIS                 (0x0 << 10)
+#define RT5640_MB2_OC_STKY_EN                  (0x1 << 10)
+#define RT5640_MB1_OC_P_MASK                   (0x1 << 7)
+#define RT5640_MB1_OC_P_SFT                    7
+#define RT5640_MB1_OC_P_NOR                    (0x0 << 7)
+#define RT5640_MB1_OC_P_INV                    (0x1 << 7)
+#define RT5640_MB2_OC_P_MASK                   (0x1 << 6)
+#define RT5640_MB2_OC_P_SFT                    6
+#define RT5640_MB2_OC_P_NOR                    (0x0 << 6)
+#define RT5640_MB2_OC_P_INV                    (0x1 << 6)
+#define RT5640_MB1_OC_CLR                      (0x1 << 3)
+#define RT5640_MB1_OC_CLR_SFT                  3
+#define RT5640_MB2_OC_CLR                      (0x1 << 2)
+#define RT5640_MB2_OC_CLR_SFT                  2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5640_GP1_PIN_MASK                    (0x1 << 15)
+#define RT5640_GP1_PIN_SFT                     15
+#define RT5640_GP1_PIN_GPIO1                   (0x0 << 15)
+#define RT5640_GP1_PIN_IRQ                     (0x1 << 15)
+#define RT5640_GP2_PIN_MASK                    (0x1 << 14)
+#define RT5640_GP2_PIN_SFT                     14
+#define RT5640_GP2_PIN_GPIO2                   (0x0 << 14)
+#define RT5640_GP2_PIN_DMIC1_SCL               (0x1 << 14)
+#define RT5640_GP3_PIN_MASK                    (0x3 << 12)
+#define RT5640_GP3_PIN_SFT                     12
+#define RT5640_GP3_PIN_GPIO3                   (0x0 << 12)
+#define RT5640_GP3_PIN_DMIC1_SDA               (0x1 << 12)
+#define RT5640_GP3_PIN_IRQ                     (0x2 << 12)
+#define RT5640_GP4_PIN_MASK                    (0x1 << 11)
+#define RT5640_GP4_PIN_SFT                     11
+#define RT5640_GP4_PIN_GPIO4                   (0x0 << 11)
+#define RT5640_GP4_PIN_DMIC2_SDA               (0x1 << 11)
+#define RT5640_DP_SIG_MASK                     (0x1 << 10)
+#define RT5640_DP_SIG_SFT                      10
+#define RT5640_DP_SIG_TEST                     (0x0 << 10)
+#define RT5640_DP_SIG_AP                       (0x1 << 10)
+#define RT5640_GPIO_M_MASK                     (0x1 << 9)
+#define RT5640_GPIO_M_SFT                      9
+#define RT5640_GPIO_M_FLT                      (0x0 << 9)
+#define RT5640_GPIO_M_PH                       (0x1 << 9)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5640_GP4_PF_MASK                     (0x1 << 11)
+#define RT5640_GP4_PF_SFT                      11
+#define RT5640_GP4_PF_IN                       (0x0 << 11)
+#define RT5640_GP4_PF_OUT                      (0x1 << 11)
+#define RT5640_GP4_OUT_MASK                    (0x1 << 10)
+#define RT5640_GP4_OUT_SFT                     10
+#define RT5640_GP4_OUT_LO                      (0x0 << 10)
+#define RT5640_GP4_OUT_HI                      (0x1 << 10)
+#define RT5640_GP4_P_MASK                      (0x1 << 9)
+#define RT5640_GP4_P_SFT                       9
+#define RT5640_GP4_P_NOR                       (0x0 << 9)
+#define RT5640_GP4_P_INV                       (0x1 << 9)
+#define RT5640_GP3_PF_MASK                     (0x1 << 8)
+#define RT5640_GP3_PF_SFT                      8
+#define RT5640_GP3_PF_IN                       (0x0 << 8)
+#define RT5640_GP3_PF_OUT                      (0x1 << 8)
+#define RT5640_GP3_OUT_MASK                    (0x1 << 7)
+#define RT5640_GP3_OUT_SFT                     7
+#define RT5640_GP3_OUT_LO                      (0x0 << 7)
+#define RT5640_GP3_OUT_HI                      (0x1 << 7)
+#define RT5640_GP3_P_MASK                      (0x1 << 6)
+#define RT5640_GP3_P_SFT                       6
+#define RT5640_GP3_P_NOR                       (0x0 << 6)
+#define RT5640_GP3_P_INV                       (0x1 << 6)
+#define RT5640_GP2_PF_MASK                     (0x1 << 5)
+#define RT5640_GP2_PF_SFT                      5
+#define RT5640_GP2_PF_IN                       (0x0 << 5)
+#define RT5640_GP2_PF_OUT                      (0x1 << 5)
+#define RT5640_GP2_OUT_MASK                    (0x1 << 4)
+#define RT5640_GP2_OUT_SFT                     4
+#define RT5640_GP2_OUT_LO                      (0x0 << 4)
+#define RT5640_GP2_OUT_HI                      (0x1 << 4)
+#define RT5640_GP2_P_MASK                      (0x1 << 3)
+#define RT5640_GP2_P_SFT                       3
+#define RT5640_GP2_P_NOR                       (0x0 << 3)
+#define RT5640_GP2_P_INV                       (0x1 << 3)
+#define RT5640_GP1_PF_MASK                     (0x1 << 2)
+#define RT5640_GP1_PF_SFT                      2
+#define RT5640_GP1_PF_IN                       (0x0 << 2)
+#define RT5640_GP1_PF_OUT                      (0x1 << 2)
+#define RT5640_GP1_OUT_MASK                    (0x1 << 1)
+#define RT5640_GP1_OUT_SFT                     1
+#define RT5640_GP1_OUT_LO                      (0x0 << 1)
+#define RT5640_GP1_OUT_HI                      (0x1 << 1)
+#define RT5640_GP1_P_MASK                      (0x1)
+#define RT5640_GP1_P_SFT                       0
+#define RT5640_GP1_P_NOR                       (0x0)
+#define RT5640_GP1_P_INV                       (0x1)
+
+/* FM34-500 Register Control 1 (0xc4) */
+#define RT5640_DSP_ADD_SFT                     0
+
+/* FM34-500 Register Control 2 (0xc5) */
+#define RT5640_DSP_DAT_SFT                     0
+
+/* FM34-500 Register Control 3 (0xc6) */
+#define RT5640_DSP_BUSY_MASK                   (0x1 << 15)
+#define RT5640_DSP_BUSY_BIT                    15
+#define RT5640_DSP_DS_MASK                     (0x1 << 14)
+#define RT5640_DSP_DS_SFT                      14
+#define RT5640_DSP_DS_FM3010                   (0x1 << 14)
+#define RT5640_DSP_DS_TEMP                     (0x1 << 14)
+#define RT5640_DSP_CLK_MASK                    (0x3 << 12)
+#define RT5640_DSP_CLK_SFT                     12
+#define RT5640_DSP_CLK_384K                    (0x0 << 12)
+#define RT5640_DSP_CLK_192K                    (0x1 << 12)
+#define RT5640_DSP_CLK_96K                     (0x2 << 12)
+#define RT5640_DSP_CLK_64K                     (0x3 << 12)
+#define RT5640_DSP_PD_PIN_MASK                 (0x1 << 11)
+#define RT5640_DSP_PD_PIN_SFT                  11
+#define RT5640_DSP_PD_PIN_LO                   (0x0 << 11)
+#define RT5640_DSP_PD_PIN_HI                   (0x1 << 11)
+#define RT5640_DSP_RST_PIN_MASK                        (0x1 << 10)
+#define RT5640_DSP_RST_PIN_SFT                 10
+#define RT5640_DSP_RST_PIN_LO                  (0x0 << 10)
+#define RT5640_DSP_RST_PIN_HI                  (0x1 << 10)
+#define RT5640_DSP_R_EN                                (0x1 << 9)
+#define RT5640_DSP_R_EN_BIT                    9
+#define RT5640_DSP_W_EN                                (0x1 << 8)
+#define RT5640_DSP_W_EN_BIT                    8
+#define RT5640_DSP_CMD_MASK                    (0xff)
+#define RT5640_DSP_CMD_SFT                     0
+#define RT5640_DSP_CMD_MW                      (0x3B)  /* Memory Write */
+#define RT5640_DSP_CMD_MR                      (0x37)  /* Memory Read */
+#define RT5640_DSP_CMD_RR                      (0x60)  /* Register Read */
+#define RT5640_DSP_CMD_RW                      (0x68)  /* Register Write */
+
+/* Programmable Register Array Control 1 (0xc8) */
+#define RT5640_REG_SEQ_MASK                    (0xf << 12)
+#define RT5640_REG_SEQ_SFT                     12
+#define RT5640_SEQ1_ST_MASK                    (0x1 << 11) /*RO*/
+#define RT5640_SEQ1_ST_SFT                     11
+#define RT5640_SEQ1_ST_RUN                     (0x0 << 11)
+#define RT5640_SEQ1_ST_FIN                     (0x1 << 11)
+#define RT5640_SEQ2_ST_MASK                    (0x1 << 10) /*RO*/
+#define RT5640_SEQ2_ST_SFT                     10
+#define RT5640_SEQ2_ST_RUN                     (0x0 << 10)
+#define RT5640_SEQ2_ST_FIN                     (0x1 << 10)
+#define RT5640_REG_LV_MASK                     (0x1 << 9)
+#define RT5640_REG_LV_SFT                      9
+#define RT5640_REG_LV_MX                       (0x0 << 9)
+#define RT5640_REG_LV_PR                       (0x1 << 9)
+#define RT5640_SEQ_2_PT_MASK                   (0x1 << 8)
+#define RT5640_SEQ_2_PT_BIT                    8
+#define RT5640_REG_IDX_MASK                    (0xff)
+#define RT5640_REG_IDX_SFT                     0
+
+/* Programmable Register Array Control 2 (0xc9) */
+#define RT5640_REG_DAT_MASK                    (0xffff)
+#define RT5640_REG_DAT_SFT                     0
+
+/* Programmable Register Array Control 3 (0xca) */
+#define RT5640_SEQ_DLY_MASK                    (0xff << 8)
+#define RT5640_SEQ_DLY_SFT                     8
+#define RT5640_PROG_MASK                       (0x1 << 7)
+#define RT5640_PROG_SFT                                7
+#define RT5640_PROG_DIS                                (0x0 << 7)
+#define RT5640_PROG_EN                         (0x1 << 7)
+#define RT5640_SEQ1_PT_RUN                     (0x1 << 6)
+#define RT5640_SEQ1_PT_RUN_BIT                 6
+#define RT5640_SEQ2_PT_RUN                     (0x1 << 5)
+#define RT5640_SEQ2_PT_RUN_BIT                 5
+
+/* Programmable Register Array Control 4 (0xcb) */
+#define RT5640_SEQ1_START_MASK                 (0xf << 8)
+#define RT5640_SEQ1_START_SFT                  8
+#define RT5640_SEQ1_END_MASK                   (0xf)
+#define RT5640_SEQ1_END_SFT                    0
+
+/* Programmable Register Array Control 5 (0xcc) */
+#define RT5640_SEQ2_START_MASK                 (0xf << 8)
+#define RT5640_SEQ2_START_SFT                  8
+#define RT5640_SEQ2_END_MASK                   (0xf)
+#define RT5640_SEQ2_END_SFT                    0
+
+/* Scramble Function (0xcd) */
+#define RT5640_SCB_KEY_MASK                    (0xff)
+#define RT5640_SCB_KEY_SFT                     0
+
+/* Scramble Control (0xce) */
+#define RT5640_SCB_SWAP_MASK                   (0x1 << 15)
+#define RT5640_SCB_SWAP_SFT                    15
+#define RT5640_SCB_SWAP_DIS                    (0x0 << 15)
+#define RT5640_SCB_SWAP_EN                     (0x1 << 15)
+#define RT5640_SCB_MASK                                (0x1 << 14)
+#define RT5640_SCB_SFT                         14
+#define RT5640_SCB_DIS                         (0x0 << 14)
+#define RT5640_SCB_EN                          (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5640_BB_MASK                         (0x1 << 15)
+#define RT5640_BB_SFT                          15
+#define RT5640_BB_DIS                          (0x0 << 15)
+#define RT5640_BB_EN                           (0x1 << 15)
+#define RT5640_BB_CT_MASK                      (0x7 << 12)
+#define RT5640_BB_CT_SFT                       12
+#define RT5640_BB_CT_A                         (0x0 << 12)
+#define RT5640_BB_CT_B                         (0x1 << 12)
+#define RT5640_BB_CT_C                         (0x2 << 12)
+#define RT5640_BB_CT_D                         (0x3 << 12)
+#define RT5640_M_BB_L_MASK                     (0x1 << 9)
+#define RT5640_M_BB_L_SFT                      9
+#define RT5640_M_BB_R_MASK                     (0x1 << 8)
+#define RT5640_M_BB_R_SFT                      8
+#define RT5640_M_BB_HPF_L_MASK                 (0x1 << 7)
+#define RT5640_M_BB_HPF_L_SFT                  7
+#define RT5640_M_BB_HPF_R_MASK                 (0x1 << 6)
+#define RT5640_M_BB_HPF_R_SFT                  6
+#define RT5640_G_BB_BST_MASK                   (0x3f)
+#define RT5640_G_BB_BST_SFT                    0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5640_M_MP3_L_MASK                    (0x1 << 15)
+#define RT5640_M_MP3_L_SFT                     15
+#define RT5640_M_MP3_R_MASK                    (0x1 << 14)
+#define RT5640_M_MP3_R_SFT                     14
+#define RT5640_M_MP3_MASK                      (0x1 << 13)
+#define RT5640_M_MP3_SFT                       13
+#define RT5640_M_MP3_DIS                       (0x0 << 13)
+#define RT5640_M_MP3_EN                                (0x1 << 13)
+#define RT5640_EG_MP3_MASK                     (0x1f << 8)
+#define RT5640_EG_MP3_SFT                      8
+#define RT5640_MP3_HLP_MASK                    (0x1 << 7)
+#define RT5640_MP3_HLP_SFT                     7
+#define RT5640_MP3_HLP_DIS                     (0x0 << 7)
+#define RT5640_MP3_HLP_EN                      (0x1 << 7)
+#define RT5640_M_MP3_ORG_L_MASK                        (0x1 << 6)
+#define RT5640_M_MP3_ORG_L_SFT                 6
+#define RT5640_M_MP3_ORG_R_MASK                        (0x1 << 5)
+#define RT5640_M_MP3_ORG_R_SFT                 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5640_MP3_WT_MASK                     (0x1 << 13)
+#define RT5640_MP3_WT_SFT                      13
+#define RT5640_MP3_WT_1_4                      (0x0 << 13)
+#define RT5640_MP3_WT_1_2                      (0x1 << 13)
+#define RT5640_OG_MP3_MASK                     (0x1f << 8)
+#define RT5640_OG_MP3_SFT                      8
+#define RT5640_HG_MP3_MASK                     (0x3f)
+#define RT5640_HG_MP3_SFT                      0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5640_3D_CF_MASK                      (0x1 << 15)
+#define RT5640_3D_CF_SFT                       15
+#define RT5640_3D_CF_DIS                       (0x0 << 15)
+#define RT5640_3D_CF_EN                                (0x1 << 15)
+#define RT5640_3D_HP_MASK                      (0x1 << 14)
+#define RT5640_3D_HP_SFT                       14
+#define RT5640_3D_HP_DIS                       (0x0 << 14)
+#define RT5640_3D_HP_EN                                (0x1 << 14)
+#define RT5640_3D_BT_MASK                      (0x1 << 13)
+#define RT5640_3D_BT_SFT                       13
+#define RT5640_3D_BT_DIS                       (0x0 << 13)
+#define RT5640_3D_BT_EN                                (0x1 << 13)
+#define RT5640_3D_1F_MIX_MASK                  (0x3 << 11)
+#define RT5640_3D_1F_MIX_SFT                   11
+#define RT5640_3D_HP_M_MASK                    (0x1 << 10)
+#define RT5640_3D_HP_M_SFT                     10
+#define RT5640_3D_HP_M_SUR                     (0x0 << 10)
+#define RT5640_3D_HP_M_FRO                     (0x1 << 10)
+#define RT5640_M_3D_HRTF_MASK                  (0x1 << 9)
+#define RT5640_M_3D_HRTF_SFT                   9
+#define RT5640_M_3D_D2H_MASK                   (0x1 << 8)
+#define RT5640_M_3D_D2H_SFT                    8
+#define RT5640_M_3D_D2R_MASK                   (0x1 << 7)
+#define RT5640_M_3D_D2R_SFT                    7
+#define RT5640_M_3D_REVB_MASK                  (0x1 << 6)
+#define RT5640_M_3D_REVB_SFT                   6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5640_2ND_HPF_MASK                    (0x1 << 15)
+#define RT5640_2ND_HPF_SFT                     15
+#define RT5640_2ND_HPF_DIS                     (0x0 << 15)
+#define RT5640_2ND_HPF_EN                      (0x1 << 15)
+#define RT5640_HPF_CF_L_MASK                   (0x7 << 12)
+#define RT5640_HPF_CF_L_SFT                    12
+#define RT5640_1ST_HPF_MASK                    (0x1 << 11)
+#define RT5640_1ST_HPF_SFT                     11
+#define RT5640_1ST_HPF_DIS                     (0x0 << 11)
+#define RT5640_1ST_HPF_EN                      (0x1 << 11)
+#define RT5640_HPF_CF_R_MASK                   (0x7 << 8)
+#define RT5640_HPF_CF_R_SFT                    8
+#define RT5640_ZD_T_MASK                       (0x3 << 6)
+#define RT5640_ZD_T_SFT                                6
+#define RT5640_ZD_F_MASK                       (0x3 << 4)
+#define RT5640_ZD_F_SFT                                4
+#define RT5640_ZD_F_IM                         (0x0 << 4)
+#define RT5640_ZD_F_ZC_IM                      (0x1 << 4)
+#define RT5640_ZD_F_ZC_IOD                     (0x2 << 4)
+#define RT5640_ZD_F_UN                         (0x3 << 4)
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5640_SI_DAC_MASK                     (0x1 << 11)
+#define RT5640_SI_DAC_SFT                      11
+#define RT5640_SI_DAC_AUTO                     (0x0 << 11)
+#define RT5640_SI_DAC_TEST                     (0x1 << 11)
+#define RT5640_DC_CAL_M_MASK                   (0x1 << 10)
+#define RT5640_DC_CAL_M_SFT                    10
+#define RT5640_DC_CAL_M_CAL                    (0x0 << 10)
+#define RT5640_DC_CAL_M_NOR                    (0x1 << 10)
+#define RT5640_DC_CAL_MASK                     (0x1 << 9)
+#define RT5640_DC_CAL_SFT                      9
+#define RT5640_DC_CAL_DIS                      (0x0 << 9)
+#define RT5640_DC_CAL_EN                       (0x1 << 9)
+#define RT5640_HPD_RCV_MASK                    (0x7 << 6)
+#define RT5640_HPD_RCV_SFT                     6
+#define RT5640_HPD_PS_MASK                     (0x1 << 5)
+#define RT5640_HPD_PS_SFT                      5
+#define RT5640_HPD_PS_DIS                      (0x0 << 5)
+#define RT5640_HPD_PS_EN                       (0x1 << 5)
+#define RT5640_CAL_M_MASK                      (0x1 << 4)
+#define RT5640_CAL_M_SFT                       4
+#define RT5640_CAL_M_DEP                       (0x0 << 4)
+#define RT5640_CAL_M_CAL                       (0x1 << 4)
+#define RT5640_CAL_MASK                                (0x1 << 3)
+#define RT5640_CAL_SFT                         3
+#define RT5640_CAL_DIS                         (0x0 << 3)
+#define RT5640_CAL_EN                          (0x1 << 3)
+#define RT5640_CAL_TEST_MASK                   (0x1 << 2)
+#define RT5640_CAL_TEST_SFT                    2
+#define RT5640_CAL_TEST_DIS                    (0x0 << 2)
+#define RT5640_CAL_TEST_EN                     (0x1 << 2)
+#define RT5640_CAL_P_MASK                      (0x3)
+#define RT5640_CAL_P_SFT                       0
+#define RT5640_CAL_P_NONE                      (0x0)
+#define RT5640_CAL_P_CAL                       (0x1)
+#define RT5640_CAL_P_DAC_CAL                   (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5640_SV_MASK                         (0x1 << 15)
+#define RT5640_SV_SFT                          15
+#define RT5640_SV_DIS                          (0x0 << 15)
+#define RT5640_SV_EN                           (0x1 << 15)
+#define RT5640_SPO_SV_MASK                     (0x1 << 14)
+#define RT5640_SPO_SV_SFT                      14
+#define RT5640_SPO_SV_DIS                      (0x0 << 14)
+#define RT5640_SPO_SV_EN                       (0x1 << 14)
+#define RT5640_OUT_SV_MASK                     (0x1 << 13)
+#define RT5640_OUT_SV_SFT                      13
+#define RT5640_OUT_SV_DIS                      (0x0 << 13)
+#define RT5640_OUT_SV_EN                       (0x1 << 13)
+#define RT5640_HP_SV_MASK                      (0x1 << 12)
+#define RT5640_HP_SV_SFT                       12
+#define RT5640_HP_SV_DIS                       (0x0 << 12)
+#define RT5640_HP_SV_EN                                (0x1 << 12)
+#define RT5640_ZCD_DIG_MASK                    (0x1 << 11)
+#define RT5640_ZCD_DIG_SFT                     11
+#define RT5640_ZCD_DIG_DIS                     (0x0 << 11)
+#define RT5640_ZCD_DIG_EN                      (0x1 << 11)
+#define RT5640_ZCD_MASK                                (0x1 << 10)
+#define RT5640_ZCD_SFT                         10
+#define RT5640_ZCD_PD                          (0x0 << 10)
+#define RT5640_ZCD_PU                          (0x1 << 10)
+#define RT5640_M_ZCD_MASK                      (0x3f << 4)
+#define RT5640_M_ZCD_SFT                       4
+#define RT5640_M_ZCD_RM_L                      (0x1 << 9)
+#define RT5640_M_ZCD_RM_R                      (0x1 << 8)
+#define RT5640_M_ZCD_SM_L                      (0x1 << 7)
+#define RT5640_M_ZCD_SM_R                      (0x1 << 6)
+#define RT5640_M_ZCD_OM_L                      (0x1 << 5)
+#define RT5640_M_ZCD_OM_R                      (0x1 << 4)
+#define RT5640_SV_DLY_MASK                     (0xf)
+#define RT5640_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5640_ZCD_HP_MASK                     (0x1 << 15)
+#define RT5640_ZCD_HP_SFT                      15
+#define RT5640_ZCD_HP_DIS                      (0x0 << 15)
+#define RT5640_ZCD_HP_EN                       (0x1 << 15)
+
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5640_3D_SPK_MASK                     (0x1 << 15)
+#define RT5640_3D_SPK_SFT                      15
+#define RT5640_3D_SPK_DIS                      (0x0 << 15)
+#define RT5640_3D_SPK_EN                       (0x1 << 15)
+#define RT5640_3D_SPK_M_MASK                   (0x3 << 13)
+#define RT5640_3D_SPK_M_SFT                    13
+#define RT5640_3D_SPK_CG_MASK                  (0x1f << 8)
+#define RT5640_3D_SPK_CG_SFT                   8
+#define RT5640_3D_SPK_SG_MASK                  (0x1f)
+#define RT5640_3D_SPK_SG_SFT                   0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5640_WND_MASK                                (0x1 << 15)
+#define RT5640_WND_SFT                         15
+#define RT5640_WND_DIS                         (0x0 << 15)
+#define RT5640_WND_EN                          (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5640_WND_FC_NW_MASK                  (0x3f << 10)
+#define RT5640_WND_FC_NW_SFT                   10
+#define RT5640_WND_FC_WK_MASK                  (0x3f << 4)
+#define RT5640_WND_FC_WK_SFT                   4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5640_HPF_FC_MASK                     (0x3f << 6)
+#define RT5640_HPF_FC_SFT                      6
+#define RT5640_WND_FC_ST_MASK                  (0x3f)
+#define RT5640_WND_FC_ST_SFT                   0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5640_WND_TH_LO_MASK                  (0x3ff)
+#define RT5640_WND_TH_LO_SFT                   0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5640_WND_TH_HI_MASK                  (0x3ff)
+#define RT5640_WND_TH_HI_SFT                   0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5640_WND_WIND_MASK                   (0x1 << 13) /* Read-Only */
+#define RT5640_WND_WIND_SFT                    13
+#define RT5640_WND_STRONG_MASK                 (0x1 << 12) /* Read-Only */
+#define RT5640_WND_STRONG_SFT                  12
+enum {
+       RT5640_NO_WIND,
+       RT5640_BREEZE,
+       RT5640_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5640_DP_ATT_MASK                     (0x3 << 14)
+#define RT5640_DP_ATT_SFT                      14
+#define RT5640_DP_SPK_MASK                     (0x1 << 10)
+#define RT5640_DP_SPK_SFT                      10
+#define RT5640_DP_SPK_DIS                      (0x0 << 10)
+#define RT5640_DP_SPK_EN                       (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5640_EQ_PRE_VOL_MASK                 (0xffff)
+#define RT5640_EQ_PRE_VOL_SFT                  0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5640_EQ_PST_VOL_MASK                 (0xffff)
+#define RT5640_EQ_PST_VOL_SFT                  0
+
+#define RT5640_NO_JACK         BIT(0)
+#define RT5640_HEADSET_DET     BIT(1)
+#define RT5640_HEADPHO_DET     BIT(2)
+
+/* System Clock Source */
+#define RT5640_SCLK_S_MCLK     0
+#define RT5640_SCLK_S_PLL1     1
+#define RT5640_SCLK_S_PLL1_TK  2
+#define RT5640_SCLK_S_RCCLK    3
+
+/* PLL1 Source */
+#define RT5640_PLL1_S_MCLK     0
+#define RT5640_PLL1_S_BCLK1    1
+#define RT5640_PLL1_S_BCLK2    2
+#define RT5640_PLL1_S_BCLK3    3
+
+
+enum {
+       RT5640_AIF1,
+       RT5640_AIF2,
+       RT5640_AIF3,
+       RT5640_AIFS,
+};
+
+enum {
+       RT5640_U_IF1 = 0x1,
+       RT5640_U_IF2 = 0x2,
+       RT5640_U_IF3 = 0x4,
+};
+
+enum {
+       RT5640_IF_123,
+       RT5640_IF_132,
+       RT5640_IF_312,
+       RT5640_IF_321,
+       RT5640_IF_231,
+       RT5640_IF_213,
+       RT5640_IF_113,
+       RT5640_IF_223,
+       RT5640_IF_ALL,
+};
+
+enum {
+       RT5640_DMIC_DIS,
+       RT5640_DMIC1,
+       RT5640_DMIC2,
+};
+
+struct rt5640_pll_code {
+       bool m_bp; /* Indicates bypass m code or not. */
+       int m_code;
+       int n_code;
+       int k_code;
+};
+
+struct rt5640_priv {
+       struct snd_soc_codec *codec;
+       struct rt5640_platform_data pdata;
+       struct regmap *regmap;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5640_AIFS];
+       int bclk[RT5640_AIFS];
+       int master[RT5640_AIFS];
+
+       struct rt5640_pll_code pll_code;
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+       int dmic_en;
+};
+
+#endif
index 92bbfec..d441559 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/clk.h>
+#include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
 #define SGTL5000_MAX_REG_OFFSET        0x013A
 
 /* default value of sgtl5000 registers */
-static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] =  {
-       [SGTL5000_CHIP_CLK_CTRL] = 0x0008,
-       [SGTL5000_CHIP_I2S_CTRL] = 0x0010,
-       [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
-       [SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
-       [SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
-       [SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
-       [SGTL5000_CHIP_ANA_CTRL] = 0x0111,
-       [SGTL5000_CHIP_LINE_OUT_VOL] = 0x0404,
-       [SGTL5000_CHIP_ANA_POWER] = 0x7060,
-       [SGTL5000_CHIP_PLL_CTRL] = 0x5000,
-       [SGTL5000_DAP_BASS_ENHANCE] = 0x0040,
-       [SGTL5000_DAP_BASS_ENHANCE_CTRL] = 0x051f,
-       [SGTL5000_DAP_SURROUND] = 0x0040,
-       [SGTL5000_DAP_EQ_BASS_BAND0] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND1] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND2] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND3] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND4] = 0x002f,
-       [SGTL5000_DAP_MAIN_CHAN] = 0x8000,
-       [SGTL5000_DAP_AVC_CTRL] = 0x0510,
-       [SGTL5000_DAP_AVC_THRESHOLD] = 0x1473,
-       [SGTL5000_DAP_AVC_ATTACK] = 0x0028,
-       [SGTL5000_DAP_AVC_DECAY] = 0x0050,
+static const struct reg_default sgtl5000_reg_defaults[] = {
+       { SGTL5000_CHIP_CLK_CTRL,               0x0008 },
+       { SGTL5000_CHIP_I2S_CTRL,               0x0010 },
+       { SGTL5000_CHIP_SSS_CTRL,               0x0008 },
+       { SGTL5000_CHIP_DAC_VOL,                0x3c3c },
+       { SGTL5000_CHIP_PAD_STRENGTH,           0x015f },
+       { SGTL5000_CHIP_ANA_HP_CTRL,            0x1818 },
+       { SGTL5000_CHIP_ANA_CTRL,               0x0111 },
+       { SGTL5000_CHIP_LINE_OUT_VOL,           0x0404 },
+       { SGTL5000_CHIP_ANA_POWER,              0x7060 },
+       { SGTL5000_CHIP_PLL_CTRL,               0x5000 },
+       { SGTL5000_DAP_BASS_ENHANCE,            0x0040 },
+       { SGTL5000_DAP_BASS_ENHANCE_CTRL,       0x051f },
+       { SGTL5000_DAP_SURROUND,                0x0040 },
+       { SGTL5000_DAP_EQ_BASS_BAND0,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND1,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND2,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND3,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND4,           0x002f },
+       { SGTL5000_DAP_MAIN_CHAN,               0x8000 },
+       { SGTL5000_DAP_AVC_CTRL,                0x0510 },
+       { SGTL5000_DAP_AVC_THRESHOLD,           0x1473 },
+       { SGTL5000_DAP_AVC_ATTACK,              0x0028 },
+       { SGTL5000_DAP_AVC_DECAY,               0x0050 },
 };
 
 /* regulator supplies for sgtl5000, VDDD is an optional external supply */
@@ -112,6 +113,8 @@ struct sgtl5000_priv {
        int fmt;        /* i2s data format */
        struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM];
        struct ldo_regulator *ldo;
+       struct regmap *regmap;
+       struct clk *mclk;
 };
 
 /*
@@ -151,12 +154,12 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
        switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
                break;
 
-       case SND_SOC_DAPM_POST_PMD:
+       case SND_SOC_DAPM_PRE_PMD:
                snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, 0);
                msleep(400);
@@ -217,12 +220,11 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
                                0, SGTL5000_CHIP_DIG_POWER,
                                1, 0),
 
-       SND_SOC_DAPM_SUPPLY("VAG_POWER", SGTL5000_CHIP_ANA_POWER, 7, 0,
-                           power_vag_event,
-                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
        SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
        SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0),
+
+       SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event),
+       SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event),
 };
 
 /* routes for sgtl5000 */
@@ -230,16 +232,13 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
        {"Capture Mux", "LINE_IN", "LINE_IN"},  /* line_in --> adc_mux */
        {"Capture Mux", "MIC_IN", "MIC_IN"},    /* mic_in --> adc_mux */
 
-       {"ADC", NULL, "VAG_POWER"},
        {"ADC", NULL, "Capture Mux"},           /* adc_mux --> adc */
        {"AIFOUT", NULL, "ADC"},                /* adc --> i2s_out */
 
-       {"DAC", NULL, "VAG_POWER"},
        {"DAC", NULL, "AIFIN"},                 /* i2s-->dac,skip audio mux */
        {"Headphone Mux", "DAC", "DAC"},        /* dac --> hp_mux */
        {"LO", NULL, "DAC"},                    /* dac --> line_out */
 
-       {"LINE_IN", NULL, "VAG_POWER"},
        {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
        {"HP", NULL, "Headphone Mux"},          /* hp_mux --> hp */
 
@@ -909,10 +908,25 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
                        if (ret)
                                return ret;
                        udelay(10);
+
+                       regcache_cache_only(sgtl5000->regmap, false);
+
+                       ret = regcache_sync(sgtl5000->regmap);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to restore cache: %d\n", ret);
+
+                               regcache_cache_only(sgtl5000->regmap, true);
+                               regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+                                                      sgtl5000->supplies);
+
+                               return ret;
+                       }
                }
 
                break;
        case SND_SOC_BIAS_OFF:
+               regcache_cache_only(sgtl5000->regmap, true);
                regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
                                        sgtl5000->supplies);
                break;
@@ -958,17 +972,76 @@ static struct snd_soc_dai_driver sgtl5000_dai = {
        .symmetric_rates = 1,
 };
 
-static int sgtl5000_volatile_register(struct snd_soc_codec *codec,
-                                       unsigned int reg)
+static bool sgtl5000_volatile(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case SGTL5000_CHIP_ID:
        case SGTL5000_CHIP_ADCDAC_CTRL:
        case SGTL5000_CHIP_ANA_STATUS:
-               return 1;
+               return true;
        }
 
-       return 0;
+       return false;
+}
+
+static bool sgtl5000_readable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SGTL5000_CHIP_ID:
+       case SGTL5000_CHIP_DIG_POWER:
+       case SGTL5000_CHIP_CLK_CTRL:
+       case SGTL5000_CHIP_I2S_CTRL:
+       case SGTL5000_CHIP_SSS_CTRL:
+       case SGTL5000_CHIP_ADCDAC_CTRL:
+       case SGTL5000_CHIP_DAC_VOL:
+       case SGTL5000_CHIP_PAD_STRENGTH:
+       case SGTL5000_CHIP_ANA_ADC_CTRL:
+       case SGTL5000_CHIP_ANA_HP_CTRL:
+       case SGTL5000_CHIP_ANA_CTRL:
+       case SGTL5000_CHIP_LINREG_CTRL:
+       case SGTL5000_CHIP_REF_CTRL:
+       case SGTL5000_CHIP_MIC_CTRL:
+       case SGTL5000_CHIP_LINE_OUT_CTRL:
+       case SGTL5000_CHIP_LINE_OUT_VOL:
+       case SGTL5000_CHIP_ANA_POWER:
+       case SGTL5000_CHIP_PLL_CTRL:
+       case SGTL5000_CHIP_CLK_TOP_CTRL:
+       case SGTL5000_CHIP_ANA_STATUS:
+       case SGTL5000_CHIP_SHORT_CTRL:
+       case SGTL5000_CHIP_ANA_TEST2:
+       case SGTL5000_DAP_CTRL:
+       case SGTL5000_DAP_PEQ:
+       case SGTL5000_DAP_BASS_ENHANCE:
+       case SGTL5000_DAP_BASS_ENHANCE_CTRL:
+       case SGTL5000_DAP_AUDIO_EQ:
+       case SGTL5000_DAP_SURROUND:
+       case SGTL5000_DAP_FLT_COEF_ACCESS:
+       case SGTL5000_DAP_COEF_WR_B0_MSB:
+       case SGTL5000_DAP_COEF_WR_B0_LSB:
+       case SGTL5000_DAP_EQ_BASS_BAND0:
+       case SGTL5000_DAP_EQ_BASS_BAND1:
+       case SGTL5000_DAP_EQ_BASS_BAND2:
+       case SGTL5000_DAP_EQ_BASS_BAND3:
+       case SGTL5000_DAP_EQ_BASS_BAND4:
+       case SGTL5000_DAP_MAIN_CHAN:
+       case SGTL5000_DAP_MIX_CHAN:
+       case SGTL5000_DAP_AVC_CTRL:
+       case SGTL5000_DAP_AVC_THRESHOLD:
+       case SGTL5000_DAP_AVC_ATTACK:
+       case SGTL5000_DAP_AVC_DECAY:
+       case SGTL5000_DAP_COEF_WR_B1_MSB:
+       case SGTL5000_DAP_COEF_WR_B1_LSB:
+       case SGTL5000_DAP_COEF_WR_B2_MSB:
+       case SGTL5000_DAP_COEF_WR_B2_LSB:
+       case SGTL5000_DAP_COEF_WR_A1_MSB:
+       case SGTL5000_DAP_COEF_WR_A1_LSB:
+       case SGTL5000_DAP_COEF_WR_A2_MSB:
+       case SGTL5000_DAP_COEF_WR_A2_LSB:
+               return true;
+
+       default:
+               return false;
+       }
 }
 
 #ifdef CONFIG_SUSPEND
@@ -1214,7 +1287,7 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
 
 static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
 {
-       u16 reg;
+       int reg;
        int ret;
        int rev;
        int i;
@@ -1242,23 +1315,17 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
        /* wait for all power rails bring up */
        udelay(10);
 
-       /* read chip information */
-       reg = snd_soc_read(codec, SGTL5000_CHIP_ID);
-       if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
-           SGTL5000_PARTID_PART_ID) {
-               dev_err(codec->dev,
-                       "Device with ID register %x is not a sgtl5000\n", reg);
-               ret = -ENODEV;
-               goto err_regulator_disable;
-       }
-
-       rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
-       dev_info(codec->dev, "sgtl5000 revision 0x%x\n", rev);
-
        /*
         * 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),
@@ -1300,7 +1367,8 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
        /* setup i2c data ops */
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       codec->control_data = sgtl5000->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -1391,11 +1459,6 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
        .suspend = sgtl5000_suspend,
        .resume = sgtl5000_resume,
        .set_bias_level = sgtl5000_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(sgtl5000_regs),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_step = 2,
-       .reg_cache_default = sgtl5000_regs,
-       .volatile_register = sgtl5000_volatile_register,
        .controls = sgtl5000_snd_controls,
        .num_controls = ARRAY_SIZE(sgtl5000_snd_controls),
        .dapm_widgets = sgtl5000_dapm_widgets,
@@ -1404,28 +1467,114 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
        .num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes),
 };
 
+static const struct regmap_config sgtl5000_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .max_register = SGTL5000_MAX_REG_OFFSET,
+       .volatile_reg = sgtl5000_volatile,
+       .readable_reg = sgtl5000_readable,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = sgtl5000_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(sgtl5000_reg_defaults),
+};
+
+/*
+ * Write all the default values from sgtl5000_reg_defaults[] array into the
+ * sgtl5000 registers, to make sure we always start with the sane registers
+ * values as stated in the datasheet.
+ *
+ * Since sgtl5000 does not have a reset line, nor a reset command in software,
+ * we follow this approach to guarantee we always start from the default values
+ * and avoid problems like, not being able to probe after an audio playback
+ * followed by a system reset or a 'reboot' command in Linux
+ */
+static int sgtl5000_fill_defaults(struct sgtl5000_priv *sgtl5000)
+{
+       int i, ret, val, index;
+
+       for (i = 0; i < ARRAY_SIZE(sgtl5000_reg_defaults); i++) {
+               val = sgtl5000_reg_defaults[i].def;
+               index = sgtl5000_reg_defaults[i].reg;
+               ret = regmap_write(sgtl5000->regmap, index, val);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int sgtl5000_i2c_probe(struct i2c_client *client,
                              const struct i2c_device_id *id)
 {
        struct sgtl5000_priv *sgtl5000;
-       int ret;
+       int ret, reg, rev;
 
        sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
                                                                GFP_KERNEL);
        if (!sgtl5000)
                return -ENOMEM;
 
+       sgtl5000->regmap = devm_regmap_init_i2c(client, &sgtl5000_regmap);
+       if (IS_ERR(sgtl5000->regmap)) {
+               ret = PTR_ERR(sgtl5000->regmap);
+               dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+               return ret;
+       }
+
+       sgtl5000->mclk = devm_clk_get(&client->dev, NULL);
+       if (IS_ERR(sgtl5000->mclk)) {
+               ret = PTR_ERR(sgtl5000->mclk);
+               dev_err(&client->dev, "Failed to get mclock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sgtl5000->mclk);
+       if (ret)
+               return ret;
+
+       /* read chip information */
+       ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
+       if (ret)
+               goto disable_clk;
+
+       if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
+           SGTL5000_PARTID_PART_ID) {
+               dev_err(&client->dev,
+                       "Device with ID register %x is not a sgtl5000\n", reg);
+               ret = -ENODEV;
+               goto disable_clk;
+       }
+
+       rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
+       dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
+
        i2c_set_clientdata(client, sgtl5000);
 
+       /* Ensure sgtl5000 will start with sane register values */
+       ret = sgtl5000_fill_defaults(sgtl5000);
+       if (ret)
+               goto disable_clk;
+
        ret = snd_soc_register_codec(&client->dev,
                        &sgtl5000_driver, &sgtl5000_dai, 1);
+       if (ret)
+               goto disable_clk;
+
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(sgtl5000->mclk);
        return ret;
 }
 
 static int sgtl5000_i2c_remove(struct i2c_client *client)
 {
-       snd_soc_unregister_codec(&client->dev);
+       struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
 
+       snd_soc_unregister_codec(&client->dev);
+       clk_disable_unprepare(sgtl5000->mclk);
        return 0;
 }
 
index 8a9f435..4b69229 100644 (file)
@@ -12,7 +12,7 @@
 #define _SGTL5000_H
 
 /*
- * Register values.
+ * Registers addresses
  */
 #define SGTL5000_CHIP_ID                       0x0000
 #define SGTL5000_CHIP_DIG_POWER                        0x0002
index d1ae869..dba26e6 100644 (file)
@@ -883,7 +883,7 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-struct snd_soc_codec_driver sn95031_codec = {
+static struct snd_soc_codec_driver sn95031_codec = {
        .probe          = sn95031_codec_probe,
        .remove         = sn95031_codec_remove,
        .read           = sn95031_read,
index dd8d856..e9d7881 100644 (file)
@@ -21,6 +21,7 @@
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
+#include <linux/of.h>
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -51,12 +52,21 @@ static int spdif_dir_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id spdif_dir_dt_ids[] = {
+       { .compatible = "linux,spdif-dir", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, spdif_dir_dt_ids);
+#endif
+
 static struct platform_driver spdif_dir_driver = {
        .probe          = spdif_dir_probe,
        .remove         = spdif_dir_remove,
        .driver         = {
                .name   = "spdif-dir",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(spdif_dir_dt_ids),
        },
 };
 
similarity index 88%
rename from sound/soc/codecs/spdif_transciever.c
rename to sound/soc/codecs/spdif_transmitter.c
index 112a49d..1828049 100644 (file)
@@ -20,6 +20,7 @@
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
+#include <linux/of.h>
 
 #define DRV_NAME "spdif-dit"
 
@@ -52,12 +53,21 @@ static int spdif_dit_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id spdif_dit_dt_ids[] = {
+       { .compatible = "linux,spdif-dit", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, spdif_dit_dt_ids);
+#endif
+
 static struct platform_driver spdif_dit_driver = {
        .probe          = spdif_dit_probe,
        .remove         = spdif_dit_remove,
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(spdif_dit_dt_ids),
        },
 };
 
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
new file mode 100644 (file)
index 0000000..95aed55
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_data/ssm2518.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "ssm2518.h"
+
+#define SSM2518_REG_POWER1             0x00
+#define SSM2518_REG_CLOCK              0x01
+#define SSM2518_REG_SAI_CTRL1          0x02
+#define SSM2518_REG_SAI_CTRL2          0x03
+#define SSM2518_REG_CHAN_MAP           0x04
+#define SSM2518_REG_LEFT_VOL           0x05
+#define SSM2518_REG_RIGHT_VOL          0x06
+#define SSM2518_REG_MUTE_CTRL          0x07
+#define SSM2518_REG_FAULT_CTRL         0x08
+#define SSM2518_REG_POWER2             0x09
+#define SSM2518_REG_DRC_1              0x0a
+#define SSM2518_REG_DRC_2              0x0b
+#define SSM2518_REG_DRC_3              0x0c
+#define SSM2518_REG_DRC_4              0x0d
+#define SSM2518_REG_DRC_5              0x0e
+#define SSM2518_REG_DRC_6              0x0f
+#define SSM2518_REG_DRC_7              0x10
+#define SSM2518_REG_DRC_8              0x11
+#define SSM2518_REG_DRC_9              0x12
+
+#define SSM2518_POWER1_RESET                   BIT(7)
+#define SSM2518_POWER1_NO_BCLK                 BIT(5)
+#define SSM2518_POWER1_MCS_MASK                        (0xf << 1)
+#define SSM2518_POWER1_MCS_64FS                        (0x0 << 1)
+#define SSM2518_POWER1_MCS_128FS               (0x1 << 1)
+#define SSM2518_POWER1_MCS_256FS               (0x2 << 1)
+#define SSM2518_POWER1_MCS_384FS               (0x3 << 1)
+#define SSM2518_POWER1_MCS_512FS               (0x4 << 1)
+#define SSM2518_POWER1_MCS_768FS               (0x5 << 1)
+#define SSM2518_POWER1_MCS_100FS               (0x6 << 1)
+#define SSM2518_POWER1_MCS_200FS               (0x7 << 1)
+#define SSM2518_POWER1_MCS_400FS               (0x8 << 1)
+#define SSM2518_POWER1_SPWDN                   BIT(0)
+
+#define SSM2518_CLOCK_ASR                      BIT(0)
+
+#define SSM2518_SAI_CTRL1_FMT_MASK             (0x3 << 5)
+#define SSM2518_SAI_CTRL1_FMT_I2S              (0x0 << 5)
+#define SSM2518_SAI_CTRL1_FMT_LJ               (0x1 << 5)
+#define SSM2518_SAI_CTRL1_FMT_RJ_24BIT         (0x2 << 5)
+#define SSM2518_SAI_CTRL1_FMT_RJ_16BIT         (0x3 << 5)
+
+#define SSM2518_SAI_CTRL1_SAI_MASK             (0x7 << 2)
+#define SSM2518_SAI_CTRL1_SAI_I2S              (0x0 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_2            (0x1 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_4            (0x2 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_8            (0x3 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_16           (0x4 << 2)
+#define SSM2518_SAI_CTRL1_SAI_MONO             (0x5 << 2)
+
+#define SSM2518_SAI_CTRL1_FS_MASK              (0x3)
+#define SSM2518_SAI_CTRL1_FS_8000_12000                (0x0)
+#define SSM2518_SAI_CTRL1_FS_16000_24000       (0x1)
+#define SSM2518_SAI_CTRL1_FS_32000_48000       (0x2)
+#define SSM2518_SAI_CTRL1_FS_64000_96000       (0x3)
+
+#define SSM2518_SAI_CTRL2_BCLK_INTERAL         BIT(7)
+#define SSM2518_SAI_CTRL2_LRCLK_PULSE          BIT(6)
+#define SSM2518_SAI_CTRL2_LRCLK_INVERT         BIT(5)
+#define SSM2518_SAI_CTRL2_MSB                  BIT(4)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_MASK      (0x3 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_32                (0x0 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_24                (0x1 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_16                (0x2 << 2)
+#define SSM2518_SAI_CTRL2_BCLK_INVERT          BIT(1)
+
+#define SSM2518_CHAN_MAP_RIGHT_SLOT_OFFSET     4
+#define SSM2518_CHAN_MAP_RIGHT_SLOT_MASK       0xf0
+#define SSM2518_CHAN_MAP_LEFT_SLOT_OFFSET      0
+#define SSM2518_CHAN_MAP_LEFT_SLOT_MASK                0x0f
+
+#define SSM2518_MUTE_CTRL_ANA_GAIN             BIT(5)
+#define SSM2518_MUTE_CTRL_MUTE_MASTER          BIT(0)
+
+#define SSM2518_POWER2_APWDN                   BIT(0)
+
+#define SSM2518_DAC_MUTE                       BIT(6)
+#define SSM2518_DAC_FS_MASK                    0x07
+#define SSM2518_DAC_FS_8000                    0x00
+#define SSM2518_DAC_FS_16000                   0x01
+#define SSM2518_DAC_FS_32000                   0x02
+#define SSM2518_DAC_FS_64000                   0x03
+#define SSM2518_DAC_FS_128000                  0x04
+
+struct ssm2518 {
+       struct regmap *regmap;
+       bool right_j;
+
+       unsigned int sysclk;
+       const struct snd_pcm_hw_constraint_list *constraints;
+
+       int enable_gpio;
+};
+
+static const struct reg_default ssm2518_reg_defaults[] = {
+       { 0x00, 0x05 },
+       { 0x01, 0x00 },
+       { 0x02, 0x02 },
+       { 0x03, 0x00 },
+       { 0x04, 0x10 },
+       { 0x05, 0x40 },
+       { 0x06, 0x40 },
+       { 0x07, 0x81 },
+       { 0x08, 0x0c },
+       { 0x09, 0x99 },
+       { 0x0a, 0x7c },
+       { 0x0b, 0x5b },
+       { 0x0c, 0x57 },
+       { 0x0d, 0x89 },
+       { 0x0e, 0x8c },
+       { 0x0f, 0x77 },
+       { 0x10, 0x26 },
+       { 0x11, 0x1c },
+       { 0x12, 0x97 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(ssm2518_vol_tlv, -7125, 2400);
+static const DECLARE_TLV_DB_SCALE(ssm2518_compressor_tlv, -3400, 200, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_expander_tlv, -8100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_noise_gate_tlv, -9600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_post_drc_tlv, -2400, 300, 0);
+
+static const DECLARE_TLV_DB_RANGE(ssm2518_limiter_tlv,
+       0, 7, TLV_DB_SCALE_ITEM(-2200, 200, 0),
+       7, 15, TLV_DB_SCALE_ITEM(-800, 100, 0),
+);
+
+static const char * const ssm2518_drc_peak_detector_attack_time_text[] = {
+       "0 ms", "0.1 ms", "0.19 ms", "0.37 ms", "0.75 ms", "1.5 ms", "3 ms",
+       "6 ms", "12 ms", "24 ms", "48 ms", "96 ms", "192 ms", "384 ms",
+       "768 ms", "1536 ms",
+};
+
+static const char * const ssm2518_drc_peak_detector_release_time_text[] = {
+       "0 ms", "1.5 ms", "3 ms", "6 ms", "12 ms", "24 ms", "48 ms", "96 ms",
+       "192 ms", "384 ms", "768 ms", "1536 ms", "3072 ms", "6144 ms",
+       "12288 ms", "24576 ms"
+};
+
+static const char * const ssm2518_drc_hold_time_text[] = {
+       "0 ms", "0.67 ms", "1.33 ms", "2.67 ms", "5.33 ms", "10.66 ms",
+       "21.32 ms", "42.64 ms", "85.28 ms", "170.56 ms", "341.12 ms",
+       "682.24 ms", "1364 ms",
+};
+
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,
+       SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum,
+       SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum,
+       SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum,
+       SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum,
+       SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum,
+       SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum,
+       SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text);
+
+static const struct snd_kcontrol_new ssm2518_snd_controls[] = {
+       SOC_SINGLE("Playback De-emphasis Switch", SSM2518_REG_MUTE_CTRL,
+                       4, 1, 0),
+       SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2518_REG_LEFT_VOL,
+                       SSM2518_REG_RIGHT_VOL, 0, 0xff, 1, ssm2518_vol_tlv),
+       SOC_DOUBLE("Master Playback Switch", SSM2518_REG_MUTE_CTRL, 2, 1, 1, 1),
+
+       SOC_SINGLE("Amp Low Power Mode Switch", SSM2518_REG_POWER2, 4, 1, 0),
+       SOC_SINGLE("DAC Low Power Mode Switch", SSM2518_REG_POWER2, 3, 1, 0),
+
+       SOC_SINGLE("DRC Limiter Switch", SSM2518_REG_DRC_1, 5, 1, 0),
+       SOC_SINGLE("DRC Compressor Switch", SSM2518_REG_DRC_1, 4, 1, 0),
+       SOC_SINGLE("DRC Expander Switch", SSM2518_REG_DRC_1, 3, 1, 0),
+       SOC_SINGLE("DRC Noise Gate Switch", SSM2518_REG_DRC_1, 2, 1, 0),
+       SOC_DOUBLE("DRC Switch", SSM2518_REG_DRC_1, 0, 1, 1, 0),
+
+       SOC_SINGLE_TLV("DRC Limiter Threshold Volume",
+                       SSM2518_REG_DRC_3, 4, 15, 1, ssm2518_limiter_tlv),
+       SOC_SINGLE_TLV("DRC Compressor Lower Threshold Volume",
+                       SSM2518_REG_DRC_3, 0, 15, 1, ssm2518_compressor_tlv),
+       SOC_SINGLE_TLV("DRC Expander Upper Threshold Volume", SSM2518_REG_DRC_4,
+                       4, 15, 1, ssm2518_expander_tlv),
+       SOC_SINGLE_TLV("DRC Noise Gate Threshold Volume",
+                       SSM2518_REG_DRC_4, 0, 15, 1, ssm2518_noise_gate_tlv),
+       SOC_SINGLE_TLV("DRC Upper Output Threshold Volume",
+                       SSM2518_REG_DRC_5, 4, 15, 1, ssm2518_limiter_tlv),
+       SOC_SINGLE_TLV("DRC Lower Output Threshold Volume",
+                       SSM2518_REG_DRC_5, 0, 15, 1, ssm2518_noise_gate_tlv),
+       SOC_SINGLE_TLV("DRC Post Volume", SSM2518_REG_DRC_8,
+                       2, 15, 1, ssm2518_post_drc_tlv),
+
+       SOC_ENUM("DRC Peak Detector Attack Time",
+               ssm2518_drc_peak_detector_attack_time_enum),
+       SOC_ENUM("DRC Peak Detector Release Time",
+               ssm2518_drc_peak_detector_release_time_enum),
+       SOC_ENUM("DRC Attack Time", ssm2518_drc_attack_time_enum),
+       SOC_ENUM("DRC Decay Time", ssm2518_drc_decay_time_enum),
+       SOC_ENUM("DRC Hold Time", ssm2518_drc_hold_time_enum),
+       SOC_ENUM("DRC Noise Gate Hold Time",
+               ssm2518_drc_noise_gate_hold_time_enum),
+       SOC_ENUM("DRC RMS Averaging Time", ssm2518_drc_rms_averaging_time_enum),
+};
+
+static const struct snd_soc_dapm_widget ssm2518_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DACL", "HiFi Playback", SSM2518_REG_POWER2, 1, 1),
+       SND_SOC_DAPM_DAC("DACR", "HiFi Playback", SSM2518_REG_POWER2, 2, 1),
+
+       SND_SOC_DAPM_OUTPUT("OUTL"),
+       SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route ssm2518_routes[] = {
+       { "OUTL", NULL, "DACL" },
+       { "OUTR", NULL, "DACR" },
+};
+
+struct ssm2518_mcs_lut {
+       unsigned int rate;
+       const unsigned int *sysclks;
+};
+
+static const unsigned int ssm2518_sysclks_2048000[] = {
+       2048000, 4096000, 8192000, 12288000, 16384000, 24576000,
+       3200000, 6400000, 12800000, 0
+};
+
+static const unsigned int ssm2518_sysclks_2822000[] = {
+       2822000, 5644800, 11289600, 16934400, 22579200, 33868800,
+       4410000, 8820000, 17640000, 0
+};
+
+static const unsigned int ssm2518_sysclks_3072000[] = {
+       3072000, 6144000, 12288000, 16384000, 24576000, 38864000,
+       4800000, 9600000, 19200000, 0
+};
+
+static const struct ssm2518_mcs_lut ssm2518_mcs_lut[] = {
+       { 8000,  ssm2518_sysclks_2048000, },
+       { 11025, ssm2518_sysclks_2822000, },
+       { 12000, ssm2518_sysclks_3072000, },
+       { 16000, ssm2518_sysclks_2048000, },
+       { 24000, ssm2518_sysclks_3072000, },
+       { 22050, ssm2518_sysclks_2822000, },
+       { 32000, ssm2518_sysclks_2048000, },
+       { 44100, ssm2518_sysclks_2822000, },
+       { 48000, ssm2518_sysclks_3072000, },
+       { 96000, ssm2518_sysclks_3072000, },
+};
+
+static const unsigned int ssm2518_rates_2048000[] = {
+       8000, 16000, 32000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_2048000 = {
+       .list = ssm2518_rates_2048000,
+       .count = ARRAY_SIZE(ssm2518_rates_2048000),
+};
+
+static const unsigned int ssm2518_rates_2822000[] = {
+       11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_2822000 = {
+       .list = ssm2518_rates_2822000,
+       .count = ARRAY_SIZE(ssm2518_rates_2822000),
+};
+
+static const unsigned int ssm2518_rates_3072000[] = {
+       12000, 24000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_3072000 = {
+       .list = ssm2518_rates_3072000,
+       .count = ARRAY_SIZE(ssm2518_rates_3072000),
+};
+
+static const unsigned int ssm2518_rates_12288000[] = {
+       8000, 12000, 16000, 24000, 32000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = {
+       .list = ssm2518_rates_12288000,
+       .count = ARRAY_SIZE(ssm2518_rates_12288000),
+};
+
+static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
+       unsigned int rate)
+{
+       const unsigned int *sysclks = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ssm2518_mcs_lut); i++) {
+               if (ssm2518_mcs_lut[i].rate == rate) {
+                       sysclks = ssm2518_mcs_lut[i].sysclks;
+                       break;
+               }
+       }
+
+       if (!sysclks)
+               return -EINVAL;
+
+       for (i = 0; sysclks[i]; i++) {
+               if (sysclks[i] == ssm2518->sysclk)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int ssm2518_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       unsigned int rate = params_rate(params);
+       unsigned int ctrl1, ctrl1_mask;
+       int mcs;
+       int ret;
+
+       mcs = ssm2518_lookup_mcs(ssm2518, rate);
+       if (mcs < 0)
+               return mcs;
+
+       ctrl1_mask = SSM2518_SAI_CTRL1_FS_MASK;
+
+       if (rate >= 8000 && rate <= 12000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_8000_12000;
+       else if (rate >= 16000 && rate <= 24000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_16000_24000;
+       else if (rate >= 32000 && rate <= 48000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_32000_48000;
+       else if (rate >= 64000 && rate <= 96000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_64000_96000;
+       else
+               return -EINVAL;
+
+       if (ssm2518->right_j) {
+               switch (params_format(params)) {
+               case SNDRV_PCM_FORMAT_S16_LE:
+                       ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_16BIT;
+                       break;
+               case SNDRV_PCM_FORMAT_S24_LE:
+                       ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               ctrl1_mask |= SSM2518_SAI_CTRL1_FMT_MASK;
+       }
+
+       /* Disable auto samplerate detection */
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_CLOCK,
+                               SSM2518_CLOCK_ASR, SSM2518_CLOCK_ASR);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL1,
+                               ctrl1_mask, ctrl1);
+       if (ret < 0)
+               return ret;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                               SSM2518_POWER1_MCS_MASK, mcs << 1);
+}
+
+static int ssm2518_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int val;
+
+       if (mute)
+               val = SSM2518_MUTE_CTRL_MUTE_MASTER;
+       else
+               val = 0;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_MUTE_CTRL,
+                       SSM2518_MUTE_CTRL_MUTE_MASTER, val);
+}
+
+static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int ctrl1 = 0, ctrl2 = 0;
+       bool invert_fclk;
+       int ret;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               invert_fclk = false;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               ctrl2 |= SSM2518_SAI_CTRL2_BCLK_INVERT;
+               invert_fclk = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               invert_fclk = true;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               ctrl2 |= SSM2518_SAI_CTRL2_BCLK_INVERT;
+               invert_fclk = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ssm2518->right_j = false;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_LJ;
+               invert_fclk = !invert_fclk;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT;
+               ssm2518->right_j = true;
+               invert_fclk = !invert_fclk;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_PULSE;
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_I2S;
+               invert_fclk = false;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_PULSE;
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_LJ;
+               invert_fclk = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (invert_fclk)
+               ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_INVERT;
+
+       ret = regmap_write(ssm2518->regmap, SSM2518_REG_SAI_CTRL1, ctrl1);
+       if (ret)
+               return ret;
+
+       return regmap_write(ssm2518->regmap, SSM2518_REG_SAI_CTRL2, ctrl2);
+}
+
+static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable)
+{
+       int ret = 0;
+
+       if (!enable) {
+               ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_SPWDN, SSM2518_POWER1_SPWDN);
+               regcache_mark_dirty(ssm2518->regmap);
+       }
+
+       if (gpio_is_valid(ssm2518->enable_gpio))
+               gpio_set_value(ssm2518->enable_gpio, enable);
+
+       regcache_cache_only(ssm2518->regmap, !enable);
+
+       if (enable) {
+               ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_SPWDN | SSM2518_POWER1_RESET, 0x00);
+               regcache_sync(ssm2518->regmap);
+       }
+
+       return ret;
+}
+
+static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       ret = ssm2518_set_power(ssm2518, true);
+               break;
+       case SND_SOC_BIAS_OFF:
+               ret = ssm2518_set_power(ssm2518, false);
+               break;
+       }
+
+       if (ret)
+               return ret;
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+       unsigned int rx_mask, int slots, int width)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int ctrl1, ctrl2;
+       int left_slot, right_slot;
+       int ret;
+
+       if (slots == 0)
+               return regmap_update_bits(ssm2518->regmap,
+                       SSM2518_REG_SAI_CTRL1, SSM2518_SAI_CTRL1_SAI_MASK,
+                       SSM2518_SAI_CTRL1_SAI_I2S);
+
+       if (tx_mask == 0 || rx_mask != 0)
+               return -EINVAL;
+
+       if (slots == 1) {
+               if (tx_mask != 1)
+                       return -EINVAL;
+               left_slot = 0;
+               right_slot = 0;
+       } else {
+               /* We assume the left channel < right channel */
+               left_slot = ffs(tx_mask);
+               tx_mask &= ~(1 << tx_mask);
+               if (tx_mask == 0) {
+                       right_slot = left_slot;
+               } else {
+                       right_slot = ffs(tx_mask);
+                       tx_mask &= ~(1 << tx_mask);
+               }
+       }
+
+       if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
+               return -EINVAL;
+
+       switch (width) {
+       case 16:
+               ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_16;
+               break;
+       case 24:
+               ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_24;
+               break;
+       case 32:
+               ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (slots) {
+       case 1:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_MONO;
+               break;
+       case 2:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_2;
+               break;
+       case 4:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_4;
+               break;
+       case 8:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_8;
+               break;
+       case 16:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_write(ssm2518->regmap, SSM2518_REG_CHAN_MAP,
+               (left_slot << SSM2518_CHAN_MAP_LEFT_SLOT_OFFSET) |
+               (right_slot << SSM2518_CHAN_MAP_RIGHT_SLOT_OFFSET));
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL1,
+               SSM2518_SAI_CTRL1_SAI_MASK, ctrl1);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL2,
+               SSM2518_SAI_CTRL2_SLOT_WIDTH_MASK, ctrl2);
+}
+
+static int ssm2518_startup(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+
+       if (ssm2518->constraints)
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, ssm2518->constraints);
+
+       return 0;
+}
+
+#define SSM2518_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
+
+static const struct snd_soc_dai_ops ssm2518_dai_ops = {
+       .startup = ssm2518_startup,
+       .hw_params      = ssm2518_hw_params,
+       .digital_mute   = ssm2518_mute,
+       .set_fmt        = ssm2518_set_dai_fmt,
+       .set_tdm_slot   = ssm2518_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ssm2518_dai = {
+       .name = "ssm2518-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SSM2518_FORMATS,
+       },
+       .ops = &ssm2518_dai_ops,
+};
+
+static int ssm2518_probe(struct snd_soc_codec *codec)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       codec->control_data = ssm2518->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int ssm2518_remove(struct snd_soc_codec *codec)
+{
+       ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+       int source, unsigned int freq, int dir)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+
+       if (clk_id != SSM2518_SYSCLK)
+               return -EINVAL;
+
+       switch (source) {
+       case SSM2518_SYSCLK_SRC_MCLK:
+               val = 0;
+               break;
+       case SSM2518_SYSCLK_SRC_BCLK:
+               /* In this case the bitclock is used as the system clock, and
+                * the bitclock signal needs to be connected to the MCLK pin and
+                * the BCLK pin is left unconnected */
+               val = SSM2518_POWER1_NO_BCLK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (freq) {
+       case 0:
+               ssm2518->constraints = NULL;
+               break;
+       case 2048000:
+       case 4096000:
+       case 8192000:
+       case 3200000:
+       case 6400000:
+       case 12800000:
+               ssm2518->constraints = &ssm2518_constraints_2048000;
+               break;
+       case 2822000:
+       case 5644800:
+       case 11289600:
+       case 16934400:
+       case 22579200:
+       case 33868800:
+       case 4410000:
+       case 8820000:
+       case 17640000:
+               ssm2518->constraints = &ssm2518_constraints_2822000;
+               break;
+       case 3072000:
+       case 6144000:
+       case 38864000:
+       case 4800000:
+       case 9600000:
+       case 19200000:
+               ssm2518->constraints = &ssm2518_constraints_3072000;
+               break;
+       case 12288000:
+       case 16384000:
+       case 24576000:
+               ssm2518->constraints = &ssm2518_constraints_12288000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ssm2518->sysclk = freq;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_NO_BCLK, val);
+}
+
+static struct snd_soc_codec_driver ssm2518_codec_driver = {
+       .probe = ssm2518_probe,
+       .remove = ssm2518_remove,
+       .set_bias_level = ssm2518_set_bias_level,
+       .set_sysclk = ssm2518_set_sysclk,
+       .idle_bias_off = true,
+
+       .controls = ssm2518_snd_controls,
+       .num_controls = ARRAY_SIZE(ssm2518_snd_controls),
+       .dapm_widgets = ssm2518_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets),
+       .dapm_routes = ssm2518_routes,
+       .num_dapm_routes = ARRAY_SIZE(ssm2518_routes),
+};
+
+static bool ssm2518_register_volatile(struct device *dev, unsigned int reg)
+{
+       return false;
+}
+
+static const struct regmap_config ssm2518_regmap_config = {
+       .val_bits = 8,
+       .reg_bits = 8,
+
+       .max_register = SSM2518_REG_DRC_9,
+       .volatile_reg = ssm2518_register_volatile,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = ssm2518_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ssm2518_reg_defaults),
+};
+
+static int ssm2518_i2c_probe(struct i2c_client *i2c,
+       const struct i2c_device_id *id)
+{
+       struct ssm2518_platform_data *pdata = i2c->dev.platform_data;
+       struct ssm2518 *ssm2518;
+       int ret;
+
+       ssm2518 = devm_kzalloc(&i2c->dev, sizeof(*ssm2518), GFP_KERNEL);
+       if (ssm2518 == NULL)
+               return -ENOMEM;
+
+       if (pdata) {
+               ssm2518->enable_gpio = pdata->enable_gpio;
+       } else if (i2c->dev.of_node) {
+               ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0);
+               if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT)
+                       return ssm2518->enable_gpio;
+       } else {
+               ssm2518->enable_gpio = -1;
+       }
+
+       if (gpio_is_valid(ssm2518->enable_gpio)) {
+               ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio,
+                               GPIOF_OUT_INIT_HIGH, "SSM2518 nSD");
+               if (ret)
+                       return ret;
+       }
+
+       i2c_set_clientdata(i2c, ssm2518);
+
+       ssm2518->regmap = devm_regmap_init_i2c(i2c, &ssm2518_regmap_config);
+       if (IS_ERR(ssm2518->regmap))
+               return PTR_ERR(ssm2518->regmap);
+
+       /*
+        * The reset bit is obviously volatile, but we need to be able to cache
+        * the other bits in the register, so we can't just mark the whole
+        * register as volatile. Since this is the only place where we'll ever
+        * touch the reset bit just bypass the cache for this operation.
+        */
+       regcache_cache_bypass(ssm2518->regmap, true);
+       ret = regmap_write(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_RESET);
+       regcache_cache_bypass(ssm2518->regmap, false);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER2,
+                               SSM2518_POWER2_APWDN, 0x00);
+       if (ret)
+               return ret;
+
+       ret = ssm2518_set_power(ssm2518, false);
+       if (ret)
+               return ret;
+
+       return snd_soc_register_codec(&i2c->dev, &ssm2518_codec_driver,
+                       &ssm2518_dai, 1);
+}
+
+static int ssm2518_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id ssm2518_i2c_ids[] = {
+       { "ssm2518", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids);
+
+static struct i2c_driver ssm2518_driver = {
+       .driver = {
+               .name = "ssm2518",
+               .owner = THIS_MODULE,
+       },
+       .probe = ssm2518_i2c_probe,
+       .remove = ssm2518_i2c_remove,
+       .id_table = ssm2518_i2c_ids,
+};
+module_i2c_driver(ssm2518_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2518 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2518.h b/sound/soc/codecs/ssm2518.h
new file mode 100644 (file)
index 0000000..62511d8
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SND_SOC_CODECS_SSM2518_H__
+#define __SND_SOC_CODECS_SSM2518_H__
+
+#define SSM2518_SYSCLK 0
+
+enum ssm2518_sysclk_src {
+       SSM2518_SYSCLK_SRC_MCLK = 0,
+       SSM2518_SYSCLK_SRC_BCLK = 1,
+};
+
+#endif
index 370af0c..f5e8356 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 #include <linux/irqreturn.h>
 #include <linux/init.h>
 #include <linux/spi/spi.h>
@@ -972,6 +973,13 @@ static int wm0010_spi_probe(struct spi_device *spi)
        }
        wm0010->irq = irq;
 
+       ret = irq_set_irq_wake(irq, 1);
+       if (ret) {
+               dev_err(wm0010->dev, "Failed to set IRQ %d as wake source: %d\n",
+                       irq, ret);
+               return ret;
+       }
+
        if (spi->max_speed_hz)
                wm0010->board_max_spi_speed = spi->max_speed_hz;
        else
@@ -995,6 +1003,8 @@ static int wm0010_spi_remove(struct spi_device *spi)
        gpio_set_value_cansleep(wm0010->gpio_reset,
                                wm0010->gpio_reset_value);
 
+       irq_set_irq_wake(wm0010->irq, 0);
+
        if (wm0010->irq)
                free_irq(wm0010->irq, wm0010);
 
index 100fdad..282fd23 100644 (file)
@@ -814,7 +814,20 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
 
 SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
 SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
-SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]),
+SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
+
+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_SINGLE("EPOUT DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE3L_ENA_SHIFT, 1, 0),
+
+SOC_SINGLE("DRE Threshold", ARIZONA_DRE_CONTROL_2,
+          ARIZONA_DRE_T_LOW_SHIFT, 63, 0),
+
+SOC_SINGLE("DRE Low Level ABS", ARIZONA_DRE_CONTROL_3,
+          ARIZONA_DRE_LOW_LEVEL_ABS_SHIFT, 15, 0),
 
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -852,6 +865,15 @@ ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -898,6 +920,15 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
 
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
 ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
@@ -1117,6 +1148,56 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
 ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
 
 SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
@@ -1189,6 +1270,15 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
 ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
 ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
 
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
 ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
 ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
 ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
@@ -1249,6 +1339,14 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
        { name, "AIF2RX2", "AIF2RX2" }, \
        { name, "AIF3RX1", "AIF3RX1" }, \
        { name, "AIF3RX2", "AIF3RX2" }, \
+       { name, "SLIMRX1", "SLIMRX1" }, \
+       { name, "SLIMRX2", "SLIMRX2" }, \
+       { name, "SLIMRX3", "SLIMRX3" }, \
+       { name, "SLIMRX4", "SLIMRX4" }, \
+       { name, "SLIMRX5", "SLIMRX5" }, \
+       { name, "SLIMRX6", "SLIMRX6" }, \
+       { name, "SLIMRX7", "SLIMRX7" }, \
+       { name, "SLIMRX8", "SLIMRX8" }, \
        { name, "EQ1", "EQ1" }, \
        { name, "EQ2", "EQ2" }, \
        { name, "EQ3", "EQ3" }, \
@@ -1304,10 +1402,21 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "OUT5L", NULL, "SYSCLK" },
        { "OUT5R", NULL, "SYSCLK" },
 
+       { "IN1L", NULL, "SYSCLK" },
+       { "IN1R", NULL, "SYSCLK" },
+       { "IN2L", NULL, "SYSCLK" },
+       { "IN2R", NULL, "SYSCLK" },
+       { "IN3L", NULL, "SYSCLK" },
+       { "IN3R", NULL, "SYSCLK" },
+
        { "MICBIAS1", NULL, "MICVDD" },
        { "MICBIAS2", NULL, "MICVDD" },
        { "MICBIAS3", NULL, "MICVDD" },
 
+       { "Noise Generator", NULL, "SYSCLK" },
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
        { "Noise Generator", NULL, "NOISE" },
        { "Tone Generator 1", NULL, "TONE" },
        { "Tone Generator 2", NULL, "TONE" },
@@ -1345,13 +1454,41 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "AIF3RX1", NULL, "AIF3 Playback" },
        { "AIF3RX2", NULL, "AIF3 Playback" },
 
+       { "Slim1 Capture", NULL, "SLIMTX1" },
+       { "Slim1 Capture", NULL, "SLIMTX2" },
+       { "Slim1 Capture", NULL, "SLIMTX3" },
+       { "Slim1 Capture", NULL, "SLIMTX4" },
+
+       { "SLIMRX1", NULL, "Slim1 Playback" },
+       { "SLIMRX2", NULL, "Slim1 Playback" },
+       { "SLIMRX3", NULL, "Slim1 Playback" },
+       { "SLIMRX4", NULL, "Slim1 Playback" },
+
+       { "Slim2 Capture", NULL, "SLIMTX5" },
+       { "Slim2 Capture", NULL, "SLIMTX6" },
+
+       { "SLIMRX5", NULL, "Slim2 Playback" },
+       { "SLIMRX6", NULL, "Slim2 Playback" },
+
+       { "Slim3 Capture", NULL, "SLIMTX7" },
+       { "Slim3 Capture", NULL, "SLIMTX8" },
+
+       { "SLIMRX7", NULL, "Slim3 Playback" },
+       { "SLIMRX8", NULL, "Slim3 Playback" },
+
        { "AIF1 Playback", NULL, "SYSCLK" },
        { "AIF2 Playback", NULL, "SYSCLK" },
        { "AIF3 Playback", NULL, "SYSCLK" },
+       { "Slim1 Playback", NULL, "SYSCLK" },
+       { "Slim2 Playback", NULL, "SYSCLK" },
+       { "Slim3 Playback", NULL, "SYSCLK" },
 
        { "AIF1 Capture", NULL, "SYSCLK" },
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
+       { "Slim1 Capture", NULL, "SYSCLK" },
+       { "Slim2 Capture", NULL, "SYSCLK" },
+       { "Slim3 Capture", NULL, "SYSCLK" },
 
        { "IN1L PGA", NULL, "IN1L" },
        { "IN1R PGA", NULL, "IN1R" },
@@ -1408,6 +1545,15 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
        ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
 
+       ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+       ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+       ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+       ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+       ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+       ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+       ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+       ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
        ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
        ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
        ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
@@ -1560,6 +1706,63 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
        },
+       {
+               .name = "wm5102-slim1",
+               .id = 4,
+               .playback = {
+                       .stream_name = "Slim1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = WM5102_RATES,
+                       .formats = WM5102_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 4,
+                        .rates = WM5102_RATES,
+                        .formats = WM5102_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5102-slim2",
+               .id = 5,
+               .playback = {
+                       .stream_name = "Slim2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5102_RATES,
+                       .formats = WM5102_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5102_RATES,
+                        .formats = WM5102_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5102-slim3",
+               .id = 6,
+               .playback = {
+                       .stream_name = "Slim3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5102_RATES,
+                       .formats = WM5102_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim3 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5102_RATES,
+                        .formats = WM5102_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
 };
 
 static int wm5102_codec_probe(struct snd_soc_codec *codec)
index 88ad7db..2e7cb4b 100644 (file)
@@ -309,6 +309,15 @@ ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -360,6 +369,15 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
 
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
 ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
@@ -550,6 +568,56 @@ SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
                    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
 SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
                     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
@@ -640,6 +708,15 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
 ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
 ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
 
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
 ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
 ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
 ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
@@ -690,6 +767,14 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
        { name, "AIF2RX2", "AIF2RX2" }, \
        { name, "AIF3RX1", "AIF3RX1" }, \
        { name, "AIF3RX2", "AIF3RX2" }, \
+       { name, "SLIMRX1", "SLIMRX1" }, \
+       { name, "SLIMRX2", "SLIMRX2" }, \
+       { name, "SLIMRX3", "SLIMRX3" }, \
+       { name, "SLIMRX4", "SLIMRX4" }, \
+       { name, "SLIMRX5", "SLIMRX5" }, \
+       { name, "SLIMRX6", "SLIMRX6" }, \
+       { name, "SLIMRX7", "SLIMRX7" }, \
+       { name, "SLIMRX8", "SLIMRX8" }, \
        { name, "EQ1", "EQ1" }, \
        { name, "EQ2", "EQ2" }, \
        { name, "EQ3", "EQ3" }, \
@@ -736,10 +821,23 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "OUT6L", NULL, "SYSCLK" },
        { "OUT6R", NULL, "SYSCLK" },
 
+       { "IN1L", NULL, "SYSCLK" },
+       { "IN1R", NULL, "SYSCLK" },
+       { "IN2L", NULL, "SYSCLK" },
+       { "IN2R", NULL, "SYSCLK" },
+       { "IN3L", NULL, "SYSCLK" },
+       { "IN3R", NULL, "SYSCLK" },
+       { "IN4L", NULL, "SYSCLK" },
+       { "IN4R", NULL, "SYSCLK" },
+
        { "MICBIAS1", NULL, "MICVDD" },
        { "MICBIAS2", NULL, "MICVDD" },
        { "MICBIAS3", NULL, "MICVDD" },
 
+       { "Noise Generator", NULL, "SYSCLK" },
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
        { "Noise Generator", NULL, "NOISE" },
        { "Tone Generator 1", NULL, "TONE" },
        { "Tone Generator 2", NULL, "TONE" },
@@ -777,13 +875,41 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "AIF3RX1", NULL, "AIF3 Playback" },
        { "AIF3RX2", NULL, "AIF3 Playback" },
 
+       { "Slim1 Capture", NULL, "SLIMTX1" },
+       { "Slim1 Capture", NULL, "SLIMTX2" },
+       { "Slim1 Capture", NULL, "SLIMTX3" },
+       { "Slim1 Capture", NULL, "SLIMTX4" },
+
+       { "SLIMRX1", NULL, "Slim1 Playback" },
+       { "SLIMRX2", NULL, "Slim1 Playback" },
+       { "SLIMRX3", NULL, "Slim1 Playback" },
+       { "SLIMRX4", NULL, "Slim1 Playback" },
+
+       { "Slim2 Capture", NULL, "SLIMTX5" },
+       { "Slim2 Capture", NULL, "SLIMTX6" },
+
+       { "SLIMRX5", NULL, "Slim2 Playback" },
+       { "SLIMRX6", NULL, "Slim2 Playback" },
+
+       { "Slim3 Capture", NULL, "SLIMTX7" },
+       { "Slim3 Capture", NULL, "SLIMTX8" },
+
+       { "SLIMRX7", NULL, "Slim3 Playback" },
+       { "SLIMRX8", NULL, "Slim3 Playback" },
+
        { "AIF1 Playback", NULL, "SYSCLK" },
        { "AIF2 Playback", NULL, "SYSCLK" },
        { "AIF3 Playback", NULL, "SYSCLK" },
+       { "Slim1 Playback", NULL, "SYSCLK" },
+       { "Slim2 Playback", NULL, "SYSCLK" },
+       { "Slim3 Playback", NULL, "SYSCLK" },
 
        { "AIF1 Capture", NULL, "SYSCLK" },
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
+       { "Slim1 Capture", NULL, "SYSCLK" },
+       { "Slim2 Capture", NULL, "SYSCLK" },
+       { "Slim3 Capture", NULL, "SYSCLK" },
 
        { "IN1L PGA", NULL, "IN1L" },
        { "IN1R PGA", NULL, "IN1R" },
@@ -829,6 +955,15 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
        ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
 
+       ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+       ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+       ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+       ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+       ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+       ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+       ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+       ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
        ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
        ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
        ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
@@ -963,6 +1098,63 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
        },
+       {
+               .name = "wm5110-slim1",
+               .id = 4,
+               .playback = {
+                       .stream_name = "Slim1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 4,
+                        .rates = WM5110_RATES,
+                        .formats = WM5110_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5110-slim2",
+               .id = 5,
+               .playback = {
+                       .stream_name = "Slim2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5110_RATES,
+                        .formats = WM5110_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5110-slim3",
+               .id = 6,
+               .playback = {
+                       .stream_name = "Slim3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim3 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5110_RATES,
+                        .formats = WM5110_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
 };
 
 static int wm5110_codec_probe(struct snd_soc_codec *codec)
index e971028..b1dc7d4 100644 (file)
@@ -51,6 +51,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8962_priv {
+       struct wm8962_pdata pdata;
        struct regmap *regmap;
        struct snd_soc_codec *codec;
 
@@ -1600,7 +1601,6 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       u16 *reg_cache = codec->reg_cache;
        int ret;
 
        /* Apply the update (if any) */
@@ -1609,16 +1609,19 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                return 0;
 
        /* If the left PGA is enabled hit that VU bit... */
-       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTL_PGA_ENA)
-               return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
-                                    reg_cache[WM8962_HPOUTL_VOLUME]);
+       ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+       if (ret & WM8962_HPOUTL_PGA_ENA) {
+               snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+                             snd_soc_read(codec, WM8962_HPOUTL_VOLUME));
+               return 1;
+       }
 
        /* ...otherwise the right.  The VU is stereo. */
-       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTR_PGA_ENA)
-               return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
-                                    reg_cache[WM8962_HPOUTR_VOLUME]);
+       if (ret & WM8962_HPOUTR_PGA_ENA)
+               snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+                             snd_soc_read(codec, WM8962_HPOUTR_VOLUME));
 
-       return 0;
+       return 1;
 }
 
 /* The VU bits for the speakers are in a different register to the mute
@@ -2345,12 +2348,13 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
 
 static int wm8962_add_widgets(struct snd_soc_codec *codec)
 {
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        snd_soc_add_codec_controls(codec, wm8962_snd_controls,
                             ARRAY_SIZE(wm8962_snd_controls));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls,
                                     ARRAY_SIZE(wm8962_spk_mono_controls));
        else
@@ -2360,7 +2364,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_new_controls(dapm, wm8962_dapm_widgets,
                                  ARRAY_SIZE(wm8962_dapm_widgets));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_mono_widgets,
                                          ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
        else
@@ -2369,7 +2373,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(dapm, wm8962_intercon,
                                ARRAY_SIZE(wm8962_intercon));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_dapm_add_routes(dapm, wm8962_spk_mono_intercon,
                                        ARRAY_SIZE(wm8962_spk_mono_intercon));
        else
@@ -3333,14 +3337,14 @@ static struct gpio_chip wm8962_template_chip = {
 static void wm8962_init_gpio(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        int ret;
 
        wm8962->gpio_chip = wm8962_template_chip;
        wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
        wm8962->gpio_chip.dev = codec->dev;
 
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                wm8962->gpio_chip.base = pdata->gpio_base;
        else
                wm8962->gpio_chip.base = -1;
@@ -3374,7 +3378,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        int ret;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
-       u16 *reg_cache = codec->reg_cache;
        int i, trigger, irq_pol;
        bool dmicclk, dmicdat;
 
@@ -3421,30 +3424,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                            WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
                            0);
 
-       if (pdata) {
-               /* Apply static configuration for GPIOs */
-               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
-                       if (pdata->gpio_init[i]) {
-                               wm8962_set_gpio_mode(codec, i + 1);
-                               snd_soc_write(codec, 0x200 + i,
-                                             pdata->gpio_init[i] & 0xffff);
-                       }
+       /* Apply static configuration for GPIOs */
+       for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+               if (pdata->gpio_init[i]) {
+                       wm8962_set_gpio_mode(codec, i + 1);
+                       snd_soc_write(codec, 0x200 + i,
+                                       pdata->gpio_init[i] & 0xffff);
+               }
 
-               /* Put the speakers into mono mode? */
-               if (pdata->spk_mono)
-                       reg_cache[WM8962_CLASS_D_CONTROL_2]
-                               |= WM8962_SPK_MONO;
 
-               /* Micbias setup, detection enable and detection
-                * threasholds. */
-               if (pdata->mic_cfg)
-                       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
-                                           WM8962_MICDET_ENA |
-                                           WM8962_MICDET_THR_MASK |
-                                           WM8962_MICSHORT_THR_MASK |
-                                           WM8962_MICBIAS_LVL,
-                                           pdata->mic_cfg);
-       }
+       /* Put the speakers into mono mode? */
+       if (pdata->spk_mono)
+               snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2,
+                               WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
+
+       /* Micbias setup, detection enable and detection
+        * threasholds. */
+       if (pdata->mic_cfg)
+               snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                                   WM8962_MICDET_ENA |
+                                   WM8962_MICDET_THR_MASK |
+                                   WM8962_MICSHORT_THR_MASK |
+                                   WM8962_MICBIAS_LVL,
+                                   pdata->mic_cfg);
 
        /* Latch volume update bits */
        snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME,
@@ -3506,7 +3508,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        wm8962_init_gpio(codec);
 
        if (wm8962->irq) {
-               if (pdata && pdata->irq_active_low) {
+               if (pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8962_IRQ_POL;
                } else {
@@ -3584,6 +3586,34 @@ static const struct regmap_config wm8962_regmap = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
+                                   struct wm8962_pdata *pdata)
+{
+       const struct device_node *np = i2c->dev.of_node;
+       u32 val32;
+       int i;
+
+       if (of_property_read_bool(np, "spk-mono"))
+               pdata->spk_mono = true;
+
+       if (of_property_read_u32(np, "mic-cfg", &val32) >= 0)
+               pdata->mic_cfg = val32;
+
+       if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_init,
+                                      ARRAY_SIZE(pdata->gpio_init)) >= 0)
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) {
+                       /*
+                        * The range of GPIO register value is [0x0, 0xffff]
+                        * While the default value of each register is 0x0
+                        * Any other value will be regarded as default value
+                        */
+                       if (pdata->gpio_init[i] > 0xffff)
+                               pdata->gpio_init[i] = 0x0;
+               }
+
+       return 0;
+}
+
 static int wm8962_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -3603,6 +3633,15 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
        init_completion(&wm8962->fll_lock);
        wm8962->irq = i2c->irq;
 
+       /* If platform data was supplied, update the default data in priv */
+       if (pdata) {
+               memcpy(&wm8962->pdata, pdata, sizeof(struct wm8962_pdata));
+       } else if (i2c->dev.of_node) {
+               ret = wm8962_set_pdata_from_of(i2c, &wm8962->pdata);
+               if (ret != 0)
+                       return ret;
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
                wm8962->supplies[i].supply = wm8962_supply_names[i];
 
@@ -3666,7 +3705,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
                goto err_enable;
        }
 
-       if (pdata && pdata->in4_dc_measure) {
+       if (wm8962->pdata.in4_dc_measure) {
                ret = regmap_register_patch(wm8962->regmap,
                                            wm8962_dc_measure,
                                            ARRAY_SIZE(wm8962_dc_measure));
@@ -3719,8 +3758,34 @@ static int wm8962_runtime_resume(struct device *dev)
 
        wm8962_reset(wm8962);
 
+       /* SYSCLK defaults to on; make sure it is off so we can safely
+        * write to registers if the device is declocked.
+        */
+       regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+                          WM8962_SYSCLK_ENA, 0);
+
+       /* Ensure we have soft control over all registers */
+       regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+                          WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
+       /* Ensure that the oscillator and PLLs are disabled */
+       regmap_update_bits(wm8962->regmap, WM8962_PLL2,
+                          WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+                          0);
+
        regcache_sync(wm8962->regmap);
 
+       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
+
+       /* Bias enable at 2*5k (fast start-up) */
+       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+                          WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK,
+                          WM8962_BIAS_ENA | 0x180);
+
+       msleep(5);
+
        return 0;
 }
 
index 9e13edd..1d4b1ec 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/gcd.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -1494,6 +1495,24 @@ static const char *aif1dac_text[] = {
        "AIF1DACDAT", "AIF3DACDAT",
 };
 
+static const char *loopback_text[] = {
+       "None", "ADCDAT",
+};
+
+static const struct soc_enum aif1_loopback_enum =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2,
+                       loopback_text);
+
+static const struct snd_kcontrol_new aif1_loopback =
+       SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);
+
+static const struct soc_enum aif2_loopback_enum =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2,
+                       loopback_text);
+
+static const struct snd_kcontrol_new aif2_loopback =
+       SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);
+
 static const struct soc_enum aif1dac_enum =
        SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
 
@@ -1740,6 +1759,9 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
 
+SND_SOC_DAPM_MUX("AIF1 Loopback", SND_SOC_NOPM, 0, 0, &aif1_loopback),
+SND_SOC_DAPM_MUX("AIF2 Loopback", SND_SOC_NOPM, 0, 0, &aif2_loopback),
+
 SND_SOC_DAPM_POST("Debug log", post_ev),
 };
 
@@ -1871,9 +1893,9 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF1DAC2L", NULL, "AIF1DAC Mux" },
        { "AIF1DAC2R", NULL, "AIF1DAC Mux" },
 
-       { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" },
+       { "AIF1DAC Mux", "AIF1DACDAT", "AIF1 Loopback" },
        { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
-       { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" },
+       { "AIF2DAC Mux", "AIF2DACDAT", "AIF2 Loopback" },
        { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
        { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
        { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
@@ -1924,6 +1946,12 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" },
        { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" },
 
+       /* Loopback */
+       { "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" },
+       { "AIF1 Loopback", "None", "AIF1DACDAT" },
+       { "AIF2 Loopback", "ADCDAT", "AIF2ADCDAT" },
+       { "AIF2 Loopback", "None", "AIF2DACDAT" },
+
        /* Sidetone */
        { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" },
        { "Left Sidetone", "DMIC2", "DMIC2L" },
@@ -2006,15 +2034,16 @@ struct fll_div {
        u16 outdiv;
        u16 n;
        u16 k;
+       u16 lambda;
        u16 clk_ref_div;
        u16 fll_fratio;
 };
 
-static int wm8994_get_fll_config(struct fll_div *fll,
+static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
                                 int freq_in, int freq_out)
 {
        u64 Kpart;
-       unsigned int K, Ndiv, Nmod;
+       unsigned int K, Ndiv, Nmod, gcd_fll;
 
        pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
 
@@ -2063,20 +2092,32 @@ static int wm8994_get_fll_config(struct fll_div *fll,
        Nmod = freq_out % freq_in;
        pr_debug("Nmod=%d\n", Nmod);
 
-       /* Calculate fractional part - scale up so we can round. */
-       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+       switch (control->type) {
+       case WM8994:
+               /* Calculate fractional part - scale up so we can round. */
+               Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+               do_div(Kpart, freq_in);
+
+               K = Kpart & 0xFFFFFFFF;
 
-       do_div(Kpart, freq_in);
+               if ((K % 10) >= 5)
+                       K += 5;
 
-       K = Kpart & 0xFFFFFFFF;
+               /* Move down to proper range now rounding is done */
+               fll->k = K / 10;
+               fll->lambda = 0;
 
-       if ((K % 10) >= 5)
-               K += 5;
+               pr_debug("N=%x K=%x\n", fll->n, fll->k);
+               break;
 
-       /* Move down to proper range now rounding is done */
-       fll->k = K / 10;
+       default:
+               gcd_fll = gcd(freq_out, freq_in);
 
-       pr_debug("N=%x K=%x\n", fll->n, fll->k);
+               fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll;
+               fll->lambda = freq_in / gcd_fll;
+               
+       }
 
        return 0;
 }
@@ -2140,9 +2181,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
         * analysis bugs spewing warnings.
         */
        if (freq_out)
-               ret = wm8994_get_fll_config(&fll, freq_in, freq_out);
+               ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out);
        else
-               ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in,
+               ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in,
                                            wm8994->fll[id].out);
        if (ret < 0)
                return ret;
@@ -2187,6 +2228,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                            WM8994_FLL1_N_MASK,
                            fll.n << WM8994_FLL1_N_SHIFT);
 
+       if (fll.lambda) {
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset,
+                                   WM8958_FLL1_LAMBDA_MASK,
+                                   fll.lambda);
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+                                   WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA);
+       } else {
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+                                   WM8958_FLL1_EFS_ENA, 0);
+       }
+
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
                            WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
@@ -2551,17 +2603,24 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct wm8994 *control = wm8994->wm8994;
        int ms_reg;
        int aif1_reg;
+       int dac_reg;
+       int adc_reg;
        int ms = 0;
        int aif1 = 0;
+       int lrclk = 0;
 
        switch (dai->id) {
        case 1:
                ms_reg = WM8994_AIF1_MASTER_SLAVE;
                aif1_reg = WM8994_AIF1_CONTROL_1;
+               dac_reg = WM8994_AIF1DAC_LRCLK;
+               adc_reg = WM8994_AIF1ADC_LRCLK;
                break;
        case 2:
                ms_reg = WM8994_AIF2_MASTER_SLAVE;
                aif1_reg = WM8994_AIF2_CONTROL_1;
+               dac_reg = WM8994_AIF1DAC_LRCLK;
+               adc_reg = WM8994_AIF1ADC_LRCLK;
                break;
        default:
                return -EINVAL;
@@ -2580,6 +2639,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif1 |= WM8994_AIF1_LRCLK_INV;
+               lrclk |= WM8958_AIF1_LRCLK_INV;
        case SND_SOC_DAIFMT_DSP_A:
                aif1 |= 0x18;
                break;
@@ -2618,12 +2678,14 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                        break;
                case SND_SOC_DAIFMT_IB_IF:
                        aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
+                       lrclk |= WM8958_AIF1_LRCLK_INV;
                        break;
                case SND_SOC_DAIFMT_IB_NF:
                        aif1 |= WM8994_AIF1_BCLK_INV;
                        break;
                case SND_SOC_DAIFMT_NB_IF:
                        aif1 |= WM8994_AIF1_LRCLK_INV;
+                       lrclk |= WM8958_AIF1_LRCLK_INV;
                        break;
                default:
                        return -EINVAL;
@@ -2654,6 +2716,10 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                            aif1);
        snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR,
                            ms);
+       snd_soc_update_bits(codec, dac_reg,
+                           WM8958_AIF1_LRCLK_INV, lrclk);
+       snd_soc_update_bits(codec, adc_reg,
+                           WM8958_AIF1_LRCLK_INV, lrclk);
 
        return 0;
 }
@@ -3092,24 +3158,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
 static int wm8994_codec_resume(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = wm8994->wm8994;
        int i, ret;
-       unsigned int val, mask;
-
-       if (control->revision < 4) {
-               /* force a HW read */
-               ret = regmap_read(control->regmap,
-                                 WM8994_POWER_MANAGEMENT_5, &val);
-
-               /* modify the cache only */
-               codec->cache_only = 1;
-               mask =  WM8994_DAC1R_ENA | WM8994_DAC1L_ENA |
-                       WM8994_DAC2R_ENA | WM8994_DAC2L_ENA;
-               val &= mask;
-               snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
-                                   mask, val);
-               codec->cache_only = 0;
-       }
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                if (!wm8994->fll_suspend[i].out)
@@ -3491,6 +3540,31 @@ static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
                            wm8994->btn_mask);
 }
 
+static void wm8958_open_circuit_work(struct work_struct *work)
+{
+       struct wm8994_priv *wm8994 = container_of(work,
+                                                 struct wm8994_priv,
+                                                 open_circuit_work.work);
+       struct device *dev = wm8994->wm8994->dev;
+
+       wm1811_micd_stop(wm8994->hubs.codec);
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       dev_dbg(dev, "Reporting open circuit\n");
+
+       wm8994->jack_mic = false;
+       wm8994->mic_detecting = true;
+
+       wm8958_micd_set_rate(wm8994->hubs.codec);
+
+       snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+                           wm8994->btn_mask |
+                           SND_JACK_HEADSET);
+
+       mutex_unlock(&wm8994->accdet_lock);
+}
+
 static void wm8958_mic_id(void *data, u16 status)
 {
        struct snd_soc_codec *codec = data;
@@ -3500,16 +3574,9 @@ static void wm8958_mic_id(void *data, u16 status)
        if (!(status & WM8958_MICD_STS)) {
                /* If nothing present then clear our statuses */
                dev_dbg(codec->dev, "Detected open circuit\n");
-               wm8994->jack_mic = false;
-               wm8994->mic_detecting = true;
-
-               wm1811_micd_stop(codec);
-
-               wm8958_micd_set_rate(codec);
 
-               snd_soc_jack_report(wm8994->micdet[0].jack, 0,
-                                   wm8994->btn_mask |
-                                   SND_JACK_HEADSET);
+               schedule_delayed_work(&wm8994->open_circuit_work,
+                                     msecs_to_jiffies(2500));
                return;
        }
 
@@ -3594,6 +3661,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 
        pm_runtime_get_sync(codec->dev);
 
+       cancel_delayed_work_sync(&wm8994->mic_complete_work);
+
        mutex_lock(&wm8994->accdet_lock);
 
        reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
@@ -3776,11 +3845,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 }
 EXPORT_SYMBOL_GPL(wm8958_mic_detect);
 
+static void wm8958_mic_work(struct work_struct *work)
+{
+       struct wm8994_priv *wm8994 = container_of(work,
+                                                 struct wm8994_priv,
+                                                 mic_complete_work.work);
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
+
+       dev_crit(codec->dev, "MIC WORK %x\n", wm8994->mic_status);
+
+       pm_runtime_get_sync(codec->dev);
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status);
+
+       mutex_unlock(&wm8994->accdet_lock);
+
+       pm_runtime_put(codec->dev);
+
+       dev_crit(codec->dev, "MIC WORK %x DONE\n", wm8994->mic_status);
+}
+
 static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
        struct snd_soc_codec *codec = wm8994->hubs.codec;
-       int reg, count, ret;
+       int reg, count, ret, id_delay;
 
        /*
         * Jack detection may have detected a removal simulataneously
@@ -3790,6 +3881,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
                return IRQ_HANDLED;
 
+       cancel_delayed_work_sync(&wm8994->mic_complete_work);
+       cancel_delayed_work_sync(&wm8994->open_circuit_work);
+
        pm_runtime_get_sync(codec->dev);
 
        /* We may occasionally read a detection without an impedence
@@ -3842,8 +3936,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                goto out;
        }
 
+       wm8994->mic_status = reg;
+       id_delay = wm8994->wm8994->pdata.mic_id_delay;
+
        if (wm8994->mic_detecting)
-               wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg);
+               schedule_delayed_work(&wm8994->mic_complete_work,
+                                     msecs_to_jiffies(id_delay));
        else
                wm8958_button_det(codec, reg);
 
@@ -3895,6 +3993,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        mutex_init(&wm8994->accdet_lock);
        INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
                          wm1811_jackdet_bootstrap);
+       INIT_DELAYED_WORK(&wm8994->open_circuit_work,
+                         wm8958_open_circuit_work);
 
        switch (control->type) {
        case WM8994:
@@ -3907,6 +4007,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
+       INIT_DELAYED_WORK(&wm8994->mic_complete_work, wm8958_mic_work);
+
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
 
index 55ddf4d..6536f8d 100644 (file)
@@ -134,6 +134,9 @@ struct wm8994_priv {
        struct mutex accdet_lock;
        struct wm8994_micdet micdet[2];
        struct delayed_work mic_work;
+       struct delayed_work open_circuit_work;
+       struct delayed_work mic_complete_work;
+       u16 mic_status;
        bool mic_detecting;
        bool jack_mic;
        int btn_mask;
index ddba3fe..05252ac 100644 (file)
@@ -310,7 +310,7 @@ static const struct soc_enum wm_adsp2_rate_enum[] = {
                              ARIZONA_DSP1_RATE_SHIFT, 0xf,
                              ARIZONA_RATE_ENUM_SIZE,
                              arizona_rate_text, arizona_rate_val),
-       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
                              ARIZONA_DSP1_RATE_SHIFT, 0xf,
                              ARIZONA_RATE_ENUM_SIZE,
                              arizona_rate_text, arizona_rate_val),
index 9e11a14..c82f89c 100644 (file)
@@ -54,16 +54,6 @@ config  SND_DM6467_SOC_EVM
        help
          Say Y if you want to add support for SoC audio on TI
 
-config SND_DAVINCI_SOC_SFFSDR
-       tristate "SoC Audio support for SFFSDR"
-       depends on SND_DAVINCI_SOC && MACH_SFFSDR
-       select SND_DAVINCI_SOC_I2S
-       select SND_SOC_PCM3008
-       select SFFSDR_FPGA
-       help
-         Say Y if you want to add support for SoC audio on
-         Lyrtech SFFSDR board.
-
 config  SND_DA830_SOC_EVM
        tristate "SoC Audio support for DA830/OMAP-L137 EVM"
        depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
index a93679d..a396ab6 100644 (file)
@@ -11,10 +11,8 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
 
 # DAVINCI Machine Support
 snd-soc-evm-objs := davinci-evm.o
-snd-soc-sffsdr-objs := davinci-sffsdr.o
 
 obj-$(CONFIG_SND_DAVINCI_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_SFFSDR) += snd-soc-sffsdr.o
index 81490fe..32ddb7f 100644 (file)
@@ -1024,7 +1024,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
        struct device_node *np = pdev->dev.of_node;
        struct snd_platform_data *pdata = NULL;
        const struct of_device_id *match =
-                       of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev);
+                       of_match_device(mcasp_dt_ids, &pdev->dev);
 
        const u32 *of_serial_dir32;
        u8 *of_serial_dir;
@@ -1257,7 +1257,7 @@ static struct platform_driver davinci_mcasp_driver = {
        .driver         = {
                .name   = "davinci-mcasp",
                .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(mcasp_dt_ids),
+               .of_match_table = mcasp_dt_ids,
        },
 };
 
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
deleted file mode 100644 (file)
index 5be65aa..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ASoC driver for Lyrtech SFFSDR board.
- *
- * Author:     Hugo Villeneuve
- * Copyright (C) 2008 Lyrtech inc
- *
- * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow:
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <asm/mach-types.h>
-#ifdef CONFIG_SFFSDR_FPGA
-#include <asm/plat-sffsdr/sffsdr-fpga.h>
-#endif
-
-#include <mach/edma.h>
-
-#include "../codecs/pcm3008.h"
-#include "davinci-pcm.h"
-#include "davinci-i2s.h"
-
-/*
- * CLKX and CLKR are the inputs for the Sample Rate Generator.
- * FSX and FSR are outputs, driven by the sample Rate Generator.
- */
-#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B |   \
-                     SND_SOC_DAIFMT_CBM_CFS |  \
-                     SND_SOC_DAIFMT_IB_NF)
-
-static int sffsdr_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;
-       int fs;
-       int ret = 0;
-
-       /* Fsref can be 32000, 44100 or 48000. */
-       fs = params_rate(params);
-
-#ifndef CONFIG_SFFSDR_FPGA
-       /* Without the FPGA module, the Fs is fixed at 44100 Hz */
-       if (fs != 44100) {
-               pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n");
-               return -EINVAL;
-       }
-#endif
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
-       if (ret < 0)
-               return ret;
-
-       pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs);
-
-#ifndef CONFIG_SFFSDR_FPGA
-       return 0;
-#else
-       return sffsdr_fpga_set_codec_fs(fs);
-#endif
-}
-
-static struct snd_soc_ops sffsdr_ops = {
-       .hw_params = sffsdr_hw_params,
-};
-
-/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sffsdr_dai = {
-       .name = "PCM3008", /* Codec name */
-       .stream_name = "PCM3008 HiFi",
-       .cpu_dai_name = "davinci-mcbsp",
-       .codec_dai_name = "pcm3008-hifi",
-       .codec_name = "pcm3008-codec",
-       .platform_name = "davinci-mcbsp",
-       .ops = &sffsdr_ops,
-};
-
-/* davinci-sffsdr audio machine driver */
-static struct snd_soc_card snd_soc_sffsdr = {
-       .name = "DaVinci SFFSDR",
-       .owner = THIS_MODULE,
-       .dai_link = &sffsdr_dai,
-       .num_links = 1,
-};
-
-/* sffsdr audio private data */
-static struct pcm3008_setup_data sffsdr_pcm3008_setup = {
-       .dem0_pin = GPIO(45),
-       .dem1_pin = GPIO(46),
-       .pdad_pin = GPIO(47),
-       .pdda_pin = GPIO(38),
-};
-
-struct platform_device pcm3008_codec = {
-               .name = "pcm3008-codec",
-               .id = 0,
-               .dev = {
-                               .platform_data = &sffsdr_pcm3008_setup,
-               },
-};
-
-static struct resource sffsdr_snd_resources[] = {
-       {
-               .start = DAVINCI_MCBSP_BASE,
-               .end = DAVINCI_MCBSP_BASE + SZ_8K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-};
-
-static struct evm_snd_platform_data sffsdr_snd_data = {
-       .tx_dma_ch      = DAVINCI_DMA_MCBSP_TX,
-       .rx_dma_ch      = DAVINCI_DMA_MCBSP_RX,
-};
-
-static struct platform_device *sffsdr_snd_device;
-
-static int __init sffsdr_init(void)
-{
-       int ret;
-
-       if (!machine_is_sffsdr())
-               return -EINVAL;
-
-       platform_device_register(&pcm3008_codec);
-
-       sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
-       if (!sffsdr_snd_device) {
-               printk(KERN_ERR "platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
-       platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
-                                sizeof(sffsdr_snd_data));
-
-       ret = platform_device_add_resources(sffsdr_snd_device,
-                                           sffsdr_snd_resources,
-                                           ARRAY_SIZE(sffsdr_snd_resources));
-       if (ret) {
-               printk(KERN_ERR "platform device add resources failed\n");
-               goto error;
-       }
-
-       ret = platform_device_add(sffsdr_snd_device);
-       if (ret)
-               goto error;
-
-       return ret;
-
-error:
-       platform_device_put(sffsdr_snd_device);
-       return ret;
-}
-
-static void __exit sffsdr_exit(void)
-{
-       platform_device_unregister(sffsdr_snd_device);
-       platform_device_unregister(&pcm3008_codec);
-}
-
-module_init(sffsdr_init);
-module_exit(sffsdr_exit);
-
-MODULE_AUTHOR("Hugo Villeneuve");
-MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver");
-MODULE_LICENSE("GPL");
index 593a3ea..70eb37a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC Synopsys I2S Audio Layer
  *
- * sound/soc/spear/designware_i2s.c
+ * sound/soc/dwc/designware_i2s.c
  *
  * Copyright (C) 2010 ST Microelectronics
  * Rajeev Kumar <rajeev-dlh.kumar@st.com>
@@ -396,7 +396,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        if (cap & DWC_I2S_PLAY) {
-               dev_dbg(&pdev->dev, " SPEAr: play supported\n");
+               dev_dbg(&pdev->dev, " designware: play supported\n");
                dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
                dw_i2s_dai->playback.channels_max = pdata->channel;
                dw_i2s_dai->playback.formats = pdata->snd_fmts;
@@ -404,7 +404,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        if (cap & DWC_I2S_RECORD) {
-               dev_dbg(&pdev->dev, "SPEAr: record supported\n");
+               dev_dbg(&pdev->dev, "designware: record supported\n");
                dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
                dw_i2s_dai->capture.channels_max = pdata->channel;
                dw_i2s_dai->capture.formats = pdata->snd_fmts;
index 3843a18..aa43854 100644 (file)
@@ -108,18 +108,13 @@ if SND_IMX_SOC
 config SND_SOC_IMX_SSI
        tristate
 
-config SND_SOC_IMX_PCM
-       tristate
-
 config SND_SOC_IMX_PCM_FIQ
        bool
        select FIQ
-       select SND_SOC_IMX_PCM
 
 config SND_SOC_IMX_PCM_DMA
        bool
        select SND_SOC_GENERIC_DMAENGINE_PCM
-       select SND_SOC_IMX_PCM
 
 config SND_SOC_IMX_AUDMUX
        tristate
@@ -173,6 +168,18 @@ config SND_SOC_EUKREA_TLV320
          Enable I2S based access to the TLV320AIC23B codec attached
          to the SSI interface
 
+config SND_SOC_IMX_WM8962
+       tristate "SoC Audio support for i.MX boards with wm8962"
+       depends on OF && I2C
+       select SND_SOC_WM8962
+       select SND_SOC_IMX_PCM_DMA
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_FSL_SSI
+       select SND_SOC_FSL_UTILS
+       help
+         Say Y if you want to add support for SoC audio on an i.MX board with
+         a wm8962 codec.
+
 config SND_SOC_IMX_SGTL5000
        tristate "SoC Audio support for i.MX boards with sgtl5000"
        depends on OF && I2C
index afd3479..d4b4aa8 100644 (file)
@@ -30,18 +30,11 @@ obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 # i.MX Platform Support
 snd-soc-imx-ssi-objs := imx-ssi.o
 snd-soc-imx-audmux-objs := imx-audmux.o
-snd-soc-imx-pcm-objs := imx-pcm.o
-ifneq ($(CONFIG_SND_SOC_IMX_PCM_FIQ),)
-       snd-soc-imx-pcm-objs += imx-pcm-fiq.o
-endif
-ifneq ($(CONFIG_SND_SOC_IMX_PCM_DMA),)
-       snd-soc-imx-pcm-objs += imx-pcm-dma.o
-endif
-
 obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
 
-obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
+obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
@@ -49,6 +42,7 @@ snd-soc-phycore-ac97-objs := phycore-ac97.o
 snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
 snd-soc-wm1133-ev1-objs := wm1133-ev1.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
+snd-soc-imx-wm8962-objs := imx-wm8962.o
 snd-soc-imx-mc13783-objs := imx-mc13783.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
@@ -56,4 +50,5 @@ obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
 obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
 obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
+obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
 obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
index 75ffdf0..9a4a0ca 100644 (file)
@@ -80,7 +80,7 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
        .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name  = "imx-fiq-pcm-audio.0",
+       .platform_name  = "imx-ssi.0",
        .codec_name     = "tlv320aic23-codec.0-001a",
        .cpu_dai_name   = "imx-ssi.0",
        .ops            = &eukrea_tlv320_snd_ops,
index 0f0bed6..2f2d837 100644 (file)
@@ -122,7 +122,6 @@ struct fsl_ssi_private {
        bool new_binding;
        bool ssi_on_imx;
        struct clk *clk;
-       struct platform_device *imx_pcm_pdev;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct imx_dma_data filter_data_tx;
@@ -809,13 +808,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
        if (ssi_private->ssi_on_imx) {
-               ssi_private->imx_pcm_pdev =
-                       platform_device_register_simple("imx-pcm-audio",
-                                                       -1, NULL, 0);
-               if (IS_ERR(ssi_private->imx_pcm_pdev)) {
-                       ret = PTR_ERR(ssi_private->imx_pcm_pdev);
+               ret = imx_pcm_dma_init(pdev);
+               if (ret)
                        goto error_dev;
-               }
        }
 
        /*
@@ -854,7 +849,7 @@ done:
 
 error_dai:
        if (ssi_private->ssi_on_imx)
-               platform_device_unregister(ssi_private->imx_pcm_pdev);
+               imx_pcm_dma_exit(pdev);
        snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
@@ -889,7 +884,7 @@ 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) {
-               platform_device_unregister(ssi_private->imx_pcm_pdev);
+               imx_pcm_dma_exit(pdev);
                clk_disable_unprepare(ssi_private->clk);
                clk_put(ssi_private->clk);
        }
index 47f046a..e260f1f 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/pinctrl/consumer.h>
 
 #include "imx-audmux.h"
 
@@ -247,7 +246,6 @@ EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
 static int imx_audmux_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       struct pinctrl *pinctrl;
        const struct of_device_id *of_id =
                        of_match_device(imx_audmux_dt_ids, &pdev->dev);
 
@@ -256,12 +254,6 @@ static int imx_audmux_probe(struct platform_device *pdev)
        if (IS_ERR(audmux_base))
                return PTR_ERR(audmux_base);
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(&pdev->dev, "setup pinctrl failed!");
-               return PTR_ERR(pinctrl);
-       }
-
        audmux_clk = devm_clk_get(&pdev->dev, "audmux");
        if (IS_ERR(audmux_clk)) {
                dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
index 4ae30f2..9df173c 100644 (file)
@@ -64,7 +64,7 @@ static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
                .codec_dai_name  = "mc13783-hifi",
                .codec_name      = "mc13783-codec",
                .cpu_dai_name    = "imx-ssi.0",
-               .platform_name   = "imx-pcm-audio.0",
+               .platform_name   = "imx-ssi.0",
                .ops             = &imx_mc13783_hifi_ops,
                .symmetric_rates = 1,
                .dai_fmt         = FMT_SSI,
index c246fb5..fde4d2e 100644 (file)
@@ -67,8 +67,10 @@ int imx_pcm_dma_init(struct platform_device *pdev)
                SND_DMAENGINE_PCM_FLAG_NO_DT |
                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);
index 670b96b..310d902 100644 (file)
@@ -225,6 +225,22 @@ static int snd_imx_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
+               struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
+               runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+
+       pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+                       runtime->dma_area,
+                       runtime->dma_addr,
+                       runtime->dma_bytes);
+       return ret;
+}
+
 static struct snd_pcm_ops imx_pcm_ops = {
        .open           = snd_imx_open,
        .close          = snd_imx_close,
@@ -236,6 +252,54 @@ static struct snd_pcm_ops imx_pcm_ops = {
        .mmap           = snd_imx_pcm_mmap,
 };
 
+static int imx_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 = IMX_SSI_DMABUF_SIZE;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+                                          &buf->addr, GFP_KERNEL);
+       if (!buf->area)
+               return -ENOMEM;
+       buf->bytes = size;
+
+       return 0;
+}
+
+static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret = 0;
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &imx_pcm_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+               ret = imx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               ret = imx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       return ret;
+}
+
 static int ssi_irq = 0;
 
 static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
@@ -268,6 +332,27 @@ static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static void imx_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+
+               dma_free_writecombine(pcm->card->dev, buf->bytes,
+                                     buf->area, buf->addr);
+               buf->area = NULL;
+       }
+}
+
 static void imx_pcm_fiq_free(struct snd_pcm *pcm)
 {
        mxc_set_irq_fiq(ssi_irq, 0);
@@ -314,3 +399,10 @@ failed_register:
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(imx_pcm_fiq_init);
+
+void imx_pcm_fiq_exit(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+}
+EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
deleted file mode 100644 (file)
index c498964..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This code is based on code copyrighted by Freescale,
- * Liam Girdwood, Javier Martin and probably others.
- *
- * 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/dma-mapping.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "imx-pcm.h"
-
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
-               struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int ret;
-
-       ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
-               runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
-
-       pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
-                       runtime->dma_area,
-                       runtime->dma_addr,
-                       runtime->dma_bytes);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
-
-static int imx_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 = IMX_SSI_DMABUF_SIZE;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-       buf->bytes = size;
-
-       return 0;
-}
-
-static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
-
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &imx_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = imx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = imx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
-
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(imx_pcm_new);
-
-void imx_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-EXPORT_SYMBOL_GPL(imx_pcm_free);
-
-static int imx_pcm_probe(struct platform_device *pdev)
-{
-       if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
-               return imx_pcm_fiq_init(pdev);
-
-       return imx_pcm_dma_init(pdev);
-}
-
-static int imx_pcm_remove(struct platform_device *pdev)
-{
-       if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
-               snd_soc_unregister_platform(&pdev->dev);
-       else
-               imx_pcm_dma_exit(pdev);
-
-       return 0;
-}
-
-static struct platform_device_id imx_pcm_devtype[] = {
-       { .name = "imx-pcm-audio", },
-       { .name = "imx-fiq-pcm-audio", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_pcm_devtype);
-
-static struct platform_driver imx_pcm_driver = {
-       .driver = {
-                       .name = "imx-pcm",
-                       .owner = THIS_MODULE,
-       },
-       .id_table = imx_pcm_devtype,
-       .probe = imx_pcm_probe,
-       .remove = imx_pcm_remove,
-};
-module_platform_driver(imx_pcm_driver);
-
-MODULE_DESCRIPTION("Freescale i.MX PCM driver");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_LICENSE("GPL");
index b7fa0d7..67f656c 100644 (file)
@@ -32,11 +32,6 @@ imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
                dma_data->peripheral_type = IMX_DMATYPE_SSI;
 }
 
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
-                    struct vm_area_struct *vma);
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
-void imx_pcm_free(struct snd_pcm *pcm);
-
 #ifdef CONFIG_SND_SOC_IMX_PCM_DMA
 int imx_pcm_dma_init(struct platform_device *pdev);
 void imx_pcm_dma_exit(struct platform_device *pdev);
@@ -53,11 +48,16 @@ static inline void imx_pcm_dma_exit(struct platform_device *pdev)
 
 #ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
 int imx_pcm_fiq_init(struct platform_device *pdev);
+void imx_pcm_fiq_exit(struct platform_device *pdev);
 #else
 static inline int imx_pcm_fiq_init(struct platform_device *pdev)
 {
        return -ENODEV;
 }
+
+static inline void imx_pcm_fiq_exit(struct platform_device *pdev)
+{
+}
 #endif
 
 #endif /* _IMX_PCM_H */
index 9584e78..7a8bc12 100644 (file)
@@ -128,28 +128,18 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       data->codec_clk = clk_get(&codec_dev->dev, NULL);
-       if (IS_ERR(data->codec_clk)) {
-               /* assuming clock enabled by default */
-               data->codec_clk = NULL;
-               ret = of_property_read_u32(codec_np, "clock-frequency",
-                                       &data->clk_frequency);
-               if (ret) {
-                       dev_err(&codec_dev->dev,
-                               "clock-frequency missing or invalid\n");
-                       goto fail;
-               }
-       } else {
-               data->clk_frequency = clk_get_rate(data->codec_clk);
-               clk_prepare_enable(data->codec_clk);
-       }
+       data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+       if (IS_ERR(data->codec_clk))
+               goto fail;
+
+       data->clk_frequency = clk_get_rate(data->codec_clk);
 
        data->dai.name = "HiFi";
        data->dai.stream_name = "HiFi";
        data->dai.codec_dai_name = "sgtl5000";
        data->dai.codec_of_node = codec_np;
        data->dai.cpu_of_node = ssi_np;
-       data->dai.platform_name = "imx-pcm-audio";
+       data->dai.platform_of_node = ssi_np;
        data->dai.init = &imx_sgtl5000_dai_init;
        data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                            SND_SOC_DAIFMT_CBM_CFM;
@@ -157,10 +147,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        data->card.dev = &pdev->dev;
        ret = snd_soc_of_parse_card_name(&data->card, "model");
        if (ret)
-               goto clk_fail;
+               goto fail;
        ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
        if (ret)
-               goto clk_fail;
+               goto fail;
        data->card.num_links = 1;
        data->card.owner = THIS_MODULE;
        data->card.dai_link = &data->dai;
@@ -170,12 +160,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        ret = snd_soc_register_card(&data->card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-               goto clk_fail;
+               goto fail;
        }
 
        platform_set_drvdata(pdev, data);
-clk_fail:
-       clk_put(data->codec_clk);
+       of_node_put(ssi_np);
+       of_node_put(codec_np);
+
+       return 0;
+
 fail:
        if (ssi_np)
                of_node_put(ssi_np);
@@ -189,10 +182,6 @@ static int imx_sgtl5000_remove(struct platform_device *pdev)
 {
        struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
 
-       if (data->codec_clk) {
-               clk_disable_unprepare(data->codec_clk);
-               clk_put(data->codec_clk);
-       }
        snd_soc_unregister_card(&data->card);
 
        return 0;
index bd40849..51be377 100644 (file)
@@ -595,41 +595,19 @@ static int imx_ssi_probe(struct platform_device *pdev)
                goto failed_register;
        }
 
-       ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
-       if (!ssi->soc_platform_pdev_fiq) {
-               ret = -ENOMEM;
-               goto failed_pdev_fiq_alloc;
-       }
-
-       platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
-       ret = platform_device_add(ssi->soc_platform_pdev_fiq);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add platform device\n");
-               goto failed_pdev_fiq_add;
-       }
+       ret = imx_pcm_fiq_init(pdev);
+       if (ret)
+               goto failed_pcm_fiq;
 
-       ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
-       if (!ssi->soc_platform_pdev) {
-               ret = -ENOMEM;
-               goto failed_pdev_alloc;
-       }
-
-       platform_set_drvdata(ssi->soc_platform_pdev, ssi);
-       ret = platform_device_add(ssi->soc_platform_pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add platform device\n");
-               goto failed_pdev_add;
-       }
+       ret = imx_pcm_dma_init(pdev);
+       if (ret)
+               goto failed_pcm_dma;
 
        return 0;
 
-failed_pdev_add:
-       platform_device_put(ssi->soc_platform_pdev);
-failed_pdev_alloc:
-       platform_device_del(ssi->soc_platform_pdev_fiq);
-failed_pdev_fiq_add:
-       platform_device_put(ssi->soc_platform_pdev_fiq);
-failed_pdev_fiq_alloc:
+failed_pcm_dma:
+       imx_pcm_fiq_exit(pdev);
+failed_pcm_fiq:
        snd_soc_unregister_component(&pdev->dev);
 failed_register:
        release_mem_region(res->start, resource_size(res));
@@ -645,8 +623,8 @@ static int imx_ssi_remove(struct platform_device *pdev)
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 
-       platform_device_unregister(ssi->soc_platform_pdev);
-       platform_device_unregister(ssi->soc_platform_pdev_fiq);
+       imx_pcm_dma_exit(pdev);
+       imx_pcm_fiq_exit(pdev);
 
        snd_soc_unregister_component(&pdev->dev);
 
index bb6b3db..d5003ce 100644 (file)
@@ -211,9 +211,6 @@ struct imx_ssi {
        struct imx_dma_data filter_data_rx;
 
        int enabled;
-
-       struct platform_device *soc_platform_pdev;
-       struct platform_device *soc_platform_pdev_fiq;
 };
 
 #endif /* _IMX_SSI_H */
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
new file mode 100644 (file)
index 0000000..52a36a9
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Based on imx-sgtl5000.c
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "../codecs/wm8962.h"
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE  32
+
+struct imx_wm8962_data {
+       struct snd_soc_dai_link dai;
+       struct snd_soc_card card;
+       char codec_dai_name[DAI_NAME_SIZE];
+       char platform_name[DAI_NAME_SIZE];
+       struct clk *codec_clk;
+       unsigned int clk_frequency;
+};
+
+struct imx_priv {
+       struct platform_device *pdev;
+};
+static struct imx_priv card_priv;
+
+static const struct snd_soc_dapm_widget imx_wm8962_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static int sample_rate = 44100;
+static snd_pcm_format_t sample_format = SNDRV_PCM_FORMAT_S16_LE;
+
+static int imx_hifi_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       sample_rate = params_rate(params);
+       sample_format = params_format(params);
+
+       return 0;
+}
+
+static struct snd_soc_ops imx_hifi_ops = {
+       .hw_params = imx_hifi_hw_params,
+};
+
+static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
+                                       struct snd_soc_dapm_context *dapm,
+                                       enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct imx_priv *priv = &card_priv;
+       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct device *dev = &priv->pdev->dev;
+       unsigned int pll_out;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       if (sample_format == SNDRV_PCM_FORMAT_S24_LE)
+                               pll_out = sample_rate * 384;
+                       else
+                               pll_out = sample_rate * 256;
+
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                       WM8962_FLL_MCLK, data->clk_frequency,
+                                       pll_out);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to start FLL: %d\n", ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                       WM8962_SYSCLK_FLL, pll_out,
+                                       SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (dapm->bias_level == SND_SOC_BIAS_PREPARE) {
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                       WM8962_SYSCLK_MCLK, data->clk_frequency,
+                                       SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               dev_err(dev,
+                                       "failed to switch away from FLL: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                       0, 0, 0);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to stop FLL: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int imx_wm8962_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct imx_priv *priv = &card_priv;
+       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct device *dev = &priv->pdev->dev;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
+                       data->clk_frequency, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(dev, "failed to set sysclk in %s\n", __func__);
+
+       return ret;
+}
+
+static int imx_wm8962_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np, *codec_np;
+       struct platform_device *ssi_pdev;
+       struct imx_priv *priv = &card_priv;
+       struct i2c_client *codec_dev;
+       struct imx_wm8962_data *data;
+       int int_port, ext_port;
+       int ret;
+
+       priv->pdev = pdev;
+
+       ret = of_property_read_u32(np, "mux-int-port", &int_port);
+       if (ret) {
+               dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
+               return ret;
+       }
+       ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+       if (ret) {
+               dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
+               return ret;
+       }
+
+       /*
+        * The port numbering in the hardware manual starts at 1, while
+        * the audmux API expects it starts at 0.
+        */
+       int_port--;
+       ext_port--;
+       ret = imx_audmux_v2_configure_port(int_port,
+                       IMX_AUDMUX_V2_PTCR_SYN |
+                       IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TFSDIR |
+                       IMX_AUDMUX_V2_PTCR_TCLKDIR,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+       if (ret) {
+               dev_err(&pdev->dev, "audmux internal port setup failed\n");
+               return ret;
+       }
+       imx_audmux_v2_configure_port(ext_port,
+                       IMX_AUDMUX_V2_PTCR_SYN,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+       if (ret) {
+               dev_err(&pdev->dev, "audmux external port setup failed\n");
+               return ret;
+       }
+
+       ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+       codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+       if (!ssi_np || !codec_np) {
+               dev_err(&pdev->dev, "phandle missing or invalid\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ssi_pdev = of_find_device_by_node(ssi_np);
+       if (!ssi_pdev) {
+               dev_err(&pdev->dev, "failed to find SSI platform device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+       codec_dev = of_find_i2c_device_by_node(codec_np);
+       if (!codec_dev || !codec_dev->driver) {
+               dev_err(&pdev->dev, "failed to find codec platform device\n");
+               return -EINVAL;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+       if (IS_ERR(data->codec_clk)) {
+               ret = PTR_ERR(data->codec_clk);
+               dev_err(&codec_dev->dev, "failed to get codec clk: %d\n", ret);
+               goto fail;
+       }
+
+       data->clk_frequency = clk_get_rate(data->codec_clk);
+       ret = clk_prepare_enable(data->codec_clk);
+       if (ret) {
+               dev_err(&codec_dev->dev, "failed to enable codec clk: %d\n", ret);
+               goto fail;
+       }
+
+       data->dai.name = "HiFi";
+       data->dai.stream_name = "HiFi";
+       data->dai.codec_dai_name = "wm8962";
+       data->dai.codec_of_node = codec_np;
+       data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+       data->dai.platform_of_node = ssi_np;
+       data->dai.ops = &imx_hifi_ops;
+       data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                           SND_SOC_DAIFMT_CBM_CFM;
+
+       data->card.dev = &pdev->dev;
+       ret = snd_soc_of_parse_card_name(&data->card, "model");
+       if (ret)
+               goto clk_fail;
+       ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+       if (ret)
+               goto clk_fail;
+       data->card.num_links = 1;
+       data->card.dai_link = &data->dai;
+       data->card.dapm_widgets = imx_wm8962_dapm_widgets;
+       data->card.num_dapm_widgets = ARRAY_SIZE(imx_wm8962_dapm_widgets);
+
+       data->card.late_probe = imx_wm8962_late_probe;
+       data->card.set_bias_level = imx_wm8962_set_bias_level;
+
+       ret = snd_soc_register_card(&data->card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               goto clk_fail;
+       }
+
+       platform_set_drvdata(pdev, data);
+       of_node_put(ssi_np);
+       of_node_put(codec_np);
+
+       return 0;
+
+clk_fail:
+       if (!IS_ERR(data->codec_clk))
+               clk_disable_unprepare(data->codec_clk);
+fail:
+       if (ssi_np)
+               of_node_put(ssi_np);
+       if (codec_np)
+               of_node_put(codec_np);
+
+       return ret;
+}
+
+static int imx_wm8962_remove(struct platform_device *pdev)
+{
+       struct imx_wm8962_data *data = platform_get_drvdata(pdev);
+
+       if (!IS_ERR(data->codec_clk))
+               clk_disable_unprepare(data->codec_clk);
+       snd_soc_unregister_card(&data->card);
+
+       return 0;
+}
+
+static const struct of_device_id imx_wm8962_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-wm8962", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_wm8962_dt_ids);
+
+static struct platform_driver imx_wm8962_driver = {
+       .driver = {
+               .name = "imx-wm8962",
+               .owner = THIS_MODULE,
+               .of_match_table = imx_wm8962_dt_ids,
+       },
+       .probe = imx_wm8962_probe,
+       .remove = imx_wm8962_remove,
+};
+module_platform_driver(imx_wm8962_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX WM8962 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-wm8962");
index 3d10741..f4c3bda 100644 (file)
@@ -161,7 +161,7 @@ static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
        .name           = "tlv320aic32x4",
        .stream_name    = "TLV320AIC32X4",
        .codec_dai_name = "tlv320aic32x4-hifi",
-       .platform_name  = "imx-pcm-audio.0",
+       .platform_name  = "imx-ssi.0",
        .codec_name     = "tlv320aic32x4.0-0018",
        .cpu_dai_name   = "imx-ssi.0",
        .ops            = &mx27vis_aic32x4_snd_ops,
index f8da6dd..ae403c2 100644 (file)
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
                .codec_dai_name         = "wm9712-hifi",
                .codec_name     = "wm9712-codec",
                .cpu_dai_name   = "imx-ssi.0",
-               .platform_name  = "imx-fiq-pcm-audio.0",
+               .platform_name  = "imx-ssi.0",
                .ops            = &imx_phycore_hifi_ops,
        },
 };
index fe54a69..fce6325 100644 (file)
@@ -245,7 +245,7 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
        .stream_name = "Audio",
        .cpu_dai_name = "imx-ssi.0",
        .codec_dai_name = "wm8350-hifi",
-       .platform_name = "imx-fiq-pcm-audio.0",
+       .platform_name = "imx-ssi.0",
        .codec_name = "wm8350-codec.0-0x1a",
        .init = wm1133_ev1_init,
        .ops = &wm1133_ev1_ops,
index 9a12644..4c849a4 100644 (file)
@@ -118,7 +118,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
        ctrl |= JZ_AIC_CTRL_FLUSH;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
-       clk_enable(i2s->clk_i2s);
+       clk_prepare_enable(i2s->clk_i2s);
 
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
        conf |= JZ_AIC_CONF_ENABLE;
@@ -140,7 +140,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        conf &= ~JZ_AIC_CONF_ENABLE;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
-       clk_disable(i2s->clk_i2s);
+       clk_disable_unprepare(i2s->clk_i2s);
 }
 
 static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -314,10 +314,10 @@ static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
                conf &= ~JZ_AIC_CONF_ENABLE;
                jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
-               clk_disable(i2s->clk_i2s);
+               clk_disable_unprepare(i2s->clk_i2s);
        }
 
-       clk_disable(i2s->clk_aic);
+       clk_disable_unprepare(i2s->clk_aic);
 
        return 0;
 }
@@ -327,10 +327,10 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
-       clk_enable(i2s->clk_aic);
+       clk_prepare_enable(i2s->clk_aic);
 
        if (dai->active) {
-               clk_enable(i2s->clk_i2s);
+               clk_prepare_enable(i2s->clk_i2s);
 
                conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
                conf |= JZ_AIC_CONF_ENABLE;
@@ -368,7 +368,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
-       clk_enable(i2s->clk_aic);
+       clk_prepare_enable(i2s->clk_aic);
 
        jz4740_i2c_init_pcm_config(i2s);
 
@@ -388,7 +388,7 @@ static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
-       clk_disable(i2s->clk_aic);
+       clk_disable_unprepare(i2s->clk_aic);
        return 0;
 }
 
@@ -509,7 +509,6 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev)
        iounmap(i2s->base);
        release_mem_region(i2s->mem->start, resource_size(i2s->mem));
 
-       platform_set_drvdata(pdev, NULL);
        kfree(i2s);
 
        return 0;
index d3d4bdc..a9f1453 100644 (file)
@@ -289,7 +289,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
        return count;
 }
 
-struct snd_pcm_ops kirkwood_dma_ops = {
+static struct snd_pcm_ops kirkwood_dma_ops = {
        .open =         kirkwood_dma_open,
        .close =        kirkwood_dma_close,
        .ioctl =        snd_pcm_lib_ioctl,
index b41fffc..b16abbb 100644 (file)
@@ -49,24 +49,8 @@ static const struct snd_pcm_hardware snd_mxs_hardware = {
        .fifo_size              = 32,
 };
 
-static bool filter(struct dma_chan *chan, void *param)
-{
-       struct mxs_pcm_dma_params *dma_params = param;
-
-       if (!mxs_dma_is_apbx(chan))
-               return false;
-
-       if (chan->chan_id != dma_params->chan_num)
-               return false;
-
-       chan->private = &dma_params->dma_data;
-
-       return true;
-}
-
 static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = {
        .pcm_hardware = &snd_mxs_hardware,
-       .compat_filter_fn = filter,
        .prealloc_buffer_size = 64 * 1024,
 };
 
@@ -74,8 +58,6 @@ int mxs_pcm_platform_register(struct device *dev)
 {
        return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
                SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
-               SND_DMAENGINE_PCM_FLAG_NO_DT |
-               SND_DMAENGINE_PCM_FLAG_COMPAT |
                SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX);
 }
 EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
index 3aa918f..bc685b6 100644 (file)
 #ifndef _MXS_PCM_H
 #define _MXS_PCM_H
 
-#include <linux/fsl/mxs-dma.h>
-
-struct mxs_pcm_dma_params {
-       struct mxs_dma_data dma_data;
-       int chan_num;
-};
-
 int mxs_pcm_platform_register(struct device *dev);
 void mxs_pcm_platform_unregister(struct device *dev);
 
index d31dc52..49d8700 100644 (file)
@@ -26,8 +26,6 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/time.h>
-#include <linux/fsl/mxs-dma.h>
-#include <linux/pinctrl/consumer.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -605,8 +603,6 @@ static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
        struct mxs_saif *saif = dev_get_drvdata(dai->dev);
 
        snd_soc_dai_set_drvdata(dai, saif);
-       dai->playback_dma_data = &saif->dma_param;
-       dai->capture_dma_data = &saif->dma_param;
 
        return 0;
 }
@@ -665,9 +661,8 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
 static int mxs_saif_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct resource *iores, *dmares;
+       struct resource *iores;
        struct mxs_saif *saif;
-       struct pinctrl *pinctrl;
        int ret = 0;
        struct device_node *master;
 
@@ -707,12 +702,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
        mxs_saif[saif->id] = saif;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               return ret;
-       }
-
        saif->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(saif->clk)) {
                ret = PTR_ERR(saif->clk);
@@ -727,22 +716,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
        if (IS_ERR(saif->base))
                return PTR_ERR(saif->base);
 
-       dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmares) {
-               /*
-                * TODO: This is a temporary solution and should be changed
-                * to use generic DMA binding later when the helplers get in.
-                */
-               ret = of_property_read_u32(np, "fsl,saif-dma-channel",
-                                          &saif->dma_param.chan_num);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to get dma channel\n");
-                       return ret;
-               }
-       } else {
-               saif->dma_param.chan_num = dmares->start;
-       }
-
        saif->irq = platform_get_irq(pdev, 0);
        if (saif->irq < 0) {
                ret = saif->irq;
@@ -759,14 +732,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
-       if (saif->dma_param.dma_data.chan_irq < 0) {
-               ret = saif->dma_param.dma_data.chan_irq;
-               dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
-                       ret);
-               return ret;
-       }
-
        platform_set_drvdata(pdev, saif);
 
        ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
index 3cb342e..53eaa4b 100644 (file)
@@ -117,7 +117,6 @@ struct mxs_saif {
        unsigned int mclk_in_use;
        void __iomem *base;
        int irq;
-       struct mxs_pcm_dma_params dma_param;
        unsigned int id;
        unsigned int master_id;
        unsigned int cur_rate;
index b1d9b5e..1b134d7 100644 (file)
@@ -90,17 +90,11 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
                .name           = "HiFi Tx",
                .stream_name    = "HiFi Playback",
                .codec_dai_name = "sgtl5000",
-               .codec_name     = "sgtl5000.0-000a",
-               .cpu_dai_name   = "mxs-saif.0",
-               .platform_name  = "mxs-saif.0",
                .ops            = &mxs_sgtl5000_hifi_ops,
        }, {
                .name           = "HiFi Rx",
                .stream_name    = "HiFi Capture",
                .codec_dai_name = "sgtl5000",
-               .codec_name     = "sgtl5000.0-000a",
-               .cpu_dai_name   = "mxs-saif.1",
-               .platform_name  = "mxs-saif.1",
                .ops            = &mxs_sgtl5000_hifi_ops,
        },
 };
@@ -116,7 +110,7 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct device_node *saif_np[2], *codec_np;
-       int i, ret = 0;
+       int i;
 
        if (!np)
                return 1; /* no device tree */
@@ -142,7 +136,7 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
        of_node_put(saif_np[0]);
        of_node_put(saif_np[1]);
 
-       return ret;
+       return 0;
 }
 
 static int mxs_sgtl5000_probe(struct platform_device *pdev)
index 60259f2..9f5d55e 100644 (file)
@@ -103,7 +103,7 @@ config SND_OMAP_SOC_OMAP_HDMI
        tristate "SoC Audio support for Texas Instruments OMAP HDMI"
        depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
        select SND_OMAP_SOC_HDMI
-       select SND_SOC_OMAP_HDMI_CODEC
+       select SND_SOC_HDMI_CODEC
        select OMAP4_DSS_HDMI_AUDIO
        help
          Say Y if you want to add support for SoC HDMI audio on Texas Instruments
index 2b22594..a725905 100644 (file)
@@ -26,7 +26,6 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
 obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
 obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o
 obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
index d4eaa92..7e66e9c 100644 (file)
@@ -35,7 +35,7 @@ static struct snd_soc_dai_link omap_hdmi_dai = {
        .cpu_dai_name = "omap-hdmi-audio-dai",
        .platform_name = "omap-pcm-audio",
        .codec_name = "hdmi-audio-codec",
-       .codec_dai_name = "omap-hdmi-hifi",
+       .codec_dai_name = "hdmi-hifi",
 };
 
 static struct snd_soc_card snd_soc_omap_hdmi = {
index eadbfb6..7483efb 100644 (file)
@@ -814,8 +814,6 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
 
        clk_put(mcbsp->fclk);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 4d2e46f..b358094 100644 (file)
@@ -130,26 +130,6 @@ config SND_PXA2XX_SOC_PALM27X
          Say Y if you want to add support for SoC audio on
          Palm T|X, T5, E2 or LifeDrive handheld computer.
 
-config SND_SOC_SAARB
-       tristate "SoC Audio support for Marvell Saarb"
-       depends on SND_PXA2XX_SOC && MACH_SAARB
-       select MFD_88PM860X
-       select SND_PXA_SOC_SSP
-       select SND_SOC_88PM860X
-       help
-         Say Y if you want to add support for SoC audio on the
-         Marvell Saarb reference platform.
-
-config SND_SOC_TAVOREVB3
-       tristate "SoC Audio support for Marvell Tavor EVB3"
-       depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
-       select MFD_88PM860X
-       select SND_PXA_SOC_SSP
-       select SND_SOC_88PM860X
-       help
-         Say Y if you want to add support for SoC audio on the
-         Marvell Saarb reference platform.
-
 config SND_PXA910_SOC
        tristate "SoC Audio for Marvell PXA910 chip"
        depends on ARCH_MMP && SND
index d8a265d..2cff67b 100644 (file)
@@ -23,8 +23,6 @@ snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
 snd-soc-palm27x-objs := palm27x.o
-snd-soc-saarb-objs := saarb.o
-snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
 snd-soc-hx4700-objs := hx4700.o
 snd-soc-magician-objs := magician.o
@@ -48,8 +46,6 @@ obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
-obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
-obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
index 3499300..5d57e07 100644 (file)
@@ -147,7 +147,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
                vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
-struct snd_pcm_ops mmp_pcm_ops = {
+static struct snd_pcm_ops mmp_pcm_ops = {
        .open           = mmp_pcm_open,
        .close          = snd_dmaengine_pcm_close_release_chan,
        .ioctl          = snd_pcm_lib_ioctl,
@@ -208,7 +208,7 @@ static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
        return 0;
 }
 
-int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
+static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm_substream *substream;
        struct snd_pcm *pcm = rtd->pcm;
@@ -229,7 +229,7 @@ err:
        return ret;
 }
 
-struct snd_soc_platform_driver mmp_soc_platform = {
+static struct snd_soc_platform_driver mmp_soc_platform = {
        .ops            = &mmp_pcm_ops,
        .pcm_new        = mmp_pcm_new,
        .pcm_free       = mmp_pcm_free_dma_buffers,
index a647799..62142ce 100644 (file)
@@ -388,7 +388,7 @@ static struct snd_soc_dai_ops mmp_sspa_dai_ops = {
        .set_fmt        = mmp_sspa_set_dai_fmt,
 };
 
-struct snd_soc_dai_driver mmp_sspa_dai = {
+static struct snd_soc_dai_driver mmp_sspa_dai = {
        .probe = mmp_sspa_probe,
        .playback = {
                .channels_min = 1,
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
deleted file mode 100644 (file)
index c34146b..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * saarb.c -- SoC audio for saarb
- *
- * Copyright (C) 2010 Marvell International Ltd.
- *     Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include "../codecs/88pm860x-codec.h"
-#include "pxa-ssp.h"
-
-static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
-
-static struct platform_device *saarb_snd_device;
-
-static struct snd_soc_jack hs_jack, mic_jack;
-
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
-};
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
-       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
-};
-
-/* saarb machine dapm widgets */
-static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
-       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
-};
-
-/* saarb machine audio map */
-static const struct snd_soc_dapm_route saarb_audio_map[] = {
-       {"Headset Stereophone", NULL, "HS1"},
-       {"Headset Stereophone", NULL, "HS2"},
-
-       {"Ext Speaker", NULL, "LSP"},
-       {"Ext Speaker", NULL, "LSN"},
-
-       {"Lineout Out 1", NULL, "LINEOUT1"},
-       {"Lineout Out 2", NULL, "LINEOUT2"},
-
-       {"MIC1P", NULL, "Mic1 Bias"},
-       {"MIC1N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Ext Mic 1"},
-
-       {"MIC2P", NULL, "Mic1 Bias"},
-       {"MIC2N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Headset Mic 2"},
-
-       {"MIC3P", NULL, "Mic3 Bias"},
-       {"MIC3N", NULL, "Mic3 Bias"},
-       {"Mic3 Bias", NULL, "Ext Mic 3"},
-};
-
-static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int width = snd_pcm_format_physical_width(params_format(params));
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
-                                    PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
-
-       return ret;
-}
-
-static struct snd_soc_ops saarb_i2s_ops = {
-       .hw_params      = saarb_i2s_hw_params,
-};
-
-static struct snd_soc_dai_link saarb_dai[] = {
-       {
-               .name           = "88PM860x I2S",
-               .stream_name    = "I2S Audio",
-               .cpu_dai_name   = "pxa-ssp-dai.1",
-               .codec_dai_name = "88pm860x-i2s",
-               .platform_name  = "pxa-pcm-audio",
-               .codec_name     = "88pm860x-codec",
-               .init           = saarb_pm860x_init,
-               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM,
-               .ops            = &saarb_i2s_ops,
-       },
-};
-
-static struct snd_soc_card snd_soc_card_saarb = {
-       .name = "Saarb",
-       .owner = THIS_MODULE,
-       .dai_link = saarb_dai,
-       .num_links = ARRAY_SIZE(saarb_dai),
-
-       .dapm_widgets = saarb_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(saarb_dapm_widgets),
-       .dapm_routes = saarb_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(saarb_audio_map),
-};
-
-static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* connected pins */
-       snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
-
-       /* Headset jack detection */
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
-                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
-                       &hs_jack);
-       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                             hs_jack_pins);
-       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
-                        &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
-
-       /* headphone, microphone detection & headset short detection */
-       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
-                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
-       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
-       return 0;
-}
-
-static int __init saarb_init(void)
-{
-       int ret;
-
-       if (!machine_is_saarb())
-               return -ENODEV;
-       saarb_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!saarb_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
-
-       ret = platform_device_add(saarb_snd_device);
-       if (ret)
-               platform_device_put(saarb_snd_device);
-
-       return ret;
-}
-
-static void __exit saarb_exit(void)
-{
-       platform_device_unregister(saarb_snd_device);
-}
-
-module_init(saarb_init);
-module_exit(saarb_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
deleted file mode 100644 (file)
index 8b5ab8f..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * tavorevb3.c -- SoC audio for Tavor EVB3
- *
- * Copyright (C) 2010 Marvell International Ltd.
- *     Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include "../codecs/88pm860x-codec.h"
-#include "pxa-ssp.h"
-
-static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
-
-static struct platform_device *evb3_snd_device;
-
-static struct snd_soc_jack hs_jack, mic_jack;
-
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
-};
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
-       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
-};
-
-/* tavorevb3 machine dapm widgets */
-static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
-       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
-};
-
-/* tavorevb3 machine audio map */
-static const struct snd_soc_dapm_route evb3_audio_map[] = {
-       {"Headset Stereophone", NULL, "HS1"},
-       {"Headset Stereophone", NULL, "HS2"},
-
-       {"Ext Speaker", NULL, "LSP"},
-       {"Ext Speaker", NULL, "LSN"},
-
-       {"Lineout Out 1", NULL, "LINEOUT1"},
-       {"Lineout Out 2", NULL, "LINEOUT2"},
-
-       {"MIC1P", NULL, "Mic1 Bias"},
-       {"MIC1N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Ext Mic 1"},
-
-       {"MIC2P", NULL, "Mic1 Bias"},
-       {"MIC2N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Headset Mic 2"},
-
-       {"MIC3P", NULL, "Mic3 Bias"},
-       {"MIC3N", NULL, "Mic3 Bias"},
-       {"Mic3 Bias", NULL, "Ext Mic 3"},
-};
-
-static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int width = snd_pcm_format_physical_width(params_format(params));
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
-                                    PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
-       return ret;
-}
-
-static struct snd_soc_ops evb3_i2s_ops = {
-       .hw_params      = evb3_i2s_hw_params,
-};
-
-static struct snd_soc_dai_link evb3_dai[] = {
-       {
-               .name           = "88PM860x I2S",
-               .stream_name    = "I2S Audio",
-               .cpu_dai_name   = "pxa-ssp-dai.1",
-               .codec_dai_name = "88pm860x-i2s",
-               .platform_name  = "pxa-pcm-audio",
-               .codec_name     = "88pm860x-codec",
-               .init           = evb3_pm860x_init,
-               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM,
-               .ops            = &evb3_i2s_ops,
-       },
-};
-
-static struct snd_soc_card snd_soc_card_evb3 = {
-       .name = "Tavor EVB3",
-       .owner = THIS_MODULE,
-       .dai_link = evb3_dai,
-       .num_links = ARRAY_SIZE(evb3_dai),
-
-       .dapm_widgets = evb3_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(evb3_dapm_widgets),
-       .dapm_routes = evb3_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(evb3_audio_map),
-};
-
-static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* connected pins */
-       snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
-
-       /* Headset jack detection */
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
-                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
-                       &hs_jack);
-       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                             hs_jack_pins);
-       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
-                        &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
-
-       /* headphone, microphone detection & headset short detection */
-       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
-                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
-       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
-       return 0;
-}
-
-static int __init tavorevb3_init(void)
-{
-       int ret;
-
-       if (!machine_is_tavorevb3())
-               return -ENODEV;
-       evb3_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!evb3_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
-
-       ret = platform_device_add(evb3_snd_device);
-       if (ret)
-               platform_device_put(evb3_snd_device);
-
-       return ret;
-}
-
-static void __exit tavorevb3_exit(void)
-{
-       platform_device_unregister(evb3_snd_device);
-}
-
-module_init(tavorevb3_init);
-module_exit(tavorevb3_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
-MODULE_LICENSE("GPL");
index ceb6566..db8aadf 100644 (file)
@@ -256,7 +256,6 @@ static struct snd_soc_card zylonite = {
        .resume_pre = &zylonite_resume_pre,
        .dai_link = zylonite_dai,
        .num_links = ARRAY_SIZE(zylonite_dai),
-       .owner = THIS_MODULE,
 };
 
 static struct platform_device *zylonite_snd_ac97_device;
index 475fb0d..9855dfc 100644 (file)
@@ -39,7 +39,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
        depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
        select SND_S3C24XX_I2S
        select SND_SOC_WM8753
-       select SND_SOC_DFBMCS320
+       select SND_SOC_BT_SCO
        help
          Say Y here to enable audio support for the Openmoko Neo1973
          Smartphones.
index ceed466..29e2468 100644 (file)
@@ -350,8 +350,16 @@ static struct snd_soc_codec_conf bells_codec_conf[] = {
        },
 };
 
+static struct snd_soc_dapm_widget bells_widgets[] = {
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
 static struct snd_soc_dapm_route bells_routes[] = {
        { "Sub CLK_SYS", NULL, "OPCLK" },
+
+       { "DMIC", NULL, "MICBIAS2" },
+       { "IN2L", NULL, "DMIC" },
+       { "IN2R", NULL, "DMIC" },
 };
 
 static struct snd_soc_card bells_cards[] = {
@@ -365,6 +373,8 @@ static struct snd_soc_card bells_cards[] = {
 
                .late_probe = bells_late_probe,
 
+               .dapm_widgets = bells_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
                .dapm_routes = bells_routes,
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
@@ -383,6 +393,8 @@ static struct snd_soc_card bells_cards[] = {
 
                .late_probe = bells_late_probe,
 
+               .dapm_widgets = bells_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
                .dapm_routes = bells_routes,
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
@@ -401,6 +413,8 @@ static struct snd_soc_card bells_cards[] = {
 
                .late_probe = bells_late_probe,
 
+               .dapm_widgets = bells_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
                .dapm_routes = bells_routes,
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
index e591c38..807db41 100644 (file)
@@ -373,7 +373,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Voice via BT */
        .name = "Bluetooth",
        .stream_name = "Voice",
-       .cpu_dai_name = "dfbmcs320-pcm",
+       .cpu_dai_name = "bt-sco-pcm",
        .codec_dai_name = "wm8753-voice",
        .codec_name = "wm8753.0-001a",
        .ops = &neo1973_voice_ops,
index e43bd42..23a9204 100644 (file)
@@ -176,7 +176,6 @@ static int snd_smdk_probe(struct platform_device *pdev)
 static int snd_smdk_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_card(&smdk_pcm);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 3688a32..0c84ca0 100644 (file)
@@ -146,7 +146,6 @@ static int snd_smdk_probe(struct platform_device *pdev)
 static int snd_smdk_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_card(&smdk_pcm);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index f830c41..3039026 100644 (file)
@@ -276,7 +276,7 @@ struct fsi_stream_handler {
        int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
        int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
-       void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
+       int (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
                           int enable);
 };
 #define fsi_stream_handler_call(io, func, args...)     \
@@ -1188,7 +1188,7 @@ static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io)
                                  samples);
 }
 
-static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+static int fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                               int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
@@ -1201,6 +1201,8 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 
        if (fsi_is_clk_master(fsi))
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
+
+       return 0;
 }
 
 static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
@@ -1409,7 +1411,7 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
        return 0;
 }
 
-static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                                 int start)
 {
        struct fsi_master *master = fsi_get_master(fsi);
@@ -1422,6 +1424,8 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 
        if (fsi_is_clk_master(fsi))
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
+
+       return 0;
 }
 
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
index 562d72e..309e5c9 100644 (file)
@@ -272,8 +272,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
        codec->debugfs_codec_root = debugfs_create_dir(codec->name,
                                                       debugfs_card_root);
        if (!codec->debugfs_codec_root) {
-               dev_warn(codec->dev, "ASoC: Failed to create codec debugfs"
-                       " directory\n");
+               dev_warn(codec->dev,
+                       "ASoC: Failed to create codec debugfs directory\n");
                return;
        }
 
@@ -286,8 +286,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
                                                 codec->debugfs_codec_root,
                                                 codec, &codec_reg_fops);
        if (!codec->debugfs_reg)
-               dev_warn(codec->dev, "ASoC: Failed to create codec register"
-                       " debugfs file\n");
+               dev_warn(codec->dev,
+                       "ASoC: Failed to create codec register debugfs file\n");
 
        snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
 }
@@ -631,8 +631,7 @@ int snd_soc_suspend(struct device *dev)
                                 */
                                if (codec->dapm.idle_bias_off) {
                                        dev_dbg(codec->dev,
-                                               "ASoC: idle_bias_off CODEC on"
-                                               " over suspend\n");
+                                               "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
                                }
                        case SND_SOC_BIAS_OFF:
@@ -643,8 +642,8 @@ int snd_soc_suspend(struct device *dev)
                                        regcache_mark_dirty(codec->control_data);
                                break;
                        default:
-                               dev_dbg(codec->dev, "ASoC: CODEC is on"
-                                       " over suspend\n");
+                               dev_dbg(codec->dev,
+                                       "ASoC: CODEC is on over suspend\n");
                                break;
                        }
                }
@@ -713,8 +712,8 @@ static void soc_resume_deferred(struct work_struct *work)
                                codec->suspended = 0;
                                break;
                        default:
-                               dev_dbg(codec->dev, "ASoC: CODEC was on over"
-                                       " suspend\n");
+                               dev_dbg(codec->dev,
+                                       "ASoC: CODEC was on over suspend\n");
                                break;
                        }
                }
@@ -1110,8 +1109,8 @@ static int soc_probe_codec(struct snd_soc_card *card,
                }
                WARN(codec->dapm.idle_bias_off &&
                        codec->dapm.bias_level != SND_SOC_BIAS_OFF,
-                       "codec %s can not start from non-off bias"
-                       " with idle_bias_off==1\n", codec->name);
+                       "codec %s can not start from non-off bias with idle_bias_off==1\n",
+                       codec->name);
        }
 
        /* If the driver didn't set I/O up try regmap */
@@ -1582,8 +1581,9 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
                codec->compress_type = compress_type;
        ret = snd_soc_cache_init(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "ASoC: Failed to set cache compression"
-                       " type: %d\n", ret);
+               dev_err(codec->dev,
+                       "ASoC: Failed to set cache compression type: %d\n",
+                       ret);
                return ret;
        }
        codec->cache_init = 1;
@@ -1639,8 +1639,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        card->owner, 0, &card->snd_card);
        if (ret < 0) {
-               dev_err(card->dev, "ASoC: can't create sound card for"
-                       " card %s: %d\n", card->name, ret);
+               dev_err(card->dev,
+                       "ASoC: can't create sound card for card %s: %d\n",
+                       card->name, ret);
                goto base_error;
        }
        card->snd_card->dev = card->dev;
@@ -1815,8 +1816,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        for (i = 0; i < card->num_rtd; i++) {
                ret = soc_register_ac97_dai_link(&card->rtd[i]);
                if (ret < 0) {
-                       dev_err(card->dev, "ASoC: failed to register AC97:"
-                               " %d\n", ret);
+                       dev_err(card->dev,
+                               "ASoC: failed to register AC97: %d\n", ret);
                        while (--i >= 0)
                                soc_unregister_ac97_dai_link(card->rtd[i].codec);
                        goto probe_aux_dev_err;
@@ -2234,29 +2235,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
 }
 EXPORT_SYMBOL_GPL(snd_soc_test_bits);
 
-/**
- * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
- * @substream: the pcm substream
- * @hw: the hardware parameters
- *
- * Sets the substream runtime hardware parameters.
- */
-int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
-       const struct snd_pcm_hardware *hw)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       runtime->hw.info = hw->info;
-       runtime->hw.formats = hw->formats;
-       runtime->hw.period_bytes_min = hw->period_bytes_min;
-       runtime->hw.period_bytes_max = hw->period_bytes_max;
-       runtime->hw.periods_min = hw->periods_min;
-       runtime->hw.periods_max = hw->periods_max;
-       runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
-       runtime->hw.fifo_size = hw->fifo_size;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
-
 /**
  * snd_soc_cnew - create new control
  * @_template: control template
@@ -2275,7 +2253,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
        struct snd_kcontrol_new template;
        struct snd_kcontrol *kcontrol;
        char *name = NULL;
-       int name_len;
 
        memcpy(&template, _template, sizeof(template));
        template.index = 0;
@@ -2284,13 +2261,10 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
                long_name = template.name;
 
        if (prefix) {
-               name_len = strlen(long_name) + strlen(prefix) + 2;
-               name = kmalloc(name_len, GFP_KERNEL);
+               name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name);
                if (!name)
                        return NULL;
 
-               snprintf(name, name_len, "%s %s", prefix, long_name);
-
                template.name = name;
        } else {
                template.name = long_name;
@@ -3602,14 +3576,16 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 * not both or neither.
                 */
                if (!!link->codec_name == !!link->codec_of_node) {
-                       dev_err(card->dev, "ASoC: Neither/both codec"
-                               " name/of_node are set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: Neither/both codec name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
                /* Codec DAI name must be specified */
                if (!link->codec_dai_name) {
-                       dev_err(card->dev, "ASoC: codec_dai_name not"
-                               " set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: codec_dai_name not set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
 
@@ -3618,8 +3594,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 * can be left unspecified, and a dummy platform will be used.
                 */
                if (link->platform_name && link->platform_of_node) {
-                       dev_err(card->dev, "ASoC: Both platform name/of_node"
-                               " are set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: Both platform name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
 
@@ -3629,8 +3606,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 * name alone..
                 */
                if (link->cpu_name && link->cpu_of_node) {
-                       dev_err(card->dev, "ASoC: Neither/both "
-                               "cpu name/of_node are set for %s\n",link->name);
+                       dev_err(card->dev,
+                               "ASoC: Neither/both cpu name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
                /*
@@ -3639,8 +3617,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 */
                if (!link->cpu_dai_name &&
                    !(link->cpu_name || link->cpu_of_node)) {
-                       dev_err(card->dev, "ASoC: Neither cpu_dai_name nor "
-                               "cpu_name/of_node are set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
        }
@@ -3744,8 +3723,9 @@ static inline char *fmt_multiple_name(struct device *dev,
                struct snd_soc_dai_driver *dai_drv)
 {
        if (dai_drv->name == NULL) {
-               dev_err(dev, "ASoC: error - multiple DAI %s registered with"
-                               " no name\n", dev_name(dev));
+               dev_err(dev,
+                       "ASoC: error - multiple DAI %s registered with no name\n",
+                       dev_name(dev));
                return NULL;
        }
 
@@ -3875,8 +3855,9 @@ static int snd_soc_register_dais(struct device *dev,
 
                list_for_each_entry(codec, &codec_list, list) {
                        if (codec->dev == dev) {
-                               dev_dbg(dev, "ASoC: Mapped DAI %s to "
-                                       "CODEC %s\n", dai->name, codec->name);
+                               dev_dbg(dev,
+                                       "ASoC: Mapped DAI %s to CODEC %s\n",
+                                       dai->name, codec->name);
                                dai->codec = codec;
                                break;
                        }
@@ -4312,8 +4293,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
 
        num_routes = of_property_count_strings(np, propname);
        if (num_routes < 0 || num_routes & 1) {
-               dev_err(card->dev, "ASoC: Property '%s' does not exist or its"
-                       " length is not even\n", propname);
+               dev_err(card->dev,
+                       "ASoC: Property '%s' does not exist or its length is not even\n",
+                       propname);
                return -EINVAL;
        }
        num_routes /= 2;
index c7051c4..b941908 100644 (file)
@@ -64,6 +64,7 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_virt_mux] = 5,
        [snd_soc_dapm_value_mux] = 5,
        [snd_soc_dapm_dac] = 6,
+       [snd_soc_dapm_switch] = 7,
        [snd_soc_dapm_mixer] = 7,
        [snd_soc_dapm_mixer_named_ctl] = 7,
        [snd_soc_dapm_pga] = 8,
@@ -83,6 +84,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_line] = 2,
        [snd_soc_dapm_out_drv] = 2,
        [snd_soc_dapm_pga] = 4,
+       [snd_soc_dapm_switch] = 5,
        [snd_soc_dapm_mixer_named_ctl] = 5,
        [snd_soc_dapm_mixer] = 5,
        [snd_soc_dapm_dac] = 6,
@@ -365,11 +367,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                val = soc_widget_read(w, e->reg);
                item = (val >> e->shift_l) & e->mask;
 
-               p->connect = 0;
-               for (i = 0; i < e->max; i++) {
-                       if (!(strcmp(p->name, e->texts[i])) && item == i)
-                               p->connect = 1;
-               }
+               if (item < e->max && !strcmp(p->name, e->texts[item]))
+                       p->connect = 1;
+               else
+                       p->connect = 0;
        }
        break;
        case snd_soc_dapm_virt_mux: {
@@ -399,11 +400,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                                break;
                }
 
-               p->connect = 0;
-               for (i = 0; i < e->max; i++) {
-                       if (!(strcmp(p->name, e->texts[i])) && item == i)
-                               p->connect = 1;
-               }
+               if (item < e->max && !strcmp(p->name, e->texts[item]))
+                       p->connect = 1;
+               else
+                       p->connect = 0;
        }
        break;
        /* does not affect routing - always connected */
@@ -507,6 +507,11 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
+{
+       kfree(kctl->private_data);
+}
+
 /*
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
@@ -524,7 +529,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        int wlistentries;
        size_t wlistsize;
        bool wname_in_long_name, kcname_in_long_name;
-       size_t name_len;
        char *long_name;
        const char *name;
        int ret;
@@ -589,25 +593,19 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                }
 
                if (wname_in_long_name && kcname_in_long_name) {
-                       name_len = strlen(w->name) - prefix_len + 1 +
-                                  strlen(w->kcontrol_news[kci].name) + 1;
-
-                       long_name = kmalloc(name_len, GFP_KERNEL);
-                       if (long_name == NULL) {
-                               kfree(wlist);
-                               return -ENOMEM;
-                       }
-
                        /*
                         * The control will get a prefix from the control
                         * creation process but we're also using the same
                         * prefix for widgets so cut the prefix off the
                         * front of the widget name.
                         */
-                       snprintf(long_name, name_len, "%s %s",
+                       long_name = kasprintf(GFP_KERNEL, "%s %s",
                                 w->name + prefix_len,
                                 w->kcontrol_news[kci].name);
-                       long_name[name_len - 1] = '\0';
+                       if (long_name == NULL) {
+                               kfree(wlist);
+                               return -ENOMEM;
+                       }
 
                        name = long_name;
                } else if (wname_in_long_name) {
@@ -620,17 +618,16 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
 
                kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
                                        prefix);
+               kcontrol->private_free = dapm_kcontrol_free;
+               kfree(long_name);
                ret = snd_ctl_add(card, kcontrol);
                if (ret < 0) {
                        dev_err(dapm->dev,
                                "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
                                w->name, name, ret);
                        kfree(wlist);
-                       kfree(long_name);
                        return ret;
                }
-
-               path->long_name = long_name;
        }
 
        kcontrol->private_data = wlist;
@@ -1270,6 +1267,14 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
                ev_name = "POST_PMD";
                power = 0;
                break;
+       case SND_SOC_DAPM_WILL_PMU:
+               ev_name = "WILL_PMU";
+               power = 1;
+               break;
+       case SND_SOC_DAPM_WILL_PMD:
+               ev_name = "WILL_PMD";
+               power = 0;
+               break;
        default:
                BUG();
                return;
@@ -1730,6 +1735,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
 
+       list_for_each_entry(w, &down_list, power_list) {
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+       }
+
+       list_for_each_entry(w, &up_list, power_list) {
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+       }
+
        /* Power down widgets first; try to avoid amplifying pops. */
        dapm_seq_run(dapm, &down_list, event, false);
 
@@ -2094,6 +2107,14 @@ static void snd_soc_dapm_sys_remove(struct device *dev)
        device_remove_file(dev, &dev_attr_dapm_widget);
 }
 
+static void dapm_free_path(struct snd_soc_dapm_path *path)
+{
+       list_del(&path->list_sink);
+       list_del(&path->list_source);
+       list_del(&path->list);
+       kfree(path);
+}
+
 /* free all dapm widgets and resources */
 static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 {
@@ -2109,20 +2130,12 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
                 * While removing the path, remove reference to it from both
                 * source and sink widgets so that path is removed only once.
                 */
-               list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p->long_name);
-                       kfree(p);
-               }
-               list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p->long_name);
-                       kfree(p);
-               }
+               list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
+                       dapm_free_path(p);
+
+               list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
+                       dapm_free_path(p);
+
                kfree(w->kcontrols);
                kfree(w->name);
                kfree(w);
@@ -2398,10 +2411,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
                dapm_mark_dirty(path->source, "Route removed");
                dapm_mark_dirty(path->sink, "Route removed");
 
-               list_del(&path->list);
-               list_del(&path->list_sink);
-               list_del(&path->list_source);
-               kfree(path);
+               dapm_free_path(path);
        } else {
                dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
                         source, sink);
@@ -3055,7 +3065,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget)
 {
        struct snd_soc_dapm_widget *w;
-       size_t name_len;
        int ret;
 
        if ((w = dapm_cnew_widget(widget)) == NULL)
@@ -3096,19 +3105,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                break;
        }
 
-       name_len = strlen(widget->name) + 1;
        if (dapm->codec && dapm->codec->name_prefix)
-               name_len += 1 + strlen(dapm->codec->name_prefix);
-       w->name = kmalloc(name_len, GFP_KERNEL);
+               w->name = kasprintf(GFP_KERNEL, "%s %s",
+                       dapm->codec->name_prefix, widget->name);
+       else
+               w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
+
        if (w->name == NULL) {
                kfree(w);
                return NULL;
        }
-       if (dapm->codec && dapm->codec->name_prefix)
-               snprintf((char *)w->name, name_len, "%s %s",
-                       dapm->codec->name_prefix, widget->name);
-       else
-               snprintf((char *)w->name, name_len, "%s", widget->name);
 
        switch (w->id) {
        case snd_soc_dapm_switch:
index ccb6be4..b6c6403 100644 (file)
 
 #define DPCM_MAX_BE_USERS      8
 
+/**
+ * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
+ * @substream: the pcm substream
+ * @hw: the hardware parameters
+ *
+ * Sets the substream runtime hardware parameters.
+ */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+       const struct snd_pcm_hardware *hw)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       runtime->hw.info = hw->info;
+       runtime->hw.formats = hw->formats;
+       runtime->hw.period_bytes_min = hw->period_bytes_min;
+       runtime->hw.period_bytes_max = hw->period_bytes_max;
+       runtime->hw.periods_min = hw->periods_min;
+       runtime->hw.periods_max = hw->periods_max;
+       runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
+       runtime->hw.fifo_size = hw->fifo_size;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
+
 /* DPCM stream event, send event to FE and all active BEs. */
 static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
        int event)
@@ -124,6 +147,26 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
        }
 }
 
+static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw,
+       struct snd_soc_pcm_stream *codec_stream,
+       struct snd_soc_pcm_stream *cpu_stream)
+{
+       hw->rate_min = max(codec_stream->rate_min, cpu_stream->rate_min);
+       hw->rate_max = max(codec_stream->rate_max, cpu_stream->rate_max);
+       hw->channels_min = max(codec_stream->channels_min,
+               cpu_stream->channels_min);
+       hw->channels_max = min(codec_stream->channels_max,
+               cpu_stream->channels_max);
+       hw->formats = codec_stream->formats & cpu_stream->formats;
+       hw->rates = codec_stream->rates & cpu_stream->rates;
+       if (codec_stream->rates
+               & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+               hw->rates |= cpu_stream->rates;
+       if (cpu_stream->rates
+               & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+               hw->rates |= codec_stream->rates;
+}
+
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
@@ -189,51 +232,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 
        /* Check that the codec and cpu DAIs are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               runtime->hw.rate_min =
-                       max(codec_dai_drv->playback.rate_min,
-                           cpu_dai_drv->playback.rate_min);
-               runtime->hw.rate_max =
-                       min(codec_dai_drv->playback.rate_max,
-                           cpu_dai_drv->playback.rate_max);
-               runtime->hw.channels_min =
-                       max(codec_dai_drv->playback.channels_min,
-                               cpu_dai_drv->playback.channels_min);
-               runtime->hw.channels_max =
-                       min(codec_dai_drv->playback.channels_max,
-                               cpu_dai_drv->playback.channels_max);
-               runtime->hw.formats =
-                       codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
-               runtime->hw.rates =
-                       codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
-               if (codec_dai_drv->playback.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai_drv->playback.rates;
-               if (cpu_dai_drv->playback.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai_drv->playback.rates;
+               soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->playback,
+                       &cpu_dai_drv->playback);
        } else {
-               runtime->hw.rate_min =
-                       max(codec_dai_drv->capture.rate_min,
-                           cpu_dai_drv->capture.rate_min);
-               runtime->hw.rate_max =
-                       min(codec_dai_drv->capture.rate_max,
-                           cpu_dai_drv->capture.rate_max);
-               runtime->hw.channels_min =
-                       max(codec_dai_drv->capture.channels_min,
-                               cpu_dai_drv->capture.channels_min);
-               runtime->hw.channels_max =
-                       min(codec_dai_drv->capture.channels_max,
-                               cpu_dai_drv->capture.channels_max);
-               runtime->hw.formats =
-                       codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
-               runtime->hw.rates =
-                       codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
-               if (codec_dai_drv->capture.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai_drv->capture.rates;
-               if (cpu_dai_drv->capture.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai_drv->capture.rates;
+               soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->capture,
+                       &cpu_dai_drv->capture);
        }
 
        ret = -EINVAL;
index 4b3be6c..29b211e 100644 (file)
@@ -159,15 +159,10 @@ int __init snd_soc_util_init(void)
 {
        int ret;
 
-       soc_dummy_dev = platform_device_alloc("snd-soc-dummy", -1);
-       if (!soc_dummy_dev)
-               return -ENOMEM;
-
-       ret = platform_device_add(soc_dummy_dev);
-       if (ret != 0) {
-               platform_device_put(soc_dummy_dev);
-               return ret;
-       }
+       soc_dummy_dev =
+               platform_device_register_simple("snd-soc-dummy", -1, NULL, 0);
+       if (IS_ERR(soc_dummy_dev))
+               return PTR_ERR(soc_dummy_dev);
 
        ret = platform_driver_register(&soc_dummy_driver);
        if (ret != 0)
diff --git a/sound/soc/spear/Kconfig b/sound/soc/spear/Kconfig
new file mode 100644 (file)
index 0000000..3567d73
--- /dev/null
@@ -0,0 +1,9 @@
+config SND_SPEAR_SOC
+       tristate
+       select SND_SOC_DMAENGINE_PCM
+
+config SND_SPEAR_SPDIF_OUT
+       tristate
+
+config SND_SPEAR_SPDIF_IN
+       tristate
diff --git a/sound/soc/spear/Makefile b/sound/soc/spear/Makefile
new file mode 100644 (file)
index 0000000..c4ea716
--- /dev/null
@@ -0,0 +1,8 @@
+# SPEAR Platform Support
+snd-soc-spear-pcm-objs := spear_pcm.o
+snd-soc-spear-spdif-in-objs := spdif_in.o
+snd-soc-spear-spdif-out-objs := spdif_out.o
+
+obj-$(CONFIG_SND_SPEAR_SOC) += snd-soc-spear-pcm.o
+obj-$(CONFIG_SND_SPEAR_SPDIF_IN) += snd-soc-spear-spdif-in.o
+obj-$(CONFIG_SND_SPEAR_SPDIF_OUT) += snd-soc-spear-spdif-out.o
index 14d57e8..63acfeb 100644 (file)
@@ -49,15 +49,12 @@ static void spdif_in_configure(struct spdif_in_dev *host)
        writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
 }
 
-static int spdif_in_startup(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *cpu_dai)
+static int spdif_in_dai_probe(struct snd_soc_dai *dai)
 {
-       struct spdif_in_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+       struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
 
-       if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
-               return -EINVAL;
+       dai->capture_dma_data = &host->dma_params;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
        return 0;
 }
 
@@ -70,7 +67,6 @@ static void spdif_in_shutdown(struct snd_pcm_substream *substream,
                return;
 
        writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
-       snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
 static void spdif_in_format(struct spdif_in_dev *host, u32 format)
@@ -151,13 +147,13 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static struct snd_soc_dai_ops spdif_in_dai_ops = {
-       .startup        = spdif_in_startup,
        .shutdown       = spdif_in_shutdown,
        .trigger        = spdif_in_trigger,
        .hw_params      = spdif_in_hw_params,
 };
 
-struct snd_soc_dai_driver spdif_in_dai = {
+static struct snd_soc_dai_driver spdif_in_dai = {
+       .probe = spdif_in_dai_probe,
        .capture = {
                .channels_min = 2,
                .channels_max = 2,
@@ -235,7 +231,7 @@ static int spdif_in_probe(struct platform_device *pdev)
        if (host->irq < 0)
                return -EINVAL;
 
-       host->clk = clk_get(&pdev->dev, NULL);
+       host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk))
                return PTR_ERR(host->clk);
 
@@ -257,34 +253,21 @@ static int spdif_in_probe(struct platform_device *pdev)
        ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
                        "spdif-in", host);
        if (ret) {
-               clk_put(host->clk);
                dev_warn(&pdev->dev, "request_irq failed\n");
                return ret;
        }
 
-       ret = snd_soc_register_component(&pdev->dev, &spdif_in_component,
+       return snd_soc_register_component(&pdev->dev, &spdif_in_component,
                                         &spdif_in_dai, 1);
-       if (ret != 0) {
-               clk_put(host->clk);
-               return ret;
-       }
-
-       return 0;
 }
 
 static int spdif_in_remove(struct platform_device *pdev)
 {
-       struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
-
        snd_soc_unregister_component(&pdev->dev);
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       clk_put(host->clk);
 
        return 0;
 }
 
-
 static struct platform_driver spdif_in_driver = {
        .probe          = spdif_in_probe,
        .remove         = spdif_in_remove,
index 1e3c3dd..2fdf68c 100644 (file)
@@ -62,8 +62,6 @@ static int spdif_out_startup(struct snd_pcm_substream *substream,
        if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
                return -EINVAL;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
-
        ret = clk_enable(host->clk);
        if (ret)
                return ret;
@@ -84,7 +82,6 @@ static void spdif_out_shutdown(struct snd_pcm_substream *substream,
 
        clk_disable(host->clk);
        host->running = false;
-       snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
 static void spdif_out_clock(struct spdif_out_dev *host, u32 core_freq,
@@ -243,8 +240,12 @@ static const struct snd_kcontrol_new spdif_out_controls[] = {
                        spdif_mute_get, spdif_mute_put),
 };
 
-int spdif_soc_dai_probe(struct snd_soc_dai *dai)
+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;
+
        return snd_soc_add_dai_controls(dai, spdif_out_controls,
                                ARRAY_SIZE(spdif_out_controls));
 }
@@ -281,30 +282,18 @@ static int spdif_out_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                               resource_size(res), pdev->name)) {
-               dev_warn(&pdev->dev, "Failed to get memory resourse\n");
-               return -ENOENT;
-       }
-
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
        if (!host) {
                dev_warn(&pdev->dev, "kzalloc fail\n");
                return -ENOMEM;
        }
 
-       host->io_base = devm_ioremap(&pdev->dev, res->start,
-                               resource_size(res));
-       if (!host->io_base) {
-               dev_warn(&pdev->dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(host->io_base))
+               return PTR_ERR(host->io_base);
 
-       host->clk = clk_get(&pdev->dev, NULL);
+       host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk))
                return PTR_ERR(host->clk);
 
@@ -320,22 +309,12 @@ static int spdif_out_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_component(&pdev->dev, &spdif_out_component,
                                         &spdif_out_dai, 1);
-       if (ret != 0) {
-               clk_put(host->clk);
-               return ret;
-       }
-
-       return 0;
+       return ret;
 }
 
 static int spdif_out_remove(struct platform_device *pdev)
 {
-       struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
-
        snd_soc_unregister_component(&pdev->dev);
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       clk_put(host->clk);
 
        return 0;
 }
index 2fbd489..4707f2b 100644 (file)
 
 #include <linux/module.h>
 #include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <sound/core.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 
-static struct snd_pcm_hardware spear_pcm_hardware = {
+static const struct snd_pcm_hardware spear_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_RESUME),
@@ -37,149 +31,33 @@ static struct snd_pcm_hardware spear_pcm_hardware = {
        .fifo_size = 0, /* fifo size in bytes */
 };
 
-static int spear_pcm_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
+static struct dma_chan *spear_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
+       struct snd_pcm_substream *substream)
 {
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       struct spear_dma_data *dma_data;
 
-       return 0;
-}
-
-static int spear_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_set_runtime_buffer(substream, NULL);
-
-       return 0;
-}
-
-static int spear_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       struct spear_dma_data *dma_data = (struct spear_dma_data *)
-               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       int ret;
-
-       ret = snd_soc_set_runtime_hwparams(substream, &spear_pcm_hardware);
-       if (ret)
-               return ret;
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
-       return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
-                               dma_data);
+       return snd_dmaengine_pcm_request_channel(dma_data->filter, dma_data);
 }
 
-static int spear_pcm_mmap(struct snd_pcm_substream *substream,
-               struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                       runtime->dma_area, runtime->dma_addr,
-                       runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops spear_pcm_ops = {
-       .open           = spear_pcm_open,
-       .close          = snd_dmaengine_pcm_close_release_chan,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = spear_pcm_hw_params,
-       .hw_free        = spear_pcm_hw_free,
-       .trigger        = snd_dmaengine_pcm_trigger,
-       .pointer        = snd_dmaengine_pcm_pointer,
-       .mmap           = spear_pcm_mmap,
-};
-
-static int
-spear_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
-               size_t size)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-
-       dev_info(buf->dev.dev,
-                       " preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
-                       (void *)buf->area, (void *)buf->addr, size);
-
-       buf->bytes = size;
-       return 0;
-}
-
-static void spear_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf || !buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                               buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
-static u64 spear_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       int ret;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &spear_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-       if (rtd->cpu_dai->driver->playback.channels_min) {
-               ret = spear_pcm_preallocate_dma_buffer(rtd->pcm,
-                               SNDRV_PCM_STREAM_PLAYBACK,
-                               spear_pcm_hardware.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       if (rtd->cpu_dai->driver->capture.channels_min) {
-               ret = spear_pcm_preallocate_dma_buffer(rtd->pcm,
-                               SNDRV_PCM_STREAM_CAPTURE,
-                               spear_pcm_hardware.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver spear_soc_platform = {
-       .ops            =       &spear_pcm_ops,
-       .pcm_new        =       spear_pcm_new,
-       .pcm_free       =       spear_pcm_free,
+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)
 {
-       return snd_soc_register_platform(&pdev->dev, &spear_soc_platform);
+       return snd_dmaengine_pcm_register(&pdev->dev,
+               &spear_dmaengine_pcm_config,
+               SND_DMAENGINE_PCM_FLAG_NO_DT |
+               SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 
 static int spear_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&pdev->dev);
-
+       snd_dmaengine_pcm_unregister(&pdev->dev);
        return 0;
 }
 
index b1c9d57..995b120 100644 (file)
@@ -59,6 +59,16 @@ config SND_SOC_TEGRA30_I2S
          Tegra30 I2S interface. You will also need to select the individual
          machine drivers to support below.
 
+config SND_SOC_TEGRA_RT5640
+       tristate "SoC Audio support for Tegra boards using an RT5640 codec"
+       depends on SND_SOC_TEGRA && I2C
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+       select SND_SOC_RT5640
+       help
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the RT5640 codec, such as Dalmore.
+
 config SND_SOC_TEGRA_WM8753
        tristate "SoC Audio support for Tegra boards using a WM8753 codec"
        depends on SND_SOC_TEGRA && I2C
index 416a14b..21d2550 100644 (file)
@@ -18,12 +18,14 @@ obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 
 # Tegra machine Support
+snd-soc-tegra-rt5640-objs := tegra_rt5640.o
 snd-soc-tegra-wm8753-objs := tegra_wm8753.o
 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
 
+obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
index 23e592f..d554d46 100644 (file)
@@ -627,9 +627,34 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_ahub_suspend(struct device *dev)
+{
+       regcache_mark_dirty(ahub->regmap_ahub);
+       regcache_mark_dirty(ahub->regmap_apbif);
+
+       return 0;
+}
+
+static int tegra30_ahub_resume(struct device *dev)
+{
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               return ret;
+       ret = regcache_sync(ahub->regmap_ahub);
+       ret |= regcache_sync(ahub->regmap_apbif);
+       pm_runtime_put(dev);
+
+       return ret;
+}
+#endif
+
 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
                           tegra30_ahub_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume)
 };
 
 static struct platform_driver tegra30_ahub_driver = {
index 31d092d..d04146c 100644 (file)
@@ -514,6 +514,31 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_i2s_suspend(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(i2s->regmap);
+
+       return 0;
+}
+
+static int tegra30_i2s_resume(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               return ret;
+       ret = regcache_sync(i2s->regmap);
+       pm_runtime_put(dev);
+
+       return ret;
+}
+#endif
+
 static const struct of_device_id tegra30_i2s_of_match[] = {
        { .compatible = "nvidia,tegra30-i2s", },
        {},
@@ -522,6 +547,7 @@ static const struct of_device_id tegra30_i2s_of_match[] = {
 static const struct dev_pm_ops tegra30_i2s_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
                           tegra30_i2s_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_i2s_suspend, tegra30_i2s_resume)
 };
 
 static struct platform_driver tegra30_i2s_driver = {
index 24fb001..d173880 100644 (file)
@@ -173,7 +173,6 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                          struct device *dev)
 {
        int ret;
-       bool new_clocks = false;
 
        data->dev = dev;
 
@@ -181,40 +180,28 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
        else if (of_machine_is_compatible("nvidia,tegra30"))
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
-       else if (of_machine_is_compatible("nvidia,tegra114")) {
+       else if (of_machine_is_compatible("nvidia,tegra114"))
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
-               new_clocks = true;
-       } else {
+       else {
                dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
                return -EINVAL;
        }
 
-       if (new_clocks)
-               data->clk_pll_a = clk_get(dev, "pll_a");
-       else
-               data->clk_pll_a = clk_get_sys(NULL, "pll_a");
+       data->clk_pll_a = clk_get(dev, "pll_a");
        if (IS_ERR(data->clk_pll_a)) {
                dev_err(data->dev, "Can't retrieve clk pll_a\n");
                ret = PTR_ERR(data->clk_pll_a);
                goto err;
        }
 
-       if (new_clocks)
-               data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
-       else
-               data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
+       data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
        if (IS_ERR(data->clk_pll_a_out0)) {
                dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
                ret = PTR_ERR(data->clk_pll_a_out0);
                goto err_put_pll_a;
        }
 
-       if (new_clocks)
-               data->clk_cdev1 = clk_get(dev, "mclk");
-       else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
-               data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
-       else
-               data->clk_cdev1 = clk_get_sys("extern1", NULL);
+       data->clk_cdev1 = clk_get(dev, "mclk");
        if (IS_ERR(data->clk_cdev1)) {
                dev_err(data->dev, "Can't retrieve clk cdev1\n");
                ret = PTR_ERR(data->clk_cdev1);
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
new file mode 100644 (file)
index 0000000..08794f9
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+* tegra_rt5640.c - Tegra machine ASoC driver for boards using WM8903 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 "../codecs/rt5640.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-rt5640"
+
+struct tegra_rt5640 {
+       struct tegra_asoc_utils_data util_data;
+       int gpio_hp_det;
+};
+
+static int tegra_rt5640_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_rt5640 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       mclk = 256 * srate;
+
+       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, RT5640_SCLK_S_MCLK, 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_rt5640_ops = {
+       .hw_params = tegra_rt5640_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_rt5640_hp_jack;
+
+static struct snd_soc_jack_pin tegra_rt5640_hp_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio tegra_rt5640_hp_jack_gpio = {
+       .name = "Headphone detection",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+       .invert = 1,
+};
+
+static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_SPK("Speakers", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speakers"),
+};
+
+static int tegra_rt5640_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_rt5640 *machine = snd_soc_card_get_drvdata(codec->card);
+
+       snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
+                        &tegra_rt5640_hp_jack);
+       snd_soc_jack_add_pins(&tegra_rt5640_hp_jack,
+                       ARRAY_SIZE(tegra_rt5640_hp_jack_pins),
+                       tegra_rt5640_hp_jack_pins);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det;
+               snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack,
+                                               1,
+                                               &tegra_rt5640_hp_jack_gpio);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_rt5640_dai = {
+       .name = "RT5640",
+       .stream_name = "RT5640 PCM",
+       .codec_dai_name = "rt5640-aif1",
+       .init = tegra_rt5640_asoc_init,
+       .ops = &tegra_rt5640_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_rt5640 = {
+       .name = "tegra-rt5640",
+       .owner = THIS_MODULE,
+       .dai_link = &tegra_rt5640_dai,
+       .num_links = 1,
+       .controls = tegra_rt5640_controls,
+       .num_controls = ARRAY_SIZE(tegra_rt5640_controls),
+       .dapm_widgets = tegra_rt5640_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_rt5640_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int tegra_rt5640_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &snd_soc_tegra_rt5640;
+       struct tegra_rt5640 *machine;
+       int ret;
+
+       machine = devm_kzalloc(&pdev->dev,
+                       sizeof(struct tegra_rt5640), GFP_KERNEL);
+       if (!machine) {
+               dev_err(&pdev->dev, "Can't allocate tegra_rt5640\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_rt5640_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!tegra_rt5640_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_rt5640_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_rt5640_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_rt5640_dai.platform_of_node = tegra_rt5640_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_rt5640_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
+                               &tegra_rt5640_hp_jack_gpio);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_rt5640_of_match[] = {
+       { .compatible = "nvidia,tegra-audio-rt5640", },
+       {},
+};
+
+static struct platform_driver tegra_rt5640_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_rt5640_of_match,
+       },
+       .probe = tegra_rt5640_probe,
+       .remove = tegra_rt5640_remove,
+};
+module_platform_driver(tegra_rt5640_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+RT5640 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_rt5640_of_match);
index 204b899..8f5cd00 100644 (file)
@@ -27,7 +27,7 @@
 #include "mop500_ab8500.h"
 
 /* Define the whole MOP500 soundcard, linking platform to the codec-drivers  */
-struct snd_soc_dai_link mop500_dai_links[] = {
+static struct snd_soc_dai_link mop500_dai_links[] = {
        {
                .name = "ab8500_0",
                .stream_name = "ab8500_0",
index 892ad9a..7e923ec 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/mutex.h>
 
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -24,6 +25,7 @@
 
 #include "ux500_pcm.h"
 #include "ux500_msp_dai.h"
+#include "mop500_ab8500.h"
 #include "../codecs/ab8500-codec.h"
 
 #define TX_SLOT_MONO   0x0008
 static unsigned int tx_slots = DEF_TX_SLOTS;
 static unsigned int rx_slots = DEF_RX_SLOTS;
 
+/* Configuration consistency parameters */
+static DEFINE_MUTEX(mop500_ab8500_params_lock);
+static unsigned long mop500_ab8500_usage;
+static int mop500_ab8500_rate;
+static int mop500_ab8500_channels;
+
 /* Clocks */
 static const char * const enum_mclk[] = {
        "SYSCLK",
@@ -125,9 +133,9 @@ static int mop500_ab8500_set_mclk(struct device *dev,
 static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        struct mop500_ab8500_drvdata *drvdata =
-                               snd_soc_card_get_drvdata(codec->card);
+                               snd_soc_card_get_drvdata(card);
 
        ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
 
@@ -137,9 +145,9 @@ static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
 static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        struct mop500_ab8500_drvdata *drvdata =
-                               snd_soc_card_get_drvdata(codec->card);
+                               snd_soc_card_get_drvdata(card);
        unsigned int val = ucontrol->value.enumerated.item[0];
 
        if (val > (unsigned int)MCLK_ULPCLK)
@@ -160,16 +168,6 @@ static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
        SOC_ENUM_EXT("Master Clock Select",
                soc_enum_mclk,
                mclk_input_control_get, mclk_input_control_put),
-       /* Digital interface - Clocks */
-       SOC_SINGLE("Digital Interface Master Generator Switch",
-               AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENMASTGEN,
-               1, 0),
-       SOC_SINGLE("Digital Interface 0 Bit-clock Switch",
-               AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK0,
-               1, 0),
-       SOC_SINGLE("Digital Interface 1 Bit-clock Switch",
-               AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK1,
-               1, 0),
        SOC_DAPM_PIN_SWITCH("Headset Left"),
        SOC_DAPM_PIN_SWITCH("Headset Right"),
        SOC_DAPM_PIN_SWITCH("Earpiece"),
@@ -193,7 +191,7 @@ static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
 
 /* ASoC */
 
-int mop500_ab8500_startup(struct snd_pcm_substream *substream)
+static int mop500_ab8500_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
@@ -202,7 +200,7 @@ int mop500_ab8500_startup(struct snd_pcm_substream *substream)
                                snd_soc_card_get_drvdata(rtd->card));
 }
 
-void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
+static void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct device *dev = rtd->card->dev;
@@ -216,7 +214,7 @@ void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
                rx_slots = DEF_RX_SLOTS;
 }
 
-int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
+static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
                        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -240,6 +238,21 @@ int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
                substream->name,
                substream->number);
 
+       /* Ensure configuration consistency between DAIs */
+       mutex_lock(&mop500_ab8500_params_lock);
+       if (mop500_ab8500_usage) {
+               if (mop500_ab8500_rate != params_rate(params) ||
+                   mop500_ab8500_channels != params_channels(params)) {
+                       mutex_unlock(&mop500_ab8500_params_lock);
+                       return -EBUSY;
+               }
+       } else {
+               mop500_ab8500_rate = params_rate(params);
+               mop500_ab8500_channels = params_channels(params);
+       }
+       __set_bit(cpu_dai->id, &mop500_ab8500_usage);
+       mutex_unlock(&mop500_ab8500_params_lock);
+
        channels = params_channels(params);
 
        switch (params_format(params)) {
@@ -338,9 +351,22 @@ int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+       mutex_lock(&mop500_ab8500_params_lock);
+       __clear_bit(cpu_dai->id, &mop500_ab8500_usage);
+       mutex_unlock(&mop500_ab8500_params_lock);
+
+       return 0;
+}
+
 struct snd_soc_ops mop500_ab8500_ops[] = {
        {
                .hw_params = mop500_ab8500_hw_params,
+               .hw_free = mop500_ab8500_hw_free,
                .startup = mop500_ab8500_startup,
                .shutdown = mop500_ab8500_shutdown,
        }
@@ -385,7 +411,7 @@ int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
        drvdata->mclk_sel = MCLK_ULPCLK;
 
        /* Add controls */
-       ret = snd_soc_add_codec_controls(codec, mop500_ab8500_ctrls,
+       ret = snd_soc_add_card_controls(codec->card, mop500_ab8500_ctrls,
                        ARRAY_SIZE(mop500_ab8500_ctrls));
        if (ret < 0) {
                pr_err("%s: Failed to add machine-controls (%d)!\n",
index 7d5fc13..c6fb5cc 100644 (file)
@@ -658,14 +658,11 @@ static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
 {
        struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
 
-       drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx;
-       drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx;
+       dai->playback_dma_data = &drvdata->msp->playback_dma_data;
+       dai->capture_dma_data = &drvdata->msp->capture_dma_data;
 
-       dai->playback_dma_data = &drvdata->playback_dma_data;
-       dai->capture_dma_data = &drvdata->capture_dma_data;
-
-       drvdata->playback_dma_data.data_size = drvdata->slot_width;
-       drvdata->capture_dma_data.data_size = drvdata->slot_width;
+       drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
+       drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
 
        return 0;
 }
index f531043..312ae53 100644 (file)
@@ -51,15 +51,11 @@ enum ux500_msp_clock_id {
 struct ux500_msp_i2s_drvdata {
        struct ux500_msp *msp;
        struct regulator *reg_vape;
-       struct ux500_msp_dma_params playback_dma_data;
-       struct ux500_msp_dma_params capture_dma_data;
        unsigned int fmt;
        unsigned int tx_mask;
        unsigned int rx_mask;
        int slots;
        int slot_width;
-       u8 configured;
-       int data_delay;
 
        /* Clocks */
        unsigned int master_clk;
index f2db6c9..1ca8b08 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -26,9 +25,6 @@
 
 #include "ux500_msp_i2s.h"
 
-/* MSP1/3 Tx/Rx usage protection */
-static DEFINE_SPINLOCK(msp_rxtx_lock);
-
  /* Protocol desciptors */
 static const struct msp_protdesc prot_descs[] = {
        { /* I2S */
@@ -356,24 +352,8 @@ static int configure_multichannel(struct ux500_msp *msp,
 
 static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
 {
-       int status = 0, retval = 0;
+       int status = 0;
        u32 reg_val_DMACR, reg_val_GCR;
-       unsigned long flags;
-
-       /* Check msp state whether in RUN or CONFIGURED Mode */
-       if (msp->msp_state == MSP_STATE_IDLE) {
-               spin_lock_irqsave(&msp_rxtx_lock, flags);
-               if (msp->pinctrl_rxtx_ref == 0 &&
-                       !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) {
-                       retval = pinctrl_select_state(msp->pinctrl_p,
-                                               msp->pinctrl_def);
-                       if (retval)
-                               pr_err("could not set MSP defstate\n");
-               }
-               if (!retval)
-                       msp->pinctrl_rxtx_ref++;
-               spin_unlock_irqrestore(&msp_rxtx_lock, flags);
-       }
 
        /* Configure msp with protocol dependent settings */
        configure_protocol(msp, config);
@@ -387,12 +367,14 @@ static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
        }
 
        /* Make sure the correct DMA-directions are configured */
-       if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) {
+       if ((config->direction & MSP_DIR_RX) &&
+                       !msp->capture_dma_data.dma_cfg) {
                dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
                        __func__);
                return -EINVAL;
        }
-       if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) {
+       if ((config->direction == MSP_DIR_TX) &&
+                       !msp->playback_dma_data.dma_cfg) {
                dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
                        __func__);
                return -EINVAL;
@@ -630,8 +612,7 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
 
 int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
 {
-       int status = 0, retval = 0;
-       unsigned long flags;
+       int status = 0;
 
        dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
 
@@ -643,18 +624,6 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
                               (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
                              msp->registers + MSP_GCR);
 
-               spin_lock_irqsave(&msp_rxtx_lock, flags);
-               WARN_ON(!msp->pinctrl_rxtx_ref);
-               msp->pinctrl_rxtx_ref--;
-               if (msp->pinctrl_rxtx_ref == 0 &&
-                       !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) {
-                       retval = pinctrl_select_state(msp->pinctrl_p,
-                                               msp->pinctrl_sleep);
-                       if (retval)
-                               pr_err("could not set MSP sleepstate\n");
-               }
-               spin_unlock_irqrestore(&msp_rxtx_lock, flags);
-
                writel(0, msp->registers + MSP_GCR);
                writel(0, msp->registers + MSP_TCF);
                writel(0, msp->registers + MSP_RCF);
@@ -682,7 +651,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
                        struct msp_i2s_platform_data *platform_data)
 {
        struct resource *res = NULL;
-       struct i2s_controller *i2s_cont;
        struct device_node *np = pdev->dev.of_node;
        struct ux500_msp *msp;
 
@@ -707,8 +675,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 
        msp->id = platform_data->id;
        msp->dev = &pdev->dev;
-       msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
-       msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+       msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
+       msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
@@ -717,6 +685,9 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       msp->playback_dma_data.tx_rx_addr = res->start + MSP_DR;
+       msp->capture_dma_data.tx_rx_addr = res->start + MSP_DR;
+
        msp->registers = devm_ioremap(&pdev->dev, res->start,
                                      resource_size(res));
        if (msp->registers == NULL) {
@@ -727,41 +698,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
        msp->msp_state = MSP_STATE_IDLE;
        msp->loopback_enable = 0;
 
-       /* I2S-controller is allocated and added in I2S controller class. */
-       i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
-       if (!i2s_cont) {
-               dev_err(&pdev->dev,
-                       "%s: ERROR: Failed to allocate I2S-controller!\n",
-                       __func__);
-               return -ENOMEM;
-       }
-       i2s_cont->dev.parent = &pdev->dev;
-       i2s_cont->data = (void *)msp;
-       i2s_cont->id = (s16)msp->id;
-       snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
-               msp->id);
-       dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
-       msp->i2s_cont = i2s_cont;
-
-       msp->pinctrl_p = pinctrl_get(msp->dev);
-       if (IS_ERR(msp->pinctrl_p))
-               dev_err(&pdev->dev, "could not get MSP pinctrl\n");
-       else {
-               msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p,
-                                               PINCTRL_STATE_DEFAULT);
-               if (IS_ERR(msp->pinctrl_def)) {
-                       dev_err(&pdev->dev,
-                               "could not get MSP defstate (%li)\n",
-                               PTR_ERR(msp->pinctrl_def));
-               }
-               msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p,
-                                               PINCTRL_STATE_SLEEP);
-               if (IS_ERR(msp->pinctrl_sleep))
-                       dev_err(&pdev->dev,
-                               "could not get MSP idlestate (%li)\n",
-                               PTR_ERR(msp->pinctrl_def));
-       }
-
        return 0;
 }
 
@@ -769,8 +705,6 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
                        struct ux500_msp *msp)
 {
        dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
-
-       device_unregister(&msp->i2s_cont->dev);
 }
 
 MODULE_LICENSE("GPL v2");
index e5cd105..258d0bc 100644 (file)
@@ -16,6 +16,7 @@
 #define UX500_MSP_I2S_H
 
 #include <linux/platform_device.h>
+#include <linux/platform_data/asoc-ux500-msp.h>
 
 #define MSP_INPUT_FREQ_APB 48000000
 
@@ -341,11 +342,6 @@ enum msp_compress_mode {
        MSP_COMPRESS_MODE_A_LAW = 3
 };
 
-enum msp_spi_burst_mode {
-       MSP_SPI_BURST_MODE_DISABLE = 0,
-       MSP_SPI_BURST_MODE_ENABLE = 1
-};
-
 enum msp_expand_mode {
        MSP_EXPAND_MODE_LINEAR = 0,
        MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
@@ -370,13 +366,6 @@ enum msp_protocol {
  */
 #define MAX_MSP_BACKUP_REGS 36
 
-enum enum_i2s_controller {
-       MSP_0_I2S_CONTROLLER = 0,
-       MSP_1_I2S_CONTROLLER,
-       MSP_2_I2S_CONTROLLER,
-       MSP_3_I2S_CONTROLLER,
-};
-
 enum i2s_direction_t {
        MSP_DIR_TX = 0x01,
        MSP_DIR_RX = 0x02,
@@ -454,32 +443,6 @@ struct msp_protdesc {
        u32 clocks_per_frame;
 };
 
-struct i2s_message {
-       enum i2s_direction_t i2s_direction;
-       void *txdata;
-       void *rxdata;
-       size_t txbytes;
-       size_t rxbytes;
-       int dma_flag;
-       int tx_offset;
-       int rx_offset;
-       bool cyclic_dma;
-       dma_addr_t buf_addr;
-       size_t buf_len;
-       size_t period_len;
-};
-
-struct i2s_controller {
-       struct module *owner;
-       unsigned int id;
-       unsigned int class;
-       const struct i2s_algorithm *algo; /* the algorithm to access the bus */
-       void *data;
-       struct mutex bus_lock;
-       struct device dev; /* the controller device */
-       char name[48];
-};
-
 struct ux500_msp_config {
        unsigned int f_inputclk;
        unsigned int rx_clk_sel;
@@ -491,8 +454,6 @@ struct ux500_msp_config {
        unsigned int tx_fsync_sel;
        unsigned int rx_fifo_config;
        unsigned int tx_fifo_config;
-       unsigned int spi_clk_mode;
-       unsigned int spi_burst_mode;
        unsigned int loopback_enable;
        unsigned int tx_data_enable;
        unsigned int default_protdesc;
@@ -502,43 +463,28 @@ struct ux500_msp_config {
        unsigned int direction;
        unsigned int protocol;
        unsigned int frame_freq;
-       unsigned int frame_size;
        enum msp_data_size data_size;
        unsigned int def_elem_len;
        unsigned int iodelay;
-       void (*handler) (void *data);
-       void *tx_callback_data;
-       void *rx_callback_data;
+};
+
+struct ux500_msp_dma_params {
+       unsigned int data_size;
+       dma_addr_t tx_rx_addr;
+       struct stedma40_chan_cfg *dma_cfg;
 };
 
 struct ux500_msp {
-       enum enum_i2s_controller id;
+       enum msp_i2s_id id;
        void __iomem *registers;
        struct device *dev;
-       struct i2s_controller *i2s_cont;
-       struct stedma40_chan_cfg *dma_cfg_rx;
-       struct stedma40_chan_cfg *dma_cfg_tx;
-       struct dma_chan *tx_pipeid;
-       struct dma_chan *rx_pipeid;
+       struct ux500_msp_dma_params playback_dma_data;
+       struct ux500_msp_dma_params capture_dma_data;
        enum msp_state msp_state;
-       int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
-       struct timer_list notify_timer;
        int def_elem_len;
        unsigned int dir_busy;
        int loopback_enable;
-       u32 backup_regs[MAX_MSP_BACKUP_REGS];
        unsigned int f_bitclk;
-       /* Pin modes */
-       struct pinctrl *pinctrl_p;
-       struct pinctrl_state *pinctrl_def;
-       struct pinctrl_state *pinctrl_sleep;
-       /* Reference Count */
-       int pinctrl_rxtx_ref;
-};
-
-struct ux500_msp_dma_params {
-       unsigned int data_size;
-       struct stedma40_chan_cfg *dma_cfg;
 };
 
 struct msp_i2s_platform_data;
index b6e5ae2..5f01c19 100644 (file)
@@ -103,10 +103,40 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
        return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
 }
 
+static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params,
+               struct dma_slave_config *slave_config)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ux500_msp_dma_params *dma_params;
+       struct stedma40_chan_cfg *dma_cfg;
+       int ret;
+
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       dma_cfg = dma_params->dma_cfg;
+
+       ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
+       if (ret)
+               return ret;
+
+       slave_config->dst_maxburst = 4;
+       slave_config->dst_addr_width = dma_cfg->dst_info.data_width;
+       slave_config->src_maxburst = 4;
+       slave_config->src_addr_width = dma_cfg->src_info.data_width;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               slave_config->dst_addr = dma_params->tx_rx_addr;
+       else
+               slave_config->src_addr = dma_params->tx_rx_addr;
+
+       return 0;
+}
+
 static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
        .pcm_hardware = &ux500_pcm_hw,
        .compat_request_channel = ux500_pcm_request_chan,
        .prealloc_buffer_size = 128 * 1024,
+       .prepare_slave_config = ux500_pcm_prepare_slave_config,
 };
 
 int ux500_pcm_register_platform(struct platform_device *pdev)
index 75e6016..eee7afc 100644 (file)
@@ -2670,8 +2670,6 @@ static int dbri_remove(struct platform_device *op)
        snd_dbri_free(card->private_data);
        snd_card_free(card);
 
-       dev_set_drvdata(&op->dev, NULL);
-
        return 0;
 }
 
index a1a24b9..8e3d9a6 100644 (file)
@@ -1070,7 +1070,6 @@ out:
 
        ssc_free(chip->ssc);
        snd_card_free(card);
-       dev_set_drvdata(&spi->dev, NULL);
 
        return 0;
 }
index 4394ae7..c39c779 100644 (file)
@@ -30,7 +30,7 @@
 MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
 MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
+MODULE_SUPPORTED_DEVICE("{{TerraTec,DMX 6Fire USB}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
index 40dd50a..c5b9cac 100644 (file)
@@ -450,13 +450,13 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
 static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
                struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_lib_malloc_pages(alsa_sub,
-                       params_buffer_bytes(hw_params));
+       return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+                                               params_buffer_bytes(hw_params));
 }
 
 static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
 {
-       return snd_pcm_lib_free_pages(alsa_sub);
+       return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
 }
 
 static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
@@ -560,6 +560,8 @@ static struct snd_pcm_ops pcm_ops = {
        .prepare = usb6fire_pcm_prepare,
        .trigger = usb6fire_pcm_trigger,
        .pointer = usb6fire_pcm_pointer,
+       .page = snd_pcm_lib_get_vmalloc_page,
+       .mmap = snd_pcm_lib_mmap_vmalloc,
 };
 
 static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
@@ -622,10 +624,6 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
 
-       ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                       SNDRV_DMA_TYPE_CONTINUOUS,
-                       snd_dma_continuous_data(GFP_KERNEL),
-                       MAX_BUFSIZE, MAX_BUFSIZE);
        if (ret) {
                kfree(rt);
                snd_printk(KERN_ERR PREFIX
index 225dfd7..de9408b 100644 (file)
@@ -115,5 +115,36 @@ config SND_USB_6FIRE
           and further help can be found at
           http://sixfireusb.sourceforge.net
 
+config SND_USB_HIFACE
+        tristate "M2Tech hiFace USB-SPDIF driver"
+        select SND_PCM
+        help
+         Select this option to include support for M2Tech hiFace USB-SPDIF
+         interface.
+
+         This driver supports the original M2Tech hiFace and some other
+         compatible devices. The supported products are:
+
+           * M2Tech Young
+           * M2Tech hiFace
+           * M2Tech North Star
+           * M2Tech W4S Young
+           * M2Tech Corrson
+           * M2Tech AUDIA
+           * M2Tech SL Audio
+           * M2Tech Empirical
+           * M2Tech Rockna
+           * M2Tech Pathos
+           * M2Tech Metronome
+           * M2Tech CAD
+           * M2Tech Audio Esclusive
+           * M2Tech Rotel
+           * M2Tech Eeaudio
+           * The Chord Company CHORD
+           * AVA Group A/S Vitus
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-usb-hiface.
+
 endif  # SND_USB
 
index ac256dc..abe668f 100644 (file)
@@ -23,4 +23,4 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
 
-obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/
+obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/
index c191618..7103b09 100644 (file)
@@ -183,14 +183,15 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
                                       struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
+       return snd_pcm_lib_alloc_vmalloc_buffer(sub,
+                                               params_buffer_bytes(hw_params));
 }
 
 static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 {
        struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
        deactivate_substream(cdev, sub);
-       return snd_pcm_lib_free_pages(sub);
+       return snd_pcm_lib_free_vmalloc_buffer(sub);
 }
 
 /* this should probably go upstream */
@@ -345,7 +346,9 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {
        .hw_free =      snd_usb_caiaq_pcm_hw_free,
        .prepare =      snd_usb_caiaq_pcm_prepare,
        .trigger =      snd_usb_caiaq_pcm_trigger,
-       .pointer =      snd_usb_caiaq_pcm_pointer
+       .pointer =      snd_usb_caiaq_pcm_pointer,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
@@ -852,11 +855,6 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
        snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &snd_usb_caiaq_ops);
 
-       snd_pcm_lib_preallocate_pages_for_all(cdev->pcm,
-                                       SNDRV_DMA_TYPE_CONTINUOUS,
-                                       snd_dma_continuous_data(GFP_KERNEL),
-                                       MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
-
        cdev->data_cb_info =
                kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
                                        GFP_KERNEL);
index 48b63cc..1a61dd1 100644 (file)
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("caiaq USB audio");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
-                        "{Native Instruments, RigKontrol3},"
-                        "{Native Instruments, Kore Controller},"
-                        "{Native Instruments, Kore Controller 2},"
-                        "{Native Instruments, Audio Kontrol 1},"
-                        "{Native Instruments, Audio 2 DJ},"
-                        "{Native Instruments, Audio 4 DJ},"
-                        "{Native Instruments, Audio 8 DJ},"
-                        "{Native Instruments, Traktor Audio 2},"
-                        "{Native Instruments, Session I/O},"
-                        "{Native Instruments, GuitarRig mobile},"
-                        "{Native Instruments, Traktor Kontrol X1},"
-                        "{Native Instruments, Traktor Kontrol S4},"
-                        "{Native Instruments, Maschine Controller}}");
+MODULE_SUPPORTED_DEVICE("{{Native Instruments,RigKontrol2},"
+                        "{Native Instruments,RigKontrol3},"
+                        "{Native Instruments,Kore Controller},"
+                        "{Native Instruments,Kore Controller 2},"
+                        "{Native Instruments,Audio Kontrol 1},"
+                        "{Native Instruments,Audio 2 DJ},"
+                        "{Native Instruments,Audio 4 DJ},"
+                        "{Native Instruments,Audio 8 DJ},"
+                        "{Native Instruments,Traktor Audio 2},"
+                        "{Native Instruments,Session I/O},"
+                        "{Native Instruments,GuitarRig mobile},"
+                        "{Native Instruments,Traktor Kontrol X1},"
+                        "{Native Instruments,Traktor Kontrol S4},"
+                        "{Native Instruments,Maschine Controller}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int snd_card_used[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the caiaq sound device");
@@ -388,7 +387,7 @@ static int create_card(struct usb_device *usb_dev,
        struct snd_usb_caiaqdev *cdev;
 
        for (devnum = 0; devnum < SNDRV_CARDS; devnum++)
-               if (enable[devnum] && !snd_card_used[devnum])
+               if (enable[devnum])
                        break;
 
        if (devnum >= SNDRV_CARDS)
index bf2889a..5ecacaa 100644 (file)
@@ -21,6 +21,7 @@ struct audioformat {
        unsigned char endpoint;         /* endpoint */
        unsigned char ep_attr;          /* endpoint attributes */
        unsigned char datainterval;     /* log_2 of data packet interval */
+       unsigned char protocol;         /* UAC_VERSION_1/2 */
        unsigned int maxpacksize;       /* max. packet size */
        unsigned int rates;             /* rate bitmasks */
        unsigned int rate_min, rate_max;        /* min/max rates */
index 3a2ce39..86f80c6 100644 (file)
@@ -407,9 +407,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
                             struct usb_host_interface *alts,
                             struct audioformat *fmt, int rate)
 {
-       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
-       switch (altsd->bInterfaceProtocol) {
+       switch (fmt->protocol) {
        case UAC_VERSION_1:
        default:
                return set_sample_rate_v1(chip, iface, alts, fmt, rate);
index 99299ff..3525231 100644 (file)
  */
 static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                                     struct audioformat *fp,
-                                    unsigned int format, void *_fmt,
-                                    int protocol)
+                                    unsigned int format, void *_fmt)
 {
        int sample_width, sample_bytes;
        u64 pcm_formats = 0;
 
-       switch (protocol) {
+       switch (fp->protocol) {
        case UAC_VERSION_1:
        default: {
                struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
@@ -360,11 +359,8 @@ err:
  */
 static int parse_audio_format_i(struct snd_usb_audio *chip,
                                struct audioformat *fp, unsigned int format,
-                               struct uac_format_type_i_continuous_descriptor *fmt,
-                               struct usb_host_interface *iface)
+                               struct uac_format_type_i_continuous_descriptor *fmt)
 {
-       struct usb_interface_descriptor *altsd = get_iface_desc(iface);
-       int protocol = altsd->bInterfaceProtocol;
        snd_pcm_format_t pcm_format;
        int ret;
 
@@ -387,8 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
                }
                fp->formats = pcm_format_to_bits(pcm_format);
        } else {
-               fp->formats = parse_audio_format_i_type(chip, fp, format,
-                                                       fmt, protocol);
+               fp->formats = parse_audio_format_i_type(chip, fp, format, fmt);
                if (!fp->formats)
                        return -EINVAL;
        }
@@ -398,11 +393,8 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
         * proprietary class specific descriptor.
         * audio class v2 uses class specific EP0 range requests for that.
         */
-       switch (protocol) {
+       switch (fp->protocol) {
        default:
-               snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, protocol);
-               /* fall through */
        case UAC_VERSION_1:
                fp->channels = fmt->bNrChannels;
                ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
@@ -427,12 +419,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
  */
 static int parse_audio_format_ii(struct snd_usb_audio *chip,
                                 struct audioformat *fp,
-                                int format, void *_fmt,
-                                struct usb_host_interface *iface)
+                                int format, void *_fmt)
 {
        int brate, framesize, ret;
-       struct usb_interface_descriptor *altsd = get_iface_desc(iface);
-       int protocol = altsd->bInterfaceProtocol;
 
        switch (format) {
        case UAC_FORMAT_TYPE_II_AC3:
@@ -452,11 +441,8 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 
        fp->channels = 1;
 
-       switch (protocol) {
+       switch (fp->protocol) {
        default:
-               snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, protocol);
-               /* fall through */
        case UAC_VERSION_1: {
                struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
                brate = le16_to_cpu(fmt->wMaxBitRate);
@@ -483,17 +469,17 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
                               struct audioformat *fp, unsigned int format,
                               struct uac_format_type_i_continuous_descriptor *fmt,
-                              int stream, struct usb_host_interface *iface)
+                              int stream)
 {
        int err;
 
        switch (fmt->bFormatType) {
        case UAC_FORMAT_TYPE_I:
        case UAC_FORMAT_TYPE_III:
-               err = parse_audio_format_i(chip, fp, format, fmt, iface);
+               err = parse_audio_format_i(chip, fp, format, fmt);
                break;
        case UAC_FORMAT_TYPE_II:
-               err = parse_audio_format_ii(chip, fp, format, fmt, iface);
+               err = parse_audio_format_ii(chip, fp, format, fmt);
                break;
        default:
                snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
index 6f31522..4b8a011 100644 (file)
@@ -4,6 +4,6 @@
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
                               struct audioformat *fp, unsigned int format,
                               struct uac_format_type_i_continuous_descriptor *fmt,
-                              int stream, struct usb_host_interface *iface);
+                              int stream);
 
 #endif /*  __USBAUDIO_FORMAT_H */
diff --git a/sound/usb/hiface/Makefile b/sound/usb/hiface/Makefile
new file mode 100644 (file)
index 0000000..463b136
--- /dev/null
@@ -0,0 +1,2 @@
+snd-usb-hiface-objs := chip.o pcm.o
+obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o
diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c
new file mode 100644 (file)
index 0000000..b0dcb39
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * 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/module.h>
+#include <linux/slab.h>
+#include <sound/initval.h>
+
+#include "chip.h"
+#include "pcm.h"
+
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
+MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{M2Tech,Young},"
+                        "{M2Tech,hiFace},"
+                        "{M2Tech,North Star},"
+                        "{M2Tech,W4S Young},"
+                        "{M2Tech,Corrson},"
+                        "{M2Tech,AUDIA},"
+                        "{M2Tech,SL Audio},"
+                        "{M2Tech,Empirical},"
+                        "{M2Tech,Rockna},"
+                        "{M2Tech,Pathos},"
+                        "{M2Tech,Metronome},"
+                        "{M2Tech,CAD},"
+                        "{M2Tech,Audio Esclusive},"
+                        "{M2Tech,Rotel},"
+                        "{M2Tech,Eeaudio},"
+                        "{The Chord Company,CHORD},"
+                        "{AVA Group A/S,Vitus}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
+
+#define DRIVER_NAME "snd-usb-hiface"
+#define CARD_NAME "hiFace"
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+static DEFINE_MUTEX(register_mutex);
+
+struct hiface_vendor_quirk {
+       const char *device_name;
+       u8 extra_freq;
+};
+
+static int hiface_chip_create(struct usb_device *device, int idx,
+                             const struct hiface_vendor_quirk *quirk,
+                             struct hiface_chip **rchip)
+{
+       struct snd_card *card = NULL;
+       struct hiface_chip *chip;
+       int ret;
+       int len;
+
+       *rchip = NULL;
+
+       /* if we are here, card can be registered in alsa. */
+       ret = snd_card_create(index[idx], id[idx], THIS_MODULE, sizeof(*chip), &card);
+       if (ret < 0) {
+               dev_err(&device->dev, "cannot create alsa card.\n");
+               return ret;
+       }
+
+       strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+
+       if (quirk && quirk->device_name)
+               strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname));
+       else
+               strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
+
+       strlcat(card->longname, card->shortname, sizeof(card->longname));
+       len = strlcat(card->longname, " at ", sizeof(card->longname));
+       if (len < sizeof(card->longname))
+               usb_make_path(device, card->longname + len,
+                             sizeof(card->longname) - len);
+
+       chip = card->private_data;
+       chip->dev = device;
+       chip->card = card;
+
+       *rchip = chip;
+       return 0;
+}
+
+static int hiface_chip_probe(struct usb_interface *intf,
+                            const struct usb_device_id *usb_id)
+{
+       const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
+       int ret;
+       int i;
+       struct hiface_chip *chip;
+       struct usb_device *device = interface_to_usbdev(intf);
+
+       ret = usb_set_interface(device, 0, 0);
+       if (ret != 0) {
+               dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
+               return -EIO;
+       }
+
+       /* check whether the card is already registered */
+       chip = NULL;
+       mutex_lock(&register_mutex);
+
+       for (i = 0; i < SNDRV_CARDS; i++)
+               if (enable[i])
+                       break;
+
+       if (i >= SNDRV_CARDS) {
+               dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ret = hiface_chip_create(device, i, quirk, &chip);
+       if (ret < 0)
+               goto err;
+
+       snd_card_set_dev(chip->card, &intf->dev);
+
+       ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
+       if (ret < 0)
+               goto err_chip_destroy;
+
+       ret = snd_card_register(chip->card);
+       if (ret < 0) {
+               dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
+               goto err_chip_destroy;
+       }
+
+       mutex_unlock(&register_mutex);
+
+       usb_set_intfdata(intf, chip);
+       return 0;
+
+err_chip_destroy:
+       snd_card_free(chip->card);
+err:
+       mutex_unlock(&register_mutex);
+       return ret;
+}
+
+static void hiface_chip_disconnect(struct usb_interface *intf)
+{
+       struct hiface_chip *chip;
+       struct snd_card *card;
+
+       chip = usb_get_intfdata(intf);
+       if (!chip)
+               return;
+
+       card = chip->card;
+
+       /* Make sure that the userspace cannot create new request */
+       snd_card_disconnect(card);
+
+       hiface_pcm_abort(chip);
+       snd_card_free_when_closed(card);
+}
+
+static const struct usb_device_id device_table[] = {
+       {
+               USB_DEVICE(0x04b4, 0x0384),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Young",
+                       .extra_freq = 1,
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x930b),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "hiFace",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931b),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "North Star",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "W4S Young",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931d),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Corrson",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931e),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "AUDIA",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931f),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "SL Audio",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x9320),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Empirical",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x9321),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Rockna",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9001),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Pathos",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9002),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Metronome",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9006),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "CAD",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9008),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Audio Esclusive",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x931c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Rotel",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x932c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Eeaudio",
+               }
+       },
+       {
+               USB_DEVICE(0x245f, 0x931c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "CHORD",
+               }
+       },
+       {
+               USB_DEVICE(0x25c6, 0x9002),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Vitus",
+               }
+       },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static struct usb_driver hiface_usb_driver = {
+       .name = DRIVER_NAME,
+       .probe = hiface_chip_probe,
+       .disconnect = hiface_chip_disconnect,
+       .id_table = device_table,
+};
+
+module_usb_driver(hiface_usb_driver);
diff --git a/sound/usb/hiface/chip.h b/sound/usb/hiface/chip.h
new file mode 100644 (file)
index 0000000..189a137
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * 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.
+ */
+
+#ifndef HIFACE_CHIP_H
+#define HIFACE_CHIP_H
+
+#include <linux/usb.h>
+#include <sound/core.h>
+
+struct pcm_runtime;
+
+struct hiface_chip {
+       struct usb_device *dev;
+       struct snd_card *card;
+       struct pcm_runtime *pcm;
+};
+#endif /* HIFACE_CHIP_H */
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
new file mode 100644 (file)
index 0000000..6430ed2
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * 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/slab.h>
+#include <sound/pcm.h>
+
+#include "pcm.h"
+#include "chip.h"
+
+#define OUT_EP          0x2
+#define PCM_N_URBS      8
+#define PCM_PACKET_SIZE 4096
+#define PCM_BUFFER_SIZE (2 * PCM_N_URBS * PCM_PACKET_SIZE)
+
+struct pcm_urb {
+       struct hiface_chip *chip;
+
+       struct urb instance;
+       struct usb_anchor submitted;
+       u8 *buffer;
+};
+
+struct pcm_substream {
+       spinlock_t lock;
+       struct snd_pcm_substream *instance;
+
+       bool active;
+       snd_pcm_uframes_t dma_off;    /* current position in alsa dma_area */
+       snd_pcm_uframes_t period_off; /* current position in current period */
+};
+
+enum { /* pcm streaming states */
+       STREAM_DISABLED, /* no pcm streaming */
+       STREAM_STARTING, /* pcm streaming requested, waiting to become ready */
+       STREAM_RUNNING,  /* pcm streaming running */
+       STREAM_STOPPING
+};
+
+struct pcm_runtime {
+       struct hiface_chip *chip;
+       struct snd_pcm *instance;
+
+       struct pcm_substream playback;
+       bool panic; /* if set driver won't do anymore pcm on device */
+
+       struct pcm_urb out_urbs[PCM_N_URBS];
+
+       struct mutex stream_mutex;
+       u8 stream_state; /* one of STREAM_XXX */
+       u8 extra_freq;
+       wait_queue_head_t stream_wait_queue;
+       bool stream_wait_cond;
+};
+
+static const unsigned int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000,
+                                     352800, 384000 };
+static const struct snd_pcm_hw_constraint_list constraints_extra_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static const struct snd_pcm_hardware pcm_hw = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BATCH,
+
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+
+       .rates = SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000 |
+               SNDRV_PCM_RATE_88200 |
+               SNDRV_PCM_RATE_96000 |
+               SNDRV_PCM_RATE_176400 |
+               SNDRV_PCM_RATE_192000,
+
+       .rate_min = 44100,
+       .rate_max = 192000, /* changes in hiface_pcm_open to support extra rates */
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = PCM_BUFFER_SIZE,
+       .period_bytes_min = PCM_PACKET_SIZE,
+       .period_bytes_max = PCM_BUFFER_SIZE,
+       .periods_min = 2,
+       .periods_max = 1024
+};
+
+/* message values used to change the sample rate */
+#define HIFACE_SET_RATE_REQUEST 0xb0
+
+#define HIFACE_RATE_44100  0x43
+#define HIFACE_RATE_48000  0x4b
+#define HIFACE_RATE_88200  0x42
+#define HIFACE_RATE_96000  0x4a
+#define HIFACE_RATE_176400 0x40
+#define HIFACE_RATE_192000 0x48
+#define HIFACE_RATE_352000 0x58
+#define HIFACE_RATE_384000 0x68
+
+static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate)
+{
+       struct usb_device *device = rt->chip->dev;
+       u16 rate_value;
+       int ret;
+
+       /* We are already sure that the rate is supported here thanks to
+        * ALSA constraints
+        */
+       switch (rate) {
+       case 44100:
+               rate_value = HIFACE_RATE_44100;
+               break;
+       case 48000:
+               rate_value = HIFACE_RATE_48000;
+               break;
+       case 88200:
+               rate_value = HIFACE_RATE_88200;
+               break;
+       case 96000:
+               rate_value = HIFACE_RATE_96000;
+               break;
+       case 176400:
+               rate_value = HIFACE_RATE_176400;
+               break;
+       case 192000:
+               rate_value = HIFACE_RATE_192000;
+               break;
+       case 352000:
+               rate_value = HIFACE_RATE_352000;
+               break;
+       case 384000:
+               rate_value = HIFACE_RATE_384000;
+               break;
+       default:
+               dev_err(&device->dev, "Unsupported rate %d\n", rate);
+               return -EINVAL;
+       }
+
+       /*
+        * USBIO: Vendor 0xb0(wValue=0x0043, wIndex=0x0000)
+        * 43 b0 43 00 00 00 00 00
+        * USBIO: Vendor 0xb0(wValue=0x004b, wIndex=0x0000)
+        * 43 b0 4b 00 00 00 00 00
+        * This control message doesn't have any ack from the
+        * other side
+        */
+       ret = usb_control_msg(device, usb_sndctrlpipe(device, 0),
+                             HIFACE_SET_RATE_REQUEST,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             rate_value, 0, NULL, 0, 100);
+       if (ret < 0) {
+               dev_err(&device->dev, "Error setting samplerate %d.\n", rate);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream
+                                                     *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct device *device = &rt->chip->dev->dev;
+
+       if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return &rt->playback;
+
+       dev_err(device, "Error getting pcm substream slot.\n");
+       return NULL;
+}
+
+/* call with stream_mutex locked */
+static void hiface_pcm_stream_stop(struct pcm_runtime *rt)
+{
+       int i, time;
+
+       if (rt->stream_state != STREAM_DISABLED) {
+               rt->stream_state = STREAM_STOPPING;
+
+               for (i = 0; i < PCM_N_URBS; i++) {
+                       time = usb_wait_anchor_empty_timeout(
+                                       &rt->out_urbs[i].submitted, 100);
+                       if (!time)
+                               usb_kill_anchored_urbs(
+                                       &rt->out_urbs[i].submitted);
+                       usb_kill_urb(&rt->out_urbs[i].instance);
+               }
+
+               rt->stream_state = STREAM_DISABLED;
+       }
+}
+
+/* call with stream_mutex locked */
+static int hiface_pcm_stream_start(struct pcm_runtime *rt)
+{
+       int ret = 0;
+       int i;
+
+       if (rt->stream_state == STREAM_DISABLED) {
+
+               /* reset panic state when starting a new stream */
+               rt->panic = false;
+
+               /* submit our out urbs zero init */
+               rt->stream_state = STREAM_STARTING;
+               for (i = 0; i < PCM_N_URBS; i++) {
+                       memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE);
+                       usb_anchor_urb(&rt->out_urbs[i].instance,
+                                      &rt->out_urbs[i].submitted);
+                       ret = usb_submit_urb(&rt->out_urbs[i].instance,
+                                            GFP_ATOMIC);
+                       if (ret) {
+                               hiface_pcm_stream_stop(rt);
+                               return ret;
+                       }
+               }
+
+               /* wait for first out urb to return (sent in in urb handler) */
+               wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
+                                  HZ);
+               if (rt->stream_wait_cond) {
+                       struct device *device = &rt->chip->dev->dev;
+                       dev_dbg(device, "%s: Stream is running wakeup event\n",
+                                __func__);
+                       rt->stream_state = STREAM_RUNNING;
+               } else {
+                       hiface_pcm_stream_stop(rt);
+                       return -EIO;
+               }
+       }
+       return ret;
+}
+
+/* The hardware wants word-swapped 32-bit values */
+static void memcpy_swahw32(u8 *dest, u8 *src, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n / 4; i++)
+               ((u32 *)dest)[i] = swahw32(((u32 *)src)[i]);
+}
+
+/* call with substream locked */
+/* returns true if a period elapsed */
+static bool hiface_pcm_playback(struct pcm_substream *sub, struct pcm_urb *urb)
+{
+       struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
+       struct device *device = &urb->chip->dev->dev;
+       u8 *source;
+       unsigned int pcm_buffer_size;
+
+       WARN_ON(alsa_rt->format != SNDRV_PCM_FORMAT_S32_LE);
+
+       pcm_buffer_size = snd_pcm_lib_buffer_bytes(sub->instance);
+
+       if (sub->dma_off + PCM_PACKET_SIZE <= pcm_buffer_size) {
+               dev_dbg(device, "%s: (1) buffer_size %#x dma_offset %#x\n", __func__,
+                        (unsigned int) pcm_buffer_size,
+                        (unsigned int) sub->dma_off);
+
+               source = alsa_rt->dma_area + sub->dma_off;
+               memcpy_swahw32(urb->buffer, source, PCM_PACKET_SIZE);
+       } else {
+               /* wrap around at end of ring buffer */
+               unsigned int len;
+
+               dev_dbg(device, "%s: (2) buffer_size %#x dma_offset %#x\n", __func__,
+                        (unsigned int) pcm_buffer_size,
+                        (unsigned int) sub->dma_off);
+
+               len = pcm_buffer_size - sub->dma_off;
+
+               source = alsa_rt->dma_area + sub->dma_off;
+               memcpy_swahw32(urb->buffer, source, len);
+
+               source = alsa_rt->dma_area;
+               memcpy_swahw32(urb->buffer + len, source,
+                              PCM_PACKET_SIZE - len);
+       }
+       sub->dma_off += PCM_PACKET_SIZE;
+       if (sub->dma_off >= pcm_buffer_size)
+               sub->dma_off -= pcm_buffer_size;
+
+       sub->period_off += PCM_PACKET_SIZE;
+       if (sub->period_off >= alsa_rt->period_size) {
+               sub->period_off %= alsa_rt->period_size;
+               return true;
+       }
+       return false;
+}
+
+static void hiface_pcm_out_urb_handler(struct urb *usb_urb)
+{
+       struct pcm_urb *out_urb = usb_urb->context;
+       struct pcm_runtime *rt = out_urb->chip->pcm;
+       struct pcm_substream *sub;
+       bool do_period_elapsed = false;
+       unsigned long flags;
+       int ret;
+
+       if (rt->panic || rt->stream_state == STREAM_STOPPING)
+               return;
+
+       if (unlikely(usb_urb->status == -ENOENT ||      /* unlinked */
+                    usb_urb->status == -ENODEV ||      /* device removed */
+                    usb_urb->status == -ECONNRESET ||  /* unlinked */
+                    usb_urb->status == -ESHUTDOWN)) {  /* device disabled */
+               goto out_fail;
+       }
+
+       if (rt->stream_state == STREAM_STARTING) {
+               rt->stream_wait_cond = true;
+               wake_up(&rt->stream_wait_queue);
+       }
+
+       /* now send our playback data (if a free out urb was found) */
+       sub = &rt->playback;
+       spin_lock_irqsave(&sub->lock, flags);
+       if (sub->active)
+               do_period_elapsed = hiface_pcm_playback(sub, out_urb);
+       else
+               memset(out_urb->buffer, 0, PCM_PACKET_SIZE);
+
+       spin_unlock_irqrestore(&sub->lock, flags);
+
+       if (do_period_elapsed)
+               snd_pcm_period_elapsed(sub->instance);
+
+       ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
+       if (ret < 0)
+               goto out_fail;
+
+       return;
+
+out_fail:
+       rt->panic = true;
+}
+
+static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct pcm_substream *sub = NULL;
+       struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+       int ret;
+
+       if (rt->panic)
+               return -EPIPE;
+
+       mutex_lock(&rt->stream_mutex);
+       alsa_rt->hw = pcm_hw;
+
+       if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               sub = &rt->playback;
+
+       if (!sub) {
+               struct device *device = &rt->chip->dev->dev;
+               mutex_unlock(&rt->stream_mutex);
+               dev_err(device, "Invalid stream type\n");
+               return -EINVAL;
+       }
+
+       if (rt->extra_freq) {
+               alsa_rt->hw.rates |= SNDRV_PCM_RATE_KNOT;
+               alsa_rt->hw.rate_max = 384000;
+
+               /* explicit constraints needed as we added SNDRV_PCM_RATE_KNOT */
+               ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0,
+                                                SNDRV_PCM_HW_PARAM_RATE,
+                                                &constraints_extra_rates);
+               if (ret < 0) {
+                       mutex_unlock(&rt->stream_mutex);
+                       return ret;
+               }
+       }
+
+       sub->instance = alsa_sub;
+       sub->active = false;
+       mutex_unlock(&rt->stream_mutex);
+       return 0;
+}
+
+static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       unsigned long flags;
+
+       if (rt->panic)
+               return 0;
+
+       mutex_lock(&rt->stream_mutex);
+       if (sub) {
+               hiface_pcm_stream_stop(rt);
+
+               /* deactivate substream */
+               spin_lock_irqsave(&sub->lock, flags);
+               sub->instance = NULL;
+               sub->active = false;
+               spin_unlock_irqrestore(&sub->lock, flags);
+
+       }
+       mutex_unlock(&rt->stream_mutex);
+       return 0;
+}
+
+static int hiface_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
+                               struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+                                               params_buffer_bytes(hw_params));
+}
+
+static int hiface_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
+{
+       return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
+}
+
+static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+       int ret;
+
+       if (rt->panic)
+               return -EPIPE;
+       if (!sub)
+               return -ENODEV;
+
+       mutex_lock(&rt->stream_mutex);
+
+       sub->dma_off = 0;
+       sub->period_off = 0;
+
+       if (rt->stream_state == STREAM_DISABLED) {
+
+               ret = hiface_pcm_set_rate(rt, alsa_rt->rate);
+               if (ret) {
+                       mutex_unlock(&rt->stream_mutex);
+                       return ret;
+               }
+               ret = hiface_pcm_stream_start(rt);
+               if (ret) {
+                       mutex_unlock(&rt->stream_mutex);
+                       return ret;
+               }
+       }
+       mutex_unlock(&rt->stream_mutex);
+       return 0;
+}
+
+static int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd)
+{
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+
+       if (rt->panic)
+               return -EPIPE;
+       if (!sub)
+               return -ENODEV;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irq(&sub->lock);
+               sub->active = true;
+               spin_unlock_irq(&sub->lock);
+               return 0;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irq(&sub->lock);
+               sub->active = false;
+               spin_unlock_irq(&sub->lock);
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       unsigned long flags;
+       snd_pcm_uframes_t dma_offset;
+
+       if (rt->panic || !sub)
+               return SNDRV_PCM_STATE_XRUN;
+
+       spin_lock_irqsave(&sub->lock, flags);
+       dma_offset = sub->dma_off;
+       spin_unlock_irqrestore(&sub->lock, flags);
+       return bytes_to_frames(alsa_sub->runtime, dma_offset);
+}
+
+static struct snd_pcm_ops pcm_ops = {
+       .open = hiface_pcm_open,
+       .close = hiface_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = hiface_pcm_hw_params,
+       .hw_free = hiface_pcm_hw_free,
+       .prepare = hiface_pcm_prepare,
+       .trigger = hiface_pcm_trigger,
+       .pointer = hiface_pcm_pointer,
+       .page = snd_pcm_lib_get_vmalloc_page,
+       .mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static int hiface_pcm_init_urb(struct pcm_urb *urb,
+                              struct hiface_chip *chip,
+                              unsigned int ep,
+                              void (*handler)(struct urb *))
+{
+       urb->chip = chip;
+       usb_init_urb(&urb->instance);
+
+       urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL);
+       if (!urb->buffer)
+               return -ENOMEM;
+
+       usb_fill_bulk_urb(&urb->instance, chip->dev,
+                         usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer,
+                         PCM_PACKET_SIZE, handler, urb);
+       init_usb_anchor(&urb->submitted);
+
+       return 0;
+}
+
+void hiface_pcm_abort(struct hiface_chip *chip)
+{
+       struct pcm_runtime *rt = chip->pcm;
+
+       if (rt) {
+               rt->panic = true;
+
+               mutex_lock(&rt->stream_mutex);
+               hiface_pcm_stream_stop(rt);
+               mutex_unlock(&rt->stream_mutex);
+       }
+}
+
+static void hiface_pcm_destroy(struct hiface_chip *chip)
+{
+       struct pcm_runtime *rt = chip->pcm;
+       int i;
+
+       for (i = 0; i < PCM_N_URBS; i++)
+               kfree(rt->out_urbs[i].buffer);
+
+       kfree(chip->pcm);
+       chip->pcm = NULL;
+}
+
+static void hiface_pcm_free(struct snd_pcm *pcm)
+{
+       struct pcm_runtime *rt = pcm->private_data;
+
+       if (rt)
+               hiface_pcm_destroy(rt->chip);
+}
+
+int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
+{
+       int i;
+       int ret;
+       struct snd_pcm *pcm;
+       struct pcm_runtime *rt;
+
+       rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+       if (!rt)
+               return -ENOMEM;
+
+       rt->chip = chip;
+       rt->stream_state = STREAM_DISABLED;
+       if (extra_freq)
+               rt->extra_freq = 1;
+
+       init_waitqueue_head(&rt->stream_wait_queue);
+       mutex_init(&rt->stream_mutex);
+       spin_lock_init(&rt->playback.lock);
+
+       for (i = 0; i < PCM_N_URBS; i++)
+               hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP,
+                                   hiface_pcm_out_urb_handler);
+
+       ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm);
+       if (ret < 0) {
+               kfree(rt);
+               dev_err(&chip->dev->dev, "Cannot create pcm instance\n");
+               return ret;
+       }
+
+       pcm->private_data = rt;
+       pcm->private_free = hiface_pcm_free;
+
+       strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
+
+       rt->instance = pcm;
+
+       chip->pcm = rt;
+       return 0;
+}
diff --git a/sound/usb/hiface/pcm.h b/sound/usb/hiface/pcm.h
new file mode 100644 (file)
index 0000000..77edd7c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * 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.
+ */
+
+#ifndef HIFACE_PCM_H
+#define HIFACE_PCM_H
+
+struct hiface_chip;
+
+int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq);
+void hiface_pcm_abort(struct hiface_chip *chip);
+#endif /* HIFACE_PCM_H */
index 8e01fa4..b901f46 100644 (file)
@@ -1575,8 +1575,41 @@ static struct port_info {
        EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),
        EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),
        EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),
+       /* BOSS GT-PRO */
+       CONTROL_PORT(0x0582, 0x0089, 0, "%s Control"),
        /* Edirol UM-3EX */
        CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),
+       /* Roland VG-99 */
+       CONTROL_PORT(0x0582, 0x00b2, 0, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x00b2, 1, "%s MIDI"),
+       /* Cakewalk Sonar V-Studio 100 */
+       EXTERNAL_PORT(0x0582, 0x00eb, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x00eb, 1, "%s Control"),
+       /* Roland VB-99 */
+       CONTROL_PORT(0x0582, 0x0102, 0, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x0102, 1, "%s MIDI"),
+       /* Roland A-PRO */
+       EXTERNAL_PORT(0x0582, 0x010f, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x010f, 1, "%s 1"),
+       CONTROL_PORT(0x0582, 0x010f, 2, "%s 2"),
+       /* Roland SD-50 */
+       ROLAND_SYNTH_PORT(0x0582, 0x0114, 0, "%s Synth", 128),
+       EXTERNAL_PORT(0x0582, 0x0114, 1, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0114, 2, "%s Control"),
+       /* Roland OCTA-CAPTURE */
+       EXTERNAL_PORT(0x0582, 0x0120, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0120, 1, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x0121, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0121, 1, "%s Control"),
+       /* Roland SPD-SX */
+       CONTROL_PORT(0x0582, 0x0145, 0, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x0145, 1, "%s MIDI"),
+       /* Roland A-Series */
+       CONTROL_PORT(0x0582, 0x0156, 0, "%s Keyboard"),
+       EXTERNAL_PORT(0x0582, 0x0156, 1, "%s MIDI"),
+       /* Roland INTEGRA-7 */
+       ROLAND_SYNTH_PORT(0x0582, 0x015b, 0, "%s Synth", 128),
+       CONTROL_PORT(0x0582, 0x015b, 1, "%s Control"),
        /* M-Audio MidiSport 8x8 */
        CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),
        CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),
@@ -1947,6 +1980,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
        return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
 }
 
+/*
+ * Detects the endpoints and ports of Roland devices.
+ */
+static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi,
+                                    struct snd_usb_midi_endpoint_info* endpoint)
+{
+       struct usb_interface* intf;
+       struct usb_host_interface *hostif;
+       u8* cs_desc;
+
+       intf = umidi->iface;
+       if (!intf)
+               return -ENOENT;
+       hostif = intf->altsetting;
+       /*
+        * Some devices have a descriptor <06 24 F1 02 <inputs> <outputs>>,
+        * some have standard class descriptors, or both kinds, or neither.
+        */
+       for (cs_desc = hostif->extra;
+            cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
+            cs_desc += cs_desc[0]) {
+               if (cs_desc[0] >= 6 &&
+                   cs_desc[1] == USB_DT_CS_INTERFACE &&
+                   cs_desc[2] == 0xf1 &&
+                   cs_desc[3] == 0x02) {
+                       endpoint->in_cables  = (1 << cs_desc[4]) - 1;
+                       endpoint->out_cables = (1 << cs_desc[5]) - 1;
+                       return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
+               } else if (cs_desc[0] >= 7 &&
+                          cs_desc[1] == USB_DT_CS_INTERFACE &&
+                          cs_desc[2] == UAC_HEADER) {
+                       return snd_usbmidi_get_ms_info(umidi, endpoint);
+               }
+       }
+
+       return -ENODEV;
+}
+
 /*
  * Creates the endpoints and their ports for Midiman devices.
  */
@@ -2162,6 +2233,9 @@ int snd_usbmidi_create(struct snd_card *card,
        case QUIRK_MIDI_YAMAHA:
                err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
                break;
+       case QUIRK_MIDI_ROLAND:
+               err = snd_usbmidi_detect_roland(umidi, &endpoints[0]);
+               break;
        case QUIRK_MIDI_MIDIMAN:
                umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
                memcpy(&endpoints[0], quirk->data,
index 6ad617b..8b5d2c5 100644 (file)
@@ -1349,7 +1349,7 @@ static void ua101_disconnect(struct usb_interface *interface)
        snd_card_disconnect(ua->card);
 
        /* make sure that there are no pending USB requests */
-       __list_for_each(midi, &ua->midi_list)
+       list_for_each(midi, &ua->midi_list)
                snd_usbmidi_disconnect(midi);
        abort_alsa_playback(ua);
        abort_alsa_capture(ua);
index 93b6e32..15b151e 100644 (file)
@@ -202,13 +202,11 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
                       struct usb_host_interface *alts,
                       struct audioformat *fmt)
 {
-       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
        /* if endpoint doesn't have pitch control, bail out */
        if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
                return 0;
 
-       switch (altsd->bInterfaceProtocol) {
+       switch (fmt->protocol) {
        case UAC_VERSION_1:
        default:
                return init_pitch_v1(chip, iface, alts, fmt);
@@ -300,6 +298,35 @@ static int deactivate_endpoints(struct snd_usb_substream *subs)
        return 0;
 }
 
+static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
+                                    unsigned int altsetting,
+                                    struct usb_host_interface **alts,
+                                    unsigned int *ep)
+{
+       struct usb_interface *iface;
+       struct usb_interface_descriptor *altsd;
+       struct usb_endpoint_descriptor *epd;
+
+       iface = usb_ifnum_to_if(dev, ifnum);
+       if (!iface || iface->num_altsetting < altsetting + 1)
+               return -ENOENT;
+       *alts = &iface->altsetting[altsetting];
+       altsd = get_iface_desc(*alts);
+       if (altsd->bAlternateSetting != altsetting ||
+           altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+           (altsd->bInterfaceSubClass != 2 &&
+            altsd->bInterfaceProtocol != 2   ) ||
+           altsd->bNumEndpoints < 1)
+               return -ENOENT;
+       epd = get_endpoint(*alts, 0);
+       if (!usb_endpoint_is_isoc_in(epd) ||
+           (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
+                                       USB_ENDPOINT_USAGE_IMPLICIT_FB)
+               return -ENOENT;
+       *ep = epd->bEndpointAddress;
+       return 0;
+}
+
 /*
  * find a matching format and set up the interface
  */
@@ -395,6 +422,18 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                        goto add_sync_ep;
                }
        }
+       if (is_playback &&
+           attr == USB_ENDPOINT_SYNC_ASYNC &&
+           altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+           altsd->bInterfaceProtocol == 2 &&
+           altsd->bNumEndpoints == 1 &&
+           USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
+           search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
+                                     altsd->bAlternateSetting,
+                                     &alts, &ep) >= 0) {
+               implicit_fb = 1;
+               goto add_sync_ep;
+       }
 
        if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
             (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
index 8b75bcf..9c636c2 100644 (file)
@@ -461,6 +461,17 @@ YAMAHA_DEVICE(0x7000, "DTX"),
 YAMAHA_DEVICE(0x7010, "UB99"),
 #undef YAMAHA_DEVICE
 #undef YAMAHA_INTERFACE
+/* this catches most recent vendor-specific Yamaha devices */
+{
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+                      USB_DEVICE_ID_MATCH_INT_CLASS,
+       .idVendor = 0x0499,
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUTODETECT
+       }
+},
 
 /*
  * Roland/RolandED/Edirol/BOSS devices
@@ -1136,7 +1147,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-       /* TODO: add Roland M-1000 support */
 {
        /*
         * Has ID 0x0038 when not in "Advanced Driver" mode;
@@ -1251,7 +1261,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-       /* TODO: add Edirol M-100FX support */
 {
        /* has ID 0x004e when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x004c),
@@ -1370,20 +1379,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       /* has ID 0x006b when not in "Advanced Driver" mode */
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "SP-606",
-               .ifnum = 3,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
-               }
-       }
-},
 {
        /* has ID 0x006e when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x006d),
@@ -1471,8 +1466,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-       /* TODO: add Roland V-SYNTH XT support */
-       /* TODO: add BOSS GT-PRO support */
 {
        /* has ID 0x008c when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x008b),
@@ -1486,42 +1479,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        .in_cables  = 0x0001
                }
        }
-},
-       /* TODO: add Edirol PC-80 support */
-{
-       USB_DEVICE(0x0582, 0x0096),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "UA-1EX",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x009a),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "UM-3EX",
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x000f,
-                       .in_cables  = 0x000f
-               }
-       }
 },
 {
        /*
@@ -1552,125 +1509,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        }
                }
        }
-},
-       /* TODO: add Edirol MD-P1 support */
-{
-       USB_DEVICE(0x582, 0x00a6),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "Juno-G",
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
-               }
-       }
-},
-{
-       /* Roland SH-201 */
-       USB_DEVICE(0x0582, 0x00ad),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "SH-201",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       /* Advanced mode of the Roland VG-99, with MIDI and 24-bit PCM at 44.1
-        * kHz. In standard mode, the device has ID 0582:00b3, and offers
-        * 16-bit PCM at 44.1 kHz with no MIDI.
-        */
-       USB_DEVICE(0x0582, 0x00b2),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "VG-99",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0003,
-                                       .in_cables  = 0x0003
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       /* Roland SonicCell */
-       USB_DEVICE(0x0582, 0x00c2),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "SonicCell",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
 },
 {
        /* Edirol M-16DX */
-       /* FIXME: This quirk gives a good-working capture stream but the
-        *        playback seems problematic because of lacking of sync
-        *        with capture stream.  It needs to sync with the capture
-        *        clock.  As now, you'll get frequent sound distortions
-        *        via the playback.
-        */
        USB_DEVICE(0x0582, 0x00c4),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
@@ -1698,35 +1539,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       /* BOSS GT-10 */
-       USB_DEVICE(0x0582, 0x00da),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
 {
        /* Advanced modes of the Edirol UA-25EX.
         * For the standard mode, UA-25EX has ID 0582:00e7, which
@@ -1757,42 +1569,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       /* has ID 0x00ea when not in Advanced Driver mode */
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "Roland", */
-               /* .product_name = "UA-1G", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x0104),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "Roland", */
-               /* .product_name = "UM-1G", */
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
-               }
-       }
-},
 {
        /* Edirol UM-3G */
        USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),
@@ -1806,92 +1582,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
-       /* Boss JS-8 Jam Station  */
-       USB_DEVICE(0x0582, 0x0109),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "JS-8", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       /* has ID 0x0110 when not in Advanced Driver mode */
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+       /* only 44.1 kHz works at the moment */
+       USB_DEVICE(0x0582, 0x0120),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                /* .vendor_name = "Roland", */
-               /* .product_name = "A-PRO", */
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0003,
-                       .in_cables  = 0x0007
-               }
-       }
-},
-{
-       /* Roland GAIA SH-01 */
-       USB_DEVICE(0x0582, 0x0111),
-       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "GAIA",
+               /* .product_name = "OCTO-CAPTURE", */
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = &(const struct snd_usb_midi_endpoint_info) {
-                               .out_cables = 0x0003,
-                               .in_cables  = 0x0003
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 10,
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x05,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
                                }
                        },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x0113),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "ME-25", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 12,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x85,
+                                       .ep_attr = 0x25,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
                        },
                        {
                                .ifnum = 2,
@@ -1902,30 +1635,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                }
                        },
                        {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x0127),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "Roland", */
-               /* .product_name = "GR-55", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .ifnum = 3,
+                               .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_STANDARD_INTERFACE
+                               .ifnum = 4,
+                               .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
                                .ifnum = -1
@@ -1934,34 +1649,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
-       /* Added support for Roland UM-ONE which differs from UM-1 */
-       USB_DEVICE(0x0582, 0x012a),
+       /* only 44.1 kHz works at the moment */
+       USB_DEVICE(0x0582, 0x012f),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "ROLAND", */
-               /* .product_name = "UM-ONE", */
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0003
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x011e),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "BR-800", */
+               /* .vendor_name = "Roland", */
+               /* .product_name = "QUAD-CAPTURE", */
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 4,
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x05,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 6,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x85,
+                                       .ep_attr = 0x25,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
                        },
                        {
                                .ifnum = 2,
@@ -1972,38 +1702,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                }
                        },
                        {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x0130),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "MICRO BR-80", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
+                               .ifnum = 3,
                                .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 3,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
+                               .ifnum = 4,
+                               .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
                                .ifnum = -1
@@ -2011,34 +1715,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+/* this catches most recent vendor-specific Roland devices */
 {
-       USB_DEVICE(0x0582, 0x014d),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "GT-100", */
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+                      USB_DEVICE_ID_MATCH_INT_CLASS,
+       .idVendor = 0x0582,
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 3,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
+               .type = QUIRK_AUTODETECT
        }
 },
 
index 3879eae..5b01330 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
 
 #include <sound/control.h>
 #include <sound/core.h>
@@ -175,6 +176,212 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        return 0;
 }
 
+static int create_auto_pcm_quirk(struct snd_usb_audio *chip,
+                                struct usb_interface *iface,
+                                struct usb_driver *driver)
+{
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct usb_endpoint_descriptor *epd;
+       struct uac1_as_header_descriptor *ashd;
+       struct uac_format_type_i_discrete_descriptor *fmtd;
+
+       /*
+        * Most Roland/Yamaha audio streaming interfaces have more or less
+        * standard descriptors, but older devices might lack descriptors, and
+        * future ones might change, so ensure that we fail silently if the
+        * interface doesn't look exactly right.
+        */
+
+       /* must have a non-zero altsetting for streaming */
+       if (iface->num_altsetting < 2)
+               return -ENODEV;
+       alts = &iface->altsetting[1];
+       altsd = get_iface_desc(alts);
+
+       /* must have an isochronous endpoint for streaming */
+       if (altsd->bNumEndpoints < 1)
+               return -ENODEV;
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_xfer_isoc(epd))
+               return -ENODEV;
+
+       /* must have format descriptors */
+       ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+                                      UAC_AS_GENERAL);
+       fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+                                      UAC_FORMAT_TYPE);
+       if (!ashd || ashd->bLength < 7 ||
+           !fmtd || fmtd->bLength < 8)
+               return -ENODEV;
+
+       return create_standard_audio_quirk(chip, iface, driver, NULL);
+}
+
+static int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
+                                   struct usb_interface *iface,
+                                   struct usb_driver *driver,
+                                   struct usb_host_interface *alts)
+{
+       static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
+               .type = QUIRK_MIDI_YAMAHA
+       };
+       struct usb_midi_in_jack_descriptor *injd;
+       struct usb_midi_out_jack_descriptor *outjd;
+
+       /* must have some valid jack descriptors */
+       injd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+                                      NULL, USB_MS_MIDI_IN_JACK);
+       outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+                                       NULL, USB_MS_MIDI_OUT_JACK);
+       if (!injd && !outjd)
+               return -ENODEV;
+       if (injd && (injd->bLength < 5 ||
+                    (injd->bJackType != USB_MS_EMBEDDED &&
+                     injd->bJackType != USB_MS_EXTERNAL)))
+               return -ENODEV;
+       if (outjd && (outjd->bLength < 6 ||
+                     (outjd->bJackType != USB_MS_EMBEDDED &&
+                      outjd->bJackType != USB_MS_EXTERNAL)))
+               return -ENODEV;
+       return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk);
+}
+
+static int create_roland_midi_quirk(struct snd_usb_audio *chip,
+                                   struct usb_interface *iface,
+                                   struct usb_driver *driver,
+                                   struct usb_host_interface *alts)
+{
+       static const struct snd_usb_audio_quirk roland_midi_quirk = {
+               .type = QUIRK_MIDI_ROLAND
+       };
+       u8 *roland_desc = NULL;
+
+       /* might have a vendor-specific descriptor <06 24 F1 02 ...> */
+       for (;;) {
+               roland_desc = snd_usb_find_csint_desc(alts->extra,
+                                                     alts->extralen,
+                                                     roland_desc, 0xf1);
+               if (!roland_desc)
+                       return -ENODEV;
+               if (roland_desc[0] < 6 || roland_desc[3] != 2)
+                       continue;
+               return create_any_midi_quirk(chip, iface, driver,
+                                            &roland_midi_quirk);
+       }
+}
+
+static int create_std_midi_quirk(struct snd_usb_audio *chip,
+                                struct usb_interface *iface,
+                                struct usb_driver *driver,
+                                struct usb_host_interface *alts)
+{
+       struct usb_ms_header_descriptor *mshd;
+       struct usb_ms_endpoint_descriptor *msepd;
+
+       /* must have the MIDIStreaming interface header descriptor*/
+       mshd = (struct usb_ms_header_descriptor *)alts->extra;
+       if (alts->extralen < 7 ||
+           mshd->bLength < 7 ||
+           mshd->bDescriptorType != USB_DT_CS_INTERFACE ||
+           mshd->bDescriptorSubtype != USB_MS_HEADER)
+               return -ENODEV;
+       /* must have the MIDIStreaming endpoint descriptor*/
+       msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra;
+       if (alts->endpoint[0].extralen < 4 ||
+           msepd->bLength < 4 ||
+           msepd->bDescriptorType != USB_DT_CS_ENDPOINT ||
+           msepd->bDescriptorSubtype != UAC_MS_GENERAL ||
+           msepd->bNumEmbMIDIJack < 1 ||
+           msepd->bNumEmbMIDIJack > 16)
+               return -ENODEV;
+
+       return create_any_midi_quirk(chip, iface, driver, NULL);
+}
+
+static int create_auto_midi_quirk(struct snd_usb_audio *chip,
+                                 struct usb_interface *iface,
+                                 struct usb_driver *driver)
+{
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct usb_endpoint_descriptor *epd;
+       int err;
+
+       alts = &iface->altsetting[0];
+       altsd = get_iface_desc(alts);
+
+       /* must have at least one bulk/interrupt endpoint for streaming */
+       if (altsd->bNumEndpoints < 1)
+               return -ENODEV;
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_xfer_bulk(epd) ||
+           !usb_endpoint_xfer_int(epd))
+               return -ENODEV;
+
+       switch (USB_ID_VENDOR(chip->usb_id)) {
+       case 0x0499: /* Yamaha */
+               err = create_yamaha_midi_quirk(chip, iface, driver, alts);
+               if (err < 0 && err != -ENODEV)
+                       return err;
+               break;
+       case 0x0582: /* Roland */
+               err = create_roland_midi_quirk(chip, iface, driver, alts);
+               if (err < 0 && err != -ENODEV)
+                       return err;
+               break;
+       }
+
+       return create_std_midi_quirk(chip, iface, driver, alts);
+}
+
+static int create_autodetect_quirk(struct snd_usb_audio *chip,
+                                  struct usb_interface *iface,
+                                  struct usb_driver *driver)
+{
+       int err;
+
+       err = create_auto_pcm_quirk(chip, iface, driver);
+       if (err == -ENODEV)
+               err = create_auto_midi_quirk(chip, iface, driver);
+       return err;
+}
+
+static int create_autodetect_quirks(struct snd_usb_audio *chip,
+                                   struct usb_interface *iface,
+                                   struct usb_driver *driver,
+                                   const struct snd_usb_audio_quirk *quirk)
+{
+       int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
+       int ifcount, ifnum, err;
+
+       err = create_autodetect_quirk(chip, iface, driver);
+       if (err < 0)
+               return err;
+
+       /*
+        * ALSA PCM playback/capture devices cannot be registered in two steps,
+        * so we have to claim the other corresponding interface here.
+        */
+       ifcount = chip->dev->actconfig->desc.bNumInterfaces;
+       for (ifnum = 0; ifnum < ifcount; ifnum++) {
+               if (ifnum == probed_ifnum || quirk->ifnum >= 0)
+                       continue;
+               iface = usb_ifnum_to_if(chip->dev, ifnum);
+               if (!iface ||
+                   usb_interface_claimed(iface) ||
+                   get_iface_desc(iface->altsetting)->bInterfaceClass !=
+                                                       USB_CLASS_VENDOR_SPEC)
+                       continue;
+
+               err = create_autodetect_quirk(chip, iface, driver);
+               if (err >= 0)
+                       usb_driver_claim_interface(driver, iface, (void *)-1L);
+       }
+
+       return 0;
+}
+
 /*
  * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.  
  * The only way to detect the sample rate is by looking at wMaxPacketSize.
@@ -303,9 +510,11 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
        static const quirk_func_t quirk_funcs[] = {
                [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
                [QUIRK_COMPOSITE] = create_composite_quirk,
+               [QUIRK_AUTODETECT] = create_autodetect_quirks,
                [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
                [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
                [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
+               [QUIRK_MIDI_ROLAND] = create_any_midi_quirk,
                [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
                [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
                [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
index 7db2f89..c4339f9 100644 (file)
@@ -493,10 +493,10 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                altsd = get_iface_desc(alts);
                protocol = altsd->bInterfaceProtocol;
                /* skip invalid one */
-               if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+               if (((altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+                     (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
+                      altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC)) &&
                     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
-                   (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
-                    altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
                    altsd->bNumEndpoints < 1 ||
                    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
                        continue;
@@ -512,6 +512,15 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
                        continue;
 
+               /*
+                * Roland audio streaming interfaces are marked with protocols
+                * 0/1/2, but are UAC 1 compatible.
+                */
+               if (USB_ID_VENDOR(chip->usb_id) == 0x0582 &&
+                   altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+                   protocol <= 2)
+                       protocol = UAC_VERSION_1;
+
                chconfig = 0;
                /* get audio formats */
                switch (protocol) {
@@ -635,6 +644,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
                fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
                fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+               fp->protocol = protocol;
                fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
                fp->channels = num_channels;
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
@@ -676,7 +686,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                }
 
                /* ok, let's parse further... */
-               if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
+               if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) {
                        kfree(fp->rate_table);
                        kfree(fp->chmap);
                        kfree(fp);
index bc43bca..caabe9b 100644 (file)
@@ -72,9 +72,11 @@ struct snd_usb_audio {
 enum quirk_type {
        QUIRK_IGNORE_INTERFACE,
        QUIRK_COMPOSITE,
+       QUIRK_AUTODETECT,
        QUIRK_MIDI_STANDARD_INTERFACE,
        QUIRK_MIDI_FIXED_ENDPOINT,
        QUIRK_MIDI_YAMAHA,
+       QUIRK_MIDI_ROLAND,
        QUIRK_MIDI_MIDIMAN,
        QUIRK_MIDI_NOVATION,
        QUIRK_MIDI_RAW_BYTES,
index 9af7c1f..1f9bbd5 100644 (file)
 MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
 MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
+MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604),"NAME_ALLCAPS"(0x8001)(0x8005)(0x8007)}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
index b376532..4967fe9 100644 (file)
@@ -695,9 +695,6 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
                        ((char*)(usbdata + i))[1] = ra[i].c2;
                        usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4),
                                          usbdata + i, 2, i_usX2Y_04Int, usX2Y);
-#ifdef OLD_USB
-                       us->urb[i]->transfer_flags = USB_QUEUE_BULK;
-#endif
                }
                us->submitted = 0;
                us->len =       NOOF_SETRATE_URBS;